lib/transform/nullableTransformer.ts (101 lines of code) (raw):
import { LiveValidatorLoggingLevels } from "../liveValidation/liveValidator";
import { JsonLoader } from "../swagger/jsonLoader";
import { Schema } from "../swagger/swaggerTypes";
import { xNullable } from "../util/constants";
import { allOfTransformer } from "./allOfTransformer";
import { GlobalTransformer, TransformerType } from "./transformer";
export const nullableTransformer: GlobalTransformer = {
type: TransformerType.Global,
after: [allOfTransformer],
transform({ objSchemas, allParams, arrSchemas, jsonLoader, logging }) {
for (const sch of objSchemas) {
try {
if (sch.properties !== undefined) {
for (const key of Object.keys(sch.properties)) {
sch.properties[key] = transformNullable(
sch.properties[key],
jsonLoader,
!sch.required?.includes(key)
);
}
}
const aProperty = sch.additionalProperties;
if (typeof aProperty === "object" && aProperty !== null) {
sch.additionalProperties = transformNullable(
aProperty,
jsonLoader,
undefined,
aProperty.type === "object"
);
}
} catch (e) {
if (logging) {
logging(
`Fail to transform ${sch}. ErrorMessage:${e?.message};ErrorStack:${e?.stack}.`,
LiveValidatorLoggingLevels.error
);
} else {
console.log(
`Fail to transform ${sch}. ErrorMessage:${e?.message};ErrorStack:${e?.stack}.`
);
}
}
}
for (const sch of arrSchemas) {
try {
if (sch.items) {
if (Array.isArray(sch.items)) {
sch.items = sch.items.map((item) => transformNullable(item, jsonLoader));
} else {
sch.items = transformNullable(sch.items, jsonLoader);
}
}
} catch (e) {
if (logging) {
logging(
`Fail to transform ${sch}. ErrorMessage:${e?.message};ErrorStack:${e?.stack}.`,
LiveValidatorLoggingLevels.error
);
} else {
console.log(
`Fail to transform ${sch}. ErrorMessage:${e?.message};ErrorStack:${e?.stack}.`
);
}
}
}
for (const param of allParams) {
if (param.in === "query" && param.allowEmptyValue) {
param.nullable = true;
}
}
},
};
const transformNullable = (
s: Schema,
jsonLoader: JsonLoader,
defaultNullable?: boolean,
additionalPropertiesWithObjectType?: boolean
) => {
const sch = jsonLoader.resolveRefObj(s);
const nullable = sch[xNullable] ?? sch.nullable;
// Originally it's not nullable
if (nullable === false) {
return s;
}
// By default it's not nullable
if (nullable === undefined && defaultNullable === false) {
return s;
}
// Set nullable to true
if (s !== sch) {
// s isRefLike
return {
anyOf: [s, { type: "null", _skipError: true }],
_skipError: true,
} as Schema;
} else {
if (typeof sch === "object") {
sch.nullable = true;
}
if (additionalPropertiesWithObjectType) {
sch.additionalPropertiesWithObjectType = true;
}
return sch;
}
};