UNPKG

object-shape-tester

Version:
59 lines (58 loc) 2.04 kB
import { mapObjectValues } from '@augment-vir/common'; import { Type, } from '@sinclair/typebox'; import { defineShape } from '../shape/shape.js'; import { canSchemaBeNullable, insertUnion, isObjectSchema, isUndefinedSchema, matchesSchemaGuard, operateOnExtraction, } from '../util/typebox-util.js'; /** * Creates a shape from an object shape where any property that can be any kind of nullable * (optional, `null`, or `undefined`) can now be _all_ kinds of nullable. That is, any property that * is optional or can be `null` or `undefined` becomes all three. * * @category Shape * @example * * ```ts * import { * nullToNullableShape, * unionShape, * assertValidShape, * defineShape, * } from 'object-shape-tester'; * * const myShape = nullToNullableShape({ * a: '', * b: unionShape(null, -1), * c: null, * d: { * e: unionShape(null, ''), * }, * }); * * // passes * assertValidShape({a: 'hi', b: null, d: {}}, myShape); * assertValidShape({a: 'hi', b: undefined, d: {e: undefined}}, myShape); * * // fails * assertValidShape({b: null}, myShape); * assertValidShape({a: 'hi'}, myShape); * ``` */ export function ensureNullableShape(originalShape) { const shape = defineShape(originalShape); return defineShape(operateOnExtraction(shape.$_schema, isObjectSchema, (schema) => { const newProperties = mapObjectValues(schema.properties, (propKey, propSchema) => { const mappedPropSchema = ensureNullableShape(propSchema).$_schema; if (!canSchemaBeNullable(mappedPropSchema)) { return mappedPropSchema; } return Type.Optional(matchesSchemaGuard(mappedPropSchema, isUndefinedSchema) ? mappedPropSchema : insertUnion({ originalSchema: mappedPropSchema, insertion: Type.Undefined(), })); }); return Type.Object(newProperties, { default: shape.default, }); })); }