import { getValue } from '@glimmer/tracking/primitives/cache' ; import { assert } from '@ember/debug' ; import { invokeHelper } from '@ember/helper' ; import { FUNCTION_TO_RUN , SECRET_VALUE , TrackedFunctionRunner } from './resources/function-runner' ; import { proxyClass } from './utils' ; import type { ResourceFn } from './resources/function-runner' ; import type { Cache , Constructable } from './types' ; type Vanilla < Return > = [ object , ResourceFn < Return > ] ; type WithInitialValue < Return > = [ object , NotFunction < Return > , ResourceFn < Return > ] ; type NotFunction < T > = T extends Function ? never : T ; type UseFunctionArgs < Return > = Vanilla < Return > | WithInitialValue < Return > ; param { Object } destroyable param { Function } theFunction export function trackedFunction < Return > ( ... passed ) ; param { Object } destroyable param { Object } initialValue param { Function } theFunction export function trackedFunction < Return > ( ... passed ) ; export function trackedFunction < Return > ( ... passedArgs ) { let [ context ] = passedArgs ; let initialValue ; let fn ; assert ( `Expected second argument to useFunction to either be an initialValue or the function to run` , passedArgs [ 1 ] !== undefined ) ; if ( hasNoInitialValue ( passedArgs ) ) { fn = passedArgs [ 1 ] ; } else { initialValue = passedArgs [ 1 ] ; fn = passedArgs [ 2 ] ; } let target = buildUnproxiedFunctionResource < Return > ( context , initialValue , fn ) ; return proxyClass < any > ( target ) as { value : Return ; } ; } function hasNoInitialValue < R > ( args ) { return args . length === 2 ; } type Fn = ( ... args : any [ ] ) => any ; const FUNCTION_CACHE = new WeakMap < Fn , Constructable < any > > ( ) ; /**
 * The function is wrapped in a bespoke resource per-function definition
 * because passing a vanilla function to invokeHelper would trigger a
 * different HelperManager, which we want to work a bit differently.
 * See:
 *  - function HelperManager in ember-could-get-used-to-this
 *  - Default Managers RFC
 *
 */ function buildUnproxiedFunctionResource < Return > ( context , initial , fn ) { type Klass = Constructable < TrackedFunctionRunner < Return > > ; let resource ; let klass ; let existing = FUNCTION_CACHE . get ( fn ) ; if ( existing ) { klass = existing ; } else { klass = class AnonymousFunctionRunner extends TrackedFunctionRunner < Return > { [ SECRET_VALUE ] = initial ; [ FUNCTION_TO_RUN ] = fn ; } as Klass ; FUNCTION_CACHE . set ( fn , klass ) ; } return { get value ( ) : Return { if ( ! resource ) { resource = invokeHelper ( context , klass , ( ) => { } ) as Cache < Return > ; } return getValue < Return > ( resource ) ; } , } ; }