(value: unknown, options: { stripNull?: boolean } = {})
| 26 | } |
| 27 | |
| 28 | function normalize(value: unknown, options: { stripNull?: boolean } = {}): unknown { |
| 29 | if (Array.isArray(value)) return value.map((item) => normalize(item)) |
| 30 | if (!isRecord(value)) return value |
| 31 | |
| 32 | const required = Array.isArray(value.required) |
| 33 | ? new Set(value.required.filter((item) => typeof item === "string")) |
| 34 | : undefined |
| 35 | const schema = Object.fromEntries( |
| 36 | Object.entries(value).map(([key, item]) => [ |
| 37 | key, |
| 38 | key === "properties" && isRecord(item) |
| 39 | ? Object.fromEntries( |
| 40 | Object.entries(item).map(([name, property]) => [ |
| 41 | name, |
| 42 | normalize(property, { stripNull: !required?.has(name) }), |
| 43 | ]), |
| 44 | ) |
| 45 | : normalize(item), |
| 46 | ]), |
| 47 | ) |
| 48 | |
| 49 | if (schema.additionalProperties === true) delete schema.additionalProperties |
| 50 | |
| 51 | if (options.stripNull && Array.isArray(schema.anyOf)) { |
| 52 | const withoutNull = schema.anyOf.filter((item) => !isRecord(item) || item.type !== "null") |
| 53 | if (withoutNull.length !== schema.anyOf.length) return normalize({ ...schema, anyOf: withoutNull }) |
| 54 | } |
| 55 | |
| 56 | if (Array.isArray(schema.anyOf)) { |
| 57 | const withoutNull = schema.anyOf |
| 58 | const number = withoutNull.find((item) => isRecord(item) && item.type === "number") |
| 59 | const nonFinite = withoutNull.filter( |
| 60 | (item) => isRecord(item) && Array.isArray(item.enum) && item.enum.every((entry) => isNonFiniteNumber(entry)), |
| 61 | ) |
| 62 | if (number && nonFinite.length === withoutNull.length - 1) { |
| 63 | const { anyOf: _, ...rest } = schema |
| 64 | return normalize({ ...number, ...rest }) |
| 65 | } |
| 66 | |
| 67 | if (isEmptyStructUnion(withoutNull)) { |
| 68 | const { anyOf: _, ...rest } = schema |
| 69 | return normalize({ type: "object", properties: {}, ...rest }) |
| 70 | } |
| 71 | |
| 72 | if (withoutNull.length === 1 && isRecord(withoutNull[0])) { |
| 73 | const { anyOf: _, ...rest } = schema |
| 74 | return normalize({ ...withoutNull[0], ...rest }) |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | if (Array.isArray(schema.allOf) && schema.allOf.every(isRecord) && canFlattenAllOf(schema.allOf, schema)) { |
| 79 | const { allOf, ...rest } = schema |
| 80 | return normalize({ ...Object.assign({}, ...allOf), ...rest }) |
| 81 | } |
| 82 | |
| 83 | if (schema.type === "integer" && schema.maximum === undefined) { |
| 84 | return { minimum: Number.MIN_SAFE_INTEGER, ...schema, maximum: Number.MAX_SAFE_INTEGER } |
| 85 | } |
no test coverage detected