UNPKG

@scalar/openapi-parser

Version:

modern OpenAPI parser written in TypeScript

114 lines (113 loc) 3.77 kB
import { ERRORS } from "../configuration/index.js"; import { getEntrypoint } from "./get-entrypoint.js"; import { getSegmentsFromPath } from "./get-segments-from-path.js"; import { isObject } from "./is-object.js"; import { makeFilesystem } from "./make-filesystem.js"; function resolveReferences(input, options, file, errors = []) { const clonedInput = structuredClone(input); const filesystem = makeFilesystem(clonedInput); const entrypoint = getEntrypoint(filesystem); const finalInput = file?.specification ?? entrypoint.specification; if (!isObject(finalInput)) { if (options?.throwOnError) { throw new Error(ERRORS.NO_CONTENT); } return { valid: false, errors, schema: finalInput }; } dereference(finalInput, filesystem, file ?? entrypoint, /* @__PURE__ */ new WeakSet(), errors, options); errors = errors.filter( (error, index, self) => index === self.findIndex((t) => t.message === error.message && t.code === error.code) ); return { valid: errors.length === 0, errors, schema: finalInput }; } function dereference(schema, filesystem, entrypoint, resolvedSchemas, errors, options) { if (schema === null || resolvedSchemas.has(schema)) { return; } resolvedSchemas.add(schema); function resolveExternal(externalFile) { dereference(externalFile.specification, filesystem, externalFile, resolvedSchemas, errors, options); return externalFile; } while (schema.$ref !== void 0) { const resolved = resolveUri(schema.$ref, options, entrypoint, filesystem, resolveExternal, errors); if (typeof resolved !== "object" || resolved === null) { break; } const dereferencedRef = schema.$ref; delete schema.$ref; for (const key of Object.keys(resolved)) { if (schema[key] === void 0) { schema[key] = resolved[key]; } } if (dereferencedRef) { options?.onDereference?.({ schema, ref: dereferencedRef }); } } for (const value of Object.values(schema)) { if (typeof value === "object" && value !== null) { dereference(value, filesystem, entrypoint, resolvedSchemas, errors, options); } } } function resolveUri(uri, options, file, filesystem, resolve, errors) { if (typeof uri !== "string") { if (options?.throwOnError) { throw new Error(ERRORS.INVALID_REFERENCE.replace("%s", uri)); } errors.push({ code: "INVALID_REFERENCE", message: ERRORS.INVALID_REFERENCE.replace("%s", uri) }); return void 0; } const [prefix, path] = uri.split("#", 2); const isDifferentFile = prefix !== file.filename; if (prefix && isDifferentFile) { const externalReference = filesystem.find((entry) => { return entry.filename === prefix; }); if (!externalReference) { if (options?.throwOnError) { throw new Error(ERRORS.EXTERNAL_REFERENCE_NOT_FOUND.replace("%s", prefix)); } errors.push({ code: "EXTERNAL_REFERENCE_NOT_FOUND", message: ERRORS.EXTERNAL_REFERENCE_NOT_FOUND.replace("%s", prefix) }); return void 0; } if (path === void 0) { return externalReference.specification; } return resolveUri(`#${path}`, options, resolve(externalReference), filesystem, resolve, errors); } const segments = getSegmentsFromPath(path); try { return segments.reduce((acc, key) => { return acc[key]; }, file.specification); } catch (_error) { if (options?.throwOnError) { throw new Error(ERRORS.INVALID_REFERENCE.replace("%s", uri)); } errors.push({ code: "INVALID_REFERENCE", message: ERRORS.INVALID_REFERENCE.replace("%s", uri) }); } return void 0; } export { resolveReferences }; //# sourceMappingURL=resolve-references.js.map