@samchon/openapi
Version:
OpenAPI definitions and converters for 'typia' and 'nestia'.
214 lines (213 loc) • 12 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.OpenApiV3Downgrader = void 0;
const OpenApiTypeChecker_1 = require("../utils/OpenApiTypeChecker");
var OpenApiV3Downgrader;
(function (OpenApiV3Downgrader) {
OpenApiV3Downgrader.downgrade = (input) => {
const collection = OpenApiV3Downgrader.downgradeComponents(input.components);
return {
openapi: "3.0.0",
servers: input.servers,
info: input.info,
components: collection.downgraded,
paths: input.paths
? Object.fromEntries(Object.entries(input.paths)
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [key, downgradePathItem(collection)(value)]))
: undefined,
security: input.security,
tags: input.tags,
};
};
/* -----------------------------------------------------------
OPERATORS
----------------------------------------------------------- */
const downgradePathItem = (collection) => (pathItem) => (Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, pathItem), (pathItem.get
? { get: downgradeOperation(collection)(pathItem.get) }
: undefined)), (pathItem.put
? { put: downgradeOperation(collection)(pathItem.put) }
: undefined)), (pathItem.post
? { post: downgradeOperation(collection)(pathItem.post) }
: undefined)), (pathItem.delete
? { delete: downgradeOperation(collection)(pathItem.delete) }
: undefined)), (pathItem.options
? { options: downgradeOperation(collection)(pathItem.options) }
: undefined)), (pathItem.head
? { head: downgradeOperation(collection)(pathItem.head) }
: undefined)), (pathItem.patch
? { patch: downgradeOperation(collection)(pathItem.patch) }
: undefined)), (pathItem.trace
? { trace: downgradeOperation(collection)(pathItem.trace) }
: undefined)));
const downgradeOperation = (collection) => (input) => (Object.assign(Object.assign({}, input), { parameters: input.parameters
? input.parameters.map(downgradeParameter(collection))
: undefined, requestBody: input.requestBody
? downgradeRequestBody(collection)(input.requestBody)
: undefined, responses: input.responses
? Object.fromEntries(Object.entries(input.responses)
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [
key,
downgradeResponse(collection)(value),
]))
: undefined }));
const downgradeParameter = (collection) => (input) => (Object.assign(Object.assign({}, input), { schema: OpenApiV3Downgrader.downgradeSchema(collection)(input.schema) }));
const downgradeRequestBody = (collection) => (input) => (Object.assign(Object.assign({}, input), { content: input.content
? downgradeContent(collection)(input.content)
: undefined }));
const downgradeResponse = (collection) => (input) => (Object.assign(Object.assign({}, input), { content: input.content
? downgradeContent(collection)(input.content)
: undefined, headers: input.headers
? Object.fromEntries(Object.entries(input.headers)
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [
key,
Object.assign(Object.assign({}, value), { schema: OpenApiV3Downgrader.downgradeSchema(collection)(value.schema) }),
]))
: undefined }));
const downgradeContent = (collection) => (record) => Object.fromEntries(Object.entries(record)
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [
key,
Object.assign(Object.assign({}, value), { schema: (value === null || value === void 0 ? void 0 : value.schema)
? OpenApiV3Downgrader.downgradeSchema(collection)(value.schema)
: undefined }),
]));
/* -----------------------------------------------------------
DEFINITIONS
----------------------------------------------------------- */
OpenApiV3Downgrader.downgradeComponents = (input) => {
const collection = {
original: input,
downgraded: {
securitySchemes: input.securitySchemes,
},
};
if (input.schemas) {
collection.downgraded.schemas = {};
for (const [key, value] of Object.entries(input.schemas))
if (value !== undefined)
collection.downgraded.schemas[key] =
OpenApiV3Downgrader.downgradeSchema(collection)(value);
}
return collection;
};
OpenApiV3Downgrader.downgradeSchema = (collection) => (input) => {
const nullable = isNullable(new Set())(collection.original)(input);
const union = [];
const attribute = Object.assign({ title: input.title, description: input.description, example: input.example, examples: input.examples }, Object.fromEntries(Object.entries(input).filter(([key, value]) => key.startsWith("x-") && value !== undefined)));
const visit = (schema) => {
if (OpenApiTypeChecker_1.OpenApiTypeChecker.isBoolean(schema))
union.push({ type: "boolean" });
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isBoolean(schema) ||
OpenApiTypeChecker_1.OpenApiTypeChecker.isInteger(schema) ||
OpenApiTypeChecker_1.OpenApiTypeChecker.isNumber(schema) ||
OpenApiTypeChecker_1.OpenApiTypeChecker.isString(schema) ||
OpenApiTypeChecker_1.OpenApiTypeChecker.isReference(schema))
union.push(Object.assign({}, schema));
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isArray(schema))
union.push(Object.assign(Object.assign({}, schema), { items: OpenApiV3Downgrader.downgradeSchema(collection)(schema.items) }));
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isTuple(schema))
union.push(Object.assign(Object.assign(Object.assign({}, schema), { items: (() => {
if (schema.additionalItems === true)
return {};
const elements = [
...schema.prefixItems,
...(typeof schema.additionalItems === "object"
? [OpenApiV3Downgrader.downgradeSchema(collection)(schema.additionalItems)]
: []),
];
if (elements.length === 0)
return {};
return {
oneOf: elements.map(OpenApiV3Downgrader.downgradeSchema(collection)),
};
})(), minItems: schema.prefixItems.length, maxItems: !!schema.additionalItems === true
? undefined
: schema.prefixItems.length }), {
prefixItems: undefined,
additionalItems: undefined,
}));
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isObject(schema))
union.push(Object.assign(Object.assign({}, schema), { properties: schema.properties
? Object.fromEntries(Object.entries(schema.properties)
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [
key,
OpenApiV3Downgrader.downgradeSchema(collection)(value),
]))
: undefined, additionalProperties: typeof schema.additionalProperties === "object"
? OpenApiV3Downgrader.downgradeSchema(collection)(schema.additionalProperties)
: schema.additionalProperties, required: schema.required }));
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isOneOf(schema))
schema.oneOf.forEach(visit);
};
const visitConstant = (schema) => {
const insert = (value) => {
var _a;
const matched = union.find((u) => u.type === typeof value);
if (matched !== undefined) {
(_a = matched.enum) !== null && _a !== void 0 ? _a : (matched.enum = []);
matched.enum.push(value);
}
else
union.push({ type: typeof value, enum: [value] });
};
if (OpenApiTypeChecker_1.OpenApiTypeChecker.isConstant(schema))
insert(schema.const);
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isOneOf(schema))
for (const u of schema.oneOf)
if (OpenApiTypeChecker_1.OpenApiTypeChecker.isConstant(u))
insert(u.const);
};
visit(input);
visitConstant(input);
if (nullable === true)
for (const u of union)
if (OpenApiTypeChecker_1.OpenApiTypeChecker.isReference(u))
downgradeNullableReference(new Set())(collection)(u);
else
u.nullable = true;
if (nullable === true && union.length === 0)
return Object.assign({ type: "null" }, attribute);
return Object.assign(Object.assign({}, (union.length === 0
? { type: undefined }
: union.length === 1
? Object.assign({}, union[0]) : { oneOf: union })), attribute);
};
const downgradeNullableReference = (visited) => (collection) => (schema) => {
var _a, _b, _c;
var _d;
const key = schema.$ref.split("/").pop();
if (key.endsWith(".Nullable"))
return;
const found = (_a = collection.original.schemas) === null || _a === void 0 ? void 0 : _a[key];
if (found === undefined)
return;
else if (isNullable(visited)(collection.original)(found) === true)
return;
else if (((_b = collection.downgraded.schemas) === null || _b === void 0 ? void 0 : _b[`${key}.Nullable`]) === undefined) {
(_c = (_d = collection.downgraded).schemas) !== null && _c !== void 0 ? _c : (_d.schemas = {});
collection.downgraded.schemas[`${key}.Nullable`] = {};
collection.downgraded.schemas[`${key}.Nullable`] = OpenApiV3Downgrader.downgradeSchema(collection)(OpenApiTypeChecker_1.OpenApiTypeChecker.isOneOf(found)
? Object.assign(Object.assign({}, found), { oneOf: [...found.oneOf, { type: "null" }] }) : Object.assign({ oneOf: [found, { type: "null" }], title: found.title, description: found.description, example: found.example, examples: found.examples }, Object.fromEntries(Object.entries(found).filter(([key, value]) => key.startsWith("x-") && value !== undefined))));
}
schema.$ref += ".Nullable";
};
const isNullable = (visited) => (components) => (schema) => {
var _a;
if (OpenApiTypeChecker_1.OpenApiTypeChecker.isNull(schema))
return true;
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isReference(schema)) {
if (visited.has(schema.$ref))
return false;
visited.add(schema.$ref);
const key = schema.$ref.split("/").pop();
const next = (_a = components.schemas) === null || _a === void 0 ? void 0 : _a[key];
return next ? isNullable(visited)(components)(next) : false;
}
return (OpenApiTypeChecker_1.OpenApiTypeChecker.isOneOf(schema) &&
schema.oneOf.some(isNullable(visited)(components)));
};
})(OpenApiV3Downgrader || (exports.OpenApiV3Downgrader = OpenApiV3Downgrader = {}));
;