@samchon/openapi
Version:
OpenAPI definitions and converters for 'typia' and 'nestia'.
294 lines (293 loc) • 15.7 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.SwaggerV2Downgrader = void 0;
const OpenApiTypeChecker_1 = require("../utils/OpenApiTypeChecker");
var SwaggerV2Downgrader;
(function (SwaggerV2Downgrader) {
SwaggerV2Downgrader.downgrade = (input) => {
var _a, _b, _c;
const collection = SwaggerV2Downgrader.downgradeComponents(input.components);
return {
swagger: "2.0",
info: input.info,
host: ((_b = (_a = input.servers) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.url)
? input.servers[0].url.split("://").pop()
: "",
definitions: collection.downgraded,
securityDefinitions: ((_c = input.components) === null || _c === void 0 ? void 0 : _c.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,
};
};
/* -----------------------------------------------------------
OPERATORS
----------------------------------------------------------- */
const downgradePathItem = (collection) => (pathItem) => (Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, 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) => {
var _a;
return (Object.assign(Object.assign(Object.assign({}, input), { parameters: input.parameters !== undefined || input.requestBody !== undefined
? [
...((_a = input.parameters) !== null && _a !== void 0 ? _a : []).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) => {
var _a, _b;
return (Object.assign(Object.assign(Object.assign(Object.assign({}, SwaggerV2Downgrader.downgradeSchema(collection)(input.schema)), input), { required: (_a = input.schema) === null || _a === void 0 ? void 0 : _a.required, schema: undefined, name: (_b = input.name) !== null && _b !== void 0 ? _b : `p${i}` }), {
example: undefined,
examples: undefined,
}));
};
const downgradeRequestBody = (collection) => (input) => {
var _a, _b, _c;
return ({
name: "body",
in: "body",
description: input.description,
required: input.required,
schema: SwaggerV2Downgrader.downgradeSchema(collection)((_c = (_b = Object.values((_a = input.content) !== null && _a !== void 0 ? _a : {})[0]) === null || _b === void 0 ? void 0 : _b.schema) !== null && _c !== void 0 ? _c : {}),
});
};
const downgradeResponse = (collection) => (input) => {
var _a, _b, _c;
return ({
description: input.description,
schema: SwaggerV2Downgrader.downgradeSchema(collection)((_c = (_b = Object.values((_a = input.content) !== null && _a !== void 0 ? _a : {})[0]) === null || _b === void 0 ? void 0 : _b.schema) !== null && _c !== void 0 ? _c : {}),
headers: input.headers
? Object.fromEntries(Object.entries(input.headers)
.filter(([_, v]) => v !== undefined)
.map(([key, value]) => [
key,
Object.assign(Object.assign(Object.assign({}, value), { schema: SwaggerV2Downgrader.downgradeSchema(collection)(value.schema) }), {
example: undefined,
examples: undefined,
}),
]))
: undefined,
});
};
/* -----------------------------------------------------------
DEFINITIONS
----------------------------------------------------------- */
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 = Object.assign({ 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_1.OpenApiTypeChecker.isBoolean(schema))
union.push({ type: "boolean" });
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isBoolean(schema) ||
OpenApiTypeChecker_1.OpenApiTypeChecker.isInteger(schema) ||
OpenApiTypeChecker_1.OpenApiTypeChecker.isNumber(schema) ||
OpenApiTypeChecker_1.OpenApiTypeChecker.isString(schema))
union.push(Object.assign(Object.assign({}, schema), { examples: schema.examples
? Object.values(schema.examples)
: undefined }));
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isReference(schema))
union.push({ $ref: `#/definitions/${schema.$ref.split("/").pop()}` });
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isArray(schema))
union.push(Object.assign(Object.assign({}, schema), { items: SwaggerV2Downgrader.downgradeSchema(collection)(schema.items), examples: schema.examples
? Object.values(schema.examples)
: undefined }));
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isTuple(schema))
union.push(Object.assign(Object.assign(Object.assign(Object.assign({}, 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_1.OpenApiTypeChecker.isObject(schema))
union.push(Object.assign(Object.assign({}, 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_1.OpenApiTypeChecker.isOneOf(schema))
schema.oneOf.forEach(visit);
};
const visitConstant = (schema) => {
const insert = (value) => {
var _a;
const matched = union.find((u) => u.type === value);
if (matched !== undefined) {
(_a = matched.enum) !== null && _a !== void 0 ? _a : (matched.enum = []);
matched.enum.push(value);
}
else
union.push({ type: typeof value, enum: [value] });
if (OpenApiTypeChecker_1.OpenApiTypeChecker.isConstant(schema))
insert(schema.const);
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isOneOf(schema))
schema.oneOf.forEach(insert);
};
};
visit(input);
visitConstant(input);
if (nullable) {
for (const u of union)
if (OpenApiTypeChecker_1.OpenApiTypeChecker.isReference(u))
downgradeNullableReference(new Set())(collection)(u);
else
u["x-nullable"] = true;
}
if (nullable === true && union.length === 0)
return Object.assign({ type: "null" }, attribute);
return Object.assign(Object.assign(Object.assign({}, (union.length === 0
? { type: undefined }
: union.length === 1
? Object.assign({}, union[0]) : { "x-oneOf": union })), attribute), (union.length > 1 ? { discriminator: undefined } : {}));
};
const downgradeNullableReference = (visited) => (collection) => (schema) => {
var _a;
const key = schema.$ref.split("/").pop();
if (key.endsWith(".Nullable"))
return;
const found = (_a = collection.original.schemas) === null || _a === void 0 ? void 0 : _a[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_1.OpenApiTypeChecker.isOneOf(found)
? Object.assign(Object.assign({}, found), { oneOf: [...found.oneOf, { type: "null" }] }) : Object.assign(Object.assign({ 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) => {
var _a;
if (OpenApiTypeChecker_1.OpenApiTypeChecker.isNull(schema))
return true;
else if (OpenApiTypeChecker_1.OpenApiTypeChecker.isReference(schema)) {
if (visited.has(schema.$ref))
return false;
visited.add(schema.$ref);
const key = schema.$ref.split("/").pop();
const next = (_a = components.schemas) === null || _a === void 0 ? void 0 : _a[key];
return next ? isNullable(visited)(components)(next) : false;
}
return (OpenApiTypeChecker_1.OpenApiTypeChecker.isOneOf(schema) &&
schema.oneOf.some(isNullable(visited)(components)));
};
})(SwaggerV2Downgrader || (exports.SwaggerV2Downgrader = SwaggerV2Downgrader = {}));
;