hookable 5.3.0 → 5.4.0

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
@@ -220,6 +220,19 @@ hookable.hook('test', () => { console.log('running test hook') })
220
220
  await hookable.callHook('test')
221
221
  ```
222
222
 
223
+ ### `createDebugger`
224
+
225
+ Automatically logs each hook that is called and how long it takes to run.
226
+
227
+ ```js
228
+ const debug = hookable.createDebugger(hooks, { tag: 'something' })
229
+
230
+ hooks.callHook('some-hook', 'some-arg')
231
+ // [something] some-hook: 0.21ms
232
+
233
+ debug.close()
234
+ ```
235
+
223
236
  ## Migration
224
237
 
225
238
  ### From `4.x` to `5.x`
package/dist/index.cjs CHANGED
@@ -50,6 +50,46 @@ function callEachWith(callbacks, arg0) {
50
50
  cb(arg0);
51
51
  }
52
52
  }
53
+ const isBrowser = typeof window !== "undefined";
54
+ function createDebugger(hooks, _options = {}) {
55
+ const options = {
56
+ inspect: isBrowser,
57
+ group: isBrowser,
58
+ filter: () => true,
59
+ ..._options
60
+ };
61
+ const _filter = options.filter;
62
+ const filter = typeof _filter === "string" ? (name) => name.startsWith(_filter) : _filter;
63
+ const logPrefix = options.tag ? `[${options.tag}] ` : "";
64
+ const unsubscribeBefore = hooks.beforeEach(({ name }) => {
65
+ if (!filter(name)) {
66
+ return;
67
+ }
68
+ console.time(logPrefix + name);
69
+ });
70
+ const unsubscribeAfter = hooks.afterEach(({ name, args }) => {
71
+ if (!filter(name)) {
72
+ return;
73
+ }
74
+ if (options.group) {
75
+ console.groupCollapsed(name);
76
+ }
77
+ if (options.inspect) {
78
+ console.timeLog(logPrefix + name, args);
79
+ } else {
80
+ console.timeEnd(logPrefix + name);
81
+ }
82
+ if (options.group) {
83
+ console.groupEnd();
84
+ }
85
+ });
86
+ return {
87
+ close: () => {
88
+ unsubscribeBefore();
89
+ unsubscribeAfter();
90
+ }
91
+ };
92
+ }
53
93
 
54
94
  class Hookable {
55
95
  constructor() {
@@ -171,10 +211,22 @@ class Hookable {
171
211
  beforeEach(fn) {
172
212
  this._before = this._before || [];
173
213
  this._before.push(fn);
214
+ return () => {
215
+ const index = this._before.indexOf(fn);
216
+ if (index !== -1) {
217
+ this._before.splice(index, 1);
218
+ }
219
+ };
174
220
  }
175
221
  afterEach(fn) {
176
222
  this._after = this._after || [];
177
223
  this._after.push(fn);
224
+ return () => {
225
+ const index = this._after.indexOf(fn);
226
+ if (index !== -1) {
227
+ this._after.splice(index, 1);
228
+ }
229
+ };
178
230
  }
179
231
  }
180
232
  function createHooks() {
@@ -182,6 +234,7 @@ function createHooks() {
182
234
  }
183
235
 
184
236
  exports.Hookable = Hookable;
237
+ exports.createDebugger = createDebugger;
185
238
  exports.createHooks = createHooks;
186
239
  exports.flatHooks = flatHooks;
187
240
  exports.mergeHooks = mergeHooks;
package/dist/index.d.ts CHANGED
@@ -34,6 +34,24 @@ declare type NestedHooks<T> = (Partial<StripGeneric<T>> | Partial<OnlyGeneric<T>
34
34
  }> & Partial<{
35
35
  [key in BareHooks<StripGeneric<T>>]: T[key];
36
36
  }>;
37
+ interface CreateDebuggerOptions {
38
+ /** An optional tag to prefix console logs with */
39
+ tag?: string;
40
+ /**
41
+ * Show hook params to the console output
42
+ *
43
+ * Enabled for browsers by default
44
+ */
45
+ inspect?: boolean;
46
+ /**
47
+ * Use group/groupEnd wrapper around logs happening during a specific hook
48
+ *
49
+ * Enabled for browsers by default
50
+ */
51
+ group?: boolean;
52
+ /** Filter which hooks to enable debugger for. Can be a string prefix or fn. */
53
+ filter?: string | ((event: string) => boolean);
54
+ }
37
55
 
38
56
  declare type InferCallback<HT, HN extends keyof HT> = HT[HN] extends HookCallback ? HT[HN] : never;
39
57
  declare type InferSpyEvent<HT extends Record<string, any>> = {
@@ -62,8 +80,8 @@ declare class Hookable<HooksT = Record<string, HookCallback>, HookNameT extends
62
80
  callHook<NameT extends HookNameT>(name: NameT, ...args: Parameters<InferCallback<HooksT, NameT>>): Promise<any>;
63
81
  callHookParallel<NameT extends HookNameT>(name: NameT, ...args: Parameters<InferCallback<HooksT, NameT>>): Promise<any[]>;
64
82
  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>;
65
- beforeEach(fn: (event: InferSpyEvent<HooksT>) => void): void;
66
- afterEach(fn: (event: InferSpyEvent<HooksT>) => void): void;
83
+ beforeEach(fn: (event: InferSpyEvent<HooksT>) => void): () => void;
84
+ afterEach(fn: (event: InferSpyEvent<HooksT>) => void): () => void;
67
85
  }
68
86
  declare function createHooks<T>(): Hookable<T>;
69
87
 
@@ -72,5 +90,10 @@ declare function mergeHooks<T>(...hooks: NestedHooks<T>[]): T;
72
90
  declare function serial<T>(tasks: T[], fn: (task: T) => Promise<any> | any): Promise<any>;
73
91
  declare function serialCaller(hooks: HookCallback[], args?: any[]): Promise<any>;
74
92
  declare function parallelCaller(hooks: HookCallback[], args?: any[]): Promise<any[]>;
93
+ /** Start debugging hook names and timing in console */
94
+ declare function createDebugger(hooks: Hookable, _options?: CreateDebuggerOptions): {
95
+ /** Stop debugging and remove listeners */
96
+ close: () => void;
97
+ };
75
98
 
76
- export { DeprecatedHook, DeprecatedHooks, HookCallback, HookKeys, Hookable, Hooks, NestedHooks, createHooks, flatHooks, mergeHooks, parallelCaller, serial, serialCaller };
99
+ export { CreateDebuggerOptions, DeprecatedHook, DeprecatedHooks, HookCallback, HookKeys, Hookable, Hooks, NestedHooks, createDebugger, createHooks, flatHooks, mergeHooks, parallelCaller, serial, serialCaller };
package/dist/index.mjs CHANGED
@@ -46,6 +46,46 @@ function callEachWith(callbacks, arg0) {
46
46
  cb(arg0);
47
47
  }
48
48
  }
49
+ const isBrowser = typeof window !== "undefined";
50
+ function createDebugger(hooks, _options = {}) {
51
+ const options = {
52
+ inspect: isBrowser,
53
+ group: isBrowser,
54
+ filter: () => true,
55
+ ..._options
56
+ };
57
+ const _filter = options.filter;
58
+ const filter = typeof _filter === "string" ? (name) => name.startsWith(_filter) : _filter;
59
+ const logPrefix = options.tag ? `[${options.tag}] ` : "";
60
+ const unsubscribeBefore = hooks.beforeEach(({ name }) => {
61
+ if (!filter(name)) {
62
+ return;
63
+ }
64
+ console.time(logPrefix + name);
65
+ });
66
+ const unsubscribeAfter = hooks.afterEach(({ name, args }) => {
67
+ if (!filter(name)) {
68
+ return;
69
+ }
70
+ if (options.group) {
71
+ console.groupCollapsed(name);
72
+ }
73
+ if (options.inspect) {
74
+ console.timeLog(logPrefix + name, args);
75
+ } else {
76
+ console.timeEnd(logPrefix + name);
77
+ }
78
+ if (options.group) {
79
+ console.groupEnd();
80
+ }
81
+ });
82
+ return {
83
+ close: () => {
84
+ unsubscribeBefore();
85
+ unsubscribeAfter();
86
+ }
87
+ };
88
+ }
49
89
 
50
90
  class Hookable {
51
91
  constructor() {
@@ -167,14 +207,26 @@ class Hookable {
167
207
  beforeEach(fn) {
168
208
  this._before = this._before || [];
169
209
  this._before.push(fn);
210
+ return () => {
211
+ const index = this._before.indexOf(fn);
212
+ if (index !== -1) {
213
+ this._before.splice(index, 1);
214
+ }
215
+ };
170
216
  }
171
217
  afterEach(fn) {
172
218
  this._after = this._after || [];
173
219
  this._after.push(fn);
220
+ return () => {
221
+ const index = this._after.indexOf(fn);
222
+ if (index !== -1) {
223
+ this._after.splice(index, 1);
224
+ }
225
+ };
174
226
  }
175
227
  }
176
228
  function createHooks() {
177
229
  return new Hookable();
178
230
  }
179
231
 
180
- export { Hookable, createHooks, flatHooks, mergeHooks, parallelCaller, serial, serialCaller };
232
+ export { Hookable, createDebugger, createHooks, flatHooks, mergeHooks, parallelCaller, serial, serialCaller };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hookable",
3
- "version": "5.3.0",
3
+ "version": "5.4.0",
4
4
  "description": "Awaitable hook system",
5
5
  "keywords": [
6
6
  "hook",
@@ -23,15 +23,15 @@
23
23
  ],
24
24
  "devDependencies": {
25
25
  "@nuxtjs/eslint-config-typescript": "latest",
26
- "@vitest/coverage-c8": "^0.22.1",
26
+ "@vitest/coverage-c8": "^0.24.1",
27
27
  "eslint": "latest",
28
- "expect-type": "^0.13.0",
28
+ "expect-type": "^0.14.2",
29
29
  "standard-version": "latest",
30
30
  "typescript": "latest",
31
31
  "unbuild": "latest",
32
32
  "vitest": "latest"
33
33
  },
34
- "packageManager": "pnpm@7.9.4",
34
+ "packageManager": "pnpm@7.13.4",
35
35
  "scripts": {
36
36
  "build": "unbuild",
37
37
  "dev": "vitest",