@samchon/openapi
Version:
OpenAPI definitions and converters for 'typia' and 'nestia'.
296 lines (295 loc) • 17.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.OpenApiV3Upgrader = void 0;
const OpenApiExclusiveEmender_1 = require("../utils/OpenApiExclusiveEmender");
const OpenApiTypeChecker_1 = require("../utils/OpenApiTypeChecker");
var OpenApiV3Upgrader;
(function (OpenApiV3Upgrader) {
OpenApiV3Upgrader.convert = (input) => {
var _a;
return (Object.assign(Object.assign({}, input), { components: OpenApiV3Upgrader.convertComponents((_a = input.components) !== null && _a !== void 0 ? _a : {}), paths: input.paths
? Object.fromEntries(Object.entries(input.paths)
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [key, convertPathItem(input)(value)]))
: undefined, openapi: "3.1.0", "x-samchon-emended-v4": true }));
};
/* -----------------------------------------------------------
OPERATORS
----------------------------------------------------------- */
const convertPathItem = (doc) => (pathItem) => (Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, pathItem), (pathItem.get
? { get: convertOperation(doc)(pathItem)(pathItem.get) }
: undefined)), (pathItem.put
? { put: convertOperation(doc)(pathItem)(pathItem.put) }
: undefined)), (pathItem.post
? { post: convertOperation(doc)(pathItem)(pathItem.post) }
: undefined)), (pathItem.delete
? { delete: convertOperation(doc)(pathItem)(pathItem.delete) }
: undefined)), (pathItem.options
? { options: convertOperation(doc)(pathItem)(pathItem.options) }
: undefined)), (pathItem.head
? { head: convertOperation(doc)(pathItem)(pathItem.head) }
: undefined)), (pathItem.patch
? { patch: convertOperation(doc)(pathItem)(pathItem.patch) }
: undefined)), (pathItem.trace
? { trace: convertOperation(doc)(pathItem)(pathItem.trace) }
: undefined)));
const convertOperation = (doc) => (pathItem) => (input) => {
var _a, _b;
return (Object.assign(Object.assign({}, input), { parameters: pathItem.parameters !== undefined || input.parameters !== undefined
? [...((_a = pathItem.parameters) !== null && _a !== void 0 ? _a : []), ...((_b = input.parameters) !== null && _b !== void 0 ? _b : [])]
.map((p) => {
var _a, _b, _c, _d, _e, _f, _g, _h;
if (!TypeChecker.isReference(p))
return convertParameter((_a = doc.components) !== null && _a !== void 0 ? _a : {})(p);
const found = p.$ref.startsWith("#/components/headers/")
? (_c = (_b = doc.components) === null || _b === void 0 ? void 0 : _b.headers) === null || _c === void 0 ? void 0 : _c[(_d = p.$ref.split("/").pop()) !== null && _d !== void 0 ? _d : ""]
: (_f = (_e = doc.components) === null || _e === void 0 ? void 0 : _e.parameters) === null || _f === void 0 ? void 0 : _f[(_g = p.$ref.split("/").pop()) !== null && _g !== void 0 ? _g : ""];
return found !== undefined
? convertParameter((_h = doc.components) !== null && _h !== void 0 ? _h : {})(Object.assign(Object.assign({}, found), { in: "header" }))
: undefined;
})
.filter((_, v) => v !== undefined)
: undefined, requestBody: input.requestBody
? convertRequestBody(doc)(input.requestBody)
: undefined, responses: input.responses
? Object.fromEntries(Object.entries(input.responses)
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [key, convertResponse(doc)(value)])
.filter(([_, v]) => v !== undefined))
: undefined }));
};
const convertParameter = (components) => (input) => (Object.assign(Object.assign({}, input), { schema: OpenApiV3Upgrader.convertSchema(components)(input.schema), examples: input.examples
? Object.fromEntries(Object.entries(input.examples)
.map(([key, value]) => {
var _a, _b;
return [
key,
TypeChecker.isReference(value)
? (_a = components.examples) === null || _a === void 0 ? void 0 : _a[(_b = value.$ref.split("/").pop()) !== null && _b !== void 0 ? _b : ""]
: value,
];
})
.filter(([_, v]) => v !== undefined))
: undefined }));
const convertRequestBody = (doc) => (input) => {
var _a, _b, _c, _d;
if (TypeChecker.isReference(input)) {
const found = (_b = (_a = doc.components) === null || _a === void 0 ? void 0 : _a.requestBodies) === null || _b === void 0 ? void 0 : _b[(_c = input.$ref.split("/").pop()) !== null && _c !== void 0 ? _c : ""];
if (found === undefined)
return undefined;
input = found;
}
return Object.assign(Object.assign({}, input), { content: input.content
? convertContent((_d = doc.components) !== null && _d !== void 0 ? _d : {})(input.content)
: undefined });
};
const convertResponse = (doc) => (input) => {
var _a, _b, _c, _d;
if (TypeChecker.isReference(input)) {
const found = (_b = (_a = doc.components) === null || _a === void 0 ? void 0 : _a.responses) === null || _b === void 0 ? void 0 : _b[(_c = input.$ref.split("/").pop()) !== null && _c !== void 0 ? _c : ""];
if (found === undefined)
return undefined;
input = found;
}
return Object.assign(Object.assign({}, input), { content: input.content
? convertContent((_d = doc.components) !== null && _d !== void 0 ? _d : {})(input.content)
: undefined, headers: input.headers
? Object.fromEntries(Object.entries(input.headers)
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [
key,
(() => {
var _a, _b, _c, _d, _e;
if (TypeChecker.isReference(value) === false)
return convertParameter((_a = doc.components) !== null && _a !== void 0 ? _a : {})(Object.assign(Object.assign({}, value), { in: "header" }));
const found = value.$ref.startsWith("#/components/headers/")
? (_c = (_b = doc.components) === null || _b === void 0 ? void 0 : _b.headers) === null || _c === void 0 ? void 0 : _c[(_d = value.$ref.split("/").pop()) !== null && _d !== void 0 ? _d : ""]
: undefined;
return found !== undefined
? convertParameter((_e = doc.components) !== null && _e !== void 0 ? _e : {})(Object.assign(Object.assign({}, found), { in: "header" }))
: undefined;
})(),
])
.filter(([_, v]) => v !== undefined))
: undefined });
};
const convertContent = (components) => (record) => Object.fromEntries(Object.entries(record)
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [
key,
Object.assign(Object.assign({}, value), { schema: value.schema
? OpenApiV3Upgrader.convertSchema(components)(value.schema)
: undefined, examples: value.examples
? Object.fromEntries(Object.entries(value.examples)
.map(([key, value]) => {
var _a, _b;
return [
key,
TypeChecker.isReference(value)
? (_a = components.examples) === null || _a === void 0 ? void 0 : _a[(_b = value.$ref.split("/").pop()) !== null && _b !== void 0 ? _b : ""]
: value,
];
})
.filter(([_, v]) => v !== undefined))
: undefined }),
]));
/* -----------------------------------------------------------
DEFINITIONS
----------------------------------------------------------- */
OpenApiV3Upgrader.convertComponents = (input) => {
var _a;
return ({
schemas: Object.fromEntries(Object.entries((_a = input.schemas) !== null && _a !== void 0 ? _a : {})
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [key, OpenApiV3Upgrader.convertSchema(input)(value)])),
securitySchemes: input.securitySchemes,
});
};
OpenApiV3Upgrader.convertSchema = (components) => (input) => {
const nullable = {
value: false,
default: undefined,
};
const union = [];
const attribute = Object.assign(Object.assign({ title: input.title, description: input.description }, Object.fromEntries(Object.entries(input).filter(([key, value]) => key.startsWith("x-") && value !== undefined))), { example: input.example, examples: Array.isArray(input.examples)
? Object.fromEntries(input.examples.map((v, i) => [`v${i}`, v]))
: input.examples });
const visit = (schema) => {
var _a, _b, _c, _d, _e, _f;
// NULLABLE PROPERTY
if (schema.nullable === true) {
nullable.value || (nullable.value = true);
if (schema.default === null)
nullable.default = null;
}
if (Array.isArray(schema.enum) &&
((_a = schema.enum) === null || _a === void 0 ? void 0 : _a.length) &&
((_b = schema.enum) === null || _b === void 0 ? void 0 : _b.some((e) => e === null)))
nullable.value || (nullable.value = true);
// UNION TYPE CASE
if (TypeChecker.isAnyOf(schema))
schema.anyOf.forEach(visit);
else if (TypeChecker.isOneOf(schema))
schema.oneOf.forEach(visit);
else if (TypeChecker.isAllOf(schema))
if (schema.allOf.length === 1)
visit(schema.allOf[0]);
else
union.push(convertAllOfSchema(components)(schema));
// ATOMIC TYPE CASE (CONSIDER ENUM VALUES)
else if (TypeChecker.isBoolean(schema) ||
TypeChecker.isInteger(schema) ||
TypeChecker.isNumber(schema) ||
TypeChecker.isString(schema))
if (((_c = schema.enum) === null || _c === void 0 ? void 0 : _c.length) &&
schema.enum.filter((e) => e !== null).length)
union.push(...schema.enum
.filter((v) => v !== null)
.map((value) => ({ const: value })));
else if (TypeChecker.isInteger(schema) ||
TypeChecker.isNumber(schema))
union.push(OpenApiExclusiveEmender_1.OpenApiExclusiveEmender.emend(Object.assign(Object.assign(Object.assign({}, schema), { default: ((_d = schema.default) !== null && _d !== void 0 ? _d : undefined), exclusiveMinimum: typeof schema.exclusiveMinimum === "boolean"
? schema.exclusiveMinimum === true
? schema.minimum
: undefined
: schema.exclusiveMinimum, exclusiveMaximum: typeof schema.exclusiveMaximum === "boolean"
? schema.exclusiveMaximum === true
? schema.maximum
: undefined
: schema.exclusiveMaximum, minimum: schema.exclusiveMinimum === true ? undefined : schema.minimum, maximum: schema.exclusiveMaximum === true ? undefined : schema.maximum }), { enum: undefined })));
else
union.push(Object.assign(Object.assign(Object.assign({}, schema), { default: ((_e = schema.default) !== null && _e !== void 0 ? _e : undefined) }), { enum: undefined }));
// INSTANCE TYPE CASE
else if (TypeChecker.isArray(schema))
union.push(Object.assign(Object.assign({}, schema), { items: OpenApiV3Upgrader.convertSchema(components)(schema.items) }));
else if (TypeChecker.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,
OpenApiV3Upgrader.convertSchema(components)(value),
]))
: {},
additionalProperties: schema.additionalProperties
? typeof schema.additionalProperties === "object" &&
schema.additionalProperties !== null
? OpenApiV3Upgrader.convertSchema(components)(schema.additionalProperties)
: schema.additionalProperties
: undefined,
required: (_f = schema.required) !== null && _f !== void 0 ? _f : [],
}));
else if (TypeChecker.isReference(schema))
union.push(schema);
else
union.push(schema);
};
visit(input);
if (nullable.value === true &&
!union.some((e) => e.type === "null"))
union.push({
type: "null",
default: nullable.default,
});
if (union.length === 2 &&
union.filter((x) => OpenApiTypeChecker_1.OpenApiTypeChecker.isNull(x)).length === 1) {
const type = union.filter((x) => OpenApiTypeChecker_1.OpenApiTypeChecker.isNull(x) === false)[0];
for (const key of [
"title",
"description",
"deprecated",
"example",
"examples",
])
if (type[key] !== undefined)
delete type[key];
}
return Object.assign(Object.assign(Object.assign({}, (union.length === 0
? { type: undefined }
: union.length === 1
? Object.assign({}, union[0]) : { oneOf: union.map((u) => (Object.assign(Object.assign({}, u), { nullable: undefined }))) })), attribute), { nullable: undefined });
};
const convertAllOfSchema = (components) => (input) => {
const objects = input.allOf.map((schema) => retrieveObject(components)(schema));
if (objects.some((obj) => obj === null))
return Object.assign({ type: undefined }, {
allOf: undefined,
});
return Object.assign(Object.assign(Object.assign({}, input), { type: "object", properties: Object.fromEntries(objects
.map((o) => { var _a; return Object.entries((_a = o === null || o === void 0 ? void 0 : o.properties) !== null && _a !== void 0 ? _a : {}); })
.flat()
.map(([key, value]) => [key, OpenApiV3Upgrader.convertSchema(components)(value)])) }), {
allOf: undefined,
required: [...new Set(objects.map((o) => { var _a; return (_a = o === null || o === void 0 ? void 0 : o.required) !== null && _a !== void 0 ? _a : []; }).flat())],
});
};
const retrieveObject = (components) => (input, visited = new Set()) => {
var _a, _b, _c;
if (TypeChecker.isObject(input))
return input.properties !== undefined && !input.additionalProperties
? input
: null;
else if (visited.has(input))
return null;
else
visited.add(input);
if (TypeChecker.isReference(input))
return retrieveObject(components)((_c = (_a = components.schemas) === null || _a === void 0 ? void 0 : _a[(_b = input.$ref.split("/").pop()) !== null && _b !== void 0 ? _b : ""]) !== null && _c !== void 0 ? _c : {}, visited);
return null;
};
let TypeChecker;
(function (TypeChecker) {
TypeChecker.isBoolean = (schema) => schema.type === "boolean";
TypeChecker.isInteger = (schema) => schema.type === "integer";
TypeChecker.isNumber = (schema) => schema.type === "number";
TypeChecker.isString = (schema) => schema.type === "string";
TypeChecker.isArray = (schema) => schema.type === "array";
TypeChecker.isObject = (schema) => schema.type === "object";
TypeChecker.isReference = (schema) => schema.$ref !== undefined;
TypeChecker.isAllOf = (schema) => schema.allOf !== undefined;
TypeChecker.isAnyOf = (schema) => schema.anyOf !== undefined;
TypeChecker.isOneOf = (schema) => schema.oneOf !== undefined;
TypeChecker.isNullOnly = (schema) => schema.type === "null";
})(TypeChecker = OpenApiV3Upgrader.TypeChecker || (OpenApiV3Upgrader.TypeChecker = {}));
})(OpenApiV3Upgrader || (exports.OpenApiV3Upgrader = OpenApiV3Upgrader = {}));