UNPKG

n4s

Version:

typed schema validation version of enforce

80 lines (67 loc) 2.47 kB
import { hasOwnProperty } from 'vest-utils'; import type { RuleInstance } from '../../utils/RuleInstance'; import { RuleRunReturn } from '../../utils/RuleRunReturn'; import { loose } from './loose'; import { ownKeys } from './schemaObjectUtils'; // Types colocated with shape rule import type { InferShape, SchemaInfer, SchemaInput } from './schemaRulesTypes'; /** * Validates that an object matches a schema exactly - all keys required, no extra keys allowed. * Each field value is validated against its corresponding RuleInstance in the schema. * * @template T - The object type to validate * @param value - The object to validate * @param schema - Schema mapping keys to validation rules * @returns RuleRunReturn indicating success or failure * * @example * ```typescript * // Eager API * enforce({ name: 'John', age: 30 }) * .shape({ * name: enforce.isString(), * age: enforce.isNumber().greaterThan(0) * }); // passes * * // Lazy API * const userSchema = enforce.shape({ * name: enforce.isString(), * email: enforce.isString().matches(/@/), * age: enforce.isNumber().greaterThanOrEquals(18) * }); * * userSchema.test({ name: 'Jane', email: 'jane@example.com', age: 25 }); // true * userSchema.test({ name: 'Jane', age: 25 }); // false (missing email) * userSchema.test({ name: 'Jane', email: 'jane@example.com', age: 25, extra: 'x' }); // false (extra key) * ``` */ export function shape<T extends Record<string, any>>( value: T, schema: Record<string, any>, ): RuleRunReturn<T> { const baseRes = loose(value, schema); if (!baseRes.pass) { return baseRes; } for (const key of ownKeys(value)) { if (!hasOwnProperty(schema, key)) { const res = RuleRunReturn.Failing(value); const newRes = { ...res, path: [key] }; return newRes; } } return RuleRunReturn.Passing(baseRes.type); } export type { InferShape, SchemaInfer }; export type ShapeType<T extends Record<string, RuleInstance<any>>> = SchemaInfer<T>; export type ShapeInputType<T extends Record<string, RuleInstance<any>>> = SchemaInput<T>; export type ShapeRuleInstance<S extends Record<string, RuleInstance<any>>> = RuleInstance<ShapeType<S>, [ShapeInputType<S>]>; export type ShapeValue<S extends Record<string, RuleInstance<any>>> = ShapeType<S>; export type SchemaValidationRule = <T extends Record<string, any>>( value: T, schema: Record<string, RuleInstance<any>>, ) => RuleRunReturn<T>;