52 lines
1.6 KiB
JavaScript
52 lines
1.6 KiB
JavaScript
import { readFile } from "node:fs/promises";
|
|
import { resolve } from "node:path";
|
|
|
|
export async function loadJsonSource(source) {
|
|
if (/^https?:\/\//u.test(source)) {
|
|
const response = await fetch(source, {
|
|
headers: { accept: "application/json" },
|
|
signal: AbortSignal.timeout(15_000),
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error(
|
|
`Unable to load OpenAPI document: ${response.status} ${response.statusText}`,
|
|
);
|
|
}
|
|
return response.json();
|
|
}
|
|
|
|
const content = await readFile(resolve(source), "utf8");
|
|
return JSON.parse(content);
|
|
}
|
|
|
|
export function findMissingOperations(contract, openApiDocument) {
|
|
const openApiPaths = openApiDocument?.paths;
|
|
if (!openApiPaths || typeof openApiPaths !== "object") {
|
|
throw new Error("OpenAPI document does not contain a paths object");
|
|
}
|
|
|
|
const normalizedPaths = new Map(
|
|
Object.entries(openApiPaths).map(([path, pathItem]) => [
|
|
normalizePath(path),
|
|
pathItem,
|
|
]),
|
|
);
|
|
|
|
return Object.entries(contract).flatMap(([operationId, operation]) => {
|
|
const method = operation.method.toLowerCase();
|
|
const pathItem = normalizedPaths.get(normalizePath(operation.path));
|
|
if (!pathItem) {
|
|
return [{ operationId, ...operation, reason: "path is missing" }];
|
|
}
|
|
if (!pathItem[method]) {
|
|
return [{ operationId, ...operation, reason: "method is missing" }];
|
|
}
|
|
return [];
|
|
});
|
|
}
|
|
|
|
export function normalizePath(path) {
|
|
const withoutTrailingSlash = path.length > 1 ? path.replace(/\/+$/u, "") : path;
|
|
return withoutTrailingSlash.replace(/\{[^/{}]+\}/gu, "{}");
|
|
}
|