import { getValue } from '@glimmer/tracking/primitives/cache' ; import { assert } from '@ember/debug' ; import { invokeHelper } from '@ember/helper' ; import { FUNCTION_TO_RUN , FunctionRunner , INITIAL_VALUE } from './resources/function-runner' ; import { DEFAULT_THUNK , normalizeThunk , proxyClass } from './utils' ; import type { ResourceFn } from './resources/function-runner' ; import type { Cache , Constructable } from './types' ; type NonReactiveVanilla < Return , Args extends unknown [ ] > = [ object , ResourceFn < Return , Args > ] ; type VanillaArgs < Return , Args extends unknown [ ] > = [ object , ResourceFn < Return , Args > , ( ) => Args ] ; type NonReactiveWithInitialValue < Return , Args extends unknown [ ] > = [ object , NotFunction < Return > , ResourceFn < Return , Args > ] ; type WithInitialValueArgs < Return , Args extends unknown [ ] > = [ object , NotFunction < Return > , ResourceFn < Return , Args > , ( ) => Args ] ; type NotFunction < T > = T extends Function ? never : T ; type UseFunctionArgs < Return , Args extends unknown [ ] > = NonReactiveVanilla < Return , Args > | NonReactiveWithInitialValue < Return , Args > | VanillaArgs < Return , Args > | WithInitialValueArgs < Return , Args > ; param { Object } destroyable param { Function } theFunction export function useFunction < Return , Args extends unknown [ ] = unknown [ ] > ( ... passed ) ; param { Object } destroyable param { Function } theFunction param { Function } thunk export function useFunction < Return , Args extends unknown [ ] = unknown [ ] > ( ... passed ) ; param { Object } destroyable param { Object } initialValue param { Function } theFunction param { Function } thunk export function useFunction < Return , Args extends unknown [ ] = unknown [ ] > ( ... passed ) ; param { Object } destroyable param { Object } initialValue param { Function } theFunction export function useFunction < Return , Args extends unknown [ ] = unknown [ ] > ( ... passed ) ; export function useFunction < Return , Args extends unknown [ ] = unknown [ ] > ( ... passedArgs ) { let [ context ] = passedArgs ; let initialValue ; let fn ; let thunk ; assert ( `Expected second argument to useFunction to either be an initialValue or the function to run` , passedArgs [ 1 ] !== undefined ) ; if ( isVanillaArgs ( passedArgs ) ) { fn = passedArgs [ 1 ] ; thunk = passedArgs [ 2 ] ; } else { initialValue = passedArgs [ 1 ] ; fn = passedArgs [ 2 ] ; thunk = passedArgs [ 3 ] ; } let target = buildUnproxiedFunctionResource < Return , Args > ( context , initialValue , fn , ( thunk || DEFAULT_THUNK ) as ( ) => Args ) ; return proxyClass < any > ( target ) as { value : Return ; } ; } function isVanillaArgs < R , A extends unknown [ ] > ( args ) { return typeof args [ 1 ] === 'function' ; } 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 , ArgsList extends unknown [ ] > ( context , initial , fn , thunk ) { type Klass = Constructable < FunctionRunner < Return , ArgsList > > ; let resource ; let klass ; let existing = FUNCTION_CACHE . get ( fn ) ; if ( existing ) { klass = existing ; } else { klass = class AnonymousFunctionRunner extends FunctionRunner < Return , ArgsList > { [ INITIAL_VALUE ] = initial ; [ FUNCTION_TO_RUN ] = fn ; } as Klass ; FUNCTION_CACHE . set ( fn , klass ) ; } return { get value ( ) : Return { if ( ! resource ) { resource = invokeHelper ( context , klass , ( ) => { return normalizeThunk ( thunk ) ; } ) as Cache < Return > ; } return getValue < Return > ( resource ) ; } , } ; }