@nestjs/swagger
Version:
Nest - modern, fast, powerful node.js web framework (@swagger)
82 lines (81 loc) • 2.34 kB
JavaScript
const COMBINATOR_KEYS = ['allOf', 'oneOf', 'anyOf'];
const DATA_KEYS = new Set(['example', 'examples', 'default', 'const', 'enum']);
const NAME_KEYED_MAPS = new Set([
'properties',
'patternProperties',
'$defs',
'schemas',
'headers'
]);
export function convertNullableToOas31(document) {
walk(document);
}
function walk(node) {
if (Array.isArray(node)) {
node.forEach(walk);
return;
}
if (!isObject(node)) {
return;
}
for (const [key, value] of Object.entries(node)) {
if (DATA_KEYS.has(key) || key.startsWith('x-')) {
continue;
}
if (NAME_KEYED_MAPS.has(key) && isObject(value)) {
Object.values(value).forEach(walk);
}
else {
walk(value);
}
}
convertSchema(node);
}
function convertSchema(schema) {
if (typeof schema.nullable !== 'boolean') {
return;
}
const isNullable = schema.nullable;
delete schema.nullable;
if (!isNullable) {
return;
}
const combinator = COMBINATOR_KEYS.find((key) => Array.isArray(schema[key]));
if ('$ref' in schema || combinator) {
schema.anyOf = [extractInnerSchema(schema, combinator), { type: 'null' }];
return;
}
if (schema.type !== undefined) {
const types = Array.isArray(schema.type)
? schema.type
: [schema.type];
schema.type = types.includes('null') ? types : [...types, 'null'];
}
if (Array.isArray(schema.enum) && !schema.enum.includes(null)) {
schema.enum = [...schema.enum, null];
}
}
function extractInnerSchema(schema, combinator) {
const inner = {};
if ('$ref' in schema) {
inner.$ref = schema.$ref;
delete schema.$ref;
}
if (combinator) {
const members = schema[combinator];
delete schema[combinator];
if (schema.type === 'object' && !('properties' in schema)) {
delete schema.type;
}
if (!('$ref' in inner) && combinator === 'allOf' && members.length === 1) {
Object.assign(inner, members[0]);
}
else {
inner[combinator] = members;
}
}
return inner;
}
function isObject(value) {
return typeof value === 'object' && value !== null && !Array.isArray(value);
}