UNPKG

agda-web-docs-lib

Version:

Library for enhancing Agda-generated HTML documentation

259 lines 10.5 kB
#!/usr/bin/env node "use strict"; 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