|  | 
| 1 | 1 | import { AsyncLocalStorage } from "node:async_hooks"; | 
| 2 | 2 | import * as crypto from "node:crypto"; | 
| 3 |  | -import type { Optional } from "utility-types"; | 
| 4 | 3 | 
 | 
| 5 | 4 | const asyncLocalStorage = new AsyncLocalStorage(); | 
| 6 | 5 | 
 | 
| 7 | 6 | let globalStore = {}; | 
| 8 | 7 | 
 | 
| 9 |  | -interface CreateHookOptions< | 
| 10 |  | -  State extends Record<string, any>, | 
| 11 |  | -  ExecuteResult, | 
| 12 |  | -  HookOptions | 
| 13 |  | -> { | 
|  | 8 | +interface CreateHookOptions<State, ExecuteResult, HookOptions> { | 
| 14 | 9 |   name: string; | 
| 15 | 10 |   data: () => State; | 
| 16 | 11 |   execute: (state: State, options: HookOptions) => ExecuteResult; | 
| @@ -46,30 +41,84 @@ const generateUpdateHookStateFunction = <State, ExecuteResult, HookOptions>( | 
| 46 | 41 |   }; | 
| 47 | 42 | }; | 
| 48 | 43 | 
 | 
| 49 |  | -export const createHook = <State, ExecuteResult, HookOptions>( | 
| 50 |  | -  options: Optional< | 
| 51 |  | -    Omit<CreateHookOptions<State, ExecuteResult, HookOptions>, "name">, | 
| 52 |  | -    "data" | 
| 53 |  | -  > | 
|  | 44 | +type StateAndExecuteOptions<State, ExecuteResult, HookOptions> = Omit< | 
|  | 45 | +  CreateHookOptions<State, ExecuteResult, HookOptions>, | 
|  | 46 | +  "name" | 
|  | 47 | +>; | 
|  | 48 | + | 
|  | 49 | +type StateOnlyOptions<State, HookOptions> = Omit< | 
|  | 50 | +  StateAndExecuteOptions<State, undefined, HookOptions>, | 
|  | 51 | +  "execute" | 
|  | 52 | +>; | 
|  | 53 | + | 
|  | 54 | +type ExecuteOnlyOptions<ExecuteResult, HookOptions> = Omit< | 
|  | 55 | +  StateAndExecuteOptions<undefined, ExecuteResult, HookOptions>, | 
|  | 56 | +  "data" | 
|  | 57 | +>; | 
|  | 58 | + | 
|  | 59 | +export function createHook<State, ExecuteResult, HookOptions>( | 
|  | 60 | +  options: StateAndExecuteOptions<State, ExecuteResult, HookOptions> | 
| 54 | 61 | ): [ | 
| 55 | 62 |   (parameters?: HookOptions) => ExecuteResult, | 
| 56 | 63 |   (fn: (currentState: State) => State) => void | 
| 57 |  | -] => { | 
|  | 64 | +]; | 
|  | 65 | +export function createHook<State, HookOptions>( | 
|  | 66 | +  options: StateOnlyOptions<State, HookOptions> | 
|  | 67 | +): [() => State, (fn: (currentState: State) => State) => void]; | 
|  | 68 | +export function createHook<ExecuteResult, HookOptions>( | 
|  | 69 | +  options: ExecuteOnlyOptions<ExecuteResult, HookOptions> | 
|  | 70 | +): [(parameters?: HookOptions) => ExecuteResult, (fn: () => void) => void]; | 
|  | 71 | +export function createHook<State, ExecuteResult, HookOptions>( | 
|  | 72 | +  options: | 
|  | 73 | +    | StateOnlyOptions<State, HookOptions> | 
|  | 74 | +    | ExecuteOnlyOptions<ExecuteResult, HookOptions> | 
|  | 75 | +    | StateAndExecuteOptions<State, ExecuteResult, HookOptions> | 
|  | 76 | +) { | 
| 58 | 77 |   const name = crypto.randomUUID(); | 
| 59 |  | -  const data = options.data || (() => ({} as State)); | 
|  | 78 | +  if ("data" in options && !("execute" in options)) { | 
|  | 79 | +    const execute = (state: State) => state; | 
|  | 80 | +    return [ | 
|  | 81 | +      generateHookFunction({ | 
|  | 82 | +        name, | 
|  | 83 | +        data: options.data, | 
|  | 84 | +        execute, | 
|  | 85 | +      }), | 
|  | 86 | +      generateUpdateHookStateFunction({ | 
|  | 87 | +        name, | 
|  | 88 | +        data: options.data, | 
|  | 89 | +        execute, | 
|  | 90 | +      }), | 
|  | 91 | +    ]; | 
|  | 92 | +  } | 
|  | 93 | +  if ("data" in options) { | 
|  | 94 | +    return [ | 
|  | 95 | +      generateHookFunction({ | 
|  | 96 | +        name, | 
|  | 97 | +        data: options.data, | 
|  | 98 | +        execute: options.execute, | 
|  | 99 | +      }), | 
|  | 100 | +      generateUpdateHookStateFunction({ | 
|  | 101 | +        name, | 
|  | 102 | +        data: options.data, | 
|  | 103 | +        execute: options.execute, | 
|  | 104 | +      }), | 
|  | 105 | +    ]; | 
|  | 106 | +  } | 
|  | 107 | + | 
|  | 108 | +  const data = () => undefined; | 
| 60 | 109 |   return [ | 
| 61 | 110 |     generateHookFunction({ | 
| 62 |  | -      ...options, | 
| 63 | 111 |       name, | 
| 64 | 112 |       data, | 
|  | 113 | +      execute: options.execute, | 
| 65 | 114 |     }), | 
| 66 | 115 |     generateUpdateHookStateFunction({ | 
| 67 |  | -      ...options, | 
| 68 | 116 |       name, | 
| 69 | 117 |       data, | 
|  | 118 | +      execute: options.execute, | 
| 70 | 119 |     }), | 
| 71 | 120 |   ]; | 
| 72 |  | -}; | 
|  | 121 | +} | 
| 73 | 122 | 
 | 
| 74 | 123 | export const runHookContext = async <T>( | 
| 75 | 124 |   fn: () => Promise<T> | T | 
|  | 
0 commit comments