UNPKG

@samchon/openapi

Version:

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

270 lines (265 loc) 14 kB
import { OpenApiExclusiveEmender } from "../utils/OpenApiExclusiveEmender.mjs"; import { OpenApiTypeChecker } from "../utils/OpenApiTypeChecker.mjs"; 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-v4": true }); const convertPathItem = doc => pathItem => ({ ...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 => ({ ...input, parameters: pathItem.parameters !== undefined || input.parameters !== undefined ? [ ...pathItem.parameters ?? [], ...input.parameters ?? [] ].map((p => TypeChecker.isReference(p) ? doc.parameters?.[p.$ref.split("/").pop() ?? ""] : p)).filter((p => p !== undefined && p.in !== "body" && p.schema === undefined)).map(convertParameter(doc.definitions ?? {})) : undefined, requestBody: (() => { const found = input.parameters?.find((p => { if (TypeChecker.isReference(p)) p = doc.parameters?.[p.$ref.split("/").pop() ?? ""]; return p?.schema !== undefined; })); return found ? convertRequestBody(doc.definitions ?? {})(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 => { if (TypeChecker.isReference(input)) { const found = doc.responses?.[input.$ref.split("/").pop() ?? ""]; if (found === undefined) return undefined; input = found; } return { description: input.description, content: input.schema ? { "application/json": { schema: SwaggerV2Upgrader.convertSchema(doc.definitions ?? {})(input.schema), example: input.example } } : undefined, headers: input.headers ? Object.fromEntries(Object.entries(input.headers).filter((([_, v]) => v !== undefined)).map((([key, value]) => [ key, { schema: SwaggerV2Upgrader.convertSchema(doc.definitions ?? {})(value), in: "header" } ]))) : undefined }; }; const convertComponents = input => ({ schemas: Object.fromEntries(Object.entries(input.definitions ?? {}).filter((([_, v]) => v !== undefined)).map((([key, value]) => [ key, SwaggerV2Upgrader.convertSchema(input.definitions ?? {})(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 = { 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) => [ `v${i}`, v ]))) : undefined }; const visit = schema => { if (schema["x-nullable"] === true) { nullable.value || (nullable.value = true); if (schema.default === null) nullable.default = null; } if (Array.isArray(schema.enum) && schema.enum?.length && schema.enum?.some((e => e === null))) nullable.value || (nullable.value = true); 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)); else if (TypeChecker.isBoolean(schema) || TypeChecker.isInteger(schema) || TypeChecker.isNumber(schema) || TypeChecker.isString(schema)) if (schema.enum?.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.emend({ ...schema, default: schema.default ?? undefined, examples: schema.examples ? Object.fromEntries(schema.examples.map(((v, i) => [ `v${i}`, v ]))) : 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({ ...schema, default: schema.default ?? undefined, examples: schema.examples ? Object.fromEntries(schema.examples.map(((v, i) => [ `v${i}`, v ]))) : undefined, ...{ enum: undefined } }); else if (TypeChecker.isArray(schema)) union.push({ ...schema, items: SwaggerV2Upgrader.convertSchema(definitions)(schema.items), examples: schema.examples ? Object.fromEntries(schema.examples.map(((v, i) => [ `v${i}`, v ]))) : undefined }); else if (TypeChecker.isObject(schema)) union.push({ ...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) => [ `v${i}`, v ]))) : undefined, required: schema.required ?? [] }); else if (TypeChecker.isReference(schema)) union.push({ ...schema, $ref: schema.$ref.replace("#/definitions/", "#/components/schemas/"), examples: schema.examples ? Object.fromEntries(schema.examples.map(((v, i) => [ `v${i}`, v ]))) : undefined }); else union.push({ ...schema, examples: schema.examples ? Object.fromEntries(schema.examples.map(((v, i) => [ `v${i}`, 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.isNull(x))).length === 1) { const type = union.filter((x => OpenApiTypeChecker.isNull(x) === false))[0]; for (const key of [ "title", "description", "deprecated", "example", "examples" ]) if (type[key] !== undefined) delete type[key]; } return { ...union.length === 0 ? { type: undefined } : union.length === 1 ? { ...union[0] } : { oneOf: union.map((u => ({ ...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 { type: undefined, ...{ allOf: undefined } }; return { ...input, type: "object", properties: Object.fromEntries(objects.map((o => Object.entries(o?.properties ?? {}))).flat().map((([key, value]) => [ key, SwaggerV2Upgrader.convertSchema(definitions)(value) ]))), ...{ allOf: undefined, required: [ ...new Set(objects.map((o => o?.required ?? [])).flat()) ] } }; }; const retrieveObject = definitions => (input, visited = new Set) => { 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)(definitions?.[input.$ref.split("/").pop() ?? ""] ?? {}, 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 || (SwaggerV2Upgrader = {})); export { SwaggerV2Upgrader }; //# sourceMappingURL=SwaggerV2Upgrader.mjs.map