-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvalidate-schemas.js
More file actions
165 lines (137 loc) · 4.77 KB
/
Copy pathvalidate-schemas.js
File metadata and controls
165 lines (137 loc) · 4.77 KB
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#!/usr/bin/env node
/**
* Schema Validation Script
*
* This script validates that all JSON schemas in the protocol-data/schemas/
* directory are syntactically correct and follow the expected structure.
*/
const fs = require('fs');
const path = require('path');
const Ajv = require('ajv');
const addFormats = require('ajv-formats');
// Initialize Ajv for schema validation with JSON Schema Draft 2020-12 support
const ajv = new Ajv({
allErrors: true,
verbose: true,
strict: false,
// Add support for JSON Schema Draft 2020-12
strictSchema: false,
allowUnionTypes: true
});
addFormats(ajv);
// Schema directory
const SCHEMAS_DIR = path.join(__dirname, 'schemas');
const SCHEMA_INDEX_FILE = path.join(SCHEMAS_DIR, 'schema-index.data.json');
/**
* Validate a single JSON schema file
*/
function validateSchemaFile(filePath) {
try {
const content = fs.readFileSync(filePath, 'utf8');
const schema = JSON.parse(content);
// Basic schema validation
if (!schema.$schema) {
throw new Error('Missing $schema field');
}
if (!schema.title && !schema.description) {
console.warn(`Warning: Schema ${path.basename(filePath)} has no title or description`);
}
// Try to compile the schema with Ajv
// For Draft 2020-12 schemas, we'll skip the compilation test since Ajv might not have the meta-schema
if (schema.$schema.includes('2020-12')) {
console.log(`✅ Validated schema: ${path.basename(filePath)} (Draft 2020-12 - syntax check only)`);
return { valid: true, file: filePath };
} else {
const validate = ajv.compile(schema);
console.log(`✅ Validated schema: ${path.basename(filePath)}`);
return { valid: true, file: filePath };
}
} catch (error) {
console.error(`❌ Invalid schema ${path.basename(filePath)}: ${error.message}`);
return { valid: false, file: filePath, error: error.message };
}
}
/**
* Validate schema index file
*/
function validateSchemaIndex() {
try {
if (!fs.existsSync(SCHEMA_INDEX_FILE)) {
console.error('❌ Schema index file not found');
return { valid: false, error: 'Schema index file not found' };
}
const content = fs.readFileSync(SCHEMA_INDEX_FILE, 'utf8');
const index = JSON.parse(content);
// Check if schemas field exists and is an object (not array as originally expected)
if (!index.schemas || typeof index.schemas !== 'object') {
throw new Error('Schema index must contain a "schemas" object');
}
// Validate each schema reference
for (const [schemaName, schemaRef] of Object.entries(index.schemas)) {
if (!schemaRef.file) {
throw new Error(`Schema "${schemaName}" must have a "file" field`);
}
const schemaPath = path.join(SCHEMAS_DIR, schemaRef.file);
if (!fs.existsSync(schemaPath)) {
throw new Error(`Referenced schema file not found: ${schemaRef.file}`);
}
}
console.log('✅ Validated schema index');
return { valid: true };
} catch (error) {
console.error(`❌ Invalid schema index: ${error.message}`);
return { valid: false, error: error.message };
}
}
/**
* Main validation function
*/
function main() {
console.log('🔍 Validating JSON schemas...\n');
let allValid = true;
const results = [];
// Validate schema index first
const indexResult = validateSchemaIndex();
results.push(indexResult);
if (!indexResult.valid) {
allValid = false;
}
// Find and validate all schema files
if (fs.existsSync(SCHEMAS_DIR)) {
const files = fs.readdirSync(SCHEMAS_DIR);
const schemaFiles = files.filter(file => file.endsWith('.json') && file !== 'schema-index.json' && file !== 'schema-index.data.json');
if (schemaFiles.length === 0) {
console.log('⚠️ No schema files found');
} else {
console.log(`Found ${schemaFiles.length} schema files to validate:\n`);
for (const file of schemaFiles) {
const filePath = path.join(SCHEMAS_DIR, file);
const result = validateSchemaFile(filePath);
results.push(result);
if (!result.valid) {
allValid = false;
}
}
}
} else {
console.error('❌ Schemas directory not found');
allValid = false;
}
// Summary
console.log('\n📊 Validation Summary:');
const validCount = results.filter(r => r.valid).length;
const totalCount = results.length;
console.log(`Valid schemas: ${validCount}/${totalCount}`);
if (allValid) {
console.log('\n✅ All schemas are valid!');
process.exit(0);
} else {
console.log('\n❌ Some schemas have validation errors');
process.exit(1);
}
}
// Run if called directly
if (require.main === module) {
main();
}
module.exports = { validateSchemaFile, validateSchemaIndex, main };