Initial curated itworx-knowledge-hub source from 3b1751d0d9dee551aa6994eee0093704dc334817
This commit is contained in:
commit
ad8ad252a9
825 files changed
+124216
No files matched your search
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Lightweight, dependency-free OpenAPI consistency check: valid YAML, every internal
|
||||
// $ref resolves, and every path/schema referenced by a $ref actually exists. This is
|
||||
// not a full OpenAPI 3.1 schema validator, but it catches the class of error that
|
||||
// actually breaks generated clients and docs sites: dangling references and typos.
|
||||
|
||||
import fs from "node:fs";
|
||||
import process from "node:process";
|
||||
import yaml from "js-yaml";
|
||||
|
||||
const path = "docs/api/openapi.yaml";
|
||||
const document = yaml.load(fs.readFileSync(path, "utf8"));
|
||||
|
||||
const errors = [];
|
||||
|
||||
function resolveRef(ref) {
|
||||
if (!ref.startsWith("#/")) {
|
||||
errors.push(`External or malformed $ref not supported: ${ref}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const segments = ref
|
||||
.slice(2)
|
||||
.split("/")
|
||||
.map((segment) => segment.replace(/~1/g, "/").replace(/~0/g, "~"));
|
||||
|
||||
let cursor = document;
|
||||
for (const segment of segments) {
|
||||
if (cursor === undefined || cursor === null || !(segment in cursor)) {
|
||||
errors.push(`Dangling $ref: ${ref}`);
|
||||
return;
|
||||
}
|
||||
cursor = cursor[segment];
|
||||
}
|
||||
}
|
||||
|
||||
function walk(node) {
|
||||
if (Array.isArray(node)) {
|
||||
for (const item of node) {
|
||||
walk(item);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (node && typeof node === "object") {
|
||||
for (const [key, value] of Object.entries(node)) {
|
||||
if (key === "$ref" && typeof value === "string") {
|
||||
resolveRef(value);
|
||||
} else {
|
||||
walk(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!document || typeof document !== "object") {
|
||||
errors.push("Document did not parse to an object.");
|
||||
} else {
|
||||
if (document.openapi === undefined) {
|
||||
errors.push("Missing top-level 'openapi' version field.");
|
||||
}
|
||||
if (!document.paths || Object.keys(document.paths).length === 0) {
|
||||
errors.push("No paths defined.");
|
||||
}
|
||||
walk(document);
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
console.error("OpenAPI validation failed:");
|
||||
for (const error of errors) {
|
||||
console.error(`- ${error}`);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const pathCount = Object.keys(document.paths ?? {}).length;
|
||||
const schemaCount = Object.keys(document.components?.schemas ?? {}).length;
|
||||
console.log(`OpenAPI document is well-formed: ${pathCount} paths, ${schemaCount} schemas, all $ref pointers resolve.`);
|
||||
Reference in new issue
Block a user