UNPKG

openapi-typescript

Version:

Convert OpenAPI 3.0 & 3.1 schemas to TypeScript

124 lines 4.9 kB
import { BaseResolver, bundle, makeDocumentFromString, Source, lintDocument, } from "@redocly/openapi-core"; import { performance } from "node:perf_hooks"; import { Readable } from "node:stream"; import { fileURLToPath } from "node:url"; import parseJson from "parse-json"; import { debug, error, warn } from "./utils.js"; export async function parseSchema(schema, { absoluteRef, resolver }) { if (!schema) { throw new Error("Can’t 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 = undefined; 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); } } } export 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; } //# sourceMappingURL=redoc.js.map