UNPKG

object-shape-tester

Version:
84 lines (83 loc) 3.54 kB
import { check } from '@augment-vir/assert'; import { extractErrorMessage, mapObjectValues } from '@augment-vir/common'; import { DefaultValueConstructionError } from '../errors/default-value-construction.error.js'; import { expandIndexedKeysKeys } from '../verify-shape/verify-shape.js'; import { isCustomSpecifier } from './custom-specifier.js'; import { getShapeSpecifier, isAndShapeSpecifier, isClassShapeSpecifier, isEnumShapeSpecifier, isExactShapeSpecifier, isIndexedKeysSpecifier, isNumericRangeShapeSpecifier, isOptionalShapeSpecifier, isOrShapeSpecifier, isShapeDefinition, isTupleShapeSpecifier, isUnknownShapeSpecifier, } from './shape-specifiers.js'; /** * Creates a default value for the given shape. * * @category Internal */ export function shapeToDefaultValue(shape) { return innerShapeToDefaultValue(shape); } function innerShapeToDefaultValue(shape) { const specifier = getShapeSpecifier(shape); if (isCustomSpecifier(shape)) { return shape.defaultValue; } else if (specifier) { if (isTupleShapeSpecifier(specifier)) { return specifier.parts.map((part) => innerShapeToDefaultValue(part)); } else if (isOptionalShapeSpecifier(specifier)) { return innerShapeToDefaultValue(specifier.parts[0]); } else if (isNumericRangeShapeSpecifier(specifier)) { return specifier.parts[0]; } else if (isClassShapeSpecifier(specifier)) { const classConstructor = specifier.parts[0]; try { return new classConstructor(); } catch (caught) { throw new DefaultValueConstructionError(`Failed to create default value for classShape for class '${classConstructor.name}': ${extractErrorMessage(caught)}`); } } else if (isOrShapeSpecifier(specifier) || isExactShapeSpecifier(specifier)) { return innerShapeToDefaultValue(specifier.parts[0]); } else if (isAndShapeSpecifier(specifier)) { return specifier.parts.reduce((combined, part) => { return Object.assign(combined, innerShapeToDefaultValue(part)); }, {}); } else if (isEnumShapeSpecifier(specifier)) { return specifier.parts[1] || Object.values(specifier.parts[0])[0]; } else if (isIndexedKeysSpecifier(specifier)) { const keys = expandIndexedKeysKeys(specifier); if (!specifier.parts[0].required || check.isBoolean(keys)) { return {}; } return Object.fromEntries(keys.map((key) => [ key, innerShapeToDefaultValue(specifier.parts[0].values), ])); } else if (isUnknownShapeSpecifier(specifier)) { return specifier.parts[0] ?? {}; /* v8 ignore next 7: this is an edge case fallback */ } else { throw new DefaultValueConstructionError(`found specifier but it matches no expected specifiers: ${String(specifier.specifierType)}`); } } if (isShapeDefinition(shape)) { return shapeToDefaultValue(shape.shape); } else if (shape instanceof RegExp) { return shape; } else if (check.isArray(shape)) { return shape.map(innerShapeToDefaultValue); } else if (check.isObject(shape)) { return mapObjectValues(shape, (key, value) => { return shapeToDefaultValue(value); }); } return shape; }