structure-validation
Version:
A Node.js CLI tool for validating codebase folder and file structure using a clean declarative configuration. Part of the guardz ecosystem for comprehensive TypeScript development.
164 lines ⢠7 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const yargs_1 = __importDefault(require("yargs"));
const helpers_1 = require("yargs/helpers");
const ValidationOrchestrator_1 = require("../application/services/ValidationOrchestrator");
const OutputFormatter_1 = require("../infrastructure/output/OutputFormatter");
const AutoFixService_1 = require("../application/services/AutoFixService");
const InteractiveFixService_1 = require("../application/services/InteractiveFixService");
/**
* CLI entry point for structure-validation
*/
async function main() {
const argv = await (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
.usage('$0 [options]', 'Validate codebase folder and file structure')
.option('scope', {
type: 'string',
description: 'Validation scope: all, staged, or changes',
choices: ['all', 'staged', 'changes'],
default: 'staged'
})
.option('files', {
type: 'array',
string: true,
description: 'Specific files to validate'
})
.option('config', {
type: 'string',
description: 'Path to configuration file',
default: 'structure-validation.config.json'
})
.option('fix', {
type: 'boolean',
description: 'Automatically fix file structure issues and update imports',
default: false
})
.option('dry-run', {
type: 'boolean',
description: 'Show what would be fixed without making changes',
default: false
})
.option('backup', {
type: 'boolean',
description: 'Create backup before auto-fixing',
default: true
})
.option('verify-root', {
type: 'boolean',
description: 'Enable verification of files in the root folder using {root} pattern',
default: false
})
.option('skip-error', {
type: 'boolean',
description: 'Skip interactive mode and continue on errors',
default: false
})
.help()
.alias('h', 'help')
.version()
.alias('v', 'version')
.argv;
try {
const orchestrator = new ValidationOrchestrator_1.ValidationOrchestrator(argv.config);
const formatter = new OutputFormatter_1.OutputFormatter();
const autoFixService = new AutoFixService_1.AutoFixService();
const interactiveFixService = new InteractiveFixService_1.InteractiveFixService();
let result;
if (argv.files && argv.files.length > 0) {
console.log('š Validating specific files...');
result = await orchestrator.validateSpecificFiles(argv.files, argv.verifyRoot);
}
else {
const scopeMessages = {
all: 'š Validating all files...',
staged: 'š Validating staged files...',
changes: 'š Validating all changed files...'
};
console.log(scopeMessages[argv.scope]);
result = await orchestrator.validateFilesByScope(argv.scope, argv.verifyRoot);
}
// Output the validation results
console.log(formatter.formatResult(result));
// Handle interactive mode if there are errors and --skip-error is not used
if (!result.isValid && !argv.skipError && !argv.fix && !argv.dryRun) {
console.log('\nš Starting interactive mode...');
await interactiveFixService.handleInteractiveMode([...result.errors], [...result.suggestions]);
return;
}
// Handle auto-fix if requested
if (argv.fix || argv.dryRun) {
if (result.suggestions.length > 0) {
console.log('\n' + '='.repeat(50));
// Create backup if requested
let backupDir = null;
if (argv.fix && argv.backup) {
try {
backupDir = await autoFixService.createBackup();
console.log(`š¾ Backup created: ${backupDir}`);
}
catch (error) {
console.error('ā Failed to create backup:', error instanceof Error ? error.message : String(error));
process.exit(1);
}
}
// Perform auto-fix
const dryRun = argv.dryRun || !argv.fix;
const fixResult = await autoFixService.autoFix(result.suggestions, dryRun);
// Output fix results
if (fixResult.fixed.length > 0) {
console.log('\nā
Fixed files:');
fixResult.fixed.forEach(message => console.log(` ${message}`));
}
if (fixResult.errors.length > 0) {
console.log('\nā Errors:');
fixResult.errors.forEach(error => console.log(` ${error}`));
}
// Output import update results
if (fixResult.importUpdates.length > 0) {
console.log('\nš Import updates:');
fixResult.importUpdates.forEach(update => console.log(` ${update}`));
}
if (fixResult.importErrors.length > 0) {
console.log('\nā Import update errors:');
fixResult.importErrors.forEach(error => console.log(` ${error}`));
}
console.log(fixResult.summary);
// If this was a dry run and there are fixes available, suggest running with --fix
if (dryRun && (fixResult.fixed.length > 0 || fixResult.importUpdates.length > 0)) {
console.log('\nš” To apply these changes, run:');
console.log(` npx structure-validation ${argv.scope !== 'staged' ? `--scope ${argv.scope}` : ''} --fix`);
}
}
else {
console.log('\nā
No files need fixing!');
}
}
// Exit with appropriate code (moved after interactive mode)
if (!result.isValid && !argv.fix && !argv.dryRun && !argv.skipError) {
process.exit(1);
}
}
catch (error) {
console.error('ā Error:', error instanceof Error ? error.message : String(error));
process.exit(1);
}
}
// Handle uncaught exceptions
process.on('uncaughtException', (error) => {
console.error('ā Uncaught Exception:', error.message);
process.exit(1);
});
process.on('unhandledRejection', (reason) => {
console.error('ā Unhandled Rejection:', reason);
process.exit(1);
});
// Run the CLI
main().catch((error) => {
console.error('ā Fatal Error:', error instanceof Error ? error.message : String(error));
process.exit(1);
});
//# sourceMappingURL=cli.js.map