An experimental TypeSpec syntax for Lexicon
at main 2.5 kB view raw
1#!/usr/bin/env node 2 3const fs = require('fs'); 4const path = require('path'); 5 6// Import validation from atproto lexicon package 7const atprotoPath = path.join(__dirname, '../../atproto/packages/lexicon'); 8const { Lexicons } = require(path.join(atprotoPath, 'dist/index.js')); 9 10function findJsonFiles(dir, fileList = []) { 11 const files = fs.readdirSync(dir); 12 13 files.forEach(file => { 14 // Skip node_modules, tsp-output, and common non-lexicon directories 15 if (file === 'node_modules' || file === 'tsp-output' || file === 'dist' || file === '.git') { 16 return; 17 } 18 19 const filePath = path.join(dir, file); 20 const stat = fs.statSync(filePath); 21 22 if (stat.isDirectory()) { 23 findJsonFiles(filePath, fileList); 24 } else if (file.endsWith('.json') && !file.includes('package') && !file.includes('tsconfig')) { 25 fileList.push(filePath); 26 } 27 }); 28 29 return fileList; 30} 31 32function validateLexicons() { 33 const packagesDir = path.join(__dirname, '..', 'packages'); 34 const files = findJsonFiles(packagesDir); 35 36 if (files.length === 0) { 37 console.log('No lexicon files found'); 38 return 0; 39 } 40 41 let errorCount = 0; 42 let validCount = 0; 43 let skippedCount = 0; 44 const seenIds = new Set(); 45 46 for (const filePath of files) { 47 const relPath = path.relative(path.join(__dirname, '..'), filePath); 48 49 try { 50 const content = fs.readFileSync(filePath, 'utf-8'); 51 const json = JSON.parse(content); 52 53 // Skip non-lexicon JSON files (e.g., package.json, tsconfig.json) 54 if (!json.lexicon || typeof json.lexicon !== 'number') { 55 continue; 56 } 57 58 // Skip duplicates (same ID already seen) 59 if (json.id && seenIds.has(json.id)) { 60 skippedCount++; 61 continue; 62 } 63 64 // Validate individually with a fresh Lexicons instance 65 // This avoids duplicate ID errors when validating independent lexicons 66 const lexicons = new Lexicons(); 67 lexicons.add(json); 68 69 if (json.id) { 70 seenIds.add(json.id); 71 } 72 73 validCount++; 74 console.log(`${relPath}`); 75 } catch (error) { 76 errorCount++; 77 console.error(`${relPath}: ${error.message}`); 78 } 79 } 80 81 console.log(`\nValidated ${validCount} lexicons: ${validCount} valid, ${errorCount} errors${skippedCount > 0 ? `, ${skippedCount} duplicates skipped` : ''}`); 82 83 return errorCount > 0 ? 1 : 0; 84} 85 86try { 87 const exitCode = validateLexicons(); 88 process.exit(exitCode); 89} catch (err) { 90 console.error('Fatal error:', err); 91 process.exit(1); 92}