/** * dev command * Development workflow commands * Generated from SpecVerse specification */ import { Command } from 'commander'; import { readFileSync, writeFileSync, watch } from 'fs'; import { EngineRegistry } from '@specverse/entities'; import type { ParserEngine } from '@specverse/types'; /** * Register the dev command on the program. */ export function registerDevCommand(program: Command): void { const cmd = program .command('dev') .description('Development workflow commands'); cmd .command('format ') .description('Format a .specly file with consistent styling') .option('-w, --write', 'Write formatted output back to file', false) .action(async (file: string, options: any) => { try { const registry = new EngineRegistry(); await registry.discover(); const parser = registry.getEngineForCapability('parse') as ParserEngine; if (!parser) { console.error('No parser engine found.'); process.exit(1); } await parser.initialize(); const content = readFileSync(file, 'utf8'); const result = parser.parseContent(content, file); if (result.errors.length > 0) { console.error('Cannot format invalid spec:'); result.errors.forEach((e: string) => console.error(' ', e)); process.exit(1); } const yaml = await import('js-yaml'); const formatted = yaml.dump(yaml.load(content), { lineWidth: 120, noRefs: true }); if (options.write) { writeFileSync(file, formatted); console.log('Formatted and saved: ' + file); } else { console.log(formatted); } } catch (error: any) { console.error('Error:', error.message); process.exit(1); } }); cmd .command('watch ') .description('Watch .specly files and re-validate on change') .action(async (file: string, _options: any) => { try { const registry = new EngineRegistry(); await registry.discover(); const parser = registry.getEngineForCapability('parse') as ParserEngine; if (!parser) { console.error('No parser engine found.'); process.exit(1); } await parser.initialize(); console.log('Watching ' + file + ' for changes...'); const doValidate = () => { try { const c = readFileSync(file, 'utf8'); const r = parser.parseContent(c, file); if (r.errors.length > 0) { console.log('[' + new Date().toLocaleTimeString() + '] FAILED'); r.errors.forEach((e: string) => console.error(' ', e)); } else { console.log('[' + new Date().toLocaleTimeString() + '] Valid'); } } catch (e: any) { console.error('Watch error:', e.message); } }; doValidate(); watch(file, doValidate); await new Promise(() => {}); } catch (error: any) { console.error('Error:', error.message); process.exit(1); } }); cmd .command('quick ') .description('Quick validation (schema-only, skip semantic checks)') .action(async (file: string, _options: any) => { try { const registry = new EngineRegistry(); await registry.discover(); const parser = registry.getEngineForCapability('parse') as ParserEngine; if (!parser) { console.error('No parser engine found.'); process.exit(1); } await parser.initialize(); const content = readFileSync(file, 'utf8'); const result = parser.parseContent(content, file); if (result.errors.length > 0) { console.error('Quick check: FAILED'); result.errors.forEach((e: string) => console.error(' ', e)); process.exit(1); } console.log('Quick check: OK'); } catch (error: any) { console.error('Error:', error.message); process.exit(1); } }); }