1import { readFileSync, existsSync } from 'fs';
2import { join } from 'path';
3import { glob } from 'glob';
4import pc from 'picocolors';
5import { findWorkspaceRoot } from '../utils/workspace.js';
6
7export async function validate() {
8 const workspaceRoot = findWorkspaceRoot();
9
10 console.log(pc.blue('🔍 Validating lexicon types...'));
11
12 try {
13 await validateTypeScriptGeneration(workspaceRoot);
14 await validateRustGeneration(workspaceRoot);
15 await validateConsistency(workspaceRoot);
16
17 console.log(pc.green('✅ All validations passed!'));
18 } catch (error) {
19 console.error(pc.red('❌ Validation failed:'), error instanceof Error ? error.message : String(error));
20 process.exit(1);
21 }
22}
23
24async function validateTypeScriptGeneration(workspaceRoot: string) {
25 console.log(pc.cyan(' 📦 Validating TypeScript generation...'));
26
27 const lexiconsPath = join(workspaceRoot, 'lexicons');
28 const packagesLexiconsPath = join(workspaceRoot, 'packages/lexicons');
29
30 if (!existsSync(lexiconsPath)) {
31 throw new Error('Lexicons directory not found at workspace root');
32 }
33
34 if (!existsSync(packagesLexiconsPath)) {
35 console.log(pc.yellow(' ⚠️ TypeScript lexicons package not found, skipping validation'));
36 return;
37 }
38
39 const typesPath = join(packagesLexiconsPath, 'src/types');
40
41 if (!existsSync(typesPath)) {
42 throw new Error('TypeScript types directory not found');
43 }
44
45 // Check if generated files exist for each source lexicon
46 const sourceFiles = await glob('**/*.json', { cwd: lexiconsPath });
47
48 for (const sourceFile of sourceFiles) {
49 const namespace = sourceFile.replace('.json', '').replace(/\//g, '/');
50 const expectedTypeFile = join(typesPath, namespace + '.ts');
51
52 if (!existsSync(expectedTypeFile)) {
53 console.log(pc.yellow(` ⚠️ Missing TypeScript types for: ${sourceFile}`));
54 }
55 }
56
57 console.log(pc.green(' ✓ TypeScript validation complete'));
58}
59
60async function validateRustGeneration(workspaceRoot: string) {
61 console.log(pc.cyan(' 🦀 Validating Rust generation...'));
62
63 const typesPath = join(workspaceRoot, 'services/types');
64 const lexiconsPath = join(workspaceRoot, 'lexicons');
65 const srcPath = join(typesPath, 'src');
66
67 if (!existsSync(lexiconsPath)) {
68 throw new Error('Lexicons directory not found at workspace root');
69 }
70
71 if (!existsSync(srcPath)) {
72 throw new Error('Rust src directory not found');
73 }
74
75 // Check if Cargo.toml exists
76 const cargoTomlPath = join(typesPath, 'Cargo.toml');
77 if (!existsSync(cargoTomlPath)) {
78 throw new Error('Cargo.toml not found in types directory');
79 }
80
81 console.log(pc.green(' ✓ Rust validation complete'));
82}
83
84async function validateConsistency(workspaceRoot: string) {
85 console.log(pc.cyan(' 🔄 Validating cross-language consistency...'));
86
87 // Use centralized lexicons directory
88 const lexiconsPath = join(workspaceRoot, 'lexicons');
89
90 if (!existsSync(lexiconsPath)) {
91 throw new Error('Cannot validate consistency - lexicons directory not found');
92 }
93
94 // Count lexicon files
95 const lexiconFiles = await glob('**/*.json', { cwd: lexiconsPath });
96
97 console.log(pc.gray(` Lexicon files found: ${lexiconFiles.length} files`));
98
99 // Check if TypeScript and Rust generated types exist
100 const tsTypesPath = join(workspaceRoot, 'packages/lexicons/src/types');
101 const rustTypesPath = join(workspaceRoot, 'services/types/src');
102
103 let tsExists = existsSync(tsTypesPath);
104 let rustExists = existsSync(rustTypesPath);
105
106 console.log(pc.gray(` TypeScript types: ${tsExists ? 'Found' : 'Not found'}`));
107 console.log(pc.gray(` Rust types: ${rustExists ? 'Found' : 'Not found'}`));
108
109 if (!tsExists && !rustExists) {
110 console.log(pc.yellow(' ⚠️ No generated types found for either language'));
111 }
112
113 console.log(pc.green(' ✓ Consistency validation complete'));
114}