@kubb/oas
Version:
Oas helpers
276 lines (273 loc) • 8.6 kB
JavaScript
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