import { clearExpiration } from './maxAge' ; import { clearStats , getStats } from './stats' ; import { Fn , Key , Memoized , Moizeable , MoizeConfiguration , Moized , Options , StatsProfile , } from './types' ; import { createFindKeyIndex } from './utils' ; const ALWAYS_SKIPPED_PROPERTIES = { arguments : true , callee : true , caller : true , constructor : true , length : true , name : true , prototype : true , } ; private description param originalFn param newFn param skippedProperties export function copyStaticProperties ( originalFn , newFn , skippedProperties = [ ] ) { Object . getOwnPropertyNames ( originalFn ) . forEach ( ( property ) => { if ( ! ALWAYS_SKIPPED_PROPERTIES [ property ] && skippedProperties . indexOf ( property ) === - 1 ) { const descriptor = Object . getOwnPropertyDescriptor ( originalFn , property ) ; if ( descriptor . get || descriptor . set ) { Object . defineProperty ( newFn , property , descriptor ) ; } else { newFn [ property as keyof typeof newFn ] = originalFn [ property as keyof typeof originalFn ] ; } } } ) ; } private description param memoized export function addInstanceMethods < OriginalFn extends Fn > ( memoized , { expirations } ) { const { options } = memoized ; const findKeyIndex = createFindKeyIndex ( options . isEqual , options . isMatchingKey ) ; const moized = memoized as unknown as Moized < OriginalFn , Options > ; moized . clear = function ( ) { const { _microMemoizeOptions : { onCacheChange } , cache , } = moized ; cache . keys . length = 0 ; cache . values . length = 0 ; if ( onCacheChange ) { onCacheChange ( cache , moized . options , moized ) ; } return true ; } ; moized . clearStats = function ( ) { clearStats ( moized . options . profileName ) ; } ; moized . get = function ( key ) { const { _microMemoizeOptions : { transformKey } , cache , } = moized ; const cacheKey = transformKey ? transformKey ( key ) : key ; const keyIndex = findKeyIndex ( cache . keys , cacheKey ) ; return keyIndex !== - 1 ? moized . apply ( this , key ) : undefined ; } ; moized . getStats = function ( ) : StatsProfile { return getStats ( moized . options . profileName ) ; } ; moized . has = function ( key ) { const { transformKey } = moized . _microMemoizeOptions ; const cacheKey = transformKey ? transformKey ( key ) : key ; return findKeyIndex ( moized . cache . keys , cacheKey ) !== - 1 ; } ; moized . keys = function ( ) { return moized . cacheSnapshot . keys ; } ; moized . remove = function ( key ) { const { _microMemoizeOptions : { onCacheChange , transformKey } , cache , } = moized ; const keyIndex = findKeyIndex ( cache . keys , transformKey ? transformKey ( key ) : key ) ; if ( keyIndex === - 1 ) { return false ; } const existingKey = cache . keys [ keyIndex ] ; cache . keys . splice ( keyIndex , 1 ) ; cache . values . splice ( keyIndex , 1 ) ; if ( onCacheChange ) { onCacheChange ( cache , moized . options , moized ) ; } clearExpiration ( expirations , existingKey , true ) ; return true ; } ; moized . set = function ( key , value ) { const { _microMemoizeOptions , cache , options } = moized ; const { onCacheAdd , onCacheChange , transformKey } = _microMemoizeOptions ; const cacheKey = transformKey ? transformKey ( key ) : key ; const keyIndex = findKeyIndex ( cache . keys , cacheKey ) ; if ( keyIndex === - 1 ) { const cutoff = options . maxSize - 1 ; if ( cache . size > cutoff ) { cache . keys . length = cutoff ; cache . values . length = cutoff ; } cache . keys . unshift ( cacheKey ) ; cache . values . unshift ( value ) ; if ( options . isPromise ) { cache . updateAsyncCache ( moized ) ; } if ( onCacheAdd ) { onCacheAdd ( cache , options , moized ) ; } if ( onCacheChange ) { onCacheChange ( cache , options , moized ) ; } } else { const existingKey = cache . keys [ keyIndex ] ; cache . values [ keyIndex ] = value ; if ( keyIndex > 0 ) { cache . orderByLru ( existingKey , value , keyIndex ) ; } if ( options . isPromise ) { cache . updateAsyncCache ( moized ) ; } if ( typeof onCacheChange === 'function' ) { onCacheChange ( cache , options , moized ) ; } } } ; moized . values = function ( ) { return moized . cacheSnapshot . values ; } ; } private description param memoized param expirations param options param originalFunction export function addInstanceProperties < OriginalFn extends Moizeable > ( memoized , { expirations , options : moizeOptions , originalFunction , } ) { const { options : microMemoizeOptions } = memoized ; Object . defineProperties ( memoized , { _microMemoizeOptions : { configurable : true , get ( ) { return microMemoizeOptions ; } , } , cacheSnapshot : { configurable : true , get ( ) { const { cache : currentCache } = memoized ; return { keys : currentCache . keys . slice ( 0 ) , size : currentCache . size , values : currentCache . values . slice ( 0 ) , } ; } , } , expirations : { configurable : true , get ( ) { return expirations ; } , } , expirationsSnapshot : { configurable : true , get ( ) { return expirations . slice ( 0 ) ; } , } , isMoized : { configurable : true , get ( ) { return true ; } , } , options : { configurable : true , get ( ) { return moizeOptions ; } , } , originalFunction : { configurable : true , get ( ) { return originalFunction ; } , } , } ) ; const moized = memoized as unknown as Moized < OriginalFn , Options > ; copyStaticProperties ( originalFunction , moized ) ; } private description param memoized param configuration returns export function createMoizeInstance < OriginalFn extends Moizeable , CombinedOptions extends Options > ( memoized , configuration ) { addInstanceMethods < OriginalFn > ( memoized , configuration ) ; addInstanceProperties < OriginalFn > ( memoized , configuration ) ; return memoized as Moized < OriginalFn , CombinedOptions > ; }