UNPKG

@readme/openapi-parser

Version:

Swagger 2.0 and OpenAPI 3.x parser and validator for Node and browsers

1 lines 64.4 kB
{"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 in the process. The\n * specification now requires that either `components`, `webhooks`, or `paths` be present and\n * not empty. Unfortunately the 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 (\n !Object.keys(this.api.paths || {}).length &&\n !Object.keys(this.api.webhooks || {}).length &&\n !Object.keys(this.api.components || {}).length\n ) {\n this.reportError(\n 'OpenAPI 3.1 definitions must contain at least one entry in either `paths`, `webhooks`, or `components`.',\n );\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 const parameterId = `${operationId}/parameters/${param.name}`;\n\n /**\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 this.validateParameterContent(param.content, parameterId);\n return;\n } else if ('$ref' in param.schema) {\n return;\n }\n\n this.validateSchema(param.schema, parameterId);\n });\n }\n\n /**\n * Validates parameter content object.\n * Note: The requirement for exactly one media type is already enforced by the OpenAPI JSON schema.\n */\n private validateParameterContent(\n content: OpenAPIV3_1.ParameterObject['content'] | OpenAPIV3.ParameterObject['content'],\n parameterId: string,\n ) {\n const mediaTypes = Object.keys(content);\n if (mediaTypes.length !== 1) {\n this.reportError(\n `\\`${parameterId}\\` must have exactly one media type in \\`content\\`, but found ${mediaTypes.length}.`,\n );\n return;\n }\n\n const mediaType = mediaTypes[0];\n const contentSchema = content[mediaType].schema;\n if (contentSchema) {\n if ('$ref' in contentSchema) {\n return;\n }\n this.validateSchema(contentSchema, `${parameterId}/content/${mediaType}/schema`);\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 * Va