123 lines
4.3 KiB
Plaintext
123 lines
4.3 KiB
Plaintext
import { performance } from 'node:perf_hooks';
|
|
import { Readable } from 'node:stream';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { BaseResolver, lintDocument, bundle, Source, makeDocumentFromString } from '@redocly/openapi-core';
|
|
import parseJson from 'parse-json';
|
|
import { debug, error, warn } from './utils.mjs';
|
|
|
|
async function parseSchema(schema, { absoluteRef, resolver }) {
|
|
if (!schema) {
|
|
throw new Error("Can\u2019t parse empty schema");
|
|
}
|
|
if (schema instanceof URL) {
|
|
const result = await resolver.resolveDocument(null, absoluteRef, true);
|
|
if ("parsed" in result) {
|
|
return result;
|
|
}
|
|
throw result.originalError;
|
|
}
|
|
if (schema instanceof Readable) {
|
|
const contents = await new Promise((resolve) => {
|
|
schema.resume();
|
|
schema.setEncoding("utf8");
|
|
let content = "";
|
|
schema.on("data", (chunk) => {
|
|
content += chunk;
|
|
});
|
|
schema.on("end", () => {
|
|
resolve(content.trim());
|
|
});
|
|
});
|
|
return parseSchema(contents, { absoluteRef, resolver });
|
|
}
|
|
if (schema instanceof Buffer) {
|
|
return parseSchema(schema.toString("utf8"), { absoluteRef, resolver });
|
|
}
|
|
if (typeof schema === "string") {
|
|
if (schema.startsWith("http://") || schema.startsWith("https://") || schema.startsWith("file://")) {
|
|
const url = new URL(schema);
|
|
return parseSchema(url, {
|
|
absoluteRef: url.protocol === "file:" ? fileURLToPath(url) : url.href,
|
|
resolver
|
|
});
|
|
}
|
|
if (schema[0] === "{") {
|
|
return {
|
|
source: new Source(absoluteRef, schema, "application/json"),
|
|
parsed: parseJson(schema)
|
|
};
|
|
}
|
|
return makeDocumentFromString(schema, absoluteRef);
|
|
}
|
|
if (typeof schema === "object" && !Array.isArray(schema)) {
|
|
return {
|
|
source: new Source(absoluteRef, JSON.stringify(schema), "application/json"),
|
|
parsed: schema
|
|
};
|
|
}
|
|
throw new Error(`Expected string, object, or Buffer. Got ${Array.isArray(schema) ? "Array" : typeof schema}`);
|
|
}
|
|
function _processProblems(problems, options) {
|
|
if (problems.length) {
|
|
let errorMessage;
|
|
for (const problem of problems) {
|
|
const problemLocation = problem.location?.[0].pointer;
|
|
const problemMessage = problemLocation ? `${problem.message} at ${problemLocation}` : problem.message;
|
|
if (problem.severity === "error") {
|
|
errorMessage = problemMessage;
|
|
error(problemMessage);
|
|
} else {
|
|
warn(problemMessage, options.silent);
|
|
}
|
|
}
|
|
if (errorMessage) {
|
|
throw new Error(errorMessage);
|
|
}
|
|
}
|
|
}
|
|
async function validateAndBundle(source, options) {
|
|
const redocConfigT = performance.now();
|
|
debug("Loaded Redoc config", "redoc", performance.now() - redocConfigT);
|
|
const redocParseT = performance.now();
|
|
let absoluteRef = fileURLToPath(new URL(options?.cwd ?? `file://${process.cwd()}/`));
|
|
if (source instanceof URL) {
|
|
absoluteRef = source.protocol === "file:" ? fileURLToPath(source) : source.href;
|
|
}
|
|
const resolver = new BaseResolver(options.redoc.resolve);
|
|
const document = await parseSchema(source, {
|
|
absoluteRef,
|
|
resolver
|
|
});
|
|
debug("Parsed schema", "redoc", performance.now() - redocParseT);
|
|
const openapiVersion = Number.parseFloat(document.parsed.openapi);
|
|
if (document.parsed.swagger || !document.parsed.openapi || Number.isNaN(openapiVersion) || openapiVersion < 3 || openapiVersion >= 4) {
|
|
if (document.parsed.swagger) {
|
|
throw new Error("Unsupported Swagger version: 2.x. Use OpenAPI 3.x instead.");
|
|
}
|
|
if (document.parsed.openapi || openapiVersion < 3 || openapiVersion >= 4) {
|
|
throw new Error(`Unsupported OpenAPI version: ${document.parsed.openapi}`);
|
|
}
|
|
throw new Error("Unsupported schema format, expected `openapi: 3.x`");
|
|
}
|
|
const redocLintT = performance.now();
|
|
const problems = await lintDocument({
|
|
document,
|
|
config: options.redoc.styleguide,
|
|
externalRefResolver: resolver
|
|
});
|
|
_processProblems(problems, options);
|
|
debug("Linted schema", "lint", performance.now() - redocLintT);
|
|
const redocBundleT = performance.now();
|
|
const bundled = await bundle({
|
|
config: options.redoc,
|
|
dereference: false,
|
|
doc: document
|
|
});
|
|
_processProblems(bundled.problems, options);
|
|
debug("Bundled schema", "bundle", performance.now() - redocBundleT);
|
|
return bundled.bundle.parsed;
|
|
}
|
|
|
|
export { parseSchema, validateAndBundle };
|
|
//# sourceMappingURL=redoc.mjs.map
|