UNPKG

@kubb/oas

Version:
276 lines (273 loc) • 8.6 kB
import { matchesMimeType } from 'oas/utils'; export { findSchemaDefinition, matchesMimeType } from 'oas/utils'; import { isRef } from 'oas/types'; import { isPlainObject } from 'remeda'; import { loadConfig, bundle } from '@redocly/openapi-core'; import OASNormalize from 'oas-normalize'; import swagger2openapi from 'swagger2openapi'; import BaseOas from 'oas'; import jsonpointer from 'jsonpointer'; // src/types.ts var HttpMethods = { GET: "get", POST: "post", PUT: "put", PATCH: "patch", DELETE: "delete", HEAD: "head", OPTIONS: "options", TRACE: "trace" }; var Oas = class extends BaseOas { #options = {}; document = void 0; constructor({ oas, user }, options = {}) { if (typeof oas === "string") { oas = JSON.parse(oas); } super(oas, user); this.document = oas; this.#options = options; } get($ref) { const origRef = $ref; $ref = $ref.trim(); if ($ref === "") { return false; } if ($ref.startsWith("#")) { $ref = globalThis.decodeURIComponent($ref.substring(1)); } else { return null; } const current = jsonpointer.get(this.api, $ref); if (!current) { throw new Error(`Could not find a definition for ${origRef}.`); } return current; } set($ref, value) { $ref = $ref.trim(); if ($ref === "") { return false; } if ($ref.startsWith("#")) { $ref = globalThis.decodeURIComponent($ref.substring(1)); jsonpointer.set(this.api, $ref, value); } } resolveDiscriminators() { const schemas = this.api.components?.schemas || {}; Object.entries(schemas).forEach(([_key, schemaObject]) => { if ("discriminator" in schemaObject && typeof schemaObject.discriminator !== "string") { const { mapping = {}, propertyName } = schemaObject.discriminator || {}; if (!schemaObject.properties?.[propertyName]) { schemaObject.properties = {}; } schemaObject.properties[propertyName] = { ...schemaObject.properties[propertyName], enum: Object.keys(mapping) }; Object.entries(mapping).forEach(([mappingKey, mappingValue]) => { if (mappingValue) { const childSchema = this.get(mappingValue); if (!childSchema.properties) { childSchema.properties = {}; } const property = childSchema.properties[propertyName]; if (childSchema.properties) { childSchema.properties[propertyName] = { ...childSchema.properties ? childSchema.properties[propertyName] : {}, enum: [...property?.enum?.filter((value) => value !== mappingKey) ?? [], mappingKey] }; childSchema.required = [...childSchema.required ?? [], propertyName]; this.set(mappingValue, childSchema); } } }); } }); } dereferenceWithRef(schema) { if (isReference(schema)) { return { ...schema, ...this.get(schema.$ref), $ref: schema.$ref }; } return schema; } /** * Oas does not have a getResponseBody(contentType) */ #getResponseBodyFactory(responseBody) { function hasResponseBody(res = responseBody) { return !!res; } return (contentType) => { if (!hasResponseBody(responseBody)) { return false; } if (isReference(responseBody)) { return false; } if (!responseBody.content) { return false; } if (contentType) { if (!(contentType in responseBody.content)) { return false; } return responseBody.content[contentType]; } let availablecontentType = void 0; const contentTypes = Object.keys(responseBody.content); contentTypes.forEach((mt) => { if (!availablecontentType && matchesMimeType.json(mt)) { availablecontentType = mt; } }); if (!availablecontentType) { contentTypes.forEach((mt) => { if (!availablecontentType) { availablecontentType = mt; } }); } if (availablecontentType) { return [availablecontentType, responseBody.content[availablecontentType], ...responseBody.description ? [responseBody.description] : []]; } return false; }; } getResponseSchema(operation, statusCode) { if (operation.schema.responses) { Object.keys(operation.schema.responses).forEach((key) => { const schema2 = operation.schema.responses[key]; const $ref = isReference(schema2) ? schema2.$ref : void 0; if (schema2 && $ref) { operation.schema.responses[key] = this.get($ref); } }); } const getResponseBody = this.#getResponseBodyFactory(operation.getResponseByStatusCode(statusCode)); const { contentType } = this.#options; const responseBody = getResponseBody(contentType); if (responseBody === false) { return {}; } const schema = Array.isArray(responseBody) ? responseBody[1].schema : responseBody.schema; if (!schema) { return {}; } return this.dereferenceWithRef(schema); } getRequestSchema(operation) { const { contentType } = this.#options; if (operation.schema.requestBody) { operation.schema.requestBody = this.dereferenceWithRef(operation.schema.requestBody); } const requestBody = operation.getRequestBody(contentType); if (requestBody === false) { return void 0; } const schema = Array.isArray(requestBody) ? requestBody[1].schema : requestBody.schema; if (!schema) { return void 0; } return this.dereferenceWithRef(schema); } getParametersSchema(operation, inKey) { const { contentType = operation.getContentType() } = this.#options; const params = operation.getParameters().map((schema) => { return this.dereferenceWithRef(schema); }).filter((v) => v.in === inKey); if (!params.length) { return null; } return params.reduce( (schema, pathParameters) => { const property = pathParameters.content?.[contentType]?.schema ?? pathParameters.schema; const required = [...schema.required || [], pathParameters.required ? pathParameters.name : void 0].filter(Boolean); return { ...schema, description: schema.description, deprecated: schema.deprecated, example: schema.example, required, properties: { ...schema.properties, [pathParameters.name]: { description: pathParameters.description, ...property } } }; }, { type: "object", required: [], properties: {} } ); } async valdiate() { const oasNormalize = new OASNormalize(this.api, { enablePaths: true, colorizeErrors: true }); await oasNormalize.validate({ parser: { validate: { errors: { colorize: true } } } }); } }; // src/utils.ts function isOpenApiV2Document(doc) { return doc && isPlainObject(doc) && !("openapi" in doc); } function isOpenApiV3_1Document(doc) { return doc && isPlainObject(doc) && "openapi" in doc && doc.openapi.startsWith("3.1"); } function isParameterObject(obj) { return obj && "in" in obj; } function isNullable(schema) { return schema?.nullable ?? schema?.["x-nullable"] ?? false; } function isReference(obj) { return !!obj && isRef(obj); } function isRequired(schema) { if (!schema) { return false; } return Array.isArray(schema.required) ? !!schema.required?.length : !!schema.required; } function isOptional(schema) { return !isRequired(schema); } async function parse(pathOrApi, oasClass = Oas) { if (typeof pathOrApi === "string") { const config = await loadConfig(); const bundleResults = await bundle({ ref: pathOrApi, config, base: pathOrApi }); return parse(bundleResults.bundle.parsed); } const oasNormalize = new OASNormalize(pathOrApi, { enablePaths: true, colorizeErrors: true }); const document = await oasNormalize.load(); if (isOpenApiV2Document(document)) { const { openapi } = await swagger2openapi.convertObj(document, { anchors: true }); return new oasClass({ oas: openapi }); } return new oasClass({ oas: document }); } export { HttpMethods, Oas, isNullable, isOpenApiV3_1Document, isOptional, isParameterObject, isReference, isRequired, parse }; //# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map