Skip to content

Commit

Permalink
CI: Validate schema with AJV
Browse files Browse the repository at this point in the history
  • Loading branch information
mferrera committed Dec 19, 2024
1 parent 1e167eb commit 6bb47b3
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/schemas-up-to-date.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,8 @@ jobs:
run: |
./tools/update_schema
git diff --exit-code
- name: Ensure schema validates with AJV
run: |
npm install ajv ajv-formats
./tools/schema-validate-ajv.mjs ./schema/
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,8 @@ examples/s/d/nn/xcase/iter-0/

# Apple macOS
.DS_Store

# npm/node
node_modules/
package-lock.json
package.json
95 changes: 95 additions & 0 deletions tools/schema-validate-ajv.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/usr/bin/env node

import Ajv2020 from "ajv/dist/2020.js"
import addFormats from "ajv-formats";
import fs from "fs/promises";
import path from "path";
import { fileURLToPath } from "url";

const ajv = new Ajv2020({ strict: false, discriminator: true });
addFormats(ajv);

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const GREEN = "\x1b[32m";
const RED = "\x1b[31m";
const YELLOW = "\x1b[93m";
const NC = "\x1b[0m";
const BOLD = "\x1b[1m";
const SUCCESS = `[${BOLD}${GREEN}${NC}]`;
const FAILURE = `[${BOLD}${RED}${NC}]`;
const INFO = `[${BOLD}${YELLOW}+${NC}]`;

async function loadJson(filePath) {
try {
const fullPath = path.resolve(filePath);
const fileContent = await fs.readFile(fullPath, "utf-8");
return JSON.parse(fileContent);
} catch (error) {
console.error(`${FAILURE} Error reading file at ${filePath}:`, error.message);
process.exit(1);
}
}

async function validateSchema(schemaPath) {
try {
const schema = await loadJson(schemaPath);
const validate = ajv.compile(schema);
console.log(`${SUCCESS} Schema is valid: ${schemaPath}`);
return validate;
} catch (error) {
console.error(`${FAILURE} Schema is invalid: ${schemaPath}`);
console.error(` ${INFO} Reason: ${error.message}`);
return false;
}
}

async function findJsonFiles(dir) {
let results = [];
const entries = await fs.readdir(dir, { withFileTypes: true });

for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
results = results.concat(await findJsonFiles(fullPath));
} else if (entry.isFile() && entry.name.endsWith(".json")) {
results.push(fullPath);
}
}

return results;
}

async function validateSchemasInDirectory(dirPath) {
const schemaFiles = await findJsonFiles(dirPath);

if (schemaFiles.length === 0) {
console.log(`${INFO} No JSON schema files found in directory: ${dirPath}`);
return;
}

let shouldFail = false;
console.log(`${INFO} Found ${schemaFiles.length} JSON schema file(s) in directory: ${dirPath}`);
for (const schemaPath of schemaFiles) {
const isValid = await validateSchema(schemaPath);
if (!isValid) {
shouldFail = true;
}
}
if (shouldFail) {
process.exit(1);
}
}

const directory = process.argv[2];

if (!directory) {
console.error("Usage: validate-schema-ajv.mjs <directory>");
process.exit(1);
}

validateSchemasInDirectory(directory).catch((err) => {
console.error(`${FAILURE} Unknown error: ${err.message}`);
process.exit(1);
});

0 comments on commit 6bb47b3

Please sign in to comment.