UNPKG

ctx-gen

Version:

AI-Enhanced Documentation Generator for Code Understanding

203 lines 8.12 kB
import fs from 'fs-extra'; import path from 'path'; import { glob } from 'glob'; import { writeFileWithDir } from '../utils/fileUtils.js'; /** * Generate machine-readable documentation for AI consumption * @param options - CtxGen options */ export async function generateMachineReadable(options) { // Get all markdown files const moduleDocs = await glob('**/*.md', { cwd: path.join(options.docsDir, 'modules'), ignore: ['index.md'] }); // Convert to machine-readable formats await generateAnalysisJson(options, moduleDocs); } /** * Generate an analysis JSON file with structured information about the codebase * @param options - CtxGen options * @param moduleDocs - Array of module documentation file paths */ async function generateAnalysisJson(options, moduleDocs) { // Create analysis object with basic structure const analysis = { projectInfo: {}, modules: {}, functions: {}, classes: {}, dependencies: {} }; // Get project metadata if it exists try { const metadataPath = path.join(options.docsDir, 'metadata.json'); if (await fs.pathExists(metadataPath)) { analysis.projectInfo = await fs.readJSON(metadataPath); } } catch (error) { console.error('Error reading metadata:', error); } // Process each module document for (const doc of moduleDocs) { try { // Read the markdown content const content = await fs.readFile(path.join(options.docsDir, 'modules', doc), 'utf-8'); // Extract module information const moduleName = path.basename(doc, '.md'); const moduleInfo = extractModuleInfo(content, moduleName); // Add to analysis analysis.modules[moduleName] = moduleInfo.module; // Add functions Object.entries(moduleInfo.functions).forEach(([funcName, funcInfo]) => { analysis.functions[`${moduleName}.${funcName}`] = { module: moduleName, name: funcInfo.name, description: funcInfo.description, parameters: funcInfo.parameters, returnType: funcInfo.returnType }; }); // Add classes Object.entries(moduleInfo.classes).forEach(([className, classInfo]) => { analysis.classes[`${moduleName}.${className}`] = { module: moduleName, name: classInfo.name, description: classInfo.description, methods: classInfo.methods, properties: classInfo.properties }; }); // Add dependencies if (moduleInfo.dependencies.length > 0) { analysis.dependencies[moduleName] = moduleInfo.dependencies; } } catch (error) { console.error(`Error processing ${doc} for analysis:`, error); } } // Write analysis to file const analysisPath = path.join(options.docsDir, 'analysis.json'); await writeFileWithDir(analysisPath, JSON.stringify(analysis, null, 2)); } /** * Extract module information from markdown content * @param content - Markdown content * @param moduleName - Module name * @returns Extracted module information */ function extractModuleInfo(content, moduleName) { // Initialize result object const result = { module: { name: moduleName, description: '', filePath: '', language: '' }, functions: {}, classes: {}, dependencies: [] }; // Extract file path and language const filePathMatch = content.match(/\*\*File Path:\*\* `([^`]+)`/); if (filePathMatch) { result.module.filePath = filePathMatch[1]; } const languageMatch = content.match(/\*\*Language:\*\* ([^\n]+)/); if (languageMatch) { result.module.language = languageMatch[1]; } // Extract module description const overviewMatch = content.match(/## Overview\s*\n\n([^\n]+)/); if (overviewMatch) { result.module.description = overviewMatch[1]; } // Extract enhanced description if available const aiMatch = content.match(/## AI-Enhanced Analysis\s*\n\n([\s\S]+?)(?=\n##|$)/); if (aiMatch) { // Extract the first paragraph of AI analysis const firstParagraph = aiMatch[1].split('\n\n')[0]; if (firstParagraph && firstParagraph.length > result.module.description.length) { result.module.description = firstParagraph; } // Try to extract functions const functionMatch = aiMatch[1].match(/(?:## |###) Functions\/Methods\s*\n\n([\s\S]+?)(?=\n##|$)/); if (functionMatch) { // Simple function extraction using bullet points/headers const functionSection = functionMatch[1]; // Extract function names with descriptions const functionRegex = /[*-] \*\*`([^`]+)`\*\*: ([^\n]+)/g; let match; while ((match = functionRegex.exec(functionSection)) !== null) { const functionName = match[1]; const description = match[2]; result.functions[functionName] = { name: functionName, description: description, parameters: [], returnType: '' }; } // Also try alternative function format with headers const headerFunctionRegex = /### `([^`]+)`\s*\n\n([^\n]+)/g; while ((match = headerFunctionRegex.exec(functionSection)) !== null) { const functionName = match[1]; const description = match[2]; result.functions[functionName] = { name: functionName, description: description, parameters: [], returnType: '' }; } } // Try to extract classes const classMatch = aiMatch[1].match(/(?:## |###) Classes\/Objects\s*\n\n([\s\S]+?)(?=\n##|$)/); if (classMatch) { // Simple class extraction using bullet points/headers const classSection = classMatch[1]; // Extract class names with descriptions const classRegex = /[*-] \*\*`([^`]+)`\*\*: ([^\n]+)/g; let match; while ((match = classRegex.exec(classSection)) !== null) { const className = match[1]; const description = match[2]; result.classes[className] = { name: className, description: description, methods: [], properties: [] }; } // Also try alternative class format with headers const headerClassRegex = /### `([^`]+)`\s*\n\n([^\n]+)/g; while ((match = headerClassRegex.exec(classSection)) !== null) { const className = match[1]; const description = match[2]; result.classes[className] = { name: className, description: description, methods: [], properties: [] }; } } // Try to extract dependencies const dependencyMatch = aiMatch[1].match(/(?:## |###) Dependencies\s*\n\n([\s\S]+?)(?=\n##|$)/); if (dependencyMatch) { // Simple dependency extraction using bullet points const dependencySection = dependencyMatch[1]; // Extract dependency names const dependencyRegex = /[*-] \*\*`([^`]+)`\*\*:/g; let match; while ((match = dependencyRegex.exec(dependencySection)) !== null) { result.dependencies.push(match[1]); } } } return result; } //# sourceMappingURL=machineReadableGenerator.js.map