import { composeObject , entries } from "alcalzone-shared/objects" ; export class ObjectKeyMap < TKey extends Record < string | number , any > , TValue > { public constructor ( entries ? , defaultKeyProps ? ) { if ( entries ?. length ) { for ( const [ key , value ] of entries ) { this . set ( key , value ) ; } } this . defaultKeyProps = defaultKeyProps ; } private _map = new Map < string , TValue > ( ) ; private defaultKeyProps : Partial < TKey > | undefined ; public has ( key ) { return this . _map . has ( this . keyToString ( key ) ) ; } public get ( key ) { return this . _map . get ( this . keyToString ( key ) ) ; } public set ( key , value ) { this . _map . set ( this . keyToString ( key ) , value ) ; } public delete ( key ) { return this . _map . delete ( this . keyToString ( key ) ) ; } public clear ( ) { this . _map . clear ( ) ; } public get size ( ) : number { return this . _map . size ; } public forEach ( callbackfn ) { this . _map . forEach ( ( value , keyAsString ) => { callbackfn ( value , JSON . parse ( keyAsString ) , this ) ; } ) ; } public entries ( ) { const map = this . _map ; return ( function * ( ) { const _entries = map . entries ( ) ; let entry = _entries . next ( ) ; while ( ! entry . done ) { const objKey = JSON . parse ( entry . value [ 0 ] ) ; yield [ objKey , entry . value [ 1 ] ] as [ TKey , TValue ] ; entry = _entries . next ( ) ; } } ) ( ) ; } public [ Symbol . iterator ] ( ) { return this . entries ( ) ; } public keys ( ) { const map = this . _map ; return ( function * ( ) { const _keys = map . entries ( ) ; let key = _keys . next ( ) ; while ( ! key . done ) { const objKey = JSON . parse ( key . value [ 0 ] ) as TKey ; yield objKey ; key = _keys . next ( ) ; } } ) ( ) ; } public values ( ) { return this . _map . values ( ) ; } private keyToString ( key ) { const filledKey = { ... key } ; if ( this . defaultKeyProps ) { for ( const [ required , def ] of entries ( this . defaultKeyProps ) ) { if ( ! ( required in filledKey ) ) filledKey [ required as any ] = def ; } } const _key = composeObject ( entries ( filledKey ) . filter ( ( [ , value ] ) => value != undefined ) . sort ( ( [ keyA ] , [ keyB ] ) => keyA > keyB ? 1 : keyA < keyB ? - 1 : 0 ) ) ; return JSON . stringify ( _key ) ; } } type PickSymbolIterator < T > = T extends { [ Symbol . iterator ] : infer V ; } ? T & { [ Symbol . iterator ] : V ; } : T ; export type ReadonlyObjectKeyMap < TKey extends Record < string | number , any > , TValue > = Pick < ObjectKeyMap < TKey , TValue > , "has" | "get" | "entries" | "keys" | "values" | "size" > & PickSymbolIterator < ObjectKeyMap < TKey , TValue > > ;