Add generators: code, completion, and docs generators

This commit is contained in:
2026-01-30 07:10:13 +00:00
parent 72ae630c3f
commit 10f6b69507

View File

@@ -0,0 +1,135 @@
import * as fs from 'fs';
import * as path from 'path';
import Handlebars from 'handlebars';
import type { CLISpec } from '../types/spec.js';
const TEMPLATE_DIR = path.resolve(process.cwd(), 'src', 'templates');
function getTemplatePath(templateName: string): string {
return path.join(TEMPLATE_DIR, `${templateName}.handlebars`);
}
function getTemplateContent(templateName: string): string {
const templatePath = getTemplatePath(templateName);
if (!fs.existsSync(templatePath)) {
throw new Error(`Template not found: ${templatePath}`);
}
return fs.readFileSync(templatePath, 'utf-8');
}
function compileTemplate(content: string): Handlebars.TemplateDelegate {
Handlebars.registerHelper('escape', function (str: string) {
return str.replace(/"/g, '\\"').replace(/\n/g, ' ').replace(/\s+/g, ' ');
});
Handlebars.registerHelper('defaultValue', function (value: unknown) {
if (value === undefined || value === null) return '';
return String(value);
});
Handlebars.registerHelper('toJson', function (value: unknown) {
return JSON.stringify(value, null, 2);
});
return Handlebars.compile(content, { noEscape: true });
}
export interface DocsResult {
success: boolean;
content?: string;
error?: string;
}
export function generateManPage(spec: CLISpec): DocsResult {
try {
const templateContent = getTemplateContent('manpage');
const template = compileTemplate(templateContent);
const content = template({ spec });
return { success: true, content };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error during man page generation',
};
}
}
export function generateReadmeSection(spec: CLISpec): DocsResult {
try {
const content = `## ${spec.name}
${spec.description}
### Installation
\`\`\`bash
# For Node.js
npm install -g ${spec.bin || spec.name}
# For Python
pip install ${spec.bin || spec.name}
# For Go
go install github.com/${spec.author || 'user'}/${spec.bin || spec.name}@latest
# For Rust
cargo install ${spec.bin || spec.name}
\`\`\`
### Usage
\`\`\`bash
${spec.bin || spec.name} --help
${spec.bin || spec.name} --version
\`\`\`
### Commands
${spec.commands.map(cmd => `#### \`${cmd.name}\`
${cmd.description}
${cmd.options ? `**Options:**
${cmd.options.map(opt => `- \`--${opt.name}${opt.short ? `, -${opt.short}` : ''}\`: ${opt.description}`).join('\n')}
` : ''}`).join('\n')}
### Global Options
${spec.globalOptions?.map(opt => `- \`--${opt.name}${opt.short ? `, -${opt.short}` : ''}\`: ${opt.description}`).join('\n') || 'None'}
### Examples
${spec.examples?.map(ex => `**${ex.description}**
\`\`\`bash
${ex.command}
\`\`\`
${ex.output ? `Output:
\`\`\`
${ex.output}
\`\`\`
` : ''}`).join('\n') || 'No examples available.'}
### Version
${spec.version}
${spec.author ? `**Author:** ${spec.author}` : ''}
${spec.license ? `**License:** ${spec.license}` : ''}
`;
return { success: true, content };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error during README generation',
};
}
}
export function getManPageFileName(spec: CLISpec): string {
return `${spec.bin || spec.name}.1`;
}
export function getReadmeFileName(): string {
return 'CLI_DOCS.md';
}