Skip to content

Commit dcc9ad7

Browse files
committed
feat: add file naming validation script to enforce kebab-case conventions
1 parent 5bf2a9f commit dcc9ad7

File tree

3 files changed

+415
-0
lines changed

3 files changed

+415
-0
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"validate:list": "pnpm exec tsx scripts/validation/validate-all.ts --list",
2323
"validate:quick": "pnpm exec tsx scripts/validation/validate-all.ts --quick",
2424
"validate:imports": "pnpm exec tsx scripts/validation/validate-imports.ts",
25+
"validate:naming": "pnpm exec tsx scripts/validation/validate-file-naming.ts",
2526
"validate:api": "pnpm exec tsx scripts/validation/validate-api-standardization-ast.ts",
2627
"validate:envelopes": "pnpm exec tsx scripts/validation/validate-response-envelopes-ast.ts",
2728
"validate:architecture": "pnpm exec tsx scripts/validation/validate-architecture-patterns-ast.ts",

scripts/validation/validate-all.ts

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
#!/usr/bin/env -S pnpm exec tsx
2+
3+
/**
4+
* Validation Runner - Runs all validation scripts
5+
* Orchestrates multiple validation checks across the codebase
6+
*/
7+
8+
import { spawn } from 'child_process';
9+
import path from 'path';
10+
11+
interface ValidationResult {
12+
name: string;
13+
script: string;
14+
passed: boolean;
15+
output: string;
16+
error?: string;
17+
}
18+
19+
const VALIDATION_SCRIPTS = [
20+
{
21+
name: 'Import Patterns',
22+
script: 'validate-imports.ts',
23+
description: 'Validates ESM import patterns and cross-package imports',
24+
},
25+
{
26+
name: 'File Naming Conventions',
27+
script: 'validate-file-naming.ts',
28+
description: 'Validates kebab-case naming conventions in web directory',
29+
},
30+
{
31+
name: 'API Standardization',
32+
script: 'validate-api-standardization-ast.ts',
33+
description: 'Validates API response format standardization',
34+
},
35+
{
36+
name: 'Response Envelopes',
37+
script: 'validate-response-envelopes-ast.ts',
38+
description: 'Validates response envelope patterns',
39+
},
40+
{
41+
name: 'Architecture Patterns',
42+
script: 'validate-architecture-patterns-ast.ts',
43+
description: 'Validates architectural consistency patterns',
44+
},
45+
];
46+
47+
/**
48+
* Run a single validation script
49+
*/
50+
async function runValidation(scriptPath: string): Promise<{ passed: boolean; output: string; error?: string }> {
51+
return new Promise((resolve) => {
52+
const child = spawn('pnpm', ['exec', 'tsx', scriptPath], {
53+
stdio: 'pipe',
54+
cwd: process.cwd(),
55+
});
56+
57+
let output = '';
58+
let error = '';
59+
60+
child.stdout?.on('data', (data) => {
61+
output += data.toString();
62+
});
63+
64+
child.stderr?.on('data', (data) => {
65+
error += data.toString();
66+
});
67+
68+
child.on('close', (code) => {
69+
resolve({
70+
passed: code === 0,
71+
output: output.trim(),
72+
error: error.trim() || undefined,
73+
});
74+
});
75+
76+
child.on('error', (err) => {
77+
resolve({
78+
passed: false,
79+
output: '',
80+
error: err.message,
81+
});
82+
});
83+
});
84+
}
85+
86+
/**
87+
* Main validation runner
88+
*/
89+
async function runAllValidations(): Promise<void> {
90+
const args = process.argv.slice(2);
91+
const showList = args.includes('--list');
92+
const quickMode = args.includes('--quick');
93+
94+
if (showList) {
95+
console.log('📋 Available validation scripts:\n');
96+
VALIDATION_SCRIPTS.forEach((script, index) => {
97+
console.log(`${index + 1}. ${script.name}`);
98+
console.log(` ${script.description}`);
99+
console.log(` Script: ${script.script}\n`);
100+
});
101+
return;
102+
}
103+
104+
console.log('🔍 Running all validation scripts...\n');
105+
106+
const results: ValidationResult[] = [];
107+
const scriptsToRun = quickMode
108+
? VALIDATION_SCRIPTS.filter(s => ['validate-imports.ts', 'validate-file-naming.ts'].includes(s.script))
109+
: VALIDATION_SCRIPTS;
110+
111+
// Run validations sequentially to avoid overwhelming output
112+
for (const script of scriptsToRun) {
113+
const scriptPath = path.join('scripts/validation', script.script);
114+
console.log(`🔍 Running: ${script.name}...`);
115+
116+
const result = await runValidation(scriptPath);
117+
results.push({
118+
name: script.name,
119+
script: script.script,
120+
...result,
121+
});
122+
123+
if (result.passed) {
124+
console.log(`✅ ${script.name} - PASSED`);
125+
} else {
126+
console.log(`❌ ${script.name} - FAILED`);
127+
if (!quickMode) {
128+
console.log(result.output);
129+
if (result.error) {
130+
console.log(`Error: ${result.error}`);
131+
}
132+
}
133+
}
134+
console.log('');
135+
}
136+
137+
// Summary
138+
const passed = results.filter(r => r.passed).length;
139+
const total = results.length;
140+
const failed = results.filter(r => !r.passed);
141+
142+
console.log('📊 Validation Summary:');
143+
console.log(` Passed: ${passed}/${total}`);
144+
145+
if (failed.length > 0) {
146+
console.log(` Failed: ${failed.length}`);
147+
console.log('\n❌ Failed validations:');
148+
failed.forEach(result => {
149+
console.log(` - ${result.name}`);
150+
});
151+
152+
if (quickMode && failed.length > 0) {
153+
console.log('\n💡 Run without --quick flag to see detailed error messages');
154+
}
155+
}
156+
157+
if (passed === total) {
158+
console.log('\n✅ All validations passed!');
159+
process.exit(0);
160+
} else {
161+
console.log('\n❌ Some validations failed. Please review and fix the issues above.');
162+
process.exit(1);
163+
}
164+
}
165+
166+
// Run validation if called directly
167+
if (import.meta.url === `file://${process.argv[1]}`) {
168+
runAllValidations().catch((error) => {
169+
console.error('💥 Validation runner failed:', error);
170+
process.exit(1);
171+
});
172+
}
173+
174+
export { runAllValidations };

0 commit comments

Comments
 (0)