import { defaultArgsHashFn , memoizeFn } from '../misc/memoize' ; import { isPrototype , getPropertyDescriptor } from '../misc/object' ; import type { MemoHashFn } from '../misc/memoize' ; import type { MethodTypedDecorator } from '../misc/functions' ; export function memoize ( ) ; export function memoize < H extends MemoHashFn > ( hashFn ) ; see memoizeFn export function memoize ( hashFn = defaultArgsHashFn ) { return function ( target , prop , descriptor ) : void { if ( ! descriptor || typeof ( descriptor . value || descriptor . get ) !== 'function' ) { throw new TypeError ( 'Only get accessors or class methods can be decorated via @memoize' ) ; } if ( isPrototype ( target ) ) { ( typeof descriptor . get === 'function' ) && ( descriptor . get = memoizeGetter ( descriptor . get , prop ) ) ; ( typeof descriptor . value === 'function' ) && ( descriptor . value = memoizeMethod ( descriptor . value , prop , hashFn ) ) ; } else { ( typeof descriptor . get === 'function' ) && ( descriptor . get = memoizeFn ( descriptor . get ) ) ; ( typeof descriptor . value === 'function' ) && ( descriptor . value = memoizeFn ( descriptor . value , hashFn ) ) ; } } ; } const locks = new WeakMap ( ) ; const defineOwnKeySafe = ( obj , prop , value ) : void => { locks . set ( obj , prop ) ; Object . defineProperty ( obj , prop , { value , writable : true , configurable : true } ) ; locks . delete ( obj ) ; } ; /** Cache getter result as an object own property */ function memoizeGetter ( originalMethod , prop ) { return function ( ) : any { if ( locks . get ( this ) === prop ) return originalMethod ; const value = originalMethod . call ( this ) ; defineOwnKeySafe ( this , prop , value ) ; return value ; } ; } /** Cache method memo function in the current context on call */ function memoizeMethod ( originalMethod , prop , hashFn ) { return function ( this , ... args ) : any { if ( locks . get ( this ) === prop ) return originalMethod ; const memo = memoizeFn ( originalMethod , hashFn ) ; defineOwnKeySafe ( this , prop , memo ) ; return memo . apply ( this , args ) ; } ; } /**
 * Clear memoization cache for passed target and property.
 * Accepts not own properties.
 * Note: be sure that you targeting memoized property or function.
 * Clear utility has no 100% check to prevent modifying incorrect (not memoized) property keys
 */ memoize . clear = function ( target , property ) : void { const desc = getPropertyDescriptor ( target , property ) ; if ( ! desc ) return ; if ( typeof desc . get === 'function' && typeof ( desc . get as any ) . clear === 'function' ) return ( desc . get as any ) . clear ( ) ; if ( typeof desc . value === 'function' && typeof desc . value . clear === 'function' ) return desc . value . clear ( ) ; if ( Object . hasOwnProperty . call ( target , property ) ) delete target [ property ] ; } ; /** Check if property has cache for the passed params */ memoize . has = function ( target , property , ... params ) : boolean { const desc = getPropertyDescriptor ( target , property ) ; if ( ! desc ) return false ; if ( typeof desc . get === 'function' && typeof ( desc . get as any ) . has === 'function' ) return ( desc . get as any ) . has ( ... params ) ; if ( typeof desc . value === 'function' && typeof desc . value . has === 'function' ) return desc . value . has ( ... params ) ; return Object . hasOwnProperty . call ( target , property ) ; } ;