/* 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 {isPlainObject, resolve} from '../utils'; import type {RecordState, FunctionMaybe, Schema, Tests, Traverser} from '../types'; /* MAIN */ class Rec extends Compound, Record, RecordState, Record, V>> { /* PUBLIC API */ filter ( value: unknown, defaultable: false, quiet: true ): boolean; filter ( value: unknown, defaultable?: boolean, quiet?: false ): Record; filter ( value: unknown, defaultable?: boolean, quiet?: boolean ): Record | boolean; filter ( value: unknown, defaultable: boolean = true, quiet: boolean = false ): Record | boolean { if ( !isPlainObject ( value ) ) return this._filterDefault ( defaultable, quiet ); if ( !super._test ( value, FILTERS ) ) return this._filterDefault ( defaultable, quiet ); return value; } test ( value: unknown ): value is Record { return isPlainObject ( value ) && super._test ( value, TESTS ); } traverse ( traverser: Traverser, parent?: Schema, key?: string | number ): void { traverser ( this, parent, key ); resolve ( this.state.keys )?.traverse ( traverser, this ); resolve ( this.state.values )?.traverse ( traverser, this ); } /* GENERAL TESTS API */ anyOf ( values: Record[] ): Rec { return this.with ({ anyOf: values }); } noneOf ( values: Record[] ): Rec { 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 */ keys ( keys: FunctionMaybe> ): Rec { return this.with ({ keys }); } values ( values: FunctionMaybe> ): Rec { return this.with ({ values }); } } /* UTILITIES */ const TESTS: Tests, RecordState, Record, unknown>> = { anyOf, noneOf, keys ( value, schema ) { const keys = resolve ( schema ); for ( const key in value ) { if ( !keys.test ( key ) ) return false; } return true; }, values ( value, schema ) { const values = resolve ( schema ); for ( const key in value ) { const item = value[key]; if ( !values.test ( item ) ) return false; } return true; } }; const FILTERS: Tests, RecordState, Record, unknown>> = { anyOf, noneOf, keys ( value, schema ) { const keys = resolve ( schema ); for ( const key in value ) { const filtered = keys.filter ( key, false, true ); if ( !filtered ) { delete value[key]; } } return true; }, values ( value, schema ) { const values = resolve ( schema ); for ( const key in value ) { const item = value[key]; const filtered = values.filter ( item, false, true ); if ( !filtered ) { delete value[key]; } } return true; } }; /* INIT */ Registry.register ( 'record', Rec ); /* EXPORT */ export default Rec;