credl-parser-evaluator
Version:
TypeScript-based CREDL Parser and Evaluator that processes CREDL files and outputs complete Intermediate Representations
285 lines ⢠13.5 kB
JavaScript
;
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 });
exports.createConvertCommand = createConvertCommand;
exports.executeConvertCommand = executeConvertCommand;
const commander_1 = require("commander");
const index_js_1 = require("../../api/index.js");
const path = __importStar(require("path"));
const fs = __importStar(require("fs/promises"));
// Error exit codes for different types of failures
var ExitCode;
(function (ExitCode) {
ExitCode[ExitCode["SUCCESS"] = 0] = "SUCCESS";
ExitCode[ExitCode["VALIDATION_ERROR"] = 1] = "VALIDATION_ERROR";
ExitCode[ExitCode["FILE_NOT_FOUND"] = 2] = "FILE_NOT_FOUND";
ExitCode[ExitCode["FILE_ACCESS_ERROR"] = 3] = "FILE_ACCESS_ERROR";
ExitCode[ExitCode["PARSING_ERROR"] = 4] = "PARSING_ERROR";
ExitCode[ExitCode["OUTPUT_ERROR"] = 5] = "OUTPUT_ERROR";
ExitCode[ExitCode["INVALID_ARGUMENTS"] = 6] = "INVALID_ARGUMENTS";
ExitCode[ExitCode["GENERAL_ERROR"] = 10] = "GENERAL_ERROR";
})(ExitCode || (ExitCode = {}));
function createConvertCommand() {
const convertCommand = new commander_1.Command('convert');
convertCommand
.description('Convert CREDL files to Intermediate Representation (IR)')
.argument('<file>', 'Path to the CREDL file to convert')
.option('-o, --output <path>', 'Output file path (default: console output)')
.option('-f, --format <format>', 'Output format: json, pretty', 'pretty')
.option('-q, --quiet', 'Suppress output except errors')
.option('-v, --verbose', 'Verbose output with detailed processing information')
.option('--fail-fast', 'Stop processing on first validation error')
.option('--include-metadata', 'Include processing metadata in IR', true)
.option('--resolve-presets', 'Resolve preset references', true)
.option('--resolve-templates', 'Resolve template definitions', true)
.option('--validate-references', 'Validate cross-references', true)
.option('--generate-ids', 'Generate unique IDs for elements', true)
.option('--skip-validation', 'Skip validation and generate IR from parsed content')
.action(async (filePath, options) => {
await executeConvertCommand(filePath, options);
});
return convertCommand;
}
async function executeConvertCommand(filePath, options) {
try {
// Validate file path and existence
await validateInputFile(filePath, options);
if (!options.quiet) {
console.log(`š Converting CREDL file to IR: ${filePath}`);
}
// Configure validation options
const validationOptions = {
failFast: options['fail-fast'] || false,
checkCrossReferences: options['validate-references'] !== false,
strict: false // Convert command uses standard validation by default
};
// Configure IR builder options
const irOptions = {
includeMetadata: options['include-metadata'] !== false,
resolvePresets: options['resolve-presets'] !== false,
resolveTemplates: options['resolve-templates'] !== false,
validateReferences: options['validate-references'] !== false,
generateIds: options['generate-ids'] !== false
};
if (options.verbose) {
console.log('š Conversion Configuration:');
console.log(` ⢠Skip validation: ${options['skip-validation'] ? 'yes' : 'no'}`);
console.log(` ⢠Presets: ${irOptions.resolvePresets ? 'enabled' : 'disabled'}`);
console.log(` ⢠Templates: ${irOptions.resolveTemplates ? 'enabled' : 'disabled'}`);
console.log(` ⢠Cross-references: ${irOptions.validateReferences ? 'enabled' : 'disabled'}`);
console.log(` ⢠Generate IDs: ${irOptions.generateIds ? 'enabled' : 'disabled'}`);
console.log(` ⢠Output format: ${options.format}`);
}
// Convert CREDL to IR with progress indicators
const startTime = Date.now();
if (options.verbose) {
console.log('š Starting CREDL to IR conversion pipeline...');
process.stdout.write(' š Parsing CREDL file... ');
}
// Step 1: Read and parse CREDL file
const fileContent = await fs.readFile(filePath, 'utf8');
const credlFile = await (0, index_js_1.parse)(fileContent);
if (options.verbose) {
console.log('ā
');
process.stdout.write(' š Validating structure... ');
}
// Step 2: Validate if not skipping validation
if (!options['skip-validation']) {
const validationResult = await (0, index_js_1.validate)(credlFile, validationOptions);
if (!validationResult.isValid) {
const errorDetails = validationResult.errors.map(error => `${error.field}: ${error.message}`).join('\n ⢠');
console.error(`ā Validation failed, cannot generate IR:\n ⢠${errorDetails}`);
console.error('\nš” Suggestions:');
console.error(' ⢠Review the CREDL specification to fix validation errors');
console.error(' ⢠Use --skip-validation to generate IR despite validation errors');
console.error(' ⢠Use --verbose flag for more detailed error information');
process.exit(ExitCode.VALIDATION_ERROR);
}
if (options.verbose && validationResult.warnings.length > 0) {
console.log(`ā ļø (${validationResult.warnings.length} warnings)`);
}
else if (options.verbose) {
console.log('ā
');
}
}
else if (options.verbose) {
console.log('āļø (skipped)');
}
if (options.verbose) {
process.stdout.write(' šļø Generating IR... ');
}
// Step 3: Generate IR
const ir = await (0, index_js_1.generateIR)(credlFile, irOptions);
const processingTime = Date.now() - startTime;
if (options.verbose) {
console.log('ā
');
console.log(` šÆ Conversion completed successfully`);
}
if (options.verbose) {
console.log(`ā±ļø Processing completed in ${processingTime}ms`);
console.log(`š Generated IR:`);
console.log(` ⢠Assets: ${ir.assets.length}`);
console.log(` ⢠Spaces: ${ir.spaces.length}`);
console.log(` ⢠Template-generated spaces: ${ir.template_generated_spaces?.length || 0}`);
console.log(` ⢠Assumptions: ${ir.assumptions.length}`);
console.log(` ⢠Models: ${ir.models.length}`);
console.log(` ⢠Resolution steps: ${ir.resolution_order.length}`);
if (ir.validation.warnings.length > 0) {
console.log(` ⢠Warnings: ${ir.validation.warnings.length}`);
}
}
// Format and output IR
if (options.verbose) {
process.stdout.write(' �� Formatting IR output... ');
}
const outputContent = formatIROutput(ir, options.format || 'pretty');
if (options.verbose) {
console.log('ā
');
}
if (options.output) {
try {
if (options.verbose) {
process.stdout.write(' š¾ Writing IR to file... ');
}
// Create output directory if it doesn't exist
const outputDir = path.dirname(options.output);
await fs.mkdir(outputDir, { recursive: true });
// Write to file
await fs.writeFile(options.output, outputContent, 'utf8');
if (options.verbose) {
console.log('ā
');
}
if (!options.quiet) {
console.log(`ā
IR written to: ${options.output}`);
}
}
catch (writeError) {
console.error(`ā Failed to write IR to file: ${options.output}`);
console.error(` Error: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
process.exit(ExitCode.OUTPUT_ERROR);
}
}
else {
// Output to console
if (!options.quiet && options.format !== 'json') {
console.log('š Generated IR:');
}
console.log(outputContent);
}
if (!options.quiet) {
console.log(`ā
Successfully converted CREDL to IR in ${processingTime}ms`);
}
}
catch (error) {
console.error('ā Error converting CREDL to IR:');
if (error instanceof Error) {
console.error(` ${error.message}`);
if (options.verbose && error.stack) {
console.error('\nš Stack trace:');
console.error(error.stack);
}
}
else {
console.error(` ${String(error)}`);
}
process.exit(ExitCode.GENERAL_ERROR);
}
}
async function validateInputFile(filePath, options) {
// Check if file path is provided
if (!filePath || filePath.trim().length === 0) {
console.error('ā No file path provided');
console.error('\nš” Suggestions:');
console.error(' ⢠Provide a path to a CREDL file as an argument');
console.error(' ⢠Example: credl convert my-file.credl');
process.exit(ExitCode.INVALID_ARGUMENTS);
}
// Resolve the file path
const resolvedPath = path.resolve(filePath);
if (options.verbose) {
console.log(`š Validating file: ${resolvedPath}`);
}
// Check if file exists
const fileExists = await (0, index_js_1.checkFileExists)(resolvedPath);
if (!fileExists) {
console.error(`ā File not found: ${filePath}`);
console.error(` Resolved path: ${resolvedPath}`);
console.error('\nš” Suggestions:');
console.error(' ⢠Check if the file path is correct');
console.error(' ⢠Ensure the file exists');
console.error(' ⢠Try using an absolute path');
process.exit(ExitCode.FILE_NOT_FOUND);
}
// Get file stats and validate
const fileStats = await (0, index_js_1.getFileStats)(resolvedPath);
if (!fileStats) {
console.error(`ā Cannot access file: ${filePath}`);
console.error('\nš” Suggestions:');
console.error(' ⢠Check if you have permission to read the file');
console.error(' ⢠Ensure the file is not locked by another process');
process.exit(ExitCode.FILE_ACCESS_ERROR);
}
// Check if it's a regular file (not a directory)
if (fileStats.size === 0) {
console.error(`ā File is empty: ${filePath}`);
console.error('\nš” Suggestions:');
console.error(' ⢠Ensure the file contains valid CREDL content');
console.error(' ⢠Check if the file was saved properly');
process.exit(ExitCode.PARSING_ERROR);
}
// Validate file extension (optional warning)
const fileExtension = path.extname(filePath).toLowerCase();
const validExtensions = ['.credl', '.yaml', '.yml'];
if (!validExtensions.includes(fileExtension) && !options.quiet) {
console.warn(`ā ļø Warning: File extension '${fileExtension}' is not typical for CREDL files`);
console.warn(` Expected extensions: ${validExtensions.join(', ')}`);
}
if (options.verbose) {
console.log(`ā
File validation passed:`);
console.log(` ⢠File size: ${fileStats.size} bytes`);
console.log(` ⢠Last modified: ${fileStats.modified.toISOString()}`);
console.log(` ⢠Extension: ${fileExtension || '(none)'}`);
}
}
function formatIROutput(ir, format) {
switch (format) {
case 'json':
return JSON.stringify(ir);
case 'pretty':
default:
return JSON.stringify(ir, null, 2);
}
}
//# sourceMappingURL=convert.js.map