209 lines
5.6 KiB
JavaScript
Executable File
209 lines
5.6 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
/**
|
|
* Batch validation for multiple .uxm files
|
|
* Validates multiple component or screen files in one command
|
|
*
|
|
* Usage:
|
|
* node validate-batch.js "./fluxwing/components/FILE.uxm" <schema.json>
|
|
* node validate-batch.js "./fluxwing/screens/FILE.uxm" <schema.json> --json
|
|
* node validate-batch.js "./fluxwing/ALL/FILE.uxm" <schema.json> --screens
|
|
*
|
|
* Options:
|
|
* --json Output results as JSON
|
|
* --screens Use screen validator instead of component validator
|
|
*
|
|
* Exit codes:
|
|
* 0 - All files valid
|
|
* 1 - One or more files invalid
|
|
* 2 - Missing dependencies or invalid arguments
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
// Check for glob dependency
|
|
let glob;
|
|
try {
|
|
glob = require('glob');
|
|
} catch (error) {
|
|
console.error('Error: glob library not found');
|
|
console.error('Install with: npm install glob');
|
|
process.exit(2);
|
|
}
|
|
|
|
// Import validators
|
|
const { validateComponent } = require('./validate-component.js');
|
|
const { validateScreen } = require('./validate-screen.js');
|
|
|
|
// ANSI color codes
|
|
const GREEN = '\x1b[32m';
|
|
const RED = '\x1b[31m';
|
|
const YELLOW = '\x1b[33m';
|
|
const BLUE = '\x1b[34m';
|
|
const RESET = '\x1b[0m';
|
|
|
|
/**
|
|
* Validate multiple files matching a glob pattern
|
|
* @param {string} pattern - Glob pattern for files to validate
|
|
* @param {string} schemaPath - Path to JSON schema file
|
|
* @param {Object} options - Validation options
|
|
* @returns {Object} Batch validation results
|
|
*/
|
|
function validateBatch(pattern, schemaPath, options = {}) {
|
|
const useScreenValidator = options.screens || false;
|
|
const validator = useScreenValidator ? validateScreen : validateComponent;
|
|
|
|
// Find all matching files
|
|
const files = glob.sync(pattern);
|
|
|
|
if (files.length === 0) {
|
|
return {
|
|
total: 0,
|
|
passed: 0,
|
|
failed: 0,
|
|
warnings: 0,
|
|
files: [],
|
|
message: `No files found matching pattern: ${pattern}`
|
|
};
|
|
}
|
|
|
|
const results = {
|
|
total: files.length,
|
|
passed: 0,
|
|
failed: 0,
|
|
warnings: 0,
|
|
files: []
|
|
};
|
|
|
|
// Validate each file
|
|
for (const file of files) {
|
|
const result = validator(file, schemaPath);
|
|
|
|
const fileResult = {
|
|
file: file,
|
|
id: result.stats?.id || path.basename(file, '.uxm'),
|
|
valid: result.valid,
|
|
errors: result.errors.length,
|
|
warnings: result.warnings.length,
|
|
errorDetails: result.errors,
|
|
warningDetails: result.warnings
|
|
};
|
|
|
|
results.files.push(fileResult);
|
|
|
|
if (result.valid) {
|
|
results.passed++;
|
|
} else {
|
|
results.failed++;
|
|
}
|
|
|
|
results.warnings += result.warnings.length;
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
/**
|
|
* Print human-readable batch results
|
|
* @param {Object} results - Batch validation results
|
|
*/
|
|
function printHumanReadable(results) {
|
|
if (results.total === 0) {
|
|
console.log(`${YELLOW}${results.message}${RESET}`);
|
|
return;
|
|
}
|
|
|
|
console.log(`${BLUE}Batch Validation Results${RESET}\n`);
|
|
console.log(`Total files: ${results.total}`);
|
|
console.log(`${GREEN}Passed: ${results.passed}${RESET}`);
|
|
|
|
if (results.failed > 0) {
|
|
console.log(`${RED}Failed: ${results.failed}${RESET}`);
|
|
}
|
|
|
|
if (results.warnings > 0) {
|
|
console.log(`${YELLOW}Total warnings: ${results.warnings}${RESET}`);
|
|
}
|
|
|
|
console.log('');
|
|
|
|
// Show failed files
|
|
const failedFiles = results.files.filter(f => !f.valid);
|
|
if (failedFiles.length > 0) {
|
|
console.log(`${RED}Failed Files:${RESET}\n`);
|
|
failedFiles.forEach(file => {
|
|
console.log(` ${RED}✗${RESET} ${file.id} (${file.file})`);
|
|
console.log(` Errors: ${file.errors}`);
|
|
|
|
// Show first 2 errors
|
|
file.errorDetails.slice(0, 2).forEach((error, i) => {
|
|
console.log(` ${i + 1}. ${error.message}`);
|
|
});
|
|
|
|
if (file.errors > 2) {
|
|
console.log(` ... and ${file.errors - 2} more errors`);
|
|
}
|
|
console.log('');
|
|
});
|
|
}
|
|
|
|
// Show passed files with warnings
|
|
const passedWithWarnings = results.files.filter(f => f.valid && f.warnings > 0);
|
|
if (passedWithWarnings.length > 0) {
|
|
console.log(`${YELLOW}Passed with Warnings:${RESET}\n`);
|
|
passedWithWarnings.forEach(file => {
|
|
console.log(` ${GREEN}✓${RESET} ${file.id} ${YELLOW}(${file.warnings} warnings)${RESET}`);
|
|
});
|
|
console.log('');
|
|
}
|
|
|
|
// Show fully passed files (compact)
|
|
const fullPassed = results.files.filter(f => f.valid && f.warnings === 0);
|
|
if (fullPassed.length > 0) {
|
|
console.log(`${GREEN}Fully Passed:${RESET}\n`);
|
|
fullPassed.forEach(file => {
|
|
console.log(` ${GREEN}✓${RESET} ${file.id}`);
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Print JSON results
|
|
* @param {Object} results - Batch validation results
|
|
*/
|
|
function printJSON(results) {
|
|
console.log(JSON.stringify(results, null, 2));
|
|
}
|
|
|
|
// CLI interface
|
|
if (require.main === module) {
|
|
const args = process.argv.slice(2);
|
|
|
|
if (args.length < 2) {
|
|
console.error('Usage: node validate-batch.js <pattern> <schema.json> [--json] [--screens]');
|
|
console.error('');
|
|
console.error('Examples:');
|
|
console.error(' node validate-batch.js "./fluxwing/components/*.uxm" schema.json');
|
|
console.error(' node validate-batch.js "./fluxwing/**/*.uxm" schema.json --json');
|
|
console.error(' node validate-batch.js "./fluxwing/screens/*.uxm" schema.json --screens');
|
|
process.exit(2);
|
|
}
|
|
|
|
const pattern = args[0];
|
|
const schemaPath = args[1];
|
|
const jsonOutput = args.includes('--json');
|
|
const useScreens = args.includes('--screens');
|
|
|
|
const results = validateBatch(pattern, schemaPath, { screens: useScreens });
|
|
|
|
if (jsonOutput) {
|
|
printJSON(results);
|
|
} else {
|
|
printHumanReadable(results);
|
|
}
|
|
|
|
process.exit(results.failed > 0 ? 1 : 0);
|
|
}
|
|
|
|
module.exports = { validateBatch };
|