Spaces:
Sleeping
Sleeping
File size: 5,532 Bytes
da2e594 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | #!/usr/bin/env node
/**
* Run validation on templates and provide a clean summary
*/
import { existsSync } from 'fs';
import path from 'path';
import { NodeRepository } from '../database/node-repository';
import { createDatabaseAdapter } from '../database/database-adapter';
import { WorkflowValidator } from '../services/workflow-validator';
import { EnhancedConfigValidator } from '../services/enhanced-config-validator';
import { TemplateRepository } from '../templates/template-repository';
import { Logger } from '../utils/logger';
const logger = new Logger({ prefix: '[validation-summary]' });
async function runValidationSummary() {
const dbPath = path.join(process.cwd(), 'data', 'nodes.db');
if (!existsSync(dbPath)) {
logger.error('Database not found. Run npm run rebuild first.');
process.exit(1);
}
const db = await createDatabaseAdapter(dbPath);
const repository = new NodeRepository(db);
const templateRepository = new TemplateRepository(db);
const validator = new WorkflowValidator(
repository,
EnhancedConfigValidator
);
try {
const templates = await templateRepository.getAllTemplates(50);
const results = {
total: templates.length,
valid: 0,
invalid: 0,
noErrors: 0,
errorCategories: {
unknownNodes: 0,
missingRequired: 0,
expressionErrors: 0,
connectionErrors: 0,
cycles: 0,
other: 0
},
commonUnknownNodes: new Map<string, number>(),
stickyNoteIssues: 0
};
for (const template of templates) {
try {
const workflow = JSON.parse(template.workflow_json || '{}');
const validationResult = await validator.validateWorkflow(workflow, {
profile: 'minimal' // Use minimal profile to focus on critical errors
});
if (validationResult.valid) {
results.valid++;
} else {
results.invalid++;
}
if (validationResult.errors.length === 0) {
results.noErrors++;
}
// Categorize errors
validationResult.errors.forEach((error: any) => {
const errorMsg = typeof error.message === 'string' ? error.message : JSON.stringify(error.message);
if (errorMsg.includes('Unknown node type')) {
results.errorCategories.unknownNodes++;
const match = errorMsg.match(/Unknown node type: (.+)/);
if (match) {
const nodeType = match[1];
results.commonUnknownNodes.set(nodeType, (results.commonUnknownNodes.get(nodeType) || 0) + 1);
}
} else if (errorMsg.includes('missing_required')) {
results.errorCategories.missingRequired++;
if (error.nodeName?.includes('Sticky Note')) {
results.stickyNoteIssues++;
}
} else if (errorMsg.includes('Expression error')) {
results.errorCategories.expressionErrors++;
} else if (errorMsg.includes('connection') || errorMsg.includes('Connection')) {
results.errorCategories.connectionErrors++;
} else if (errorMsg.includes('cycle')) {
results.errorCategories.cycles++;
} else {
results.errorCategories.other++;
}
});
} catch (error) {
results.invalid++;
}
}
// Print summary
console.log('\n' + '='.repeat(80));
console.log('WORKFLOW VALIDATION SUMMARY');
console.log('='.repeat(80));
console.log(`\nTemplates analyzed: ${results.total}`);
console.log(`Valid workflows: ${results.valid} (${((results.valid / results.total) * 100).toFixed(1)}%)`);
console.log(`Workflows without errors: ${results.noErrors} (${((results.noErrors / results.total) * 100).toFixed(1)}%)`);
console.log('\nError Categories:');
console.log(` - Unknown nodes: ${results.errorCategories.unknownNodes}`);
console.log(` - Missing required properties: ${results.errorCategories.missingRequired}`);
console.log(` (Sticky note issues: ${results.stickyNoteIssues})`);
console.log(` - Expression errors: ${results.errorCategories.expressionErrors}`);
console.log(` - Connection errors: ${results.errorCategories.connectionErrors}`);
console.log(` - Workflow cycles: ${results.errorCategories.cycles}`);
console.log(` - Other errors: ${results.errorCategories.other}`);
if (results.commonUnknownNodes.size > 0) {
console.log('\nTop Unknown Node Types:');
const sortedNodes = Array.from(results.commonUnknownNodes.entries())
.sort((a, b) => b[1] - a[1])
.slice(0, 10);
sortedNodes.forEach(([nodeType, count]) => {
console.log(` - ${nodeType} (${count} occurrences)`);
});
}
console.log('\nKey Insights:');
const stickyNotePercent = ((results.stickyNoteIssues / results.errorCategories.missingRequired) * 100).toFixed(1);
console.log(` - ${stickyNotePercent}% of missing required property errors are from Sticky Notes`);
console.log(` - Most workflows have some validation warnings (best practices)`);
console.log(` - Expression validation is working well`);
console.log(` - Node type normalization is handling most cases correctly`);
} catch (error) {
logger.error('Failed to run validation summary:', error);
process.exit(1);
} finally {
db.close();
}
}
// Run summary
runValidationSummary().catch(error => {
logger.error('Summary failed:', error);
process.exit(1);
}); |