UNPKG

oas-normalize

Version:

Tooling for converting, validating, and parsing OpenAPI, Swagger, and Postman API definitions

226 lines (225 loc) 6.98 kB
import { ValidationError } from "./chunk-KGEOPSPH.js"; import { getAPIDefinitionType, getType, isOpenAPI, isPostman, isSwagger, prepareURL, stringToJSON } from "./chunk-SZISBDLH.js"; // src/index.ts import fs from "fs"; import { bundle, compileErrors, dereference, validate } from "@readme/openapi-parser"; import postmanToOpenAPI from "@readme/postman-to-openapi"; import converter from "swagger2openapi"; var OASNormalize = class _OASNormalize { cache; // biome-ignore lint/suspicious/noExplicitAny: Intentionally loose because this library supports a wide variety of inputs. file; opts; type; // biome-ignore lint/suspicious/noExplicitAny: Intentionally loose because this library supports a wide variety of inputs. constructor(file, opts) { this.file = file; this.opts = { colorizeErrors: false, enablePaths: false, parser: {}, ...opts }; if (!this.opts.enablePaths) { if (!this.opts.parser) this.opts.parser = {}; if (!this.opts.parser.resolve) this.opts.parser.resolve = {}; this.opts.parser.resolve = { file: false }; } this.type = getType(this.file); this.cache = { load: false, bundle: false, deref: false }; } /** * Load and return the API definition that `oas-normalize` was initialized with. * */ async load() { if (this.cache.load) return this.cache.load; const resolve = (obj) => { const ret = stringToJSON(obj); this.cache.load = ret; return ret; }; switch (this.type) { case "json": case "string-json": case "string-yaml": return resolve(this.file); case "buffer": return resolve(this.file.toString()); case "url": { const { url, options } = prepareURL(this.file); const resp = await fetch(url, options).then((res) => res.text()); return resolve(resp); } case "path": { if (!this.opts.enablePaths) { throw new Error("Use `opts.enablePaths` to enable accessing local files."); } const contents = fs.readFileSync(this.file).toString(); if (!contents.trim()) { throw new Error("No file contents found."); } return resolve(contents); } default: throw new Error("Could not load this file."); } } static async convertPostmanToOpenAPI(schema) { return postmanToOpenAPI(JSON.stringify(schema), void 0, { outputFormat: "json", replaceVars: true }).then(JSON.parse); } /** * Bundle up the given API definition, resolving any external `$ref` pointers in the process. * */ async bundle() { if (this.cache.bundle) return this.cache.bundle; const parserOptions = this.opts.parser || {}; return this.load().then((schema) => { if (isPostman(schema)) { return _OASNormalize.convertPostmanToOpenAPI(schema); } return schema; }).then((schema) => bundle(schema, parserOptions)).then((bundled) => { this.cache.bundle = bundled; return bundled; }); } /** * Dereference the given API definition. * */ async dereference() { if (this.cache.deref) return this.cache.deref; const parserOptions = this.opts.parser || {}; return this.load().then((schema) => { if (isPostman(schema)) { return _OASNormalize.convertPostmanToOpenAPI(schema); } return schema; }).then((schema) => dereference(schema, parserOptions)).then((dereferenced) => { this.cache.deref = dereferenced; return dereferenced; }); } /** * Dereference the given API definition. * * This method is deprecated in favor of `dereference`. It will be removed in a future release. * * @deprecated */ async deref() { return this.dereference(); } /** * Convert a given API definition to OpenAPI if it is not already. * */ async convert() { if (this.cache.convert) return this.cache.convert; return this.load().then(async (schema) => { return isPostman(schema) ? _OASNormalize.convertPostmanToOpenAPI(schema) : schema; }).then(async (schema) => { if (!isSwagger(schema) && !isOpenAPI(schema)) { throw new Error("The supplied API definition is unsupported."); } else if (isOpenAPI(schema)) { return schema; } const baseVersion = parseInt(schema.swagger, 10); if (baseVersion === 1) { throw new Error("Swagger v1.2 is unsupported."); } return converter.convertObj(schema, { anchors: true }).then((options) => options.openapi); }); } /** * Validate a given API definition. * * If supplied a Postman collection it will be converted to OpenAPI first and then run through * standard OpenAPI validation. * */ async validate(opts = {}) { const parserOptions = opts.parser || this.opts.parser || {}; if (!parserOptions.validate) parserOptions.validate = {}; if (!parserOptions.validate.errors) parserOptions.validate.errors = {}; parserOptions.validate.errors.colorize = this.opts.colorizeErrors; return this.load().then(async (schema) => { return isPostman(schema) ? _OASNormalize.convertPostmanToOpenAPI(schema) : schema; }).then(async (schema) => { if (!isSwagger(schema) && !isOpenAPI(schema)) { throw new ValidationError("The supplied API definition is unsupported."); } else if (isSwagger(schema)) { const baseVersion = parseInt(schema.swagger, 10); if (baseVersion === 1) { throw new ValidationError("Swagger v1.2 is unsupported."); } } const clonedSchema = JSON.parse(JSON.stringify(schema)); const result = await validate(clonedSchema, parserOptions); if (!result.valid) { throw new ValidationError(compileErrors(result)); } return result; }); } /** * Retrieve OpenAPI, Swagger, or Postman version information about the supplied API definition. * */ async version() { return this.load().then((schema) => { switch (getAPIDefinitionType(schema)) { case "openapi": return { specification: "openapi", version: schema.openapi }; case "postman": { let version = "unknown"; if (schema?.info?.schema) { const match = (schema?.info).schema.match( /http(s?):\/\/schema.getpostman.com\/json\/collection\/v([0-9.]+)\// ); if (match) { version = match[2]; } } return { specification: "postman", version }; } case "swagger": return { specification: "swagger", version: schema.swagger }; default: throw new Error("Unknown file detected."); } }); } }; export { OASNormalize as default }; //# sourceMappingURL=index.js.map