import { type FunctionProxyState, type InsteadHookNode, type PatchedFunctionProxyState, createPatchedFunctionProxy, patchedFunctionProxyHandler, patchedFunctionProxyStates, unproxy, } from '../_internal' const insteadHookProxyHandler = { ...patchedFunctionProxyHandler, apply(hookNode: InsteadHookNode, receiver: ThisParameterType, args: Parameters) { const { next } = hookNode return Reflect.apply(hookNode.hook, receiver, [args, next === undefined ? hookNode.target : next.proxy]) }, construct>( hookNode: InsteadHookNode, args: ConstructorParameters, ctor: AbstractNewable, ) { const { next } = hookNode return Reflect.construct(hookNode.hook, [args, next === undefined ? hookNode.target : next.proxy], ctor) }, } as const satisfies Required> function unpatchInstead( state: PatchedFunctionProxyState, hookNode: InsteadHookNode, ) { if (hookNode.unpatched) return hookNode.unpatched = true const { prev, next } = hookNode if (prev === undefined) { state.instead = next if (next === undefined) { if (state.before === undefined && state.after === undefined) unproxy(state) return } } else { prev.next = next hookNode.prev = undefined if (next === undefined) return } next.prev = prev hookNode.next = undefined } export function instead, Key extends PropertyKey>( parent: Parent, key: FiniteDomain, hook: InsteadHook, ): () => void export function instead( parent: Record, key: FiniteDomain, hook: InsteadHook, ) { const target = parent[key] let state = patchedFunctionProxyStates.get(target) // biome-ignore lint/complexity/useArrowFunction: We need a function that has a constructor const hookNode = function () {} // The handler makes the proxy behave as target. hookNode.proxy = new Proxy(hookNode, insteadHookProxyHandler) as Value hookNode.target = target hookNode.unpatched = false hookNode.hook = hook hookNode.prev = undefined if (state !== undefined && state.parent === parent && state.key === key) { const head = state.instead hookNode.next = head if (head !== undefined) head.prev = hookNode state.instead = hookNode } else { hookNode.next = undefined state = createPatchedFunctionProxy(target, parent, key, undefined, hookNode, undefined) } return unpatchInstead.bind(undefined, state, hookNode) }