@samchon/openapi
Version:
OpenAPI definitions and converters for 'typia' and 'nestia'.
356 lines (355 loc) • 17.7 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.SwaggerV2Upgrader = void 0;
const OpenApiTypeChecker_1 = require("../utils/OpenApiTypeChecker");
var SwaggerV2Upgrader;
(function (SwaggerV2Upgrader) {
SwaggerV2Upgrader.convert = (input) => ({
openapi: "3.1.0",
info: input.info,
components: convertComponents(input),
paths: input.paths
? Object.fromEntries(Object.entries(input.paths)
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [key, convertPathItem(input)(value)]))
: undefined,
servers: input.host
? [
{
url: input.host,
},
]
: undefined,
security: input.security,
tags: input.tags,
"x-samchon-emended": 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, _c;
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;
return TypeChecker.isReference(p)
? (_a = doc.parameters) === null || _a === void 0 ? void 0 : _a[(_b = p.$ref.split("/").pop()) !== null && _b !== void 0 ? _b : ""]
: p;
})
.filter((p) => p !== undefined &&
p.in !== "body" &&
p.schema ===
undefined).map(convertParameter((_c = doc.definitions) !== null && _c !== void 0 ? _c : {}))
: undefined, requestBody: (() => {
var _a, _b;
const found = (_a = input.parameters) === null || _a === void 0 ? void 0 : _a.find((p) => {
var _a, _b;
if (TypeChecker.isReference(p))
p = (_a = doc.parameters) === null || _a === void 0 ? void 0 : _a[(_b = p.$ref.split("/").pop()) !== null && _b !== void 0 ? _b : ""];
return ((p === null || p === void 0 ? void 0 : p.schema) !== undefined);
});
return found
? convertRequestBody((_b = doc.definitions) !== null && _b !== void 0 ? _b : {})(found)
: 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 = (definitions) => (input) => ({
name: input.name,
in: input.in,
description: input.description,
schema: SwaggerV2Upgrader.convertSchema(definitions)(input),
required: true,
});
const convertRequestBody = (definitions) => (input) => ({
description: input.description,
content: {
"application/json": {
schema: SwaggerV2Upgrader.convertSchema(definitions)(input.schema),
},
},
});
const convertResponse = (doc) => (input) => {
var _a, _b, _c;
if (TypeChecker.isReference(input)) {
const found = (_a = doc.responses) === null || _a === void 0 ? void 0 : _a[(_b = input.$ref.split("/").pop()) !== null && _b !== void 0 ? _b : ""];
if (found === undefined)
return undefined;
input = found;
}
return {
description: input.description,
content: input.schema
? {
"application/json": {
schema: SwaggerV2Upgrader.convertSchema((_c = doc.definitions) !== null && _c !== void 0 ? _c : {})(input.schema),
example: input.example,
},
}
: undefined,
headers: input.headers
? Object.fromEntries(Object.entries(input.headers)
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => {
var _a;
return [
key,
{
schema: SwaggerV2Upgrader.convertSchema((_a = doc.definitions) !== null && _a !== void 0 ? _a : {})(value),
in: "header",
},
];
}))
: undefined,
};
};
/* -----------------------------------------------------------
DEFINITIONS
----------------------------------------------------------- */
const convertComponents = (input) => {
var _a;
return ({
schemas: Object.fromEntries(Object.entries((_a = input.definitions) !== null && _a !== void 0 ? _a : {})
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => {
var _a;
return [
key,
SwaggerV2Upgrader.convertSchema((_a = input.definitions) !== null && _a !== void 0 ? _a : {})(value),
];
})),
securitySchemes: input.securityDefinitions
? Object.fromEntries(Object.entries(input.securityDefinitions)
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [key, convertSecurityScheme(value)])
.filter(([_, v]) => v !== undefined))
: undefined,
});
};
const convertSecurityScheme = (input) => {
if (input.type === "apiKey")
return input;
else if (input.type === "basic")
return {
type: "http",
scheme: "basic",
description: input.description,
};
else if (input.type === "oauth2")
if (input.flow === "implicit")
return {
type: "oauth2",
description: input.description,
flows: {
implicit: {
authorizationUrl: input.authorizationUrl,
scopes: input.scopes,
},
},
};
else if (input.flow === "accessCode")
return {
type: "oauth2",
description: input.description,
flows: {
authorizationCode: {
authorizationUrl: input.authorizationUrl,
tokenUrl: input.tokenUrl,
scopes: input.scopes,
},
},
};
else if (input.flow === "password")
return {
type: "oauth2",
description: input.description,
flows: {
password: {
tokenUrl: input.tokenUrl,
scopes: input.scopes,
},
},
};
else if (input.flow === "application")
return {
type: "oauth2",
description: input.description,
flows: {
clientCredentials: {
tokenUrl: input.tokenUrl,
scopes: input.scopes,
},
},
};
else
return undefined;
return undefined;
};
SwaggerV2Upgrader.convertSchema = (definitions) => (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: input.examples
? Object.fromEntries(input.examples.map((v, i) => [i.toString(), v]))
: undefined });
const visit = (schema) => {
var _a, _b, _c, _d, _e;
// NULLABLE PROPERTY
if (schema["x-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["x-anyOf"].forEach(visit);
else if (TypeChecker.isOneOf(schema))
schema["x-oneOf"].forEach(visit);
else if (TypeChecker.isAllOf(schema))
if (schema.allOf.length === 1)
visit(schema.allOf[0]);
else
union.push(convertAllOfSchema(definitions)(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
union.push(Object.assign(Object.assign(Object.assign({}, schema), { default: ((_d = schema.default) !== null && _d !== void 0 ? _d : undefined), examples: schema.examples
? Object.fromEntries(schema.examples.map((v, i) => [i.toString(), v]))
: undefined }), { enum: undefined }));
// INSTANCE TYPE CASE
else if (TypeChecker.isArray(schema))
union.push(Object.assign(Object.assign({}, schema), { items: SwaggerV2Upgrader.convertSchema(definitions)(schema.items), examples: schema.examples
? Object.fromEntries(schema.examples.map((v, i) => [i.toString(), v]))
: undefined }));
else if (TypeChecker.isObject(schema))
union.push(Object.assign(Object.assign(Object.assign({}, schema), {
properties: schema.properties
? Object.fromEntries(Object.entries(schema.properties)
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [
key,
SwaggerV2Upgrader.convertSchema(definitions)(value),
]))
: {},
additionalProperties: schema.additionalProperties
? typeof schema.additionalProperties === "object" &&
schema.additionalProperties !== null
? SwaggerV2Upgrader.convertSchema(definitions)(schema.additionalProperties)
: schema.additionalProperties
: undefined,
}), { examples: schema.examples
? Object.fromEntries(schema.examples.map((v, i) => [i.toString(), v]))
: undefined, required: (_e = schema.required) !== null && _e !== void 0 ? _e : [] }));
else if (TypeChecker.isReference(schema))
union.push(Object.assign(Object.assign({}, schema), { $ref: schema.$ref.replace("#/definitions/", "#/components/schemas/"), examples: schema.examples
? Object.fromEntries(schema.examples.map((v, i) => [i.toString(), v]))
: undefined }));
else
union.push(Object.assign(Object.assign({}, schema), { examples: schema.examples
? Object.fromEntries(schema.examples.map((v, i) => [i.toString(), v]))
: undefined }));
};
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), { "x-nullable": undefined }))) })), attribute), { "x-nullable": undefined });
};
const convertAllOfSchema = (definitions) => (input) => {
const objects = input.allOf.map((schema) => retrieveObject(definitions)(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, SwaggerV2Upgrader.convertSchema(definitions)(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 = (definitions) => (input, visited = new Set()) => {
var _a, _b;
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(definitions)((_b = definitions === null || definitions === void 0 ? void 0 : definitions[(_a = input.$ref.split("/").pop()) !== null && _a !== void 0 ? _a : ""]) !== null && _b !== void 0 ? _b : {}, 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.isOneOf = (schema) => schema["x-oneOf"] !== undefined;
TypeChecker.isAnyOf = (schema) => schema["x-anyOf"] !== undefined;
TypeChecker.isNullOnly = (schema) => schema.type === "null";
})(TypeChecker || (TypeChecker = {}));
})(SwaggerV2Upgrader || (exports.SwaggerV2Upgrader = SwaggerV2Upgrader = {}));
;