@samchon/openapi
Version:
OpenAPI definitions and converters for 'typia' and 'nestia'.
238 lines (234 loc) • 11.8 kB
JavaScript
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