chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Validates that openapi.yaml documents ≥ 99% of implemented routes.
|
||||
* Routes marked x-internal: true in openapi.yaml count as "covered" because
|
||||
* they are acknowledged as existing — just not part of the public API surface.
|
||||
*
|
||||
* Fails if coverage < 99%.
|
||||
*/
|
||||
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import * as yaml from "js-yaml";
|
||||
|
||||
const ROOT = process.cwd();
|
||||
const API_ROOT = path.join(ROOT, "src", "app", "api");
|
||||
const OPENAPI_PATH = path.join(ROOT, "docs", "openapi.yaml");
|
||||
// Floor recorded on 2026-05-26 for release/v3.8.4: 137/365 routes documented.
|
||||
// The original ≥99% target tracks the OpenAPI audit follow-up (#2701);
|
||||
// until the backlog (services, free-proxies, relay-tokens, key-groups,
|
||||
// middleware/hooks, etc.) is documented, the gate enforces "no regressions"
|
||||
// instead of the absolute target. Raise this back to 99 once the backlog clears.
|
||||
const THRESHOLD = 36;
|
||||
|
||||
function collectRoutePaths(dir) {
|
||||
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
||||
const paths = [];
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(dir, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
paths.push(...collectRoutePaths(fullPath));
|
||||
continue;
|
||||
}
|
||||
if (entry.isFile() && entry.name === "route.ts") {
|
||||
const apiPath = path
|
||||
.dirname(fullPath)
|
||||
.replace(API_ROOT, "")
|
||||
.replace(/\[([^\]]+)\]/g, "{$1}");
|
||||
paths.push(`/api${apiPath}`);
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
function normalizePath(p) {
|
||||
return p.replace(/\/\[\.\.\.([^\]]+)\]/g, "/{$1}").replace(/\[([^\]]+)\]/g, "{$1}");
|
||||
}
|
||||
|
||||
if (!fs.existsSync(API_ROOT)) {
|
||||
console.error(`[openapi-coverage] FAIL — API root not found: ${API_ROOT}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!fs.existsSync(OPENAPI_PATH)) {
|
||||
console.error(`[openapi-coverage] FAIL — openapi.yaml not found: ${OPENAPI_PATH}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const implementedPaths = collectRoutePaths(API_ROOT).map(normalizePath).sort();
|
||||
const raw = yaml.load(fs.readFileSync(OPENAPI_PATH, "utf-8"));
|
||||
const documentedPaths = new Set(Object.keys(raw.paths || {}));
|
||||
|
||||
let covered = 0;
|
||||
const missing = [];
|
||||
|
||||
for (const p of implementedPaths) {
|
||||
if (documentedPaths.has(p)) {
|
||||
covered++;
|
||||
} else {
|
||||
missing.push(p);
|
||||
}
|
||||
}
|
||||
|
||||
const total = implementedPaths.length;
|
||||
const coverage = (covered / total) * 100;
|
||||
|
||||
if (coverage >= THRESHOLD) {
|
||||
console.log(
|
||||
`[openapi-coverage] PASS — ${coverage.toFixed(1)}% (${covered}/${total} routes documented)`
|
||||
);
|
||||
process.exit(0);
|
||||
} else {
|
||||
console.error(`[openapi-coverage] FAIL — coverage ${coverage.toFixed(1)}% < ${THRESHOLD}%`);
|
||||
console.error(`Missing routes (${missing.length}):`);
|
||||
missing.forEach((p) => console.error(` - ${p}`));
|
||||
process.exit(1);
|
||||
}
|
||||
Reference in New Issue
Block a user