UNPKG

@rimbu/deep

Version:

Tools to use handle plain JS objects as immutable objects

141 lines (140 loc) 6.14 kB
import { type IsAnyFunc, type IsArray, type IsPlainObj, type NotIterable } from '@rimbu/base'; import type { Protected } from './internal.mjs'; import type { Tuple } from './tuple.mjs'; /** * The type to determine the allowed input values for the `match` function. * @typeparam T - the type of value to match * @typeparam C - utility type */ export type Match<T, C extends Partial<T> = Partial<T>> = Match.Entry<T, C, T, T>; export declare namespace Match { /** * Determines the various allowed match types for given type `T`. * @typeparam T - the input value type * @typeparam C - utility type * @typeparam P - the parent type * @typeparam R - the root object type */ type Entry<T, C, P, R> = IsAnyFunc<T> extends true ? T : IsPlainObj<T> extends true ? Match.WithResult<T, P, R, Match.Obj<T, C, P, R>> : IsArray<T> extends true ? Match.Arr<T, C, P, R> | Match.Entry<T[number & keyof T], C[number & keyof C], P, R>[] | Match.Func<T, P, R, Match.Arr<T, C, P, R> | Match.Entry<T[number & keyof T], C[number & keyof C], P, R>[]> : Match.WithResult<T, P, R, { [K in keyof C]: C[K & keyof T]; }>; /** * The type that determines allowed matchers for objects. * @typeparam T - the input value type * @typeparam C - utility type * @typeparam P - the parent type * @typeparam R - the root object type */ type Obj<T, C, P, R> = Match.ObjProps<T, C, R> | Match.CompoundForObj<T, C, P, R>; /** * The type to determine allowed matchers for object properties. * @typeparam T - the input value type * @typeparam C - utility type * @typeparam R - the root object type */ type ObjProps<T, C, R> = { [K in keyof C]?: K extends keyof T ? Match.Entry<T[K], C[K], T, R> : never; }; /** * The type that determines allowed matchers for arrays/tuples. * @typeparam T - the input value type * @typeparam C - utility type * @typeparam P - the parent type * @typeparam R - the root object type */ type Arr<T, C, P, R> = C | Match.CompoundForArr<T, C, P, R> | Match.TraversalForArr<T, C, R> | (Match.TupIndices<T, C, R> & { [K in Match.CompoundType | Match.ArrayTraversalType]?: never; }); /** * A type that either directly results in result type `S` or is a function taking the value, parent, and root values, and * returns a value of type `S`. * @typeparam T - the input value type * @typeparam P - the parent type * @typeparam R - the root object type * @typeparam S - the result type */ type WithResult<T, P, R, S> = S | Match.Func<T, P, R, S>; /** * Type used to determine the allowed function types. Always includes booleans. * @typeparam T - the input value type * @typeparam P - the parent type * @typeparam R - the root object type * @typeparam S - the allowed return value type */ type Func<T, P, R, S> = (current: Protected<T>, parent: Protected<P>, root: Protected<R>) => boolean | S; /** * Type used to indicate an object containing matches for tuple indices. * @typeparam T - the input value type * @typeparam C - utility type * @typeparam R - the root object type */ type TupIndices<T, C, R> = { [K in Tuple.KeysOf<C>]?: Match.Entry<T[K & keyof T], C[K], T, R>; } & NotIterable; /** * Compound keys used to indicate the type of compound. */ type CompoundType = 'every' | 'some' | 'none' | 'single'; /** * Keys used to indicate an array match traversal. */ type ArrayTraversalType = `${CompoundType}Item`; /** * Compount matcher for objects, can only be an array staring with a compound type keyword. * @typeparam T - the input value type * @typeparam C - utility type * @typeparam P - the parent type * @typeparam R - the root object type */ type CompoundForObj<T, C, P, R> = [ Match.CompoundType, ...Match.Entry<T, C, P, R>[] ]; /** * Defines an object containing exactly one `CompoundType` key, having an array of matchers. * @typeparam T - the input value type * @typeparam C - utility type * @typeparam P - the parent type * @typeparam R - the root object type */ type CompoundForArr<T, C, P, R> = { [K in Match.CompoundType]: { [K2 in Match.CompoundType]?: K2 extends K ? Match.Entry<T, C, P, R>[] : never; }; }[Match.CompoundType]; /** * Defines an object containing exactly one `TraversalType` key, having a matcher for the array element type. * @typeparam T - the input value type * @typeparam C - utility type * @typeparam R - the root object type */ type TraversalForArr<T, C, R> = { [K in Match.ArrayTraversalType]: { [K2 in Match.ArrayTraversalType]?: K2 extends K ? Match.Entry<T[number & keyof T], C[number & keyof C], T, R> : never; }; }[Match.ArrayTraversalType]; /** * Utility type for collecting match failure reasons */ type FailureLog = string[]; } /** * Returns true if the given `value` object matches the given `matcher`, false otherwise. * @typeparam T - the input value type * @typeparam C - utility type * @param source - the value to match (should be a plain object) * @param matcher - a matcher object or a function taking the matcher API and returning a match object * @param failureLog - (optional) a string array that can be passed to collect reasons why the match failed * @example * ```ts * const input = { a: 1, b: { c: true, d: 'a' } } * match(input, { a: 1 }) // => true * match(input, { a: 2 }) // => false * match(input, { a: (v) => v > 10 }) // => false * match(input, { b: { c: true }}) // => true * match(input, (['every', { a: (v) => v > 0 }, { b: { c: true } }]) // => true * match(input, { b: { c: (v, parent, root) => v && parent.d.length > 0 && root.a > 0 } }) * // => true * ``` */ export declare function match<T, C extends Partial<T> = Partial<T>>(source: T, matcher: Match<T, C>, failureLog?: Match.FailureLog): boolean;