hookable 5.5.2 → 6.0.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,16 +10,8 @@ Awaitable hooks system.
10
10
 
11
11
  ## Install
12
12
 
13
- Using yarn:
14
-
15
- ```bash
16
- yarn add hookable
17
- ```
18
-
19
- Using npm:
20
-
21
13
  ```bash
22
- npm install hookable
14
+ npx nypm i hookable
23
15
  ```
24
16
 
25
17
  ## Usage
@@ -27,34 +19,39 @@ npm install hookable
27
19
  **Method A: Create a hookable instance:**
28
20
 
29
21
  ```js
30
- import { createHooks } from 'hookable'
22
+ import { Hookable } from "hookable";
31
23
 
32
24
  // Create a hookable instance
33
- const hooks = createHooks()
25
+ const hooks = new Hookable();
34
26
 
35
27
  // Hook on 'hello'
36
- hooks.hook('hello', () => { console.log('Hello World' )})
28
+ hooks.hook("hello", () => {
29
+ console.log("Hello World");
30
+ });
37
31
 
38
32
  // Call 'hello' hook
39
- hooks.callHook('hello')
33
+ hooks.callHook("hello");
40
34
  ```
41
35
 
36
+ > [!TIP]
37
+ > You can use `HookableCore` alternatively for less bundle and runtime footprint if simple `hook`/`callHook` functionality is only needed.
38
+
42
39
  **Method B: Extend your base class from Hookable:**
43
40
 
44
41
  ```js
45
- import { Hookable } from 'hookable'
42
+ import { Hookable } from "hookable";
46
43
 
47
44
  export default class FooLib extends Hookable {
48
45
  constructor() {
49
46
  // Call to parent to initialize
50
- super()
47
+ super();
51
48
  // Initialize Hookable with custom logger
52
49
  // super(consola)
53
50
  }
54
51
 
55
52
  async someFunction() {
56
53
  // Call and wait for `hook1` hooks (if any) sequential
57
- await this.callHook('hook1')
54
+ await this.callHook("hook1");
58
55
  }
59
56
  }
60
57
  ```
@@ -62,56 +59,67 @@ export default class FooLib extends Hookable {
62
59
  **Inside plugins, register for any hook:**
63
60
 
64
61
  ```js
65
- const lib = new FooLib()
62
+ const lib = new FooLib();
66
63
 
67
64
  // Register a handler for `hook2`
68
- lib.hook('hook2', async () => { /* ... */ })
65
+ lib.hook("hook2", async () => {
66
+ /* ... */
67
+ });
69
68
 
70
69
  // Register multiply handlers at once
71
70
  lib.addHooks({
72
- hook1: async () => { /* ... */ },
73
- hook2: [ /* can be also an array */ ]
74
- })
71
+ hook1: async () => {
72
+ /* ... */
73
+ },
74
+ hook2: [
75
+ /* can be also an array */
76
+ ],
77
+ });
75
78
  ```
76
79
 
77
80
  **Unregistering hooks:**
78
81
 
79
82
  ```js
80
- const lib = new FooLib()
83
+ const lib = new FooLib();
81
84
 
82
- const hook0 = async () => { /* ... */ }
83
- const hook1 = async () => { /* ... */ }
84
- const hook2 = async () => { /* ... */ }
85
+ const hook0 = async () => {
86
+ /* ... */
87
+ };
88
+ const hook1 = async () => {
89
+ /* ... */
90
+ };
91
+ const hook2 = async () => {
92
+ /* ... */
93
+ };
85
94
 
86
95
  // The hook() method returns an "unregister" function
87
- const unregisterHook0 = lib.hook('hook0', hook0)
88
- const unregisterHooks1and2 = lib.addHooks({ hook1, hook2 })
96
+ const unregisterHook0 = lib.hook("hook0", hook0);
97
+ const unregisterHooks1and2 = lib.addHooks({ hook1, hook2 });
89
98
 
90
99
  /* ... */
91
100
 
92
- unregisterHook0()
93
- unregisterHooks1and2()
101
+ unregisterHook0();
102
+ unregisterHooks1and2();
94
103
 
95
104
  // or
96
105
 
97
- lib.removeHooks({ hook0, hook1 })
98
- lib.removeHook('hook2', hook2)
106
+ lib.removeHooks({ hook0, hook1 });
107
+ lib.removeHook("hook2", hook2);
99
108
  ```
100
109
 
101
110
  **Triggering a hook handler once:**
102
111
 
103
112
  ```js
104
- const lib = new FooLib()
113
+ const lib = new FooLib();
105
114
 
106
- const unregister = lib.hook('hook0', async () => {
115
+ const unregister = lib.hook("hook0", async () => {
107
116
  // Unregister as soon as the hook is executed
108
- unregister()
117
+ unregister();
109
118
 
110
119
  /* ... */
111
- })
120
+ });
112
121
  ```
113
122
 
114
-
115
123
  ## Hookable class
116
124
 
117
125
  ### `constructor()`
@@ -138,10 +146,9 @@ Example:
138
146
  hookable.addHooks({
139
147
  test: {
140
148
  before: () => {},
141
- after: () => {}
142
- }
143
- })
144
-
149
+ after: () => {},
150
+ },
151
+ });
145
152
  ```
146
153
 
147
154
  This registers `test:before` and `test:after` hooks at bulk.
@@ -157,6 +164,7 @@ Used by class itself to **sequentially** call handlers of a specific hook.
157
164
  If you need custom control over how hooks are called, you can provide a custom function that will receive an array of handlers of a specific hook.
158
165
 
159
166
  `callerFn` if a callback function that accepts two arguments, `hooks` and `args`:
167
+
160
168
  - `hooks`: Array of user hooks to be called
161
169
  - `args`: Array of arguments that should be passed each time calling a hook
162
170
 
@@ -179,19 +187,21 @@ Remove multiple hook handlers.
179
187
  Example:
180
188
 
181
189
  ```js
182
- const handler = async () => { /* ... */ }
190
+ const handler = async () => {
191
+ /* ... */
192
+ };
183
193
 
184
- hookable.hook('test:before', handler)
185
- hookable.addHooks({ test: { after: handler } })
194
+ hookable.hook("test:before", handler);
195
+ hookable.addHooks({ test: { after: handler } });
186
196
 
187
197
  // ...
188
198
 
189
199
  hookable.removeHooks({
190
200
  test: {
191
201
  before: handler,
192
- after: handler
193
- }
194
- })
202
+ after: handler,
203
+ },
204
+ });
195
205
  ```
196
206
 
197
207
  ### `removeAllHooks`
@@ -203,12 +213,16 @@ Remove all hook handlers.
203
213
  Registers a (sync) callback to be called before each hook is being called.
204
214
 
205
215
  ```js
206
- hookable.beforeEach((event) => { console.log(`${event.name} hook is being called with ${event.args}`)}`)
207
- hookable.hook('test', () => { console.log('running test hook') })
216
+ hookable.beforeEach((event) => {
217
+ console.log(`${event.name} hook is being called with ${event.args}`);
218
+ });
219
+ hookable.hook("test", () => {
220
+ console.log("running test hook");
221
+ });
208
222
 
209
223
  // test hook is being called with []
210
224
  // running test hook
211
- await hookable.callHook('test')
225
+ await hookable.callHook("test");
212
226
  ```
213
227
 
214
228
  ### `afterEach (syncCallback)`
@@ -216,12 +230,16 @@ await hookable.callHook('test')
216
230
  Registers a (sync) callback to be called after each hook is being called.
217
231
 
218
232
  ```js
219
- hookable.afterEach((event) => { console.log(`${event.name} hook called with ${event.args}`)}`)
220
- hookable.hook('test', () => { console.log('running test hook') })
233
+ hookable.afterEach((event) => {
234
+ console.log(`${event.name} hook called with ${event.args}`);
235
+ });
236
+ hookable.hook("test", () => {
237
+ console.log("running test hook");
238
+ });
221
239
 
222
240
  // running test hook
223
241
  // test hook called with []
224
- await hookable.callHook('test')
242
+ await hookable.callHook("test");
225
243
  ```
226
244
 
227
245
  ### `createDebugger`
@@ -229,12 +247,12 @@ await hookable.callHook('test')
229
247
  Automatically logs each hook that is called and how long it takes to run.
230
248
 
231
249
  ```js
232
- const debug = hookable.createDebugger(hooks, { tag: 'something' })
250
+ const debug = hookable.createDebugger(hooks, { tag: "something" });
233
251
 
234
- hooks.callHook('some-hook', 'some-arg')
252
+ hooks.callHook("some-hook", "some-arg");
235
253
  // [something] some-hook: 0.21ms
236
254
 
237
- debug.close()
255
+ debug.close();
238
256
  ```
239
257
 
240
258
  ## Migration
@@ -244,9 +262,9 @@ debug.close()
244
262
  - Type checking improved. You can use `Hookable<T>` or `createHooks<T>()` to provide types interface **([c2e1e22](https://github.com/unjs/hookable/commit/c2e1e223d16e7bf87117cd8d72ad3ba211a333d8))**
245
263
  - We no longer provide an IE11 compatible umd build. Instead, you should use an ESM-aware bundler such as webpack or rollup to transpile if needed.
246
264
  - Logger param is dropped. We use `console.warn` by default for deprecated hooks.
247
- - Package now uses named exports. You should import `{ Hookable }` instead of `Hookable` or use new `createHooks` util
265
+ - Package now uses named exports. You should import `{ Hookable }` instead of `Hookable` or use new `createHooks` util
248
266
  - `mergeHooks` util is exported standalone. You should replace `Hookable.mergeHooks` and `this.mergeHooks` with new `{ mergeHooks }` export
249
- - In versions < 5.0.0 when using `callHook` if an error happened by one of the hook callbacks, we was handling errors globally and call global `error` hook + `console.error` instead and resolve `callHook` promise! This sometimes makes confusing behavior when we think code worked but it didn't. v5 introduced a breaking change that when a hook throws an error, `callHook` also rejects instead of a global `error` event. This means you should be careful to handle all errors when using `callHook` now.
267
+ - In versions < 5.0.0 when using `callHook` if an error happened by one of the hook callbacks, we was handling errors globally and call global `error` hook + `console.error` instead and resolve `callHook` promise! This sometimes makes confusing behavior when we think code worked but it didn't. v5 introduced a breaking change that when a hook throws an error, `callHook` also rejects instead of a global `error` event. This means you should be careful to handle all errors when using `callHook` now.
250
268
 
251
269
  ## Credits
252
270
 
@@ -259,6 +277,7 @@ Thanks to [Joe Paice](https://github.com/RGBboy) for donating [hookable](https:/
259
277
  MIT - Made with 💖
260
278
 
261
279
  <!-- Badges -->
280
+
262
281
  [npm-version-src]: https://img.shields.io/npm/v/hookable?style=flat&colorA=18181B&colorB=F0DB4F
263
282
  [npm-version-href]: https://npmjs.com/package/hookable
264
283
  [npm-downloads-src]: https://img.shields.io/npm/dm/hookable?style=flat&colorA=18181B&colorB=F0DB4F
@@ -0,0 +1,107 @@
1
+ //#region src/types.d.ts
2
+ type HookCallback = (...arguments_: any) => Promise<void> | void;
3
+ interface Hooks {
4
+ [key: string]: HookCallback;
5
+ }
6
+ type HookKeys<T> = keyof T & string;
7
+ type DeprecatedHook<T> = {
8
+ message?: string;
9
+ to: HookKeys<T>;
10
+ };
11
+ type DeprecatedHooks<T> = { [name in HookKeys<T>]: DeprecatedHook<T> };
12
+ type Thenable<T> = Promise<T> | T;
13
+ type ValueOf<C> = C extends Record<any, any> ? C[keyof C] : never;
14
+ type Strings<T> = Exclude<keyof T, number | symbol>;
15
+ type KnownKeys<T> = keyof { [K in keyof T as string extends K ? never : number extends K ? never : K]: never };
16
+ type StripGeneric<T> = Pick<T, KnownKeys<T> extends keyof T ? KnownKeys<T> : never>;
17
+ type OnlyGeneric<T> = Omit<T, KnownKeys<T> extends keyof T ? KnownKeys<T> : never>;
18
+ type Namespaces<T> = ValueOf<{ [key in Strings<T>]: key extends `${infer Namespace}:${string}` ? Namespace : never }>;
19
+ type BareHooks<T> = ValueOf<{ [key in Strings<T>]: key extends `${string}:${string}` ? never : key }>;
20
+ type HooksInNamespace<T, Namespace$1 extends string> = ValueOf<{ [key in Strings<T>]: key extends `${Namespace$1}:${infer HookName}` ? HookName : never }>;
21
+ type WithoutNamespace<T, Namespace$1 extends string> = { [key in HooksInNamespace<T, Namespace$1>]: `${Namespace$1}:${key}` extends keyof T ? T[`${Namespace$1}:${key}`] : never };
22
+ type NestedHooks<T> = (Partial<StripGeneric<T>> | Partial<OnlyGeneric<T>>) & Partial<{ [key in Namespaces<StripGeneric<T>>]: NestedHooks<WithoutNamespace<T, key>> }> & Partial<{ [key in BareHooks<StripGeneric<T>>]: T[key] }>;
23
+ //#endregion
24
+ //#region src/hookable.d.ts
25
+ type InferCallback<HT, HN extends keyof HT> = HT[HN] extends HookCallback ? HT[HN] : never;
26
+ type InferSpyEvent<HT extends Record<string, any>> = { [key in keyof HT]: {
27
+ name: key;
28
+ args: Parameters<HT[key]>;
29
+ context: Record<string, any>;
30
+ } }[keyof HT];
31
+ declare class Hookable<HooksT extends Record<string, any> = Record<string, HookCallback>, HookNameT extends HookKeys<HooksT> = HookKeys<HooksT>> {
32
+ private _hooks;
33
+ private _before?;
34
+ private _after?;
35
+ private _deprecatedHooks;
36
+ private _deprecatedMessages?;
37
+ constructor();
38
+ hook<NameT extends HookNameT>(name: NameT, function_: InferCallback<HooksT, NameT>, options?: {
39
+ allowDeprecated?: boolean;
40
+ }): () => void;
41
+ hookOnce<NameT extends HookNameT>(name: NameT, function_: InferCallback<HooksT, NameT>): () => void;
42
+ removeHook<NameT extends HookNameT>(name: NameT, function_: InferCallback<HooksT, NameT>): void;
43
+ deprecateHook<NameT extends HookNameT>(name: NameT, deprecated: HookKeys<HooksT> | DeprecatedHook<HooksT>): void;
44
+ deprecateHooks(deprecatedHooks: Partial<Record<HookNameT, DeprecatedHook<HooksT>>>): void;
45
+ addHooks(configHooks: NestedHooks<HooksT>): () => void;
46
+ removeHooks(configHooks: NestedHooks<HooksT>): void;
47
+ removeAllHooks(): void;
48
+ callHook<NameT extends HookNameT>(name: NameT, ...args: Parameters<InferCallback<HooksT, NameT>>): Thenable<any> | void;
49
+ callHookParallel<NameT extends HookNameT>(name: NameT, ...args: Parameters<InferCallback<HooksT, NameT>>): Thenable<any[]> | void;
50
+ callHookWith<NameT extends HookNameT, CallFunction extends (hooks: HookCallback[], args: Parameters<InferCallback<HooksT, NameT>>) => any>(caller: CallFunction, name: NameT, args: Parameters<InferCallback<HooksT, NameT>>): ReturnType<CallFunction>;
51
+ beforeEach(function_: (event: InferSpyEvent<HooksT>) => void): () => void;
52
+ afterEach(function_: (event: InferSpyEvent<HooksT>) => void): () => void;
53
+ }
54
+ declare function createHooks<T extends Record<string, any>>(): Hookable<T>;
55
+ declare class HookableCore<HooksT extends Record<string, any> = Record<string, HookCallback>, HookNameT extends HookKeys<HooksT> = HookKeys<HooksT>> {
56
+ protected _hooks: {
57
+ [key: string]: HookCallback[] | undefined;
58
+ };
59
+ constructor();
60
+ hook<NameT extends HookNameT>(name: NameT, fn: InferCallback<HooksT, NameT>): () => void;
61
+ removeHook<NameT extends HookNameT>(name: NameT, function_: InferCallback<HooksT, NameT>): void;
62
+ callHook<NameT extends HookNameT>(name: NameT, ...args: Parameters<InferCallback<HooksT, NameT>>): Thenable<any> | void;
63
+ }
64
+ //#endregion
65
+ //#region src/utils.d.ts
66
+ declare function flatHooks<T>(configHooks: NestedHooks<T>, hooks?: T, parentName?: string): T;
67
+ declare function mergeHooks<T>(...hooks: NestedHooks<T>[]): T;
68
+ declare function serial<T>(tasks: T[], function_: (task: T) => Promise<any> | any): Promise<any>;
69
+ type CreateTask = (name?: string) => {
70
+ run: (function_: () => Promise<any> | any) => Promise<any> | any;
71
+ };
72
+ declare global {
73
+ interface Console {
74
+ createTask?: CreateTask;
75
+ }
76
+ }
77
+ /** @deprecated */
78
+ declare function serialCaller(hooks: HookCallback[], arguments_?: any[]): Promise<any>;
79
+ /** @deprecated */
80
+ declare function parallelCaller(hooks: HookCallback[], args?: any[]): Promise<any>;
81
+ //#endregion
82
+ //#region src/debugger.d.ts
83
+ interface CreateDebuggerOptions {
84
+ /** An optional tag to prefix console logs with */
85
+ tag?: string;
86
+ /**
87
+ * Show hook params to the console output
88
+ *
89
+ * Enabled for browsers by default
90
+ */
91
+ inspect?: boolean;
92
+ /**
93
+ * Use group/groupEnd wrapper around logs happening during a specific hook
94
+ *
95
+ * Enabled for browsers by default
96
+ */
97
+ group?: boolean;
98
+ /** Filter which hooks to enable debugger for. Can be a string prefix or fn. */
99
+ filter?: string | ((event: string) => boolean);
100
+ }
101
+ /** Start debugging hook names and timing in console */
102
+ declare function createDebugger(hooks: Hookable<any>, _options?: CreateDebuggerOptions): {
103
+ /** Stop debugging and remove listeners */
104
+ close: () => void;
105
+ };
106
+ //#endregion
107
+ export { CreateDebuggerOptions, DeprecatedHook, DeprecatedHooks, HookCallback, HookKeys, Hookable, HookableCore, Hooks, NestedHooks, Thenable, createDebugger, createHooks, flatHooks, mergeHooks, parallelCaller, serial, serialCaller };