{"version":3,"sources":["/Users/erunion/code/readme/oas/packages/oas-normalize/dist/index.cjs","../src/index.ts"],"names":[],"mappings":"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","file":"/Users/erunion/code/readme/oas/packages/oas-normalize/dist/index.cjs","sourcesContent":[null,"import type { Options } from './lib/types.js';\nimport type { ParserOptions, ValidationResult } from '@readme/openapi-parser';\nimport type { OpenAPI, OpenAPIV2, OpenAPIV3 } from 'openapi-types';\n\nimport fs from 'node:fs';\n\nimport { bundle, compileErrors, dereference, validate } from '@readme/openapi-parser';\nimport { isUnsafeURL } from '@readme/openapi-parser/lib/urls';\nimport postmanToOpenAPI from '@readme/postman-to-openapi';\nimport converter from 'swagger2openapi';\n\nimport { ValidationError } from './lib/errors.js';\nimport {\n  getAPIDefinitionType,\n  getType,\n  isOpenAPI,\n  isPostman,\n  isSwagger,\n  prepareURL,\n  stringToJSON,\n} from './lib/utils.js';\n\nexport default class OASNormalize {\n  cache: {\n    bundle?: OpenAPI.Document | false;\n    convert?: OpenAPI.Document | false;\n    deref?: OpenAPI.Document | false;\n    load?: Record<string, unknown> | false;\n  };\n\n  file: any;\n\n  opts: Options;\n\n  type: ReturnType<typeof getType>;\n\n  constructor(file: any, opts?: Options) {\n    this.file = file;\n    this.opts = {\n      colorizeErrors: false,\n      enablePaths: false,\n      parser: {},\n      ...opts,\n    };\n\n    if (!this.opts.enablePaths) {\n      if (!this.opts.parser) this.opts.parser = {};\n      if (!this.opts.parser.resolve) this.opts.parser.resolve = {};\n      this.opts.parser.resolve = { file: false };\n    }\n\n    this.type = getType(this.file);\n\n    this.cache = {\n      load: false,\n      bundle: false,\n      deref: false,\n    };\n  }\n\n  /**\n   * Load and return the API definition that `oas-normalize` was initialized with.\n   *\n   */\n  async load(): Promise<Record<string, unknown>> {\n    if (this.cache.load) return this.cache.load;\n\n    const resolve = (obj: Parameters<typeof stringToJSON>[0]) => {\n      const ret = stringToJSON(obj);\n      if (!ret) {\n        throw new Error(`Unable to retrieve API definition, it does not appear to be valid JSON.`);\n      }\n\n      this.cache.load = ret;\n      return ret;\n    };\n\n    switch (this.type) {\n      case 'json':\n      case 'string-json':\n      case 'string-yaml':\n        return resolve(this.file);\n\n      case 'buffer':\n        return resolve(this.file.toString());\n\n      case 'url': {\n        const { url, options } = prepareURL(this.file);\n        if (isUnsafeURL(url)) {\n          throw new Error(`Sorry, we cannot access ${url}.`);\n        }\n\n        const resp = await fetch(url, options).then(res => {\n          if (!res.ok) {\n            throw new Error(`Failed to fetch ${url}: ${res.statusText}`);\n          }\n\n          return res.text();\n        });\n        return resolve(resp);\n      }\n\n      case 'path': {\n        // Load a local file\n        if (!this.opts.enablePaths) {\n          throw new Error('Use `opts.enablePaths` to enable accessing local files.');\n        }\n\n        const contents = fs.readFileSync(this.file).toString();\n        if (!contents.trim()) {\n          throw new Error('No file contents found.');\n        }\n        return resolve(contents);\n      }\n\n      default:\n        throw new Error('Could not load this file.');\n    }\n  }\n\n  private static async convertPostmanToOpenAPI(schema: Record<string, unknown>) {\n    return postmanToOpenAPI(JSON.stringify(schema), undefined, {\n      outputFormat: 'json',\n      replaceVars: true,\n    }).then(JSON.parse);\n  }\n\n  /**\n   * Bundle up the given API definition, resolving any external `$ref` pointers in the process.\n   *\n   */\n  async bundle(): Promise<OpenAPI.Document> {\n    if (this.cache.bundle) return this.cache.bundle;\n    const parserOptions = this.opts.parser || {};\n\n    return this.load()\n      .then(schema => {\n        // Though Postman collections don't support `$ref` pointers for us to bundle we'll still\n        // upconvert it to an OpenAPI definition file so our returned dataset is always one of\n        // those for a Postman dataset.\n        if (isPostman(schema)) {\n          return OASNormalize.convertPostmanToOpenAPI(schema);\n        }\n\n        return schema;\n      })\n      .then(schema => bundle(schema, parserOptions))\n      .then(bundled => {\n        this.cache.bundle = bundled;\n        return bundled;\n      });\n  }\n\n  /**\n   * Dereference the given API definition.\n   *\n   */\n  async dereference(): Promise<OpenAPI.Document> {\n    if (this.cache.deref) return this.cache.deref;\n    const parserOptions = this.opts.parser || {};\n\n    return this.load()\n      .then(schema => {\n        // Though Postman collections don't support `$ref` pointers for us to dereference we'll\n        // still upconvert it to an OpenAPI definition file so our returned dataset is always one\n        // of those for a Postman dataset.\n        if (isPostman(schema)) {\n          return OASNormalize.convertPostmanToOpenAPI(schema);\n        }\n\n        return schema;\n      })\n      .then(schema => dereference(schema, parserOptions))\n      .then(dereferenced => {\n        this.cache.deref = dereferenced;\n        return dereferenced;\n      });\n  }\n\n  /**\n   * Dereference the given API definition.\n   *\n   * This method is deprecated in favor of `dereference`. It will be removed in a future release.\n   *\n   * @deprecated\n   */\n  async deref(): Promise<OpenAPI.Document> {\n    return this.dereference();\n  }\n\n  /**\n   * Convert a given API definition to OpenAPI if it is not already.\n   *\n   */\n  async convert(): Promise<OpenAPI.Document> {\n    if (this.cache.convert) return this.cache.convert;\n\n    return this.load()\n      .then(async schema => {\n        // If we have a Postman collection we need to convert it to OpenAPI.\n        return isPostman(schema) ? OASNormalize.convertPostmanToOpenAPI(schema) : schema;\n      })\n      .then(async schema => {\n        if (!isSwagger(schema) && !isOpenAPI(schema)) {\n          throw new Error('The supplied API definition is unsupported.');\n        } else if (isOpenAPI(schema)) {\n          return schema;\n        }\n\n        const baseVersion = parseInt(schema.swagger, 10);\n        if (baseVersion === 1) {\n          throw new Error('Swagger v1.2 is unsupported.');\n        }\n\n        return converter\n          .convertObj(schema, { anchors: true })\n          .then((options: { openapi: OpenAPI.Document }) => options.openapi);\n      });\n  }\n\n  /**\n   * Validate a given API definition.\n   *\n   * If supplied a Postman collection it will be converted to OpenAPI first and then run through\n   * standard OpenAPI validation.\n   *\n   */\n  async validate(\n    opts: {\n      /**\n       * Options to supply to our OpenAPI parser. See `@readme/openapi-parser` for documentation.\n       * This option is deprecated in favor of the `parser` option on the constructor. It will be\n       * removed in a future release.\n       *\n       * @see {@link https://npm.im/@readme/openapi-parser}\n       * @deprecated\n       */\n      parser?: ParserOptions;\n\n      /**\n       * Determines if `.validate()` should throw a `ValidationError` if the API definition is\n       * invalid.\n       *\n       * By default this will always happen however if you want to always instead receive a\n       * `ValidationResult` object back, which will still allow you to determine if the supplied\n       * API definition is valid or not, you can set this to `false`.\n       */\n      shouldThrowIfInvalid?: boolean;\n    } = {},\n  ): Promise<ValidationResult> {\n    const shouldThrowIfInvalid = opts.shouldThrowIfInvalid ?? true;\n    const parserOptions = opts.parser || this.opts.parser || {};\n    if (!parserOptions.validate) parserOptions.validate = {};\n    if (!parserOptions.validate.errors) parserOptions.validate.errors = {};\n\n    parserOptions.validate.errors.colorize = this.opts.colorizeErrors;\n\n    return this.load()\n      .then(async schema => {\n        // Because we don't have something akin to `openapi-parser` for Postman collections we just\n        // always convert them to OpenAPI.\n        return isPostman(schema) ? OASNormalize.convertPostmanToOpenAPI(schema) : schema;\n      })\n      .then(async schema => {\n        if (!isSwagger(schema) && !isOpenAPI(schema)) {\n          if (shouldThrowIfInvalid) {\n            throw new ValidationError('The supplied API definition is unsupported.');\n          }\n\n          return {\n            valid: false,\n            errors: [{ message: 'The supplied API definition is unsupported.' }],\n            warnings: [],\n            additionalErrors: 0,\n            specification: null,\n          };\n        } else if (isSwagger(schema)) {\n          const baseVersion = parseInt(schema.swagger, 10);\n          if (baseVersion === 1) {\n            if (shouldThrowIfInvalid) {\n              throw new ValidationError('Swagger v1.2 is unsupported.');\n            }\n\n            return {\n              valid: false,\n              errors: [{ message: 'Swagger v1.2 is unsupported.' }],\n              warnings: [],\n              additionalErrors: 0,\n              specification: 'Swagger',\n            };\n          }\n        }\n\n        /**\n         * `OpenAPIParser.validate()` dereferences schemas at the same time as validation, mutating\n         * the supplied parameter in the process, and does not give us an option to disable this.\n         * As we already have a dereferencing method on this library, and this method just needs to\n         * tell us if the API definition is valid or not, we need to clone the schema before\n         * supplying it to `openapi-parser`.\n         */\n        const clonedSchema = structuredClone(schema);\n\n        const result = await validate(clonedSchema, parserOptions);\n        if (!result.valid && shouldThrowIfInvalid) {\n          throw new ValidationError(compileErrors(result), {\n            errors: result.errors,\n            warnings: result.warnings,\n          });\n        }\n\n        // The API definition, whatever its format or specification, is valid.\n        return result;\n      });\n  }\n\n  /**\n   * Retrieve OpenAPI, Swagger, or Postman version information about the supplied API definition.\n   *\n   */\n  async version(): Promise<{\n    specification: 'openapi' | 'postman' | 'swagger';\n    version: string | 'unknown';\n  }> {\n    return this.load().then(schema => {\n      switch (getAPIDefinitionType(schema)) {\n        case 'openapi':\n          return {\n            specification: 'openapi',\n            version: (schema as unknown as OpenAPIV3.Document).openapi,\n          };\n\n        case 'postman': {\n          let version = 'unknown';\n          if ((schema?.info as Record<string, string>)?.schema) {\n            // Though `info.schema` is required by the Postman spec there's no strictness to its\n            // contents so we'll do our best to extract a version out of this schema URL that they\n            // seem to usually match. If not we'll fallback to treating it as an `unknown` version.\n            // oxlint-disable-next-line no-unsafe-optional-chaining -- We've already narrowed `.schema` down to be present.\n            const match = (schema?.info as Record<string, string>).schema.match(\n              /http(s?):\\/\\/schema.getpostman.com\\/json\\/collection\\/v([0-9.]+)\\//,\n            );\n\n            if (match) {\n              version = match[2];\n            }\n          }\n\n          return {\n            specification: 'postman',\n            version,\n          };\n        }\n\n        case 'swagger':\n          return {\n            specification: 'swagger',\n            version: (schema as unknown as OpenAPIV2.Document).swagger,\n          };\n\n        default:\n          throw new Error('Unknown file detected.');\n      }\n    });\n  }\n}\n"]}