-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvalidate-samples.js
More file actions
178 lines (143 loc) · 5.16 KB
/
validate-samples.js
File metadata and controls
178 lines (143 loc) · 5.16 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
166
167
168
169
170
171
172
173
174
175
176
177
178
#!/usr/bin/env node
/**
* DESTIN Protocol Sample Validation Script
*
* This script automatically discovers and validates all sample JSON files against their corresponding schemas
* to ensure they comply with the DESTIN protocol specification.
*/
const fs = require('fs');
const path = require('path');
const Ajv = require('ajv/dist/2020').default;
const addFormats = require('ajv-formats');
// Initialize Ajv with JSON Schema 2020-12 support
const ajv = new Ajv({
allErrors: true,
verbose: true,
strict: false,
strictSchema: false,
allowUnionTypes: true
});
addFormats(ajv);
// Track loaded schemas to avoid duplicates
const loadedSchemas = new Set();
const compiledValidators = {};
// Colors for console output
const colors = {
green: '\x1b[32m',
red: '\x1b[31m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
reset: '\x1b[0m',
bold: '\x1b[1m'
};
function log(message, color = '') {
console.log(`${color}${message}${colors.reset}`);
}
function discoverSamples() {
const samplesDir = path.join(__dirname, 'samples');
const sampleFiles = fs.readdirSync(samplesDir)
.filter(file => file.endsWith('.sample.json'))
.map(file => file.replace('.sample.json', ''));
return sampleFiles;
}
function mapSampleToSchema(sampleName) {
// Handle special cases where multiple samples use the same schema
const specialMappings = {
'domain-profile.law': 'domain-profile',
'domain-profile.governance': 'domain-profile',
'audit-log.did_peer_1234abcd': 'audit-log',
'interoperability-export.did_peer_1234abcd': 'interoperability-export'
};
if (specialMappings[sampleName]) {
return specialMappings[sampleName];
}
// Default mapping: sample name maps to schema name
return sampleName;
}
function loadSchema(schemaFile) {
const schemaPath = path.join(__dirname, 'schemas', `${schemaFile}.json`);
try {
const schemaData = JSON.parse(fs.readFileSync(schemaPath, 'utf8'));
// Only add schema if not already loaded
if (schemaData.$id && !loadedSchemas.has(schemaData.$id)) {
ajv.addSchema(schemaData);
loadedSchemas.add(schemaData.$id);
}
return schemaData;
} catch (error) {
throw new Error(`Failed to load schema ${schemaFile}.json: ${error.message}`);
}
}
function validateSample(sampleFile, schemaFile) {
const samplePath = path.join(__dirname, 'samples', `${sampleFile}.sample.json`);
try {
// Read and parse sample
const sampleData = JSON.parse(fs.readFileSync(samplePath, 'utf8'));
// Load schema (will only load once per unique $id)
const schemaData = loadSchema(schemaFile);
// Compile schema only once per schema file
if (!compiledValidators[schemaFile]) {
compiledValidators[schemaFile] = ajv.compile(schemaData);
}
const validate = compiledValidators[schemaFile];
const isValid = validate(sampleData);
if (isValid) {
log(`✅ ${sampleFile}.sample.json is valid`, colors.green);
return { valid: true, errors: null };
} else {
log(`❌ ${sampleFile}.sample.json has validation errors:`, colors.red);
validate.errors.forEach(error => {
log(` - ${error.instancePath || 'root'}: ${error.message}`, colors.red);
});
return { valid: false, errors: validate.errors };
}
} catch (error) {
log(`💥 Error processing ${sampleFile}.sample.json: ${error.message}`, colors.red);
return { valid: false, errors: [error] };
}
}
function main() {
log('🔍 DESTIN Protocol Sample Validation', colors.bold + colors.blue);
log('=====================================\n', colors.blue);
// Discover all sample files
const sampleFiles = discoverSamples();
if (sampleFiles.length === 0) {
log('⚠️ No sample files found in samples/ directory', colors.yellow);
process.exit(0);
}
log(`📁 Found ${sampleFiles.length} sample files:`, colors.blue);
sampleFiles.forEach(file => log(` - ${file}.sample.json`, colors.blue));
log('');
const results = [];
let totalSamples = 0;
let validSamples = 0;
for (const sampleFile of sampleFiles) {
totalSamples++;
const schemaFile = mapSampleToSchema(sampleFile);
log(`Validating ${sampleFile}.sample.json against ${schemaFile}.json...`, colors.yellow);
const result = validateSample(sampleFile, schemaFile);
results.push({ sampleFile, schemaFile, ...result });
if (result.valid) {
validSamples++;
}
log(''); // Empty line for readability
}
// Summary
log('📊 Validation Summary', colors.bold + colors.blue);
log('====================', colors.blue);
log(`Total samples: ${totalSamples}`, colors.blue);
log(`Valid samples: ${validSamples}`, colors.green);
log(`Invalid samples: ${totalSamples - validSamples}`, colors.red);
if (validSamples === totalSamples) {
log('\n🎉 All samples are valid!', colors.bold + colors.green);
process.exit(0);
} else {
log('\n⚠️ Some samples have validation errors. Please fix them.', colors.bold + colors.yellow);
process.exit(1);
}
}
// Run validation if this script is executed directly
if (require.main === module) {
main();
}
module.exports = { validateSample, discoverSamples, mapSampleToSchema };