UNPKG

@samchon/openapi

Version:

OpenAPI definitions and converters for 'typia' and 'nestia'.

356 lines (355 loc) 17.7 kB
"use strict"; 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 = {}));