hookable 5.3.0 → 5.4.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
@@ -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
@@ -158,12 +158,12 @@ class Hookable {
158
158
  const result = caller(this._hooks[name] || [], args);
159
159
  if (result instanceof Promise) {
160
160
  return result.finally(() => {
161
- if (this._after) {
161
+ if (this._after && event) {
162
162
  callEachWith(this._after, event);
163
163
  }
164
164
  });
165
165
  }
166
- if (this._after) {
166
+ if (this._after && event) {
167
167
  callEachWith(this._after, event);
168
168
  }
169
169
  return result;
@@ -171,17 +171,76 @@ class Hookable {
171
171
  beforeEach(fn) {
172
172
  this._before = this._before || [];
173
173
  this._before.push(fn);
174
+ return () => {
175
+ const index = this._before.indexOf(fn);
176
+ if (index !== -1) {
177
+ this._before.splice(index, 1);
178
+ }
179
+ };
174
180
  }
175
181
  afterEach(fn) {
176
182
  this._after = this._after || [];
177
183
  this._after.push(fn);
184
+ return () => {
185
+ const index = this._after.indexOf(fn);
186
+ if (index !== -1) {
187
+ this._after.splice(index, 1);
188
+ }
189
+ };
178
190
  }
179
191
  }
180
192
  function createHooks() {
181
193
  return new Hookable();
182
194
  }
183
195
 
196
+ const isBrowser = typeof window !== "undefined";
197
+ function createDebugger(hooks, _options = {}) {
198
+ const options = {
199
+ inspect: isBrowser,
200
+ group: isBrowser,
201
+ filter: () => true,
202
+ ..._options
203
+ };
204
+ const _filter = options.filter;
205
+ const filter = typeof _filter === "string" ? (name) => name.startsWith(_filter) : _filter;
206
+ const _tag = options.tag ? `[${options.tag}] ` : "";
207
+ const logPrefix = (event) => _tag + event.name + "".padEnd(event._id, "\0");
208
+ const _idCtr = {};
209
+ const unsubscribeBefore = hooks.beforeEach((event) => {
210
+ if (!filter(event.name)) {
211
+ return;
212
+ }
213
+ _idCtr[event.name] = _idCtr[event.name] || 0;
214
+ event._id = _idCtr[event.name]++;
215
+ console.time(logPrefix(event));
216
+ });
217
+ const unsubscribeAfter = hooks.afterEach((event) => {
218
+ if (!filter(event.name)) {
219
+ return;
220
+ }
221
+ if (options.group) {
222
+ console.groupCollapsed(event.name);
223
+ }
224
+ if (options.inspect) {
225
+ console.timeLog(logPrefix(event), event.args);
226
+ } else {
227
+ console.timeEnd(logPrefix(event));
228
+ }
229
+ if (options.group) {
230
+ console.groupEnd();
231
+ }
232
+ _idCtr[event.name]--;
233
+ });
234
+ return {
235
+ close: () => {
236
+ unsubscribeBefore();
237
+ unsubscribeAfter();
238
+ }
239
+ };
240
+ }
241
+
184
242
  exports.Hookable = Hookable;
243
+ exports.createDebugger = createDebugger;
185
244
  exports.createHooks = createHooks;
186
245
  exports.flatHooks = flatHooks;
187
246
  exports.mergeHooks = mergeHooks;
package/dist/index.d.ts CHANGED
@@ -62,8 +62,8 @@ declare class Hookable<HooksT = Record<string, HookCallback>, HookNameT extends
62
62
  callHook<NameT extends HookNameT>(name: NameT, ...args: Parameters<InferCallback<HooksT, NameT>>): Promise<any>;
63
63
  callHookParallel<NameT extends HookNameT>(name: NameT, ...args: Parameters<InferCallback<HooksT, NameT>>): Promise<any[]>;
64
64
  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;
65
+ beforeEach(fn: (event: InferSpyEvent<HooksT>) => void): () => void;
66
+ afterEach(fn: (event: InferSpyEvent<HooksT>) => void): () => void;
67
67
  }
68
68
  declare function createHooks<T>(): Hookable<T>;
69
69
 
@@ -73,4 +73,28 @@ declare function serial<T>(tasks: T[], fn: (task: T) => Promise<any> | any): Pro
73
73
  declare function serialCaller(hooks: HookCallback[], args?: any[]): Promise<any>;
74
74
  declare function parallelCaller(hooks: HookCallback[], args?: any[]): Promise<any[]>;
75
75
 
76
- export { DeprecatedHook, DeprecatedHooks, HookCallback, HookKeys, Hookable, Hooks, NestedHooks, createHooks, flatHooks, mergeHooks, parallelCaller, serial, serialCaller };
76
+ interface CreateDebuggerOptions {
77
+ /** An optional tag to prefix console logs with */
78
+ tag?: string;
79
+ /**
80
+ * Show hook params to the console output
81
+ *
82
+ * Enabled for browsers by default
83
+ */
84
+ inspect?: boolean;
85
+ /**
86
+ * Use group/groupEnd wrapper around logs happening during a specific hook
87
+ *
88
+ * Enabled for browsers by default
89
+ */
90
+ group?: boolean;
91
+ /** Filter which hooks to enable debugger for. Can be a string prefix or fn. */
92
+ filter?: string | ((event: string) => boolean);
93
+ }
94
+ /** Start debugging hook names and timing in console */
95
+ declare function createDebugger(hooks: Hookable<any>, _options?: CreateDebuggerOptions): {
96
+ /** Stop debugging and remove listeners */
97
+ close: () => void;
98
+ };
99
+
100
+ export { CreateDebuggerOptions, DeprecatedHook, DeprecatedHooks, HookCallback, HookKeys, Hookable, Hooks, NestedHooks, createDebugger, createHooks, flatHooks, mergeHooks, parallelCaller, serial, serialCaller };
package/dist/index.mjs CHANGED
@@ -154,12 +154,12 @@ class Hookable {
154
154
  const result = caller(this._hooks[name] || [], args);
155
155
  if (result instanceof Promise) {
156
156
  return result.finally(() => {
157
- if (this._after) {
157
+ if (this._after && event) {
158
158
  callEachWith(this._after, event);
159
159
  }
160
160
  });
161
161
  }
162
- if (this._after) {
162
+ if (this._after && event) {
163
163
  callEachWith(this._after, event);
164
164
  }
165
165
  return result;
@@ -167,14 +167,72 @@ class Hookable {
167
167
  beforeEach(fn) {
168
168
  this._before = this._before || [];
169
169
  this._before.push(fn);
170
+ return () => {
171
+ const index = this._before.indexOf(fn);
172
+ if (index !== -1) {
173
+ this._before.splice(index, 1);
174
+ }
175
+ };
170
176
  }
171
177
  afterEach(fn) {
172
178
  this._after = this._after || [];
173
179
  this._after.push(fn);
180
+ return () => {
181
+ const index = this._after.indexOf(fn);
182
+ if (index !== -1) {
183
+ this._after.splice(index, 1);
184
+ }
185
+ };
174
186
  }
175
187
  }
176
188
  function createHooks() {
177
189
  return new Hookable();
178
190
  }
179
191
 
180
- export { Hookable, createHooks, flatHooks, mergeHooks, parallelCaller, serial, serialCaller };
192
+ const isBrowser = typeof window !== "undefined";
193
+ function createDebugger(hooks, _options = {}) {
194
+ const options = {
195
+ inspect: isBrowser,
196
+ group: isBrowser,
197
+ filter: () => true,
198
+ ..._options
199
+ };
200
+ const _filter = options.filter;
201
+ const filter = typeof _filter === "string" ? (name) => name.startsWith(_filter) : _filter;
202
+ const _tag = options.tag ? `[${options.tag}] ` : "";
203
+ const logPrefix = (event) => _tag + event.name + "".padEnd(event._id, "\0");
204
+ const _idCtr = {};
205
+ const unsubscribeBefore = hooks.beforeEach((event) => {
206
+ if (!filter(event.name)) {
207
+ return;
208
+ }
209
+ _idCtr[event.name] = _idCtr[event.name] || 0;
210
+ event._id = _idCtr[event.name]++;
211
+ console.time(logPrefix(event));
212
+ });
213
+ const unsubscribeAfter = hooks.afterEach((event) => {
214
+ if (!filter(event.name)) {
215
+ return;
216
+ }
217
+ if (options.group) {
218
+ console.groupCollapsed(event.name);
219
+ }
220
+ if (options.inspect) {
221
+ console.timeLog(logPrefix(event), event.args);
222
+ } else {
223
+ console.timeEnd(logPrefix(event));
224
+ }
225
+ if (options.group) {
226
+ console.groupEnd();
227
+ }
228
+ _idCtr[event.name]--;
229
+ });
230
+ return {
231
+ close: () => {
232
+ unsubscribeBefore();
233
+ unsubscribeAfter();
234
+ }
235
+ };
236
+ }
237
+
238
+ 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.1",
4
4
  "description": "Awaitable hook system",
5
5
  "keywords": [
6
6
  "hook",
@@ -22,16 +22,16 @@
22
22
  "dist"
23
23
  ],
24
24
  "devDependencies": {
25
- "@nuxtjs/eslint-config-typescript": "latest",
26
- "@vitest/coverage-c8": "^0.22.1",
27
- "eslint": "latest",
28
- "expect-type": "^0.13.0",
29
- "standard-version": "latest",
25
+ "@nuxtjs/eslint-config-typescript": "^11.0.0",
26
+ "@vitest/coverage-c8": "^0.24.3",
27
+ "eslint": "^8.25.0",
28
+ "expect-type": "^0.14.2",
29
+ "standard-version": "^9.5.0",
30
30
  "typescript": "latest",
31
- "unbuild": "latest",
32
- "vitest": "latest"
31
+ "unbuild": "^0.8.2",
32
+ "vitest": "^0.24.3"
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",