UNPKG

@samchon/openapi

Version:

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

238 lines (234 loc) 11.8 kB
import { OpenApiTypeChecker } from "../utils/OpenApiTypeChecker.mjs"; var SwaggerV2Downgrader; (function(SwaggerV2Downgrader) { SwaggerV2Downgrader.downgrade = input => { const collection = SwaggerV2Downgrader.downgradeComponents(input.components); return { swagger: "2.0", info: input.info, host: input.servers?.[0]?.url ? input.servers[0].url.split("://").pop() : "", definitions: collection.downgraded, securityDefinitions: input.components?.securitySchemes ? Object.fromEntries(Object.entries(input.components.securitySchemes).filter((([_, v]) => v !== undefined)).map((([key, value]) => downgradeSecurityScheme(value).map((v => [ key, v ])))).flat()) : undefined, 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 !== undefined || input.requestBody !== undefined ? [ ...(input.parameters ?? []).map(downgradeParameter(collection)), ...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, ...{ requestBody: undefined, servers: undefined } }); const downgradeParameter = collection => (input, i) => ({ ...SwaggerV2Downgrader.downgradeSchema(collection)(input.schema), ...input, required: input.schema?.required, schema: undefined, name: input.name ?? `p${i}`, ...{ example: undefined, examples: undefined } }); const downgradeRequestBody = collection => input => ({ name: "body", in: "body", description: input.description, required: input.required, schema: SwaggerV2Downgrader.downgradeSchema(collection)(Object.values(input.content ?? {})[0]?.schema ?? {}) }); const downgradeResponse = collection => input => ({ description: input.description, schema: SwaggerV2Downgrader.downgradeSchema(collection)(Object.values(input.content ?? {})[0]?.schema ?? {}), headers: input.headers ? Object.fromEntries(Object.entries(input.headers).filter((([_, v]) => v !== undefined)).map((([key, value]) => [ key, { ...value, schema: SwaggerV2Downgrader.downgradeSchema(collection)(value.schema), ...{ example: undefined, examples: undefined } } ]))) : undefined }); SwaggerV2Downgrader.downgradeComponents = input => { const collection = { original: input, downgraded: {} }; if (input.schemas) { collection.downgraded.schemas = {}; for (const [key, value] of Object.entries(input.schemas)) if (value !== undefined) collection.downgraded[key.split("/").pop()] = SwaggerV2Downgrader.downgradeSchema(collection)(value); } return collection; }; SwaggerV2Downgrader.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.values(input.examples) : undefined, ...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)) union.push({ ...schema, examples: schema.examples ? Object.values(schema.examples) : undefined }); else if (OpenApiTypeChecker.isReference(schema)) union.push({ $ref: `#/definitions/${schema.$ref.split("/").pop()}` }); else if (OpenApiTypeChecker.isArray(schema)) union.push({ ...schema, items: SwaggerV2Downgrader.downgradeSchema(collection)(schema.items), examples: schema.examples ? Object.values(schema.examples) : undefined }); else if (OpenApiTypeChecker.isTuple(schema)) union.push({ ...schema, items: (() => { if (schema.additionalItems === true) return {}; const elements = [ ...schema.prefixItems, ...typeof schema.additionalItems === "object" ? [ SwaggerV2Downgrader.downgradeSchema(collection)(schema.additionalItems) ] : [] ]; if (elements.length === 0) return {}; return { "x-oneOf": elements.map(SwaggerV2Downgrader.downgradeSchema(collection)) }; })(), minItems: schema.prefixItems.length, maxItems: !!schema.additionalItems === true ? undefined : schema.prefixItems.length, ...{ prefixItems: undefined, additionalItems: undefined }, examples: schema.examples ? Object.values(schema.examples) : 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, SwaggerV2Downgrader.downgradeSchema(collection)(value) ]))) : undefined, additionalProperties: typeof schema.additionalProperties === "object" ? SwaggerV2Downgrader.downgradeSchema(collection)(schema.additionalProperties) : schema.additionalProperties, required: schema.required, examples: schema.examples ? Object.values(schema.examples) : undefined }); else if (OpenApiTypeChecker.isOneOf(schema)) schema.oneOf.forEach(visit); }; visit(input); if (nullable) { for (const u of union) if (OpenApiTypeChecker.isReference(u)) downgradeNullableReference(new Set)(collection)(u); else u["x-nullable"] = true; } if (nullable === true && union.length === 0) return { type: "null", ...attribute }; return { ...union.length === 0 ? { type: undefined } : union.length === 1 ? { ...union[0] } : { "x-oneOf": union }, ...attribute, ...union.length > 1 ? { discriminator: undefined } : {} }; }; const downgradeNullableReference = visited => collection => schema => { 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[`${key}.Nullable`] === undefined) { collection.downgraded[`${key}.Nullable`] = {}; collection.downgraded[`${key}.Nullable`] = SwaggerV2Downgrader.downgradeSchema(collection)(OpenApiTypeChecker.isOneOf(found) ? { ...found, oneOf: [ ...found.oneOf, { type: "null" } ] } : { title: found.title, description: found.description, example: found.example, examples: found.examples ? Object.values(found.examples) : undefined, ...Object.fromEntries(Object.entries(found).filter((([key, value]) => key.startsWith("x-") && value !== undefined))), oneOf: [ found, { type: "null" } ] }); } schema.$ref += ".Nullable"; }; const downgradeSecurityScheme = input => { if (input.type === "apiKey") return [ input ]; else if (input.type === "http") if (input.scheme === "basic") return [ { type: "basic", description: input.description } ]; else return []; else if (input.type === "oauth2") { const output = []; if (input.flows.implicit) output.push({ type: "oauth2", flow: "implicit", authorizationUrl: input.flows.implicit.authorizationUrl, scopes: input.flows.implicit.scopes }); if (input.flows.password) output.push({ type: "oauth2", flow: "password", tokenUrl: input.flows.password.tokenUrl, scopes: input.flows.password.scopes }); if (input.flows.clientCredentials) output.push({ type: "oauth2", flow: "application", tokenUrl: input.flows.clientCredentials.tokenUrl, scopes: input.flows.clientCredentials.scopes }); if (input.flows.authorizationCode) output.push({ type: "oauth2", flow: "accessCode", authorizationUrl: input.flows.authorizationCode.authorizationUrl, tokenUrl: input.flows.authorizationCode.tokenUrl, scopes: input.flows.authorizationCode.scopes }); return output; } return []; }; 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)); }; })(SwaggerV2Downgrader || (SwaggerV2Downgrader = {})); export { SwaggerV2Downgrader }; //# sourceMappingURL=SwaggerV2Downgrader.mjs.map