agda-web-docs-lib
Version:
Library for enhancing Agda-generated HTML documentation
259 lines • 10.5 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
const commander_1 = require("commander");
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const indexer_1 = require("./indexer");
const search_1 = require("./search");
const transformer_1 = require("./transformer");
const program = new commander_1.Command();
// Default config file names to look for
const DEFAULT_CONFIG_FILES = ['agda-docs.config.json'];
function findConfigFile() {
const currentDir = process.cwd();
for (const configFile of DEFAULT_CONFIG_FILES) {
const configPath = path.join(currentDir, configFile);
if (fs.existsSync(configPath)) {
return configPath;
}
}
return null;
}
// Simple direct file processing without workers
async function processFiles(inputDir, outputDir, files, config, progressCallback) {
// Create transformer with config
const transformer = new transformer_1.AgdaDocsTransformer(config);
let processedCount = 0;
for (const file of files) {
try {
const inputPath = path.join(inputDir, file);
const outputPath = path.join(outputDir, file);
const content = fs.readFileSync(inputPath, 'utf8');
// Process the file
transformer.setContent(content, file);
const processed = transformer.transform();
// Ensure output directory exists
const outputDirForFile = path.dirname(outputPath);
if (!fs.existsSync(outputDirForFile)) {
fs.mkdirSync(outputDirForFile, { recursive: true });
}
fs.writeFileSync(outputPath, processed);
processedCount++;
progressCallback(processedCount, files.length);
}
catch (error) {
console.error(`Error processing ${file}:`, error);
throw error;
}
}
}
/**
* Creates a progress bar in the terminal
*/
function createProgressBar(width = 40) {
return (current, total) => {
const percent = Math.round((current / total) * 100);
const barLength = Math.round((current / total) * width);
const bar = '='.repeat(barLength) + ' '.repeat(width - barLength);
// Clear line and update progress bar
process.stdout.write(`\r[${bar}] ${percent}% (${current}/${total})`);
// Add a newline when complete
if (current === total) {
process.stdout.write('\n');
}
};
}
/**
* Copies script and style assets to the output directory
*/
function copyAssets(outputDir) {
// Find all script and style files
const possibleScriptDirs = [
// Production path (when installed as a package)
path.join(__dirname, 'scripts'),
// Development path
path.join(__dirname, '..', 'src', 'scripts'),
// Alternative development path
path.join(__dirname, '..', '..', 'src', 'scripts'),
];
const possibleStyleDirs = [
// Production path (when installed as a package)
path.join(__dirname, 'styles'),
// Development path
path.join(__dirname, '..', 'src', 'styles'),
// Alternative development path
path.join(__dirname, '..', '..', 'src', 'styles'),
];
// Find the first existing scripts directory
let scriptsDir = null;
for (const dir of possibleScriptDirs) {
if (fs.existsSync(dir)) {
scriptsDir = dir;
break;
}
}
// Find the first existing styles directory
let stylesDir = null;
for (const dir of possibleStyleDirs) {
if (fs.existsSync(dir)) {
stylesDir = dir;
break;
}
}
// Copy all JavaScript files from the scripts directory
if (scriptsDir) {
try {
const scriptFiles = fs.readdirSync(scriptsDir).filter((file) => file.endsWith('.js'));
for (const file of scriptFiles) {
const sourcePath = path.join(scriptsDir, file);
const destPath = path.join(outputDir, file);
fs.copyFileSync(sourcePath, destPath);
console.log(`Copied script: ${file}`);
}
}
catch (error) {
console.warn(`Warning: Could not copy script files: ${error}`);
}
}
else {
console.warn('Warning: Could not find scripts directory');
}
// Copy all CSS files from the styles directory
if (stylesDir) {
try {
const styleFiles = fs.readdirSync(stylesDir).filter((file) => file.endsWith('.css'));
for (const file of styleFiles) {
const sourcePath = path.join(stylesDir, file);
const destPath = path.join(outputDir, file);
fs.copyFileSync(sourcePath, destPath);
console.log(`Copied style: ${file}`);
}
}
catch (error) {
console.warn(`Warning: Could not copy style files: ${error}`);
}
}
else {
console.warn('Warning: Could not find styles directory');
}
}
program
.name('agda-docs')
.description('Process Agda-generated HTML documentation')
.version('0.1.0')
.command('process')
.description('Process Agda HTML files with custom navigation')
.option('-c, --config <path>', 'Path to config file (defaults to agda-docs.config.json in current directory)')
.option('-i, --input <path>', 'Input directory containing HTML files', '.')
.option('-o, --output <path>', 'Output directory for processed files (defaults to input directory)')
.action(async (options) => {
try {
// Find config file
let configPath = options.config;
if (!configPath) {
configPath = findConfigFile();
if (!configPath) {
console.error('Error: No config file found. Please specify a config file with -c or place agda-docs.config.json in the current directory');
process.exit(1);
}
console.log('Using config file:', configPath);
}
// Read and parse config
if (!fs.existsSync(configPath)) {
console.error('Error: Config file not found at', configPath);
process.exit(1);
}
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
// Ensure input directory exists
const inputDir = path.resolve(options.input);
if (!fs.existsSync(inputDir)) {
console.error('Error: Input directory not found at', inputDir);
process.exit(1);
}
// Create output directory if it doesn't exist - default to input dir if not specified
const outputDir = path.resolve(options.output || options.input);
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
// Ensure config has required inputDir property
const agdaConfig = {
...config,
inputDir: inputDir,
};
// Get list of HTML files
const files = fs.readdirSync(inputDir).filter((file) => file.endsWith('.html'));
if (files.length === 0) {
console.error('Error: No HTML files found in input directory');
process.exit(1);
}
console.log(`Found ${files.length} HTML files to process`);
// Build position mappings BEFORE processing files so transformation can use them
const indexingProgressBar = createProgressBar();
await indexer_1.AgdaDocsIndexer.buildPositionMappings(inputDir, indexingProgressBar);
// Copy assets to output directory first
console.log('Copying scripts and styles to output directory...');
copyAssets(outputDir);
// Process files using memory-efficient batching
console.log('Processing HTML files ...');
const processingProgressBar = createProgressBar();
await processFiles(inputDir, outputDir, files, agdaConfig, processingProgressBar);
// Build search index after processing using the existing position mappings
const searchIndex = await search_1.AgdaDocsSearcher.buildSearchIndex(indexer_1.AgdaDocsIndexer.getGlobalMappings(), outputDir);
search_1.AgdaDocsSearcher.writeSearchIndex(outputDir, searchIndex);
// Copy search script to output directory
console.log('Copying search script to output directory...');
const searchScriptPath = search_1.AgdaDocsSearcher.getSearchScriptPath();
if (searchScriptPath) {
fs.copyFileSync(searchScriptPath, path.join(outputDir, 'search.js'));
}
else {
console.warn('Warning: Could not find search script to copy');
}
console.log('Successfully processed', files.length, 'HTML files');
}
catch (error) {
if (error instanceof Error) {
console.error('Error:', error.message);
}
else {
console.error('An unknown error occurred');
}
process.exit(1);
}
});
program.parse();
//# sourceMappingURL=cli.js.map