UNPKG

@samchon/openapi

Version:

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

341 lines (337 loc) 17.8 kB
import { OpenApiExclusiveEmender } from "../utils/OpenApiExclusiveEmender.mjs"; var OpenApiV3_1Emender; (function(OpenApiV3_1Emender) { OpenApiV3_1Emender.convert = input => { if (input["x-samchon-emended-v4"] === true) return input; return { ...input, components: convertComponents(input.components ?? {}), paths: input.paths ? Object.fromEntries(Object.entries(input.paths).filter((([_, v]) => v !== undefined)).map((([key, value]) => [ key, convertPathItem(input)(value) ]))) : undefined, webhooks: input.webhooks ? Object.fromEntries(Object.entries(input.webhooks).filter((([_, v]) => v !== undefined)).map((([key, value]) => [ key, convertWebhooks(input)(value) ])).filter((([_, value]) => value !== undefined))) : undefined, "x-samchon-emended-v4": true }; }; const convertWebhooks = doc => webhook => { if (!TypeChecker.isReference(webhook)) return convertPathItem(doc)(webhook); const found = doc.components?.pathItems?.[webhook.$ref.split("/").pop() ?? ""]; return found ? convertPathItem(doc)(found) : undefined; }; 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 => { if (!TypeChecker.isReference(p)) return convertParameter(doc.components ?? {})(p); const found = p.$ref.startsWith("#/components/headers/") ? doc.components?.headers?.[p.$ref.split("/").pop() ?? ""] : doc.components?.parameters?.[p.$ref.split("/").pop() ?? ""]; return found !== undefined ? convertParameter(doc.components ?? {})({ ...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((([_, value]) => value !== undefined))) : undefined }); const convertParameter = components => input => ({ ...input, schema: convertSchema(components)(input.schema), examples: input.examples ? Object.fromEntries(Object.entries(input.examples).map((([key, value]) => [ key, TypeChecker.isReference(value) ? components.examples?.[value.$ref.split("/").pop() ?? ""] : value ])).filter((([_, v]) => v !== undefined))) : undefined }); const convertRequestBody = doc => input => { if (TypeChecker.isReference(input)) { const found = doc.components?.requestBodies?.[input.$ref.split("/").pop() ?? ""]; if (found === undefined) return undefined; input = found; } return { ...input, content: input.content ? convertContent(doc.components ?? {})(input.content) : undefined }; }; const convertResponse = doc => input => { if (TypeChecker.isReference(input)) { const found = doc.components?.responses?.[input.$ref.split("/").pop() ?? ""]; if (found === undefined) return undefined; input = found; } return { ...input, content: input.content ? convertContent(doc.components ?? {})(input.content) : undefined, headers: input.headers ? Object.fromEntries(Object.entries(input.headers).filter((([_, v]) => v !== undefined)).map((([key, value]) => [ key, (() => { if (TypeChecker.isReference(value) === false) return convertParameter(doc.components ?? {})({ ...value, in: "header" }); const found = value.$ref.startsWith("#/components/headers/") ? doc.components?.headers?.[value.$ref.split("/").pop() ?? ""] : undefined; return found !== undefined ? convertParameter(doc.components ?? {})({ ...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, { ...value, schema: value.schema ? convertSchema(components)(value.schema) : undefined, examples: value.examples ? Object.fromEntries(Object.entries(value.examples).map((([key, value]) => [ key, TypeChecker.isReference(value) ? components.examples?.[value.$ref.split("/").pop() ?? ""] : value ])).filter((([_, v]) => v !== undefined))) : undefined } ]))); const convertComponents = input => ({ schemas: Object.fromEntries(Object.entries(input.schemas ?? {}).filter((([_, v]) => v !== undefined)).map((([key, value]) => [ key, convertSchema(input)(value) ]))), securitySchemes: input.securitySchemes }); const convertSchema = components => input => { const union = []; const attribute = { title: input.title, description: input.description, ...Object.fromEntries(Object.entries(input).filter((([key, value]) => key.startsWith("x-") && value !== undefined))), examples: Array.isArray(input.examples) ? Object.fromEntries(input.examples.map(((v, i) => [ `v${i}`, v ]))) : input.examples }; const nullable = { value: false, default: undefined }; const visit = schema => { if (schema.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.isMixed(schema)) { if (schema.const !== undefined) visit({ ...schema, ...{ type: undefined, oneOf: undefined, anyOf: undefined, allOf: undefined, $ref: undefined } }); if (schema.oneOf !== undefined) visit({ ...schema, ...{ type: undefined, anyOf: undefined, allOf: undefined, $ref: undefined } }); if (schema.anyOf !== undefined) visit({ ...schema, ...{ type: undefined, oneOf: undefined, allOf: undefined, $ref: undefined } }); if (schema.allOf !== undefined) visit({ ...schema, ...{ type: undefined, oneOf: undefined, anyOf: undefined, $ref: undefined } }); for (const type of schema.type) if (type === "boolean" || type === "number" || type === "string") visit({ ...schema, ...{ enum: schema.enum?.length && schema.enum.filter((e => e !== null)) ? schema.enum.filter((x => typeof x === type)) : undefined }, type }); else if (type === "integer") visit({ ...schema, ...{ enum: schema.enum?.length && schema.enum.filter((e => e !== null)) ? schema.enum.filter((x => x !== null && typeof x === "number" && Number.isInteger(x))) : undefined }, type }); else visit({ ...schema, type }); } else if (TypeChecker.isOneOf(schema)) schema.oneOf.forEach(visit); else if (TypeChecker.isAnyOf(schema)) schema.anyOf.forEach(visit); else if (TypeChecker.isAllOf(schema)) if (schema.allOf.length === 1) visit(schema.allOf[0]); else union.push(convertAllOfSchema(components)(schema)); else if (TypeChecker.isBoolean(schema)) if (schema.enum?.length && schema.enum.filter((e => e !== null)).length) for (const value of schema.enum.filter((e => e !== null))) union.push({ const: value, ...{ ...schema, type: undefined, enum: undefined, default: undefined } }); else union.push({ ...schema, default: schema.default ?? undefined, ...{ enum: undefined } }); else if (TypeChecker.isInteger(schema) || TypeChecker.isNumber(schema)) if (schema.enum?.length && schema.enum.filter((e => e !== null))) for (const value of schema.enum.filter((e => e !== null))) union.push({ const: value, ...{ ...schema, type: undefined, enum: undefined, default: undefined, minimum: undefined, maximum: undefined, exclusiveMinimum: undefined, exclusiveMaximum: undefined, multipleOf: undefined } }); else union.push(OpenApiExclusiveEmender.emend({ ...schema, default: schema.default ?? undefined, ...{ enum: 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 })); else if (TypeChecker.isString(schema)) if (schema.enum?.length && schema.enum.filter((e => e !== null)).length) for (const value of schema.enum.filter((e => e !== null))) union.push({ const: value, ...{ ...schema, type: undefined, enum: undefined, default: undefined } }); else union.push({ ...schema, default: schema.default ?? undefined, ...{ enum: undefined } }); else if (TypeChecker.isArray(schema)) { if (Array.isArray(schema.items)) union.push({ ...schema, ...{ items: undefined, prefixItems: schema.items.map(convertSchema(components)), additionalItems: typeof schema.additionalItems === "object" && schema.additionalItems !== null ? convertSchema(components)(schema.additionalItems) : schema.additionalItems } }); else if (Array.isArray(schema.prefixItems)) union.push({ ...schema, ...{ items: undefined, prefixItems: schema.prefixItems.map(convertSchema(components)), additionalItems: typeof schema.additionalItems === "object" && schema.additionalItems !== null ? convertSchema(components)(schema.additionalItems) : schema.additionalItems } }); else if (schema.items === undefined) union.push({ ...schema, ...{ items: undefined, prefixItems: [] } }); else union.push({ ...schema, ...{ items: convertSchema(components)(schema.items), prefixItems: undefined, additionalItems: 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, convertSchema(components)(value) ]))) : {}, additionalProperties: schema.additionalProperties ? typeof schema.additionalProperties === "object" && schema.additionalProperties !== null ? convertSchema(components)(schema.additionalProperties) : schema.additionalProperties : undefined, required: schema.required ?? [] } }); else if (TypeChecker.isRecursiveReference(schema)) union.push({ ...schema, ...{ $ref: schema.$recursiveRef, $recursiveRef: undefined } }); else union.push(schema); }; visit(input); if (nullable.value === true && !union.some((e => e.type === "null"))) union.push({ type: "null", default: nullable.default }); return { ...union.length === 0 ? { type: undefined } : union.length === 1 ? { ...union[0] } : { oneOf: union.map((u => ({ ...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 { type: undefined, ...{ allOf: undefined } }; return { ...input, type: "object", properties: Object.fromEntries(objects.map((o => Object.entries(o?.properties ?? {}))).flat().map((([key, value]) => [ key, convertSchema(components)(value) ]))), ...{ allOf: undefined, required: [ ...new Set(objects.map((o => o?.required ?? [])).flat()) ] } }; }; const retrieveObject = components => (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(components)(components.schemas?.[input.$ref.split("/").pop() ?? ""] ?? {}, visited); else if (TypeChecker.isRecursiveReference(input)) return retrieveObject(components)(components.schemas?.[input.$recursiveRef.split("/").pop() ?? ""] ?? {}, visited); return null; }; let TypeChecker; (function(TypeChecker) { TypeChecker.isConstant = schema => schema.const !== undefined; 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.isRecursiveReference = schema => schema.$recursiveRef !== 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.isMixed = schema => Array.isArray(schema.type); })(TypeChecker || (TypeChecker = {})); })(OpenApiV3_1Emender || (OpenApiV3_1Emender = {})); export { OpenApiV3_1Emender }; //# sourceMappingURL=OpenApiV3_1Emender.mjs.map