UNPKG

credl-parser-evaluator

Version:

TypeScript-based CREDL Parser and Evaluator that processes CREDL files and outputs complete Intermediate Representations

441 lines 16.6 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ProgressBar = exports.JSONFormatter = exports.TableFormatter = exports.OutputFormatter = void 0; exports.createOutputFormatter = createOutputFormatter; exports.createTableFormatter = createTableFormatter; exports.createProgressBar = createProgressBar; const chalk_1 = __importDefault(require("chalk")); const ora_1 = __importDefault(require("ora")); // Output formatting utilities for CLI commands class OutputFormatter { constructor(options = {}) { this.quiet = false; this.noColor = false; this.quiet = options.quiet || false; this.noColor = options.noColor || false; } // Basic logging methods log(message) { if (!this.quiet) { console.log(message); } } info(message) { if (!this.quiet) { console.log(this.color('blue', `ℹ️ ${message}`)); } } success(message) { if (!this.quiet) { console.log(this.color('green', `✅ ${message}`)); } } warning(message) { if (!this.quiet) { console.warn(this.color('yellow', `⚠️ ${message}`)); } } error(message) { console.error(this.color('red', `❌ ${message}`)); } debug(message, verbose = false) { if (verbose && !this.quiet) { console.log(this.color('gray', `🐛 ${message}`)); } } // Progress and status indicators progress(message) { if (!this.quiet) { console.log(this.color('cyan', `🔄 ${message}`)); } } step(current, total, message) { if (!this.quiet) { const progress = `[${current}/${total}]`; console.log(this.color('cyan', `🔄 ${progress} ${message}`)); } } // Spinner methods spinner(message) { return (0, ora_1.default)({ text: message, color: 'cyan', spinner: 'dots', isEnabled: !this.quiet && !this.noColor }); } // Color utility (respects --no-color flag) color(colorName, text) { if (this.noColor) { return text; } switch (colorName) { case 'red': return chalk_1.default.red(text); case 'green': return chalk_1.default.green(text); case 'yellow': return chalk_1.default.yellow(text); case 'blue': return chalk_1.default.blue(text); case 'cyan': return chalk_1.default.cyan(text); case 'gray': return chalk_1.default.gray(text); case 'bold': return chalk_1.default.bold(text); case 'dim': return chalk_1.default.dim(text); default: return text; } } // Header and section formatting header(title) { if (!this.quiet) { console.log(''); console.log(this.color('bold', title)); console.log(this.color('dim', '='.repeat(Math.min(title.length, 50)))); } } section(title) { if (!this.quiet) { console.log(''); console.log(this.color('bold', title)); console.log(this.color('dim', '-'.repeat(Math.min(title.length, 30)))); } } // List formatting bulletList(items, indent = 0) { if (!this.quiet) { const prefix = ' '.repeat(indent); items.forEach(item => { console.log(`${prefix}${item}`); }); } } numberedList(items, indent = 0) { if (!this.quiet) { const prefix = ' '.repeat(indent); items.forEach((item, index) => { console.log(`${prefix}${index + 1}. ${item}`); }); } } // Detailed formatting with icons and colors fileStatus(filePath, status) { if (!this.quiet) { const icons = { success: '✅', error: '❌', warning: '⚠️', info: 'ℹ️' }; const colors = { success: 'green', error: 'red', warning: 'yellow', info: 'blue' }; const icon = icons[status]; const coloredPath = this.color(colors[status], filePath); console.log(` ${icon} ${coloredPath}`); } } // Code block formatting codeBlock(code, language = '') { if (!this.quiet) { console.log(''); if (language) { console.log(this.color('dim', `\`\`\`${language}`)); } else { console.log(this.color('dim', '```')); } console.log(this.color('gray', code)); console.log(this.color('dim', '```')); console.log(''); } } // Statistics and metrics formatting metric(label, value, unit) { if (!this.quiet) { const formattedValue = typeof value === 'number' ? value.toLocaleString() : value; const fullValue = unit ? `${formattedValue}${unit}` : formattedValue; console.log(` ${this.color('dim', label + ':')} ${this.color('bold', fullValue)}`); } } keyValue(key, value, indent = 0) { if (!this.quiet) { const prefix = ' '.repeat(indent); console.log(`${prefix}${this.color('cyan', key)}: ${value}`); } } } exports.OutputFormatter = OutputFormatter; class TableFormatter { constructor(options = {}) { this.noColor = false; this.noColor = options.noColor || false; } // Create formatted table formatTable(data, columns, options = {}) { const { showHeaders = true, headerStyle = 'bold', borderStyle = 'simple', maxWidth = 120 } = options; if (data.length === 0) { return 'No data to display'; } // Calculate column widths const columnWidths = this.calculateColumnWidths(data, columns, maxWidth); let output = []; // Add headers if (showHeaders) { const headers = columns.map((col, index) => this.padCell(col.header, columnWidths[index] || 10, col.align || 'left')); const headerRow = this.formatRow(headers, borderStyle); output.push(this.styleText(headerRow, headerStyle)); // Add separator line if (headerStyle !== 'none') { const separator = columns.map((_, index) => '-'.repeat(columnWidths[index] || 10)); output.push(this.formatRow(separator, borderStyle)); } } // Add data rows for (const row of data) { const cells = columns.map((col, index) => { let value = row[col.key]; if (col.formatter) { value = col.formatter(value); } else if (value === null || value === undefined) { value = ''; } else { value = String(value); } return this.padCell(value, columnWidths[index] || 10, col.align || 'left'); }); output.push(this.formatRow(cells, borderStyle)); } return output.join('\n'); } // Simple data table (key-value pairs) formatDataTable(data, options = {}) { const { indent = 0 } = options; const prefix = ' '.repeat(indent); const entries = Object.entries(data); const maxKeyLength = Math.max(...entries.map(([key]) => key.length)); return entries.map(([key, value]) => { const paddedKey = key.padEnd(maxKeyLength); const formattedValue = value === null || value === undefined ? 'N/A' : String(value); return `${prefix}${this.styleText(paddedKey, 'dim')}: ${formattedValue}`; }).join('\n'); } // Validation results table formatValidationTable(results) { const columns = [ { header: 'File', key: 'file', align: 'left' }, { header: 'Status', key: 'status', align: 'center', formatter: (status) => { switch (status) { case 'valid': return this.styleText('✅ Valid', 'green'); case 'invalid': return this.styleText('❌ Invalid', 'red'); case 'error': return this.styleText('💥 Error', 'red'); default: return String(status); } } }, { header: 'Errors', key: 'errors', align: 'right', formatter: (errors) => errors > 0 ? this.styleText(String(errors), 'red') : '0' }, { header: 'Warnings', key: 'warnings', align: 'right', formatter: (warnings) => warnings > 0 ? this.styleText(String(warnings), 'yellow') : '0' }, { header: 'Time (ms)', key: 'time', align: 'right', formatter: (time) => time ? time.toFixed(2) : 'N/A' } ]; return this.formatTable(results, columns); } calculateColumnWidths(data, columns, maxWidth) { const minWidths = columns.map(col => Math.max(col.header.length, col.width || 10)); const contentWidths = columns.map((col, index) => { const values = data.map(row => { let value = row[col.key]; if (col.formatter) { value = col.formatter(value); } return String(value || ''); }); const maxContentLength = Math.max(...values.map(v => v.length)); return Math.max(minWidths[index] || 10, maxContentLength); }); // Adjust widths if total exceeds maxWidth const totalWidth = contentWidths.reduce((sum, width) => sum + width, 0); const separatorWidth = (columns.length - 1) * 3; // " | " between columns if (totalWidth + separatorWidth > maxWidth) { const availableWidth = maxWidth - separatorWidth; const ratio = availableWidth / totalWidth; return contentWidths.map(width => Math.max(8, Math.floor(width * ratio))); } return contentWidths; } padCell(text, width, align) { if (text.length > width) { return text.substring(0, width - 3) + '...'; } switch (align) { case 'right': return text.padStart(width); case 'center': const leftPad = Math.floor((width - text.length) / 2); const rightPad = width - text.length - leftPad; return ' '.repeat(leftPad) + text + ' '.repeat(rightPad); case 'left': default: return text.padEnd(width); } } formatRow(cells, borderStyle) { switch (borderStyle) { case 'simple': return cells.join(' | '); case 'rounded': return '│ ' + cells.join(' │ ') + ' │'; case 'none': default: return cells.join(' '); } } styleText(text, style) { if (this.noColor) { return text; } switch (style) { case 'bold': return chalk_1.default.bold(text); case 'dim': return chalk_1.default.dim(text); case 'underline': return chalk_1.default.underline(text); case 'red': return chalk_1.default.red(text); case 'green': return chalk_1.default.green(text); case 'yellow': return chalk_1.default.yellow(text); case 'blue': return chalk_1.default.blue(text); case 'cyan': return chalk_1.default.cyan(text); default: return text; } } } exports.TableFormatter = TableFormatter; // JSON formatting utilities class JSONFormatter { // Pretty print JSON with optional syntax highlighting static prettyPrint(data, options = {}) { const { indent = 2, sortKeys = false, colorize = true, maxLength = 10000 } = options; try { let jsonString = JSON.stringify(data, sortKeys ? this.sortedReplacer : undefined, indent); // Truncate if too long if (jsonString.length > maxLength) { jsonString = jsonString.substring(0, maxLength) + '\n... (truncated)'; } // Add syntax highlighting if requested if (colorize && !process.env.NO_COLOR) { return this.colorizeJSON(jsonString); } return jsonString; } catch (error) { return `Error formatting JSON: ${error instanceof Error ? error.message : String(error)}`; } } // Compact JSON (single line) static compact(data) { try { return JSON.stringify(data); } catch (error) { return `Error formatting JSON: ${error instanceof Error ? error.message : String(error)}`; } } // Safe JSON stringify with circular reference handling static safeStringify(data, options = {}) { const { indent = 2, replacer } = options; const seen = new WeakSet(); const circularReplacer = (key, value) => { if (typeof value === 'object' && value !== null) { if (seen.has(value)) { return '[Circular Reference]'; } seen.add(value); } return replacer ? replacer(key, value) : value; }; try { return JSON.stringify(data, circularReplacer, indent); } catch (error) { return `Error formatting JSON: ${error instanceof Error ? error.message : String(error)}`; } } static sortedReplacer(_key, value) { if (value && typeof value === 'object' && !Array.isArray(value)) { const sortedObj = {}; Object.keys(value).sort().forEach(k => { sortedObj[k] = value[k]; }); return sortedObj; } return value; } static colorizeJSON(jsonString) { return jsonString .replace(/"([^"]+)":/g, chalk_1.default.blue('"$1"') + ':') // Keys .replace(/: "([^"]+)"/g, ': ' + chalk_1.default.green('"$1"')) // String values .replace(/: (\d+\.?\d*)/g, ': ' + chalk_1.default.yellow('$1')) // Numbers .replace(/: (true|false)/g, ': ' + chalk_1.default.magenta('$1')) // Booleans .replace(/: (null)/g, ': ' + chalk_1.default.gray('$1')) // Null .replace(/([{}[\]])/g, chalk_1.default.white('$1')); // Brackets } } exports.JSONFormatter = JSONFormatter; // Progress bar utilities class ProgressBar { constructor(total, options = {}) { this.total = total; this.width = options.width || 40; this.label = options.label || 'Progress'; this.startTime = Date.now(); } update(current, message) { const percentage = Math.min(Math.round((current / this.total) * 100), 100); const filled = Math.round((this.width * current) / this.total); const bar = '█'.repeat(filled) + '░'.repeat(this.width - filled); const elapsed = (Date.now() - this.startTime) / 1000; const rate = current / elapsed; const eta = current > 0 ? Math.round((this.total - current) / rate) : 0; const statusLine = `${this.label}: [${bar}] ${percentage}% (${current}/${this.total}) ETA: ${eta}s`; const fullLine = message ? `${statusLine} - ${message}` : statusLine; process.stdout.write(`\r${fullLine}`); if (current >= this.total) { process.stdout.write('\n'); } } complete(message) { this.update(this.total, message || 'Complete'); } } exports.ProgressBar = ProgressBar; // Export utility functions for direct use function createOutputFormatter(options) { return new OutputFormatter(options); } function createTableFormatter(options) { return new TableFormatter(options); } function createProgressBar(total, options) { return new ProgressBar(total, options); } //# sourceMappingURL=output.js.map