UNPKG

@samchon/openapi

Version:

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

196 lines (192 loc) 9.82 kB
import { OpenApiTypeChecker } from "../utils/OpenApiTypeChecker.mjs"; var OpenApiV3Downgrader; (function(OpenApiV3Downgrader) { OpenApiV3Downgrader.downgrade = input => { const collection = OpenApiV3Downgrader.downgradeComponents(input.components); return { openapi: "3.0.0", servers: input.servers, info: input.info, components: collection.downgraded, paths: input.paths ? Object.fromEntries(Object.entries(input.paths).filter((([_, v]) => v !== undefined)).map((([key, value]) => [ key, downgradePathItem(collection)(value) ]))) : undefined, security: input.security, tags: input.tags }; }; const downgradePathItem = collection => pathItem => ({ ...pathItem, ...pathItem.get ? { get: downgradeOperation(collection)(pathItem.get) } : undefined, ...pathItem.put ? { put: downgradeOperation(collection)(pathItem.put) } : undefined, ...pathItem.post ? { post: downgradeOperation(collection)(pathItem.post) } : undefined, ...pathItem.delete ? { delete: downgradeOperation(collection)(pathItem.delete) } : undefined, ...pathItem.options ? { options: downgradeOperation(collection)(pathItem.options) } : undefined, ...pathItem.head ? { head: downgradeOperation(collection)(pathItem.head) } : undefined, ...pathItem.patch ? { patch: downgradeOperation(collection)(pathItem.patch) } : undefined, ...pathItem.trace ? { trace: downgradeOperation(collection)(pathItem.trace) } : undefined }); const downgradeOperation = collection => input => ({ ...input, parameters: input.parameters ? input.parameters.map(downgradeParameter(collection)) : undefined, requestBody: input.requestBody ? downgradeRequestBody(collection)(input.requestBody) : undefined, responses: input.responses ? Object.fromEntries(Object.entries(input.responses).filter((([_, v]) => v !== undefined)).map((([key, value]) => [ key, downgradeResponse(collection)(value) ]))) : undefined }); const downgradeParameter = collection => input => ({ ...input, schema: OpenApiV3Downgrader.downgradeSchema(collection)(input.schema) }); const downgradeRequestBody = collection => input => ({ ...input, content: input.content ? downgradeContent(collection)(input.content) : undefined }); const downgradeResponse = collection => input => ({ ...input, content: input.content ? downgradeContent(collection)(input.content) : undefined, headers: input.headers ? Object.fromEntries(Object.entries(input.headers).filter((([_, v]) => v !== undefined)).map((([key, value]) => [ key, { ...value, schema: OpenApiV3Downgrader.downgradeSchema(collection)(value.schema) } ]))) : undefined }); const downgradeContent = collection => record => Object.fromEntries(Object.entries(record).filter((([_, v]) => v !== undefined)).map((([key, value]) => [ key, { ...value, schema: value?.schema ? OpenApiV3Downgrader.downgradeSchema(collection)(value.schema) : undefined } ]))); OpenApiV3Downgrader.downgradeComponents = input => { const collection = { original: input, downgraded: { securitySchemes: input.securitySchemes } }; if (input.schemas) { collection.downgraded.schemas = {}; for (const [key, value] of Object.entries(input.schemas)) if (value !== undefined) collection.downgraded.schemas[key] = OpenApiV3Downgrader.downgradeSchema(collection)(value); } return collection; }; OpenApiV3Downgrader.downgradeSchema = collection => input => { const nullable = isNullable(new Set)(collection.original)(input); const union = []; const attribute = { title: input.title, description: input.description, example: input.example, examples: input.examples, ...Object.fromEntries(Object.entries(input).filter((([key, value]) => key.startsWith("x-") && value !== undefined))) }; const visit = schema => { if (OpenApiTypeChecker.isBoolean(schema)) union.push({ type: "boolean" }); else if (OpenApiTypeChecker.isBoolean(schema) || OpenApiTypeChecker.isInteger(schema) || OpenApiTypeChecker.isNumber(schema) || OpenApiTypeChecker.isString(schema) || OpenApiTypeChecker.isReference(schema)) union.push({ ...schema }); else if (OpenApiTypeChecker.isArray(schema)) union.push({ ...schema, items: OpenApiV3Downgrader.downgradeSchema(collection)(schema.items) }); else if (OpenApiTypeChecker.isTuple(schema)) union.push({ ...schema, items: (() => { if (schema.additionalItems === true) return {}; const elements = [ ...schema.prefixItems, ...typeof schema.additionalItems === "object" ? [ OpenApiV3Downgrader.downgradeSchema(collection)(schema.additionalItems) ] : [] ]; if (elements.length === 0) return {}; return { oneOf: elements.map(OpenApiV3Downgrader.downgradeSchema(collection)) }; })(), minItems: schema.prefixItems.length, maxItems: !!schema.additionalItems === true ? undefined : schema.prefixItems.length, ...{ prefixItems: undefined, additionalItems: undefined } }); else if (OpenApiTypeChecker.isObject(schema)) union.push({ ...schema, properties: schema.properties ? Object.fromEntries(Object.entries(schema.properties).filter((([_, v]) => v !== undefined)).map((([key, value]) => [ key, OpenApiV3Downgrader.downgradeSchema(collection)(value) ]))) : undefined, additionalProperties: typeof schema.additionalProperties === "object" ? OpenApiV3Downgrader.downgradeSchema(collection)(schema.additionalProperties) : schema.additionalProperties, required: schema.required }); else if (OpenApiTypeChecker.isOneOf(schema)) schema.oneOf.forEach(visit); }; const visitConstant = schema => { const insert = value => { const matched = union.find((u => u.type === typeof value)); if (matched !== undefined) { matched.enum ?? (matched.enum = []); matched.enum.push(value); } else union.push({ type: typeof value, enum: [ value ] }); }; if (OpenApiTypeChecker.isConstant(schema)) insert(schema.const); else if (OpenApiTypeChecker.isOneOf(schema)) for (const u of schema.oneOf) if (OpenApiTypeChecker.isConstant(u)) insert(u.const); }; visit(input); visitConstant(input); if (nullable === true) for (const u of union) if (OpenApiTypeChecker.isReference(u)) downgradeNullableReference(new Set)(collection)(u); else u.nullable = true; if (nullable === true && union.length === 0) return { type: "null", ...attribute }; return { ...union.length === 0 ? { type: undefined } : union.length === 1 ? { ...union[0] } : { oneOf: union }, ...attribute }; }; const downgradeNullableReference = visited => collection => schema => { var _a; const key = schema.$ref.split("/").pop(); if (key.endsWith(".Nullable")) return; const found = collection.original.schemas?.[key]; if (found === undefined) return; else if (isNullable(visited)(collection.original)(found) === true) return; else if (collection.downgraded.schemas?.[`${key}.Nullable`] === undefined) { (_a = collection.downgraded).schemas ?? (_a.schemas = {}); collection.downgraded.schemas[`${key}.Nullable`] = {}; collection.downgraded.schemas[`${key}.Nullable`] = OpenApiV3Downgrader.downgradeSchema(collection)(OpenApiTypeChecker.isOneOf(found) ? { ...found, oneOf: [ ...found.oneOf, { type: "null" } ] } : { oneOf: [ found, { type: "null" } ], title: found.title, description: found.description, example: found.example, examples: found.examples, ...Object.fromEntries(Object.entries(found).filter((([key, value]) => key.startsWith("x-") && value !== undefined))) }); } schema.$ref += ".Nullable"; }; const isNullable = visited => components => schema => { if (OpenApiTypeChecker.isNull(schema)) return true; else if (OpenApiTypeChecker.isReference(schema)) { if (visited.has(schema.$ref)) return false; visited.add(schema.$ref); const key = schema.$ref.split("/").pop(); const next = components.schemas?.[key]; return next ? isNullable(visited)(components)(next) : false; } return OpenApiTypeChecker.isOneOf(schema) && schema.oneOf.some(isNullable(visited)(components)); }; })(OpenApiV3Downgrader || (OpenApiV3Downgrader = {})); export { OpenApiV3Downgrader }; //# sourceMappingURL=OpenApiV3Downgrader.mjs.map