/* IMPORT */ import Compound from './compound'; import Nillable from './nillable'; import Nullable from './nullable'; import Optional from './optional'; import Registry from '../registry'; import {anyOf, noneOf} from '../tests'; import {findLastIndex, isArray, isOptional, resolve} from '../utils'; import type {TupleState, FunctionMaybe, Infer, Schema, Tests, Traverser} from '../types'; /* MAIN */ //TODO: Support variadic tuples (.rest method) class Tuple extends Compound> { /* PUBLIC API */ filter ( value: unknown, defaultable: false, quiet: true ): boolean; filter ( value: unknown, defaultable?: boolean, quiet?: false ): T; filter ( value: unknown, defaultable?: boolean, quiet?: boolean ): T | boolean; filter ( value: unknown, defaultable: boolean = true, quiet: boolean = false ): T | boolean { if ( !isArray ( value ) ) return this._filterDefault ( defaultable, quiet ); if ( !super._test ( value, FILTERS ) ) return this._filterDefault ( defaultable, quiet ); return value; } test ( value: unknown ): value is T { return isArray ( value ) && super._test ( value, TESTS ); } traverse ( traverser: Traverser, parent?: Schema, key?: string | number ): void { traverser ( this, parent, key ); resolve ( this.state.items )?.forEach ( ( item, index ) => { item.traverse ( traverser, this, index ); }); } /* GENERIC TESTS API */ anyOf ( values: T[] ): Tuple { return this.with ({ anyOf: values }); } noneOf ( values: T[] ): Tuple { return this.with ({ noneOf: values }); } nillable (): Nillable { return new Nillable ({ nillable: this }); } nullable (): Nullable { return new Nullable ({ nullable: this }); } optional (): Optional { return new Optional ({ optional: this }); } /* SPECIFIC TESTS API */ items ( items: FunctionMaybe<[S0]> ): Tuple<[Infer]>; items ( items: FunctionMaybe<[S0, S1]> ): Tuple<[Infer, Infer]>; items ( items: FunctionMaybe<[S0, S1, S2]> ): Tuple<[Infer, Infer, Infer]>; items ( items: FunctionMaybe<[S0, S1, S2, S3]> ): Tuple<[Infer, Infer, Infer, Infer]>; items ( items: FunctionMaybe<[S0, S1, S2, S3, S4]> ): Tuple<[Infer, Infer, Infer, Infer, Infer]>; items ( items: FunctionMaybe<[S0, S1, S2, S3, S4, S5]> ): Tuple<[Infer, Infer, Infer, Infer, Infer, Infer]>; items ( items: FunctionMaybe<[S0, S1, S2, S3, S4, S5, S6]> ): Tuple<[Infer, Infer, Infer, Infer, Infer, Infer, Infer]>; items ( items: FunctionMaybe<[S0, S1, S2, S3, S4, S5, S6, S7]> ): Tuple<[Infer, Infer, Infer, Infer, Infer, Infer, Infer, Infer]>; items ( items: FunctionMaybe<[S0, S1, S2, S3, S4, S5, S6, S7, S8]> ): Tuple<[Infer, Infer, Infer, Infer, Infer, Infer, Infer, Infer, Infer]>; items ( items: FunctionMaybe<[S0, S1, S2, S3, S4, S5, S6, S7, S8, S9]> ): Tuple<[Infer, Infer, Infer, Infer, Infer, Infer, Infer, Infer, Infer, Infer]>; items ( items: FunctionMaybe ): Tuple; items ( items: FunctionMaybe ): Tuple { return this.with ({ items }); } length ( value: FunctionMaybe ): Tuple { return this.with ({ length: value }); } } /* UTILITIES */ const TESTS: Tests> = { anyOf, noneOf, items: ( value, schemas ) => { const items = resolve ( schemas ); const maxLength = items.length; if ( value.length > maxLength ) return false; const minLength = findLastIndex ( items, schema => !isOptional ( schema ) ) + 1; if ( value.length < minLength ) return false; for ( let i = 0, l = items.length; i < l; i++ ) { const schema = items[i]; const item = value[i]; if ( !schema.test ( item ) ) return false; } return true; }, length: ( value, length ) => { return value.length === resolve ( length ); } }; const FILTERS: Tests> = { anyOf, noneOf, items: ( value, schemas ) => { const items = resolve ( schemas ); const maxLength = items.length; if ( value.length > maxLength ) return false; const minLength = findLastIndex ( items, schema => !isOptional ( schema ) ) + 1; if ( value.length < minLength ) return false; for ( let i = 0, l = items.length; i < l; i++ ) { const schema = items[i]; const item = value[i]; const filtered = schema.filter ( item, false, true ); if ( !filtered ) return false; } return true; }, length: TESTS.length }; /* INIT */ Registry.register ( 'tuple', Tuple ); /* EXPORT */ export default Tuple;