{"version":3,"sources":["/Users/erunion/code/readme/oas/packages/parser/dist/index.cjs","../src/index.ts","../src/util.ts","../src/lib/index.ts","../src/repair.ts","../src/validators/schema.ts","../src/lib/hasInvalidPaths.ts","../src/lib/reduceAjvErrors.ts","../src/validators/spec/index.ts","../src/validators/spec/openapi.ts","../src/validators/spec/swagger.ts","../src/validators/spec.ts"],"names":[],"mappings":"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","file":"/Users/erunion/code/readme/oas/packages/parser/dist/index.cjs","sourcesContent":[null,"import type { APIDocument, ErrorDetails, ParserOptions, ValidationResult, WarningDetails } from './types.js';\n\nimport { $RefParser, dereferenceInternal, MissingPointerError } from '@apidevtools/json-schema-ref-parser';\n\nimport { isOpenAPI, isSwagger } from './lib/assertions.js';\nimport { convertOptionsForParser, normalizeArguments, repairSchema } from './util.js';\nimport { validateSchema } from './validators/schema.js';\nimport { validateSpec } from './validators/spec.js';\n\nexport type { ParserOptions, ValidationResult, ErrorDetails, WarningDetails };\n\n/**\n * Parses the given API definition, in JSON or YAML format, and returns it as a JSON object. This\n * method **does not** resolve `$ref` pointers or dereference anything. It simply parses _one_ file\n * and returns it.\n *\n * @param api - A file path or URL to a JSON Schema object, or the JSON Schema object itself.\n * @param options\n */\nexport async function parse<S extends APIDocument = APIDocument>(api: S | string, options?: ParserOptions): Promise<S> {\n  const args = normalizeArguments<S>(api);\n  const parserOptions = convertOptionsForParser(options);\n\n  const parser = new $RefParser<S>();\n  const schema = await parser.parse(args.path, args.schema, parserOptions);\n\n  // If necessary, repair the schema of any anomalies and quirks.\n  repairSchema(schema, args.path);\n\n  return schema;\n}\n\n/**\n * Bundles all referenced files and URLs into a single API definition that only has _internal_\n * `$ref` pointers. This lets you split up your definition however you want while you're building\n * it, but later combine all those files together when it's time to package or distribute the API\n * definition to other people. The resulting definition size will be small, since it will still\n * contain _internal_ JSON references rather than being fully-dereferenced.\n *\n * @param api - A file path or URL to a JSON Schema object, or the JSON Schema object itself.\n * @param options\n */\nexport async function bundle<S extends APIDocument = APIDocument>(\n  api: S | string,\n  options?: ParserOptions,\n): Promise<S> {\n  const args = normalizeArguments<S>(api);\n  const parserOptions = convertOptionsForParser(options);\n\n  const parser = new $RefParser<S>();\n  await parser.bundle(args.path, args.schema, parserOptions);\n\n  // If necessary, repair the schema of any anomalies and quirks.\n  repairSchema(parser.schema, args.path);\n\n  return parser.schema;\n}\n\n/**\n * Dereferences all `$ref` pointers in the supplied API definition, replacing each reference with\n * its resolved value. This results in an API definition that does not contain _any_ `$ref`\n * pointers. Instead, it's a normal JSON object tree that can easily be crawled and used just like\n * any other object. This is great for programmatic usage, especially when using tools that don't\n * understand JSON references.\n *\n * @param api - A file path or URL to a JSON Schema object, or the JSON Schema object itself.\n * @param options\n */\nexport async function dereference<S extends APIDocument = APIDocument>(\n  api: S | string,\n  options?: ParserOptions,\n): Promise<S> {\n  const args = normalizeArguments<S>(api);\n  const parserOptions = convertOptionsForParser(options);\n\n  const parser = new $RefParser<S>();\n  await parser.dereference(args.path, args.schema, parserOptions);\n\n  // If necessary, repair the schema of any anomalies and quirks.\n  repairSchema(parser.schema, args.path);\n\n  return parser.schema;\n}\n\n/**\n * Validates the API definition against the Swagger 2.0, OpenAPI 3.0, or OpenAPI 3.1 specifications.\n *\n * In addition to validating the API definition against their respective specification schemas it\n * will also be validated against specific areas that aren't covered by the Swagger or OpenAPI\n * schemas, such as duplicate parameters, invalid component schema names, or duplicate\n * `operationId` values.\n *\n * If validation fails an error will be thrown with information about what, and where, the error\n * lies within the API definition.\n *\n * Internally this method invokes [`dereference()`](#dereference) so the returned object, whether\n * its a Swagger or OpenAPI definition, will be fully dereferenced.\n *\n * @see {@link https://github.com/OAI/OpenAPI-Specification/tree/main/schemas/v2.0}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/tree/main/schemas/v3.0}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/tree/main/schemas/v3.1}\n * @param api - A file path or URL to a JSON Schema object, or the JSON Schema object itself.\n * @param options\n */\nexport async function validate<S extends APIDocument, Options extends ParserOptions>(\n  api: S | string,\n  options?: Options,\n): Promise<ValidationResult> {\n  const args = normalizeArguments<S>(api);\n  const parserOptions = convertOptionsForParser(options);\n\n  let result: ValidationResult;\n\n  // ZSchema doesn't support circular objects, so don't dereference circular $refs yet\n  // (see https://github.com/zaggino/z-schema/issues/137)\n  const circular$RefOption = parserOptions.dereference.circular;\n  parserOptions.dereference.circular = 'ignore';\n\n  const parser = new $RefParser<S>();\n  try {\n    await parser.dereference(args.path, args.schema, parserOptions);\n  } catch (err) {\n    // `json-schema-ref-parser` will throw exceptions on things like `$ref` pointers that can't\n    // be resolved so we need to capture and reformat those into our expected `ValidationResult`\n    // format.\n    if (err instanceof MissingPointerError) {\n      return {\n        valid: false,\n        errors: [{ message: err.message }],\n        warnings: [],\n        additionalErrors: 0,\n        specification: null,\n      };\n    }\n\n    throw err;\n  }\n\n  if (!isSwagger(parser.schema) && !isOpenAPI(parser.schema)) {\n    return {\n      valid: false,\n      errors: [{ message: 'Supplied schema is not a valid API definition.' }],\n      warnings: [],\n      additionalErrors: 0,\n      specification: null,\n    };\n  }\n\n  // Restore the original options, now that we're done dereferencing\n  parserOptions.dereference.circular = circular$RefOption;\n\n  // Validate the API against the OpenAPI or Swagger JSON schema definition.\n  // NOTE: This is safe to do, because we haven't dereferenced circular $refs yet\n  result = validateSchema(parser.schema, options);\n  if (!result.valid) {\n    return result;\n  }\n\n  if (parser.$refs?.circular) {\n    if (circular$RefOption === true) {\n      // The API has circular reference so we need to do a second pass to fully dereference it.\n      dereferenceInternal<S>(parser, parserOptions);\n    } else if (circular$RefOption === false) {\n      // The API has circular references but we're configured to not permit that.\n      throw new ReferenceError(\n        'The API contains circular references but the validator is configured to not permit them.',\n      );\n    }\n  }\n\n  // Validate the API against the OpenAPI or Swagger specification.\n  const openapiRules = options?.validate?.rules?.openapi;\n  const swaggerRules = options?.validate?.rules?.swagger;\n  result = validateSpec(parser.schema, {\n    openapi: {\n      'array-without-items': openapiRules?.['array-without-items'] || 'error',\n      'duplicate-non-request-body-parameters': openapiRules?.['duplicate-non-request-body-parameters'] || 'error',\n      'duplicate-operation-id': openapiRules?.['duplicate-operation-id'] || 'error',\n      'non-optional-path-parameters': openapiRules?.['non-optional-path-parameters'] || 'error',\n      'path-parameters-not-in-parameters': openapiRules?.['path-parameters-not-in-parameters'] || 'error',\n      'path-parameters-not-in-path': openapiRules?.['path-parameters-not-in-path'] || 'error',\n    },\n    swagger: {\n      'array-without-items': swaggerRules?.['array-without-items'] || 'error',\n      'duplicate-non-request-body-parameters': swaggerRules?.['duplicate-non-request-body-parameters'] || 'error',\n      'duplicate-operation-id': swaggerRules?.['duplicate-operation-id'] || 'error',\n      'non-optional-path-parameters': swaggerRules?.['non-optional-path-parameters'] || 'error',\n      'path-parameters-not-in-parameters': swaggerRules?.['path-parameters-not-in-parameters'] || 'error',\n      'path-parameters-not-in-path': swaggerRules?.['path-parameters-not-in-path'] || 'error',\n      'unknown-required-schema-property': swaggerRules?.['unknown-required-schema-property'] || 'error',\n    },\n  });\n\n  return result;\n}\n\n/**\n * A utility to transform the `ValidationResult` from a `validate()` call into a human-readable\n * string.\n *\n */\nexport function compileErrors(result: ValidationResult): string {\n  const specName = result.specification || 'API definition';\n  const status = !result.valid ? 'failed' : 'succeeded, but with warnings';\n\n  const message: string[] = [`${specName} schema validation ${status}.`];\n\n  if (result.valid === false) {\n    if (result.errors.length) {\n      message.push(...result.errors.map(err => err.message));\n    }\n  }\n\n  if (result.warnings.length) {\n    if (result.valid === false && result.errors.length) {\n      message.push('We have also found some additional warnings:');\n    }\n\n    message.push(...result.warnings.map(warn => warn.message));\n  }\n\n  if (result.valid === false && result.additionalErrors > 0) {\n    message.push(\n      `Plus an additional ${result.additionalErrors} errors. Please resolve the above and re-run validation to see more.`,\n    );\n  }\n\n  return message.join('\\n\\n');\n}\n","import type { ParserOptions as $RefParserOptions } from '@apidevtools/json-schema-ref-parser';\nimport type { APIDocument, ParserOptions } from './types.js';\n\nimport { getJsonSchemaRefParserDefaultOptions } from '@apidevtools/json-schema-ref-parser';\n\nimport { isOpenAPI } from './lib/assertions.js';\nimport { fixOasRelativeServers } from './repair.js';\n\n/**\n * If necessary, repair the schema of any anomalies and quirks.\n *\n */\nexport function repairSchema<S extends APIDocument = APIDocument>(schema: S, filePath?: string): void {\n  if (isOpenAPI(schema)) {\n    // This is an OpenAPI v3 schema, check if the configured `servers` have any relative paths and\n    // fix them if the content was pulled from a web resource.\n    fixOasRelativeServers(schema, filePath);\n  }\n}\n\n/**\n * Normalize our library variable arguments into a standard format to be used within\n * `json-schema-ref-parser`.\n *\n */\nexport function normalizeArguments<S extends APIDocument = APIDocument>(\n  api: S | string,\n): { path: string; schema: S | undefined } {\n  return {\n    path: typeof api === 'string' ? api : '',\n    schema: typeof api === 'object' ? (api as S) : undefined,\n  };\n}\n\n/**\n * Convert our option set to be used within `json-schema-ref-parser`.\n *\n */\nexport function convertOptionsForParser(options: ParserOptions): Partial<$RefParserOptions> {\n  const parserOptions = getJsonSchemaRefParserDefaultOptions();\n\n  return {\n    ...parserOptions,\n    dereference: {\n      ...parserOptions.dereference,\n\n      circular:\n        options?.dereference && 'circular' in options.dereference\n          ? options.dereference.circular\n          : parserOptions.dereference.circular,\n      onCircular: options?.dereference?.onCircular || parserOptions.dereference.onCircular,\n      onDereference: options?.dereference?.onDereference || parserOptions.dereference.onDereference,\n\n      // OpenAPI 3.1 allows for `summary` and `description` properties at the same level as a `$ref`\n      // pointer to be preserved when that `$ref` pointer is dereferenced. The default behavior of\n      // `json-schema-ref-parser` is to discard these properties but this option allows us to\n      // override that behavior.\n      preservedProperties: ['summary', 'description'],\n    },\n\n    resolve: {\n      ...parserOptions.resolve,\n\n      external:\n        options?.resolve && 'external' in options.resolve ? options.resolve.external : parserOptions.resolve.external,\n\n      file: options?.resolve && 'file' in options.resolve ? options.resolve.file : parserOptions.resolve.file,\n\n      http: {\n        ...(typeof parserOptions.resolve.http === 'object' ? parserOptions.resolve.http : {}),\n        timeout: options?.resolve?.http && 'timeout' in options.resolve.http ? options.resolve.http.timeout : 5000,\n      },\n    },\n\n    timeoutMs: options?.timeoutMs,\n  };\n}\n","import type { OpenAPIV2, OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';\n\nimport { isSwagger } from './assertions.js';\n\n/**\n * Regular expression that matches path parameter templating.\n *\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#path-templating}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#path-templating}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#path-templating}\n */\nexport const pathParameterTemplateRegExp: RegExp = /\\{([^/}]+)}/g;\n\n/**\n * List of HTTP verbs used for OperationItem as per the OpenAPI and Swagger specifications\n *\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#path-item-object}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#path-item-object}\n */\nexport const supportedHTTPMethods = ['get', 'post', 'put', 'delete', 'patch', 'options', 'head', 'trace'] as const;\nexport const swaggerHTTPMethods = ['get', 'put', 'post', 'delete', 'options', 'head', 'patch'] as const;\n\n/**\n * Determine the proper name for the API specification schema used by a given schema.\n *\n */\nexport function getSpecificationName(\n  api: OpenAPIV2.Document | OpenAPIV3_1.Document | OpenAPIV3.Document,\n): 'OpenAPI' | 'Swagger' {\n  return isSwagger(api) ? 'Swagger' : 'OpenAPI';\n}\n","import type { OpenAPI, OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';\n\nimport { isOpenAPI } from './lib/assertions.js';\nimport { supportedHTTPMethods } from './lib/index.js';\n\n/**\n * This function takes in a `ServerObject`, checks if it has relative path and then fixes it as per\n * the path URL.\n *\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#server-object}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#server-object}\n *\n * @param server - The server object to be fixed.\n * @param path - The path (an HTTP(S) url) from where the file was downloaded.\n * @returns The fixed server object\n */\nfunction fixServers(\n  server: OpenAPIV3_1.ReferenceObject | OpenAPIV3.ParameterObject | OpenAPIV3.ServerObject,\n  path: string,\n) {\n  // A server URL starting with \"/\" tells that it is not an HTTP(s) URL.\n  if (server && 'url' in server && server.url && server.url.startsWith('/')) {\n    try {\n      const inUrl = new URL(path);\n\n      server.url = `${inUrl.protocol}//${inUrl.hostname}${server.url}`;\n    } catch {\n      // The server path isn't valid but we shouldn't crash out.\n    }\n  }\n}\n\n/**\n * This function helps fix the relative servers in the API definition file be at root, path or\n * operation's level.\n *\n * From the OpenAPI v3 specification for the `ServerObject` `url` property:\n *\n *    REQUIRED. A URL to the target host. This URL supports Server Variables and MAY be relative,\n *    to indicate that the host location is relative to the location where the OpenAPI document is\n *    being served. Variable substitutions will be made when a variable is named in `{brackets}`.\n *\n * Further the spec says that `servers` property can show up at root level, in `PathItemObject` or\n * in `OperationObject`. However interpretation of the spec says that relative paths for servers\n * should take into account the hostname that serves the OpenAPI file.\n *\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#server-object}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#server-object}\n */\nexport function fixOasRelativeServers(schema: OpenAPI.Document, filePath?: string): void {\n  if (!schema || !isOpenAPI(schema) || !filePath || (!filePath.startsWith('http:') && !filePath.startsWith('https:'))) {\n    return;\n  }\n\n  if (schema.servers) {\n    schema.servers.map(server => fixServers(server, filePath)); // Root level servers array's fixup\n  }\n\n  (['paths', 'webhooks'] as const).forEach(component => {\n    if (component in schema) {\n      const schemaElement = schema.paths || {};\n      Object.keys(schemaElement).forEach(path => {\n        const pathItem = schemaElement[path] || {};\n        Object.keys(pathItem).forEach((opItem: keyof typeof pathItem) => {\n          const pathItemElement = pathItem[opItem];\n          if (!pathItemElement) {\n            return;\n          }\n\n          /**\n           * Servers are at the `PathItemObject` level.\n           *\n           * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#path-item-object}\n           * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#path-item-object}\n           */\n          if (opItem === 'servers' && Array.isArray(pathItemElement)) {\n            pathItemElement.forEach(server => {\n              fixServers(server, filePath);\n            });\n            return;\n          }\n\n          /**\n           * Servers are at the `OperationObject` level.\n           *\n           * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#operation-object}\n           * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#operation-object}\n           */\n          if (\n            supportedHTTPMethods.includes(opItem as unknown as (typeof supportedHTTPMethods)[number]) &&\n            typeof pathItemElement === 'object' &&\n            'servers' in pathItemElement &&\n            Array.isArray(pathItemElement.servers)\n          ) {\n            pathItemElement.servers.forEach(server => {\n              fixServers(server, filePath);\n            });\n          }\n        });\n      });\n    }\n  });\n}\n","import type { OpenAPIV2, OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';\nimport type { ParserOptions, ValidationResult } from '../types.js';\n\nimport betterAjvErrors from '@readme/better-ajv-errors';\nimport { openapi } from '@readme/openapi-schemas';\nimport Ajv from 'ajv/dist/2020.js';\nimport AjvDraft4 from 'ajv-draft-04';\n\nimport { isOpenAPI31, isOpenAPI32, isSwagger } from '../lib/assertions.js';\nimport { hasInvalidPaths } from '../lib/hasInvalidPaths.js';\nimport { getSpecificationName } from '../lib/index.js';\nimport { reduceAjvErrors } from '../lib/reduceAjvErrors.js';\n\n/**\n * We've had issues with specs larger than 2MB+ with 1,000+ errors causing memory leaks so if we\n * have a spec with more than `LARGE_SPEC_ERROR_CAP` errors and it's **stringified** length is\n * larger than `LARGE_SPEC_LIMITS` then we will only return the first `LARGE_SPEC_ERROR_CAP` errors.\n *\n * Ideally we'd be looking at the byte size of the spec instead of looking at its stringified\n * length value but the Blob API, which we'd use to get its size with `new Blob([str]).size;`, was\n * only recently introduced in Node 15.\n *\n * w/r/t the 5,000,000 limit here: The spec we found causing these memory leaks had a size of\n * 13,934,323 so 5mil seems like a decent cap to start with.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Blob}\n */\nconst LARGE_SPEC_ERROR_CAP = 20;\nconst LARGE_SPEC_SIZE_CAP = 5000000;\n\n/**\n * Determines which version of Ajv to load and prepares it for use.\n *\n */\nfunction initializeAjv(draft04: boolean = true) {\n  const opts = {\n    allErrors: true,\n    strict: false,\n    validateFormats: false,\n  };\n\n  if (draft04) {\n    return new AjvDraft4(opts);\n  }\n\n  return new Ajv(opts);\n}\n\n/**\n * Validates the given Swagger API against the Swagger 2.0 or OpenAPI 3.0 and 3.1 schemas.\n *\n */\nexport function validateSchema(\n  api: OpenAPIV2.Document | OpenAPIV3_1.Document | OpenAPIV3.Document,\n  options: ParserOptions = {},\n): ValidationResult {\n  // Pre-validation check for missing leading slashes in paths\n  if (hasInvalidPaths(api)) {\n    return {\n      valid: false,\n      errors: [\n        {\n          message:\n            getSpecificationName(api) === 'Swagger'\n              ? 'Entries in the Swagger `paths` object must begin with a leading slash.'\n              : 'Entries in the OpenAPI `paths` object must begin with a leading slash.',\n        },\n      ],\n      warnings: [],\n      additionalErrors: 0,\n      specification: getSpecificationName(api),\n    };\n  }\n\n  let ajv: AjvDraft4 | Ajv;\n\n  // Choose the appropriate schema (Swagger or OpenAPI)\n  let schema: typeof openapi.v2 | typeof openapi.v3 | typeof openapi.v31legacy;\n  const specificationName = getSpecificationName(api);\n\n  if (isSwagger(api)) {\n    schema = openapi.v2;\n    ajv = initializeAjv();\n  } else if (isOpenAPI32(api)) {\n    throw new TypeError('OpenAPI 3.2 is currently unsupported.');\n  } else if (isOpenAPI31(api)) {\n    schema = openapi.v31legacy;\n\n    /**\n     * There's a bug with Ajv in how it handles `$dynamicRef` in the way that it's used within the\n     * 3.1 schema so we need to do some adhoc workarounds.\n     *\n     * @see {@link https://github.com/OAI/OpenAPI-Specification/issues/2689}\n     * @see {@link https://github.com/ajv-validator/ajv/issues/1573}\n     */\n    const schemaDynamicRef = schema.$defs.schema;\n    if ('$dynamicAnchor' in schemaDynamicRef) {\n      delete schemaDynamicRef.$dynamicAnchor;\n    }\n\n    // @ts-expect-error Intentionally setting up this funky schema for an AJV bug.\n    schema.$defs.components.properties.schemas.additionalProperties = schemaDynamicRef;\n    // @ts-expect-error\n    schema.$defs.header.dependentSchemas.schema.properties.schema = schemaDynamicRef;\n    // @ts-expect-error\n    schema.$defs['media-type'].properties.schema = schemaDynamicRef;\n    // @ts-expect-error\n    schema.$defs.parameter.properties.schema = schemaDynamicRef;\n\n    ajv = initializeAjv(false);\n  } else {\n    schema = openapi.v3;\n    ajv = initializeAjv();\n  }\n\n  // Validate against the schema\n  const isValid = ajv.validate(schema, api);\n  if (isValid) {\n    // We don't support warnings in our schema validation, only the **spec** validator.\n    return { valid: true, warnings: [], specification: specificationName };\n  }\n\n  let additionalErrors = 0;\n  let reducedErrors = reduceAjvErrors(ajv.errors);\n  if (reducedErrors.length >= LARGE_SPEC_ERROR_CAP) {\n    try {\n      if (JSON.stringify(api).length >= LARGE_SPEC_SIZE_CAP) {\n        additionalErrors = reducedErrors.length - 20;\n        reducedErrors = reducedErrors.slice(0, 20);\n      }\n    } catch {\n      // If we failed to stringify the API definition to look at its size then we should process\n      // all of its errors as-is.\n    }\n  }\n\n  try {\n    // @ts-expect-error typing on the `ErrorObject` that we use here doesn't match what `better-ajv-errors` uses\n    const errors = betterAjvErrors(schema, api, reducedErrors, {\n      format: 'cli-array',\n      colorize: options?.validate?.errors?.colorize || false,\n      indent: 2,\n    });\n\n    return {\n      valid: false,\n      errors,\n      warnings: [],\n      additionalErrors,\n      specification: specificationName,\n    };\n  } catch (err) {\n    // If `better-ajv-errors` fails for whatever reason we should capture and return it. We'll\n    // obviously not show the user all of their validation errors but it's better than nothing.\n    return {\n      valid: false,\n      errors: [{ message: err.message }],\n      warnings: [],\n      additionalErrors,\n      specification: specificationName,\n    };\n  }\n}\n","import type { OpenAPIV2, OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';\n\n/**\n * Detects paths in the API definition that are missing leading slashes.\n * This is a common issue that causes \"ADDITIONAL PROPERTY\" validation errors.\n *\n * @param api - The API definition to check\n * @returns Array of paths that are missing leading slashes\n */\nexport function hasInvalidPaths(api: OpenAPIV2.Document | OpenAPIV3_1.Document | OpenAPIV3.Document): boolean {\n  if (!api.paths || typeof api.paths !== 'object' || Array.isArray(api.paths)) {\n    return false;\n  }\n\n  // Return paths that do not start with a leading slash\n  return Object.keys(api.paths).some(path => !path.startsWith('/'));\n}\n","import type { ErrorObject } from 'ajv';\n\n/**\n * Because of the way that Ajv works, if a validation error occurs deep within a schema there's a\n * chance that errors will also be thrown for its immediate parents, leading to a case where we'll\n * eventually show the error indecipherable errors like \"$ref is missing here!\" instance of what's\n * _actually_ going on where they may have mistyped `enum` as `enumm`.\n *\n * To alleviate this confusing noise, we're compressing Ajv errors down to only surface the deepest\n * point for each lineage, so that if a user typos `enum` as `enumm` we'll surface just that error\n * for them (because really that's **the** error).\n *\n */\nexport function reduceAjvErrors(errors: ErrorObject[]): ErrorObject[] {\n  const flattened = new Map<string, ErrorObject>();\n\n  errors.forEach(err => {\n    // These two errors appear when a child schema of them has a problem and instead of polluting\n    // the user with indecipherable noise we should instead relay the more specific error to them.\n    // If this is all that's present in the stack then as a safety net before we wrap up we'll just\n    // return the original `errors` stack.\n    if ([\"must have required property '$ref'\", 'must match exactly one schema in oneOf'].includes(err.message)) {\n      return;\n    }\n\n    // If this is our first run through let's initialize our dataset and move along.\n    if (!flattened.size) {\n      flattened.set(err.instancePath, err);\n      return;\n    } else if (flattened.has(err.instancePath)) {\n      // If we already have an error recorded for this `instancePath` we can ignore it because we\n      // (likely) already have recorded the more specific error.\n      return;\n    }\n\n    // If this error hasn't already been recorded, maybe it's an error against the same\n    // `instancePath` stack, in which case we should ignore it because the more specific error has\n    // already been recorded.\n    let shouldRecordError = true;\n    flattened.forEach(flat => {\n      if (flat.instancePath.includes(err.instancePath)) {\n        shouldRecordError = false;\n      }\n    });\n\n    if (shouldRecordError) {\n      flattened.set(err.instancePath, err);\n    }\n  });\n\n  // If we weren't able to fold errors down for whatever reason just return the original stack.\n  if (!flattened.size) {\n    return errors;\n  }\n\n  return [...flattened.values()];\n}\n","import type { ErrorDetails, WarningDetails } from '../../types.js';\n\nexport abstract class SpecificationValidator {\n  errors: ErrorDetails[] = [];\n\n  warnings: WarningDetails[] = [];\n\n  protected reportError(message: string): void {\n    this.errors.push({ message });\n  }\n\n  protected reportWarning(message: string): void {\n    this.warnings.push({ message });\n  }\n\n  abstract run(): void;\n}\n","import type { OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';\nimport type { ParserRulesOpenAPI } from '../../types.js';\n\nimport { isOpenAPI30, isOpenAPI31 } from '../../lib/assertions.js';\nimport { pathParameterTemplateRegExp, supportedHTTPMethods } from '../../lib/index.js';\nimport { SpecificationValidator } from './index.js';\n\ntype ParameterObject =\n  | (OpenAPIV3_1.ParameterObject | OpenAPIV3_1.ReferenceObject)\n  | (OpenAPIV3.ParameterObject | OpenAPIV3.ReferenceObject);\n\n/**\n * Validates parts of the OpenAPI 3.0 and 3.1 specification that aren't covered by their JSON\n * Schema definitions.\n *\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md}\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md}\n */\nexport class OpenAPISpecificationValidator extends SpecificationValidator {\n  api: OpenAPIV3_1.Document | OpenAPIV3.Document;\n\n  rules: ParserRulesOpenAPI;\n\n  constructor(api: OpenAPIV3_1.Document | OpenAPIV3.Document, rules: ParserRulesOpenAPI) {\n    super();\n\n    this.api = api;\n    this.rules = rules;\n  }\n\n  run(): void {\n    const operationIds: string[] = [];\n    Object.keys(this.api.paths || {}).forEach(pathName => {\n      const path = this.api.paths[pathName];\n      const pathId = `/paths${pathName}`;\n\n      if (path && pathName.startsWith('/')) {\n        this.validatePath(path, pathId, operationIds);\n      }\n    });\n\n    /**\n     * There's a problem with how the 3.0 schema uses `patternProperties` for defining the format of\n     * scheme names that it ignores anything that doesn't match, so if you for example have a space\n     * in a schema name it'll be seen as valid when it should instead trigger a validation error.\n     *\n     * @see {@link https://github.com/APIDevTools/swagger-parser/issues/184}\n     */\n    if (isOpenAPI30(this.api)) {\n      if (this.api.components) {\n        Object.keys(this.api.components).forEach((componentType: keyof typeof this.api.components) => {\n          Object.keys(this.api.components[componentType]).forEach(componentName => {\n            if (!/^[a-zA-Z0-9.\\-_]+$/.test(componentName)) {\n              const componentId = `/components/${componentType}/${componentName}`;\n\n              this.reportError(\n                `\\`${componentId}\\` has an invalid name. Component names should match against: /^[a-zA-Z0-9.-_]+$/`,\n              );\n            }\n          });\n        });\n      }\n    }\n\n    /**\n     * OpenAPI 3.1 brought the addition of `webhooks` and made `paths` optional however the\n     * specification requires that one or the other be present, and not be empty. Unfortunately the\n     * JSON Schema for the specification is unable to specify this.\n     *\n     * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#openapi-document}\n     */\n    if (isOpenAPI31(this.api)) {\n      if (!Object.keys(this.api.paths || {}).length && !Object.keys(this.api.webhooks || {}).length) {\n        this.reportError('OpenAPI 3.1 definitions must contain at least one entry in either `paths` or `webhook`.');\n      }\n    }\n  }\n\n  /**\n   * Validates the given path.\n   *\n   */\n  private validatePath(\n    path: OpenAPIV3_1.PathItemObject | OpenAPIV3.PathItemObject,\n    pathId: string,\n    operationIds: string[],\n  ) {\n    supportedHTTPMethods.forEach(operationName => {\n      const operation = path[operationName];\n      const operationId = `${pathId}/${operationName}`;\n\n      if (operation) {\n        const declaredOperationId = operation.operationId;\n        if (declaredOperationId) {\n          if (!operationIds.includes(declaredOperationId)) {\n            operationIds.push(declaredOperationId);\n          } else if (this.rules['duplicate-operation-id'] === 'warning') {\n            this.reportWarning(`The operationId \\`${declaredOperationId}\\` is duplicated and should be made unique.`);\n          } else {\n            this.reportError(`The operationId \\`${declaredOperationId}\\` is duplicated and must be made unique.`);\n          }\n        }\n\n        this.validateParameters(path, pathId, operation, operationId);\n\n        Object.keys(operation.responses || {}).forEach(responseCode => {\n          const response = operation.responses[responseCode];\n          const responseId = `${operationId}/responses/${responseCode}`;\n          if (response && !('$ref' in response)) {\n            this.validateResponse(response, responseId);\n          }\n        });\n      }\n    });\n  }\n\n  /**\n   * Validates the parameters for the given operation.\n   *\n   */\n  private validateParameters(\n    path: OpenAPIV3_1.PathItemObject | OpenAPIV3.PathItemObject,\n    pathId: string,\n    operation: OpenAPIV3_1.OperationObject | OpenAPIV3.OperationObject,\n    operationId: string,\n  ) {\n    const pathParams = path.parameters || [];\n    const operationParams = operation.parameters || [];\n\n    // Check for duplicate path parameters.\n    this.checkForDuplicates(pathParams, pathId);\n\n    // Check for duplicate operation parameters.\n    this.checkForDuplicates(operationParams, operationId);\n\n    // Combine the path and operation parameters, with the operation params taking precedence over\n    // the path params.\n    const params = pathParams.reduce((combinedParams, value) => {\n      const duplicate = combinedParams.some(param => {\n        if ('$ref' in param || '$ref' in value) {\n          return false;\n        }\n\n        return param.in === value.in && param.name === value.name;\n      });\n\n      if (!duplicate) {\n        combinedParams.push(value);\n      }\n\n      return combinedParams;\n    }, operationParams.slice());\n\n    this.validatePathParameters(params, pathId, operationId);\n    this.validateParameterTypes(params, operationId);\n  }\n\n  /**\n   * Validates path parameters for the given path.\n   *\n   */\n  private validatePathParameters(params: ParameterObject[], pathId: string, operationId: string) {\n    // Find all `{placeholders}` in the path string. And because paths can have path parameters duped\n    // we need to convert this to a unique array so we can eliminate false positives of placeholders\n    // that might be duplicated.\n    const placeholders = [...new Set(pathId.match(pathParameterTemplateRegExp) || [])];\n\n    params\n      .filter(param => 'in' in param)\n      .filter(param => param.in === 'path')\n      .forEach(param => {\n        if (param.required !== true) {\n          if (this.rules['non-optional-path-parameters'] === 'warning') {\n            this.reportWarning(\n              `Path parameters should not be optional. Set \\`required=true\\` for the \\`${param.name}\\` parameter at \\`${operationId}\\`.`,\n            );\n          } else {\n            this.reportError(\n              `Path parameters cannot be optional. Set \\`required=true\\` for the \\`${param.name}\\` parameter at \\`${operationId}\\`.`,\n            );\n          }\n        }\n\n        const match = placeholders.indexOf(`{${param.name}}`);\n        if (match === -1) {\n          const error = `\\`${operationId}\\` has a path parameter named \\`${param.name}\\`, but there is no corresponding \\`{${param.name}}\\` in the path string.`;\n\n          if (this.rules['path-parameters-not-in-path'] === 'warning') {\n            this.reportWarning(error);\n          } else {\n            this.reportError(error);\n          }\n        }\n\n        placeholders.splice(match, 1);\n      });\n\n    if (placeholders.length > 0) {\n      const list = new Intl.ListFormat('en', { style: 'long', type: 'conjunction' }).format(\n        placeholders.map(placeholder => `\\`${placeholder}\\``),\n      );\n\n      const error = `\\`${operationId}\\` is missing path parameter(s) for ${list}.`;\n      if (this.rules['path-parameters-not-in-parameters'] === 'warning') {\n        this.reportWarning(error);\n      } else {\n        this.reportError(error);\n      }\n    }\n  }\n\n  /**\n   * Validates data types of parameters for the given operation.\n   *\n   */\n  private validateParameterTypes(params: ParameterObject[], operationId: string) {\n    params.forEach(param => {\n      if ('$ref' in param) {\n        return;\n      }\n\n      /**\n       * @todo add better handling when `content` is present instead of `schema`.\n       * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#fixed-fields-10}\n       * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#fixed-fields-10}\n       */\n      if (!param.schema && param.content) {\n        return;\n      } else if ('$ref' in param.schema) {\n        return;\n      }\n\n      const parameterId = `${operationId}/parameters/${param.name}`;\n\n      this.validateSchema(param.schema, parameterId);\n    });\n  }\n\n  /**\n   * Validates the given response object.\n   *\n   */\n  private validateResponse(response: OpenAPIV3_1.ResponseObject | OpenAPIV3.ResponseObject, responseId: string) {\n    Object.keys(response.headers || {}).forEach(headerName => {\n      const header = response.headers[headerName];\n      const headerId = `${responseId}/headers/${headerName}`;\n      if ('$ref' in header) {\n        return;\n      }\n\n      if (header.schema) {\n        if (!('$ref' in header.schema)) {\n          this.validateSchema(header.schema, headerId);\n        }\n      } else if (header.content) {\n        Object.keys(header.content).forEach(mediaType => {\n          if (header.content[mediaType].schema) {\n            if (!('$ref' in header.content[mediaType].schema)) {\n              this.validateSchema(header.content[mediaType].schema || {}, `${headerId}/content/${mediaType}/schema`);\n            }\n          }\n        });\n      }\n    });\n\n    if (response.content) {\n      Object.keys(response.content).forEach(mediaType => {\n        if (response.content[mediaType].schema) {\n          if (!('$ref' in response.content[mediaType].schema)) {\n            this.validateSchema(response.content[mediaType].schema || {}, `${responseId}/content/${mediaType}/schema`);\n          }\n        }\n      });\n    }\n  }\n\n  /**\n   * Validates the given Swagger schema object.\n   *\n   */\n  private validateSchema(schema: OpenAPIV3_1.SchemaObject | OpenAPIV3.SchemaObject, schemaId: string) {\n    if (schema.type === 'array' && !schema.items) {\n      if (this.rules['array-without-items'] === 'warning') {\n        this.reportWarning(`\\`${schemaId}\\` is an array, so it should include an \\`items\\` schema.`);\n      } else {\n        this.reportError(`\\`${schemaId}\\` is an array, so it must include an \\`items\\` schema.`);\n      }\n    }\n  }\n\n  /**\n   * Checks the given parameter list for duplicates.\n   *\n   */\n  private checkForDuplicates(params: ParameterObject[], schemaId: string) {\n    for (let i = 0; i < params.length - 1; i++) {\n      const outer = params[i];\n      for (let j = i + 1; j < params.length; j++) {\n        const inner = params[j];\n        if ('$ref' in outer || '$ref' in inner) {\n          continue;\n        }\n\n        if (outer.name === inner.name && outer.in === inner.in) {\n          const error = `Found multiple \\`${outer.in}\\` parameters named \\`${outer.name}\\` in \\`${schemaId}\\`.`;\n\n          if (this.rules['duplicate-non-request-body-parameters'] === 'warning') {\n            this.reportWarning(error);\n          } else {\n            this.reportError(error);\n          }\n        }\n      }\n    }\n  }\n}\n","import type { IJsonSchema, OpenAPIV2 } from 'openapi-types';\nimport type { ParserRulesSwagger } from '../../types.js';\n\nimport { pathParameterTemplateRegExp, swaggerHTTPMethods } from '../../lib/index.js';\nimport { SpecificationValidator } from './index.js';\n\n/**\n * Validates parts of the Swagger 2.0 specification that aren't covered by its JSON Schema\n * definitions.\n *\n * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md}\n */\nexport class SwaggerSpecificationValidator extends SpecificationValidator {\n  api: OpenAPIV2.Document;\n\n  rules: ParserRulesSwagger;\n\n  constructor(api: OpenAPIV2.Document, rules: ParserRulesSwagger) {\n    super();\n\n    this.api = api;\n    this.rules = rules;\n  }\n\n  run(): void {\n    const operationIds: string[] = [];\n    Object.keys(this.api.paths || {}).forEach(pathName => {\n      const path = this.api.paths[pathName];\n      const pathId = `/paths${pathName}`;\n\n      if (path && pathName.startsWith('/')) {\n        this.validatePath(path, pathId, operationIds);\n      }\n    });\n\n    Object.keys(this.api.definitions || {}).forEach(definitionName => {\n      const definition = this.api.definitions[definitionName];\n      const definitionId = `/definitions/${definitionName}`;\n\n      if (!/^[a-zA-Z0-9.\\-_]+$/.test(definitionName)) {\n        this.reportError(\n          `\\`${definitionId}\\` has an invalid name. Definition names should match against: /^[a-zA-Z0-9.-_]+$/`,\n        );\n      }\n\n      this.validateRequiredPropertiesExist(definition, definitionId);\n    });\n  }\n\n  /**\n   * Validates the given path.\n   *\n   */\n  private validatePath(path: OpenAPIV2.PathItemObject, pathId: string, operationIds: string[]) {\n    swaggerHTTPMethods.forEach(operationName => {\n      const operation = path[operationName];\n      const operationId = `${pathId}/${operationName}`;\n\n      if (operation) {\n        const declaredOperationId = operation.operationId;\n        if (declaredOperationId) {\n          if (!operationIds.includes(declaredOperationId)) {\n            operationIds.push(declaredOperationId);\n          } else if (this.rules['duplicate-operation-id'] === 'warning') {\n            this.reportWarning(`The operationId \\`${declaredOperationId}\\` is duplicated and should be made unique.`);\n          } else {\n            this.reportError(`The operationId \\`${declaredOperationId}\\` is duplicated and must be made unique.`);\n          }\n        }\n\n        this.validateParameters(path, pathId, operation, operationId);\n\n        Object.keys(operation.responses || {}).forEach(responseName => {\n          const response = operation.responses[responseName];\n          if ('$ref' in response || !response) {\n            return;\n          }\n\n          const responseId = `${operationId}/responses/${responseName}`;\n          this.validateResponse(responseName, response, responseId);\n        });\n      }\n    });\n  }\n\n  /**\n   * Validates the parameters for the given operation.\n   *\n   */\n  private validateParameters(\n    path: OpenAPIV2.PathItemObject,\n    pathId: string,\n    operation: OpenAPIV2.OperationObject,\n    operationId: string,\n  ) {\n    const pathParams = (path.parameters || []).filter(param => !('$ref' in param)) as OpenAPIV2.ParameterObject[];\n    const operationParams = (operation.parameters || []).filter(\n      param => !('$ref' in param),\n    ) as OpenAPIV2.ParameterObject[];\n\n    // Check for duplicate path parameters\n    this.checkForDuplicates(pathParams, pathId);\n\n    // Check for duplicate operation parameters\n    this.checkForDuplicates(operationParams, operationId);\n\n    // Combine the path and operation parameters,\n    // with the operation params taking precedence over the path params\n    const params = pathParams.reduce((combinedParams, value) => {\n      const duplicate = combinedParams.some(param => {\n        if ('$ref' in param || '$ref' in value) {\n          return false;\n        }\n        return param.in === value.in && param.name === value.name;\n      });\n      if (!duplicate) {\n        combinedParams.push(value);\n      }\n      return combinedParams;\n    }, operationParams.slice());\n\n    this.validateBodyParameters(params, operationId);\n    this.validatePathParameters(params, pathId, operationId);\n    this.validateParameterTypes(params, operation, operationId);\n  }\n\n  /**\n   * Validates body and formData parameters for the given operation.\n   *\n   */\n  private validateBodyParameters(params: OpenAPIV2.ParameterObject[], operationId: string) {\n    const bodyParams = params.filter(param => param.in === 'body');\n    const formParams = params.filter(param => param.in === 'formData');\n\n    // There can only be one \"body\" parameter\n    if (bodyParams.length > 1) {\n      this.reportError(`\\`${operationId}\\` has ${bodyParams.length} body parameters. Only one is allowed.`);\n    } else if (bodyParams.length > 0 && formParams.length > 0) {\n      // \"body\" params and \"formData\" params are mutually exclusive\n      this.reportError(\n        `\\`${operationId}\\` has \\`body\\` and \\`formData\\` parameters. Only one or the other is allowed.`,\n      );\n    }\n  }\n\n  /**\n   * Validates path parameters for the given path.\n   *\n   */\n  private validatePathParameters(params: OpenAPIV2.ParameterObject[], pathId: string, operationId: string) {\n    // Find all {placeholders} in the path string\n    const placeholders: string[] = pathId.match(pathParameterTemplateRegExp) || [];\n\n    // Check for duplicates\n    for (let i = 0; i < placeholders.length; i++) {\n      for (let j = i + 1; j < placeholders.length; j++) {\n        if (placeholders[i] === placeholders[j]) {\n          this.reportError(`\\`${operationId}\\` has multiple path placeholders named \\`${placeholders[i]}\\`.`);\n        }\n      }\n    }\n\n    params\n      .filter(param => param.in === 'path')\n      .forEach(param => {\n        if (param.required !== true) {\n          if (this.rules['non-optional-path-parameters'] === 'warning') {\n            this.reportWarning(\n              `Path parameters should not be optional. Set \\`required=true\\` for the \\`${param.name}\\` parameter at \\`${operationId}\\`.`,\n            );\n          } else {\n            this.reportError(\n              `Path parameters cannot be optional. Set \\`required=true\\` for the \\`${param.name}\\` parameter at \\`${operationId}\\`.`,\n            );\n          }\n        }\n\n        const match = placeholders.indexOf(`{${param.name}}`);\n        if (match === -1) {\n          const error = `\\`${operationId}\\` has a path parameter named \\`${param.name}\\`, but there is no corresponding \\`{${param.name}}\\` in the path string.`;\n\n          if (this.rules['path-parameters-not-in-path'] === 'warning') {\n            this.reportWarning(error);\n          } else {\n            this.reportError(error);\n          }\n        }\n\n        placeholders.splice(match, 1);\n      });\n\n    if (placeholders.length > 0) {\n      const list = new Intl.ListFormat('en', { style: 'long', type: 'conjunction' }).format(\n        placeholders.map(placeholder => `\\`${placeholder}\\``),\n      );\n\n      const error = `\\`${operationId}\\` is missing path parameter(s) for ${list}.`;\n      if (this.rules['path-parameters-not-in-parameters'] === 'warning') {\n        this.reportWarning(error);\n      } else {\n        this.reportError(error);\n      }\n    }\n  }\n\n  /**\n   * Validates data types of parameters for the given operation.\n   *\n   */\n  private validateParameterTypes(\n    params: OpenAPIV2.ParameterObject[],\n    operation: OpenAPIV2.OperationObject,\n    operationId: string,\n  ) {\n    params.forEach(param => {\n      const parameterId = `${operationId}/parameters/${param.name}`;\n      let schema: any;\n\n      switch (param.in) {\n        case 'body':\n          schema = param.schema;\n          break;\n        case 'formData':\n          schema = param;\n          break;\n        default:\n          schema = param;\n      }\n\n      this.validateSchema(schema, parameterId);\n      this.validateRequiredPropertiesExist(schema, parameterId);\n\n      if (schema.type === 'file') {\n        // \"file\" params must consume at least one of these MIME types\n        const formData = /multipart\\/(.*\\+)?form-data/;\n        const urlEncoded = /application\\/(.*\\+)?x-www-form-urlencoded/;\n\n        const consumes = operation.consumes || this.api.consumes || [];\n\n        const hasValidMimeType = consumes.some(consume => {\n          return formData.test(consume) || urlEncoded.test(consume);\n        });\n\n        if (!hasValidMimeType) {\n          this.reportError(\n            `\\`${operationId}\\` has a file parameter, so it must consume \\`multipart/form-data\\` or \\`application/x-www-form-urlencoded\\`.`,\n          );\n        }\n      }\n    });\n  }\n\n  /**\n   * Validates the given response object.\n   *\n   */\n  private validateResponse(code: number | string, response: OpenAPIV2.ResponseObject, responseId: string) {\n    /**\n     * The Swagger JSON Schema allows for any HTTP code between `000` and `999`, where as the OpenAPI\n     * JSON Schema fixed this to require it to be a _known_ code between 100 and 599.\n     *\n     * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/f9a2302ee6707cb65f4aaf180fdce9b0a906701e/schemas/v2.0/schema.json#L350}\n     */\n    if (code !== 'default') {\n      if (\n        (typeof code === 'number' && (code < 100 || code > 599)) ||\n        (typeof code === 'string' && (Number(code) < 100 || Number(code) > 599))\n      ) {\n        this.reportError(`\\`${responseId}\\` has an invalid response code: ${code}`);\n      }\n    }\n\n    Object.keys(response.headers || {}).forEach(headerName => {\n      const header = response.headers[headerName];\n      const headerId = `${responseId}/headers/${headerName}`;\n      this.validateSchema(header, headerId);\n    });\n\n    if (response.schema) {\n      if ('$ref' in response.schema) {\n        return;\n      }\n\n      this.validateSchema(response.schema, `${responseId}/schema`);\n    }\n  }\n\n  /**\n   * Validates the given Swagger schema object.\n   *\n   */\n  private validateSchema(schema: OpenAPIV2.SchemaObject, schemaId: string) {\n    if (schema.type === 'array' && !schema.items) {\n      if (this.rules['array-without-items'] === 'warning') {\n        this.reportWarning(`\\`${schemaId}\\` is an array, so it should include an \\`items\\` schema.`);\n      } else {\n        this.reportError(`\\`${schemaId}\\` is an array, so it must include an \\`items\\` schema.`);\n      }\n    }\n  }\n\n  /**\n   * Validates that the declared properties of the given Swagger schema object actually exist.\n   *\n   */\n  private validateRequiredPropertiesExist(schema: IJsonSchema, schemaId: string) {\n    // Recursively collects all properties of the schema and its ancestors. They are added to the props object.\n    function collectProperties(schemaObj: IJsonSchema, props: Record<string, IJsonSchema>) {\n      if (schemaObj.properties) {\n        Object.keys(schemaObj.properties).forEach(property => {\n          // biome-ignore lint/suspicious/noPrototypeBuiltins: Intentional\n          if (schemaObj.properties.hasOwnProperty(property)) {\n            props[property] = schemaObj.properties[property];\n          }\n        });\n      }\n\n      if (schemaObj.allOf) {\n        schemaObj.allOf.forEach(parent => {\n          collectProperties(parent, props);\n        });\n      }\n    }\n\n    if (schema.required && Array.isArray(schema.required)) {\n      const props: Record<string, IJsonSchema> = {};\n      collectProperties(schema, props);\n      schema.required.forEach(requiredProperty => {\n        if (!props[requiredProperty]) {\n          const error = `Property \\`${requiredProperty}\\` is listed as required but does not exist in \\`${schemaId}\\`.`;\n          if (this.rules['unknown-required-schema-property'] === 'warning') {\n            this.reportWarning(error);\n          } else {\n            this.reportError(error);\n          }\n        }\n      });\n    }\n  }\n\n  /**\n   * Checks the given parameter list for duplicates.\n   *\n   */\n  private checkForDuplicates(params: OpenAPIV2.ParameterObject[], schemaId: string) {\n    for (let i = 0; i < params.length - 1; i++) {\n      const outer = params[i];\n      for (let j = i + 1; j < params.length; j++) {\n        const inner = params[j];\n        if (outer.name === inner.name && outer.in === inner.in) {\n          const error = `Found multiple \\`${outer.in}\\` parameters named \\`${outer.name}\\` in \\`${schemaId}\\`.`;\n\n          if (this.rules['duplicate-non-request-body-parameters'] === 'warning') {\n            this.reportWarning(error);\n          } else {\n            this.reportError(error);\n          }\n        }\n      }\n    }\n  }\n}\n","import type { OpenAPIV2, OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';\nimport type { ParserRulesOpenAPI, ParserRulesSwagger, ValidationResult } from '../types.js';\nimport type { SpecificationValidator } from './spec/index.js';\n\nimport { isOpenAPI } from '../lib/assertions.js';\nimport { getSpecificationName } from '../lib/index.js';\nimport { OpenAPISpecificationValidator } from './spec/openapi.js';\nimport { SwaggerSpecificationValidator } from './spec/swagger.js';\n\n/**\n * Validates either a Swagger 2.0 or OpenAPI 3.x API definition against cases that aren't covered\n * by their respective JSON Schema definitions.\n *\n * Some specification-level cases can be treated as warnings, instead of hard validation erros, by\n * supplying a `rules` configuration to the parsers `validate` option.\n *\n */\nexport function validateSpec(\n  api: OpenAPIV2.Document | OpenAPIV3_1.Document | OpenAPIV3.Document,\n  rules: {\n    openapi: ParserRulesOpenAPI;\n    swagger: ParserRulesSwagger;\n  },\n): ValidationResult {\n  let validator: SpecificationValidator;\n\n  const specificationName = getSpecificationName(api);\n  if (isOpenAPI(api)) {\n    validator = new OpenAPISpecificationValidator(api, rules.openapi);\n  } else {\n    validator = new SwaggerSpecificationValidator(api, rules.swagger);\n  }\n\n  validator.run();\n\n  if (!validator.errors.length) {\n    return {\n      valid: true,\n      warnings: validator.warnings,\n      specification: specificationName,\n    };\n  }\n\n  return {\n    valid: false,\n    errors: validator.errors,\n    warnings: validator.warnings,\n    additionalErrors: 0,\n    specification: specificationName,\n  };\n}\n"]}