UNPKG

oas

Version:

Comprehensive tooling for working with OpenAPI definitions

1,253 lines (1,241 loc) 40.6 kB
import { findSchemaDefinition, supportedMethods } from "./chunk-W2TD4LSC.js"; import { cloneObject, getParametersAsJSONSchema, getSchemaVersionString, isObject, isPrimitive, matches_mimetype_default, toJSONSchema } from "./chunk-5KFARTQ3.js"; import { getExtension } from "./chunk-L2OVXZK3.js"; import { isRef } from "./chunk-DPTPURCR.js"; // src/operation/lib/dedupe-common-parameters.ts function dedupeCommonParameters(parameters, commonParameters) { return commonParameters.filter((param) => { return !parameters.find((param2) => { if (param.name && param2.name) { return param.name === param2.name && param.in === param2.in; } else if (isRef(param) && isRef(param2)) { return param.$ref === param2.$ref; } return false; }); }); } // src/samples/index.ts import mergeJSONSchemaAllOf from "json-schema-merge-allof"; import memoize from "memoizee"; // src/samples/utils.ts function usesPolymorphism(schema) { if (schema.oneOf) { return "oneOf"; } else if (schema.anyOf) { return "anyOf"; } else if (schema.allOf) { return "allOf"; } return false; } function objectify(thing) { if (!isObject(thing)) { return {}; } return thing; } function normalizeArray(arr) { if (Array.isArray(arr)) { return arr; } return [arr]; } function isFunc(thing) { return typeof thing === "function"; } function deeplyStripKey(input, keyToStrip, predicate = (obj, key) => true) { if (typeof input !== "object" || Array.isArray(input) || input === null || !keyToStrip) { return input; } const obj = { ...input }; Object.keys(obj).forEach((k) => { if (k === keyToStrip && predicate(obj[k], k)) { delete obj[k]; return; } obj[k] = deeplyStripKey(obj[k], keyToStrip, predicate); }); return obj; } // src/samples/index.ts var sampleDefaults = (genericSample) => { return (schema) => typeof schema.default === typeof genericSample ? schema.default : genericSample; }; var primitives = { string: sampleDefaults("string"), string_email: sampleDefaults("user@example.com"), "string_date-time": sampleDefaults((/* @__PURE__ */ new Date()).toISOString()), string_date: sampleDefaults((/* @__PURE__ */ new Date()).toISOString().substring(0, 10)), "string_YYYY-MM-DD": sampleDefaults((/* @__PURE__ */ new Date()).toISOString().substring(0, 10)), string_uuid: sampleDefaults("3fa85f64-5717-4562-b3fc-2c963f66afa6"), string_hostname: sampleDefaults("example.com"), string_ipv4: sampleDefaults("198.51.100.42"), string_ipv6: sampleDefaults("2001:0db8:5b96:0000:0000:426f:8e17:642a"), number: sampleDefaults(0), number_float: sampleDefaults(0), integer: sampleDefaults(0), boolean: sampleDefaults(true) }; var primitive = (schema) => { schema = objectify(schema); const { format } = schema; let { type } = schema; if (type === "null") { return null; } else if (Array.isArray(type)) { if (type.length === 1) { type = type[0]; } else { if (type.includes("null")) { type = type.filter((t) => t !== "null"); } type = type.shift(); } } const fn = primitives[`${type}_${format}`] || primitives[type]; if (isFunc(fn)) { return fn(schema); } return `Unknown Type: ${schema.type}`; }; function sampleFromSchema(schema, opts = {}) { const objectifySchema = objectify(schema); let { type } = objectifySchema; const hasPolymorphism = usesPolymorphism(objectifySchema); if (hasPolymorphism === "allOf") { try { return sampleFromSchema( mergeJSONSchemaAllOf(objectifySchema, { resolvers: { // Ignore any unrecognized OAS-specific keywords that might be present on the schema // (like `xml`). defaultResolver: mergeJSONSchemaAllOf.options.resolvers.title } }), opts ); } catch (error) { return void 0; } } else if (hasPolymorphism) { const samples = objectifySchema[hasPolymorphism].map((s) => { return sampleFromSchema(s, opts); }); if (samples.length === 1) { return samples[0]; } else if (samples.some((s) => s === null)) { return samples.find((s) => s !== null); } return samples[0]; } const { example, additionalProperties, properties, items } = objectifySchema; const { includeReadOnly, includeWriteOnly } = opts; if (example !== void 0) { return deeplyStripKey(example, "$$ref", (val) => { return typeof val === "string" && val.indexOf("#") > -1; }); } if (!type) { if (properties || additionalProperties) { type = "object"; } else if (items) { type = "array"; } else { return void 0; } } if (type === "object" || Array.isArray(type) && type.includes("object")) { const props = objectify(properties); const obj = {}; for (const name in props) { if (props[name] && props[name].deprecated) { continue; } if (props[name] && props[name].readOnly && !includeReadOnly) { continue; } if (props[name] && props[name].writeOnly && !includeWriteOnly) { continue; } if (props[name].examples?.length) { obj[name] = props[name].examples[0]; continue; } obj[name] = sampleFromSchema(props[name], opts); } if (additionalProperties === true) { obj.additionalProp = {}; } else if (additionalProperties) { const additionalProps = objectify(additionalProperties); const additionalPropVal = sampleFromSchema(additionalProps, opts); obj.additionalProp = additionalPropVal; } return obj; } if (type === "array" || Array.isArray(type) && type.includes("array")) { if (typeof items === "undefined") { return []; } if (Array.isArray(items.anyOf)) { return items.anyOf.map((i) => sampleFromSchema(i, opts)); } if (Array.isArray(items.oneOf)) { return items.oneOf.map((i) => sampleFromSchema(i, opts)); } return [sampleFromSchema(items, opts)]; } if (schema.enum) { if (schema.default) { return schema.default; } return normalizeArray(schema.enum)[0]; } if (type === "file") { return void 0; } return primitive(schema); } var memo = memoize(sampleFromSchema); var samples_default = memo; // src/operation/lib/get-mediatype-examples.ts function getMediaTypeExamples(mediaType, mediaTypeObject, opts = {}) { if (mediaTypeObject.example) { return [ { value: mediaTypeObject.example } ]; } else if (mediaTypeObject.examples) { const { examples } = mediaTypeObject; const multipleExamples = Object.keys(examples).map((key) => { let summary = key; let description; let example = examples[key]; if (example !== null && typeof example === "object") { if ("summary" in example) { summary = example.summary; } if ("description" in example) { description = example.description; } if ("value" in example) { if (example.value !== null && typeof example.value === "object" && "$ref" in example.value) { return false; } example = example.value; } } const ret = { summary, title: key, value: example }; if (description) { ret.description = description; } return ret; }).filter(Boolean); if (multipleExamples.length) { return multipleExamples; } } if (mediaTypeObject.schema) { if (!matches_mimetype_default.xml(mediaType)) { return [ { // eslint-disable-next-line try-catch-failsafe/json-parse value: samples_default(JSON.parse(JSON.stringify(mediaTypeObject.schema)), opts) } ]; } } return []; } // src/operation/lib/get-response-examples.ts function getResponseExamples(operation) { return Object.keys(operation.responses || {}).map((status) => { const response = operation.responses[status]; let onlyHeaders = false; if (isRef(response)) { return false; } const mediaTypes = {}; (response.content ? Object.keys(response.content) : []).forEach((mediaType) => { if (!mediaType) return; const mediaTypeObject = response.content[mediaType]; const examples = getMediaTypeExamples(mediaType, mediaTypeObject, { includeReadOnly: true, includeWriteOnly: false }); if (examples) { mediaTypes[mediaType] = examples; } }); if (response.headers && Object.keys(response.headers).length && !Object.keys(mediaTypes).length) { mediaTypes["*/*"] = []; onlyHeaders = true; } if (!Object.keys(mediaTypes).length) { return false; } return { status, mediaTypes, ...onlyHeaders ? { onlyHeaders } : {} }; }).filter(Boolean); } // src/operation/lib/get-callback-examples.ts function getCallbackExamples(operation) { const ret = []; return ret.concat( ...Object.keys(operation.callbacks || {}).map((identifier) => { const callback = operation.callbacks[identifier]; return [].concat( ...Object.keys(callback).map((expression) => { return Object.keys(callback[expression]).map((method) => { const pathItem = callback[expression]; const example = getResponseExamples(pathItem[method]); if (example.length === 0) return false; return { identifier, expression, method, example }; }); }) ).filter(Boolean); }) ); } // src/operation/lib/get-example-groups.ts var noCorrespondingResponseKey = "NoCorrespondingResponseForCustomCodeSample"; function addMatchingResponseExamples(groups, operation) { operation.getResponseExamples().forEach((example) => { Object.entries(example.mediaTypes || {}).forEach(([mediaType, mediaTypeExamples]) => { mediaTypeExamples.forEach((mediaTypeExample) => { if (mediaTypeExample.title && Object.keys(groups).includes(mediaTypeExample.title)) { groups[mediaTypeExample.title].response = { mediaType, mediaTypeExample, status: example.status }; if (!groups[mediaTypeExample.title].name) { groups[mediaTypeExample.title].name = mediaTypeExample.summary; } } }); }); }); } function getDefaultName(sample, count) { return sample.name && sample.name.length > 0 ? sample.name : `Default${count[sample.language] > 1 ? ` #${count[sample.language]}` : ""}`; } function getExampleGroups(operation) { const namelessCodeSampleCounts = {}; const groups = {}; const codeSamples = getExtension("code-samples", operation.api, operation); codeSamples?.forEach((sample, i) => { if (namelessCodeSampleCounts[sample.language]) { namelessCodeSampleCounts[sample.language] += 1; } else { namelessCodeSampleCounts[sample.language] = 1; } const name = getDefaultName(sample, namelessCodeSampleCounts); if (groups[sample.correspondingExample]?.customCodeSamples?.length) { groups[sample.correspondingExample].customCodeSamples.push({ ...sample, name, originalIndex: i }); } else if (sample.correspondingExample) { groups[sample.correspondingExample] = { name, customCodeSamples: [{ ...sample, name, originalIndex: i }] }; } else if (groups[noCorrespondingResponseKey]?.customCodeSamples?.length) { groups[noCorrespondingResponseKey].customCodeSamples.push({ ...sample, name, originalIndex: i }); } else { groups[noCorrespondingResponseKey] = { name, customCodeSamples: [{ ...sample, name, originalIndex: i }] }; } }); if (Object.keys(groups).length) { addMatchingResponseExamples(groups, operation); return groups; } operation.getParameters().forEach((param) => { Object.entries(param.examples || {}).forEach(([exampleKey, paramExample]) => { groups[exampleKey] = { ...groups[exampleKey], name: groups[exampleKey]?.name || paramExample.summary, request: { ...groups[exampleKey]?.request, [param.in]: { ...groups[exampleKey]?.request?.[param.in], [param.name]: paramExample.value } } }; }); }); operation.getRequestBodyExamples().forEach((requestExample) => { requestExample.examples.forEach((mediaTypeExample) => { if (mediaTypeExample.title) { const mediaType = requestExample.mediaType === "application/x-www-form-urlencoded" ? "formData" : "body"; groups[mediaTypeExample.title] = { ...groups[mediaTypeExample.title], name: groups[mediaTypeExample.title]?.name || mediaTypeExample.summary, request: { ...groups[mediaTypeExample.title]?.request, [mediaType]: mediaTypeExample.value } }; } }); }); if (Object.keys(groups).length) { addMatchingResponseExamples(groups, operation); } Object.entries(groups).forEach(([groupId, group]) => { if (group.request && !group.response) { delete groups[groupId]; } }); return groups; } // src/operation/lib/get-requestbody-examples.ts function getRequestBodyExamples(operation) { const requestBody = operation.requestBody; if (!requestBody || !requestBody.content) { return []; } return Object.keys(requestBody.content || {}).map((mediaType) => { const mediaTypeObject = requestBody.content[mediaType]; const examples = getMediaTypeExamples(mediaType, mediaTypeObject, { includeReadOnly: false, includeWriteOnly: true }); if (!examples.length) { return false; } return { mediaType, examples }; }).filter((x) => x !== false); } // src/operation/lib/get-response-as-json-schema.ts var isJSON = matches_mimetype_default.json; function buildHeadersSchema(response, opts) { const headers = response.headers; const headersSchema = { type: "object", properties: {} }; Object.keys(headers).forEach((key) => { if (headers[key] && headers[key].schema) { const header = headers[key]; headersSchema.properties[key] = toJSONSchema(header.schema, { addEnumsToDescriptions: true, transformer: opts.transformer }); if (header.description) { headersSchema.properties[key].description = header.description; } } }); const headersWrapper = { schema: headersSchema, type: "object", label: "Headers" }; if (response.description && headersWrapper.schema) { headersWrapper.description = response.description; } return headersWrapper; } function getResponseAsJSONSchema(operation, api, statusCode, opts) { const response = operation.getResponseByStatusCode(statusCode); const jsonSchema = []; if (!response) { return null; } let hasCircularRefs = false; let hasDiscriminatorMappingRefs = false; function refLogger(ref, type) { if (type === "ref") { hasCircularRefs = true; } else { hasDiscriminatorMappingRefs = true; } } function getPreferredSchema(content) { if (!content) { return null; } const contentTypes = Object.keys(content); if (!contentTypes.length) { return null; } for (let i = 0; i < contentTypes.length; i++) { if (isJSON(contentTypes[i])) { return toJSONSchema(cloneObject(content[contentTypes[i]].schema), { addEnumsToDescriptions: true, refLogger, transformer: opts.transformer }); } } const contentType = contentTypes.shift(); return toJSONSchema(cloneObject(content[contentType].schema), { addEnumsToDescriptions: true, refLogger, transformer: opts.transformer }); } const foundSchema = getPreferredSchema(response.content); if (foundSchema) { const schema = cloneObject(foundSchema); const schemaWrapper = { // If there's no `type` then the root schema is a circular `$ref` that we likely won't be // able to render so instead of generating a JSON Schema with an `undefined` type we should // default to `string` so there's at least *something* the end-user can interact with. type: foundSchema.type || "string", schema: isPrimitive(schema) ? schema : { ...schema, $schema: getSchemaVersionString(schema, api) }, label: "Response body" }; if (response.description && schemaWrapper.schema) { schemaWrapper.description = response.description; } if (api.components && schemaWrapper.schema) { if (hasCircularRefs || hasDiscriminatorMappingRefs && opts.includeDiscriminatorMappingRefs) { schemaWrapper.schema.components = api.components; } } jsonSchema.push(schemaWrapper); } if (response.headers) { jsonSchema.push(buildHeadersSchema(response, opts)); } return jsonSchema.length ? jsonSchema : null; } // src/operation/index.ts var Operation = class { /** * Schema of the operation from the API Definition. */ schema; /** * OpenAPI API Definition that this operation originated from. */ api; /** * Path that this operation is targeted towards. */ path; /** * HTTP Method that this operation is targeted towards. */ method; /** * The primary Content Type that this operation accepts. */ contentType; /** * An object with groups of all example definitions (body/header/query/path/response/etc.) */ exampleGroups; /** * Request body examples for this operation. */ requestBodyExamples; /** * Response examples for this operation. */ responseExamples; /** * Callback examples for this operation (if it has callbacks). */ callbackExamples; /** * Flattened out arrays of both request and response headers that are utilized on this operation. */ headers; constructor(api, path, method, operation) { this.schema = operation; this.api = api; this.path = path; this.method = method; this.contentType = void 0; this.requestBodyExamples = void 0; this.responseExamples = void 0; this.callbackExamples = void 0; this.exampleGroups = void 0; this.headers = { request: [], response: [] }; } getSummary() { if (this.schema?.summary && typeof this.schema.summary === "string") { return this.schema.summary; } else if (this.api.paths[this.path].summary && typeof this.api.paths[this.path].summary === "string") { return this.api.paths[this.path].summary; } return void 0; } getDescription() { if (this.schema?.description && typeof this.schema.description === "string") { return this.schema.description; } else if (this.api.paths[this.path].description && typeof this.api.paths[this.path].description === "string") { return this.api.paths[this.path].description; } return void 0; } getContentType() { if (this.contentType) { return this.contentType; } let types = []; if (this.schema.requestBody) { if ("$ref" in this.schema.requestBody) { this.schema.requestBody = findSchemaDefinition(this.schema.requestBody.$ref, this.api); } if ("content" in this.schema.requestBody) { types = Object.keys(this.schema.requestBody.content); } } this.contentType = "application/json"; if (types && types.length) { this.contentType = types[0]; } types.forEach((t) => { if (matches_mimetype_default.json(t)) { this.contentType = t; } }); return this.contentType; } isFormUrlEncoded() { return matches_mimetype_default.formUrlEncoded(this.getContentType()); } isMultipart() { return matches_mimetype_default.multipart(this.getContentType()); } isJson() { return matches_mimetype_default.json(this.getContentType()); } isXml() { return matches_mimetype_default.xml(this.getContentType()); } /** * Checks if the current operation is a webhook or not. * */ isWebhook() { return this instanceof Webhook; } /** * Returns an array of all security requirements associated wtih this operation. If none are * defined at the operation level, the securities for the entire API definition are returned * (with an empty array as a final fallback). * */ getSecurity() { if (!this.api?.components?.securitySchemes || !Object.keys(this.api.components.securitySchemes).length) { return []; } return this.schema.security || this.api.security || []; } /** * Retrieve a collection of grouped security schemes. The inner array determines AND-grouped * security schemes, the outer array determines OR-groups. * * @see {@link https://swagger.io/docs/specification/authentication/#multiple} * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#security-requirement-object} * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#security-requirement-object} * @param filterInvalid Optional flag that, when set to `true`, filters out invalid/nonexistent * security schemes, rather than returning `false`. */ getSecurityWithTypes(filterInvalid = false) { const securityRequirements = this.getSecurity(); return securityRequirements.map((requirement) => { let keys; try { keys = Object.keys(requirement); } catch (e) { return false; } const keysWithTypes = keys.map((key) => { let security; try { security = this.api.components.securitySchemes[key]; } catch (e) { return false; } if (!security) return false; let type = null; if (security.type === "http") { if (security.scheme === "basic") type = "Basic"; else if (security.scheme === "bearer") type = "Bearer"; else type = security.type; } else if (security.type === "oauth2") { type = "OAuth2"; } else if (security.type === "apiKey") { if (security.in === "query") type = "Query"; else if (security.in === "header") type = "Header"; else if (security.in === "cookie") type = "Cookie"; else type = security.type; } else { return false; } return { type, security: { ...security, _key: key, _requirements: requirement[key] } }; }); if (filterInvalid) return keysWithTypes.filter((key) => key !== false); return keysWithTypes; }); } /** * Retrieve an object where the keys are unique scheme types, and the values are arrays * containing each security scheme of that type. * */ prepareSecurity() { const securitiesWithTypes = this.getSecurityWithTypes(); return securitiesWithTypes.reduce( (prev, securities) => { if (!securities) return prev; securities.forEach((security) => { if (!security) return; if (!prev[security.type]) prev[security.type] = []; const exists = prev[security.type].some((sec) => sec._key === security.security._key); if (!exists) { if (security.security?._requirements) delete security.security._requirements; prev[security.type].push(security.security); } }); return prev; }, {} ); } getHeaders() { const security = this.prepareSecurity(); if (security.Header) { this.headers.request = security.Header.map((h) => { return h.name; }); } if (security.Bearer || security.Basic || security.OAuth2) { this.headers.request.push("Authorization"); } if (security.Cookie) { this.headers.request.push("Cookie"); } if (this.schema.parameters) { this.headers.request = this.headers.request.concat( // Remove the reference object because we will have already dereferenced. this.schema.parameters.map((p) => { if (p.in && p.in === "header") return p.name; return void 0; }).filter((p) => p) ); } if (this.schema.responses) { this.headers.response = Object.keys(this.schema.responses).filter((r) => this.schema.responses[r].headers).map( (r) => ( // Remove the reference object because we will have already dereferenced. Object.keys(this.schema.responses[r].headers) ) ).reduce((a, b) => a.concat(b), []); } if (!this.headers.request.includes("Content-Type") && this.schema.requestBody) { if (this.schema.requestBody.content && Object.keys(this.schema.requestBody.content)) { this.headers.request.push("Content-Type"); } } if (this.schema.responses) { if (Object.keys(this.schema.responses).some( (response) => !!this.schema.responses[response].content )) { if (!this.headers.request.includes("Accept")) this.headers.request.push("Accept"); if (!this.headers.response.includes("Content-Type")) this.headers.response.push("Content-Type"); } } return this.headers; } /** * Determine if the operation has an operation present in its schema. Note that if one is present * in the schema but is an empty string then this will return false. * */ hasOperationId() { return Boolean("operationId" in this.schema && this.schema.operationId.length); } /** * Get an `operationId` for this operation. If one is not present (it's not required by the spec!) * a hash of the path and method will be returned instead. * */ getOperationId(opts = {}) { function sanitize(id) { return id.replace(opts?.camelCase || opts?.friendlyCase ? /[^a-zA-Z0-9_]/g : /[^a-zA-Z0-9]/g, "-").replace(/--+/g, "-").replace(/^-|-$/g, ""); } let operationId; if (this.hasOperationId()) { operationId = this.schema.operationId; } else { operationId = sanitize(this.path).toLowerCase(); } const method = this.method.toLowerCase(); if (opts?.camelCase || opts?.friendlyCase) { if (opts?.friendlyCase) { operationId = operationId.replaceAll("_", " "); if (!this.hasOperationId()) { operationId = operationId.replace(/[^a-zA-Z0-9_]+(.)/g, (_, chr) => ` ${chr}`).split(" ").filter((word, i, arr) => word !== arr[i - 1]).join(" "); } } operationId = operationId.replace(/[^a-zA-Z0-9_]+(.)/g, (_, chr) => chr.toUpperCase()); if (this.hasOperationId()) { operationId = sanitize(operationId); } operationId = operationId.replace(/^[0-9]/g, (match) => `_${match}`); operationId = operationId.charAt(0).toLowerCase() + operationId.slice(1); if (operationId.startsWith(method)) { return operationId; } if (this.hasOperationId()) { return operationId; } operationId = operationId.charAt(0).toUpperCase() + operationId.slice(1); return `${method}${operationId}`; } else if (this.hasOperationId()) { return operationId; } return `${method}_${operationId}`; } /** * Return an array of all tags, and their metadata, that exist on this operation. * */ getTags() { if (!("tags" in this.schema)) { return []; } const oasTagMap = /* @__PURE__ */ new Map(); if ("tags" in this.api) { this.api.tags.forEach((tag) => { oasTagMap.set(tag.name, tag); }); } const oasTags = Object.fromEntries(oasTagMap); const tags = []; if (Array.isArray(this.schema.tags)) { this.schema.tags.forEach((tag) => { if (tag in oasTags) { tags.push(oasTags[tag]); } else { tags.push({ name: tag }); } }); } return tags; } /** * Return is the operation is flagged as `deprecated` or not. * */ isDeprecated() { return "deprecated" in this.schema ? this.schema.deprecated : false; } /** * Determine if the operation has any (non-request body) parameters. * */ hasParameters() { return !!this.getParameters().length; } /** * Return the parameters (non-request body) on the operation. * */ getParameters() { let parameters = this.schema?.parameters || []; const commonParams = this.api?.paths?.[this.path]?.parameters || []; if (commonParams.length) { parameters = parameters.concat(dedupeCommonParameters(parameters, commonParams) || []); } return parameters; } /** * Determine if this operation has any required parameters. * */ hasRequiredParameters() { return this.getParameters().some((param) => "required" in param && param.required); } /** * Convert the operation into an array of JSON Schema schemas for each available type of * parameter available on the operation. * */ getParametersAsJSONSchema(opts = {}) { return getParametersAsJSONSchema(this, this.api, { includeDiscriminatorMappingRefs: true, transformer: (s) => s, ...opts }); } /** * Get a single response for this status code, formatted as JSON schema. * * @param statusCode Status code to pull a JSON Schema response for. */ getResponseAsJSONSchema(statusCode, opts = {}) { return getResponseAsJSONSchema(this, this.api, statusCode, { includeDiscriminatorMappingRefs: true, transformer: (s) => s, ...opts }); } /** * Get an array of all valid response status codes for this operation. * */ getResponseStatusCodes() { return this.schema.responses ? Object.keys(this.schema.responses) : []; } /** * Determine if the operation has any request bodies. * */ hasRequestBody() { return !!this.schema.requestBody; } /** * Retrieve the list of all available media types that the operations request body can accept. * * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#media-type-object} * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object} */ getRequestBodyMediaTypes() { if (!this.hasRequestBody()) { return []; } const requestBody = this.schema.requestBody; if (isRef(requestBody)) { return []; } return Object.keys(requestBody.content); } /** * Determine if this operation has a required request body. * */ hasRequiredRequestBody() { if (!this.hasRequestBody()) { return false; } const requestBody = this.schema.requestBody; if (isRef(requestBody)) { return false; } if (requestBody.required) { return true; } return !!this.getParametersAsJSONSchema().filter((js) => ["body", "formData"].includes(js.type)).find((js) => js.schema && Array.isArray(js.schema.required) && js.schema.required.length); } /** * Retrieve a specific request body content schema off this operation. * * If no media type is supplied this will return either the first available JSON-like request * body, or the first available if there are no JSON-like media types present. When this return * comes back it's in the form of an array with the first key being the selected media type, * followed by the media type object in question. * * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#media-type-object} * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object} * @param mediaType Specific request body media type to retrieve if present. */ getRequestBody(mediaType) { if (!this.hasRequestBody()) { return false; } const requestBody = this.schema.requestBody; if (isRef(requestBody)) { return false; } if (mediaType) { if (!(mediaType in requestBody.content)) { return false; } return requestBody.content[mediaType]; } let availableMediaType; const mediaTypes = this.getRequestBodyMediaTypes(); mediaTypes.forEach((mt) => { if (!availableMediaType && matches_mimetype_default.json(mt)) { availableMediaType = mt; } }); if (!availableMediaType) { mediaTypes.forEach((mt) => { if (!availableMediaType) { availableMediaType = mt; } }); } if (availableMediaType) { return [ availableMediaType, requestBody.content[availableMediaType], ...requestBody.description ? [requestBody.description] : [] ]; } return false; } /** * Retrieve an array of request body examples that this operation has. * */ getRequestBodyExamples() { const isRequestExampleValueDefined = typeof this.requestBodyExamples?.[0]?.examples?.[0].value !== "undefined"; if (this.requestBodyExamples && isRequestExampleValueDefined) { return this.requestBodyExamples; } this.requestBodyExamples = getRequestBodyExamples(this.schema); return this.requestBodyExamples; } /** * Return a specific response out of the operation by a given HTTP status code. * * @param statusCode Status code to pull a response object for. */ getResponseByStatusCode(statusCode) { if (!this.schema.responses) { return false; } if (typeof this.schema.responses[statusCode] === "undefined") { return false; } const response = this.schema.responses[statusCode]; if (isRef(response)) { return false; } return response; } /** * Retrieve an array of response examples that this operation has. * */ getResponseExamples() { if (this.responseExamples) { return this.responseExamples; } this.responseExamples = getResponseExamples(this.schema); return this.responseExamples; } /** * Determine if the operation has callbacks. * */ hasCallbacks() { return !!this.schema.callbacks; } /** * Retrieve a specific callback. * * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#callback-object} * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#callback-object} * @param identifier Callback identifier to look for. * @param expression Callback expression to look for. * @param method HTTP Method on the callback to look for. */ getCallback(identifier, expression, method) { if (!this.schema.callbacks) return false; const callback = this.schema.callbacks[identifier] ? this.schema.callbacks[identifier][expression] : false; if (!callback || !callback[method]) return false; return new Callback(this.api, expression, method, callback[method], identifier, callback); } /** * Retrieve an array of operations created from each callback. * */ getCallbacks() { const callbackOperations = []; if (!this.hasCallbacks()) return false; Object.keys(this.schema.callbacks).forEach((callback) => { Object.keys(this.schema.callbacks[callback]).forEach((expression) => { const cb = this.schema.callbacks[callback]; if (!isRef(cb)) { const exp = cb[expression]; if (!isRef(exp)) { Object.keys(exp).forEach((method) => { if (!supportedMethods.includes(method)) return; callbackOperations.push(this.getCallback(callback, expression, method)); }); } } }); }); return callbackOperations; } /** * Retrieve an array of callback examples that this operation has. * */ getCallbackExamples() { if (this.callbackExamples) { return this.callbackExamples; } this.callbackExamples = getCallbackExamples(this.schema); return this.callbackExamples; } /** * Determine if a given a custom specification extension exists within the operation. * * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specification-extensions} * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#specification-extensions} * @param extension Specification extension to lookup. */ hasExtension(extension) { return Boolean(this.schema && extension in this.schema); } /** * Retrieve a custom specification extension off of the operation. * * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specification-extensions} * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#specification-extensions} * @param extension Specification extension to lookup. * * @deprecated Use `oas.getExtension(extension, operation)` instead. */ getExtension(extension) { return this.schema?.[extension]; } /** * Returns an object with groups of all example definitions (body/header/query/path/response/etc.). * The examples are grouped by their key when defined via the `examples` map. * * Any custom code samples defined via the `x-readme.code-samples` extension are returned, * regardless of if they have a matching response example. * * For standard OAS request parameter (e.g., body/header/query/path/etc.) examples, * they are only present in the return object if they have a corresponding response example * (i.e., a response example with the same key in the `examples` map). */ getExampleGroups() { if (this.exampleGroups) return this.exampleGroups; const groups = getExampleGroups(this); this.exampleGroups = groups; return groups; } }; var Callback = class extends Operation { /** * The identifier that this callback is set to. */ identifier; /** * The parent path item object that this Callback exists within. */ parentSchema; constructor(oas, path, method, operation, identifier, parentPathItem) { super(oas, path, method, operation); this.identifier = identifier; this.parentSchema = parentPathItem; } /** * Return the primary identifier for this callback. * * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#callback-object} * @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#callback-object} */ getIdentifier() { return this.identifier; } getSummary() { if (this.schema?.summary && typeof this.schema.summary === "string") { return this.schema.summary; } else if (this.parentSchema.summary && typeof this.parentSchema.summary === "string") { return this.parentSchema.summary; } return void 0; } getDescription() { if (this.schema?.description && typeof this.schema.description === "string") { return this.schema.description; } else if (this.parentSchema.description && typeof this.parentSchema.description === "string") { return this.parentSchema.description; } return void 0; } getParameters() { let parameters = this.schema?.parameters || []; const commonParams = this.parentSchema.parameters || []; if (commonParams.length) { parameters = parameters.concat(dedupeCommonParameters(parameters, commonParams) || []); } return parameters; } }; var Webhook = class extends Operation { getSummary() { if (this.schema?.summary && typeof this.schema.summary === "string") { return this.schema.summary; } else if (this.api.webhooks[this.path].summary && typeof this.api.webhooks[this.path].summary === "string") { return this.api.webhooks[this.path].summary; } return void 0; } getDescription() { if (this.schema?.description && typeof this.schema.description === "string") { return this.schema.description; } else if (this.api.webhooks[this.path].description && typeof this.api.webhooks[this.path].description === "string") { return this.api.webhooks[this.path].description; } return void 0; } }; export { Operation, Callback, Webhook }; /** * Portions of this file have been extracted and modified from Swagger UI. * * @license Apache-2.0 * @see {@link https://github.com/swagger-api/swagger-ui/blob/master/src/core/utils.js} */ /** * This file has been extracted and modified from Swagger UI. * * @license Apache-2.0 * @see {@link https://github.com/swagger-api/swagger-ui/blob/master/src/core/plugins/samples/fn.js} */ //# sourceMappingURL=chunk-HGHW4JSM.js.map