|
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