hookified 1.12.0 → 1.12.2

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.
@@ -307,10 +307,31 @@ type HookifiedOptions = {
307
307
  * Whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
308
308
  */
309
309
  throwHookErrors?: boolean;
310
+ /**
311
+ * Whether to enforce that all hook names start with 'before' or 'after'. Default is false.
312
+ * @type {boolean}
313
+ * @default false
314
+ */
315
+ enforceBeforeAfter?: boolean;
316
+ /**
317
+ * Map of deprecated hook names to deprecation messages. When a deprecated hook is used, a warning will be emitted.
318
+ * @type {Map<string, string>}
319
+ * @default new Map()
320
+ */
321
+ deprecatedHooks?: Map<string, string>;
322
+ /**
323
+ * Whether to allow deprecated hooks to be registered and executed. Default is true.
324
+ * @type {boolean}
325
+ * @default true
326
+ */
327
+ allowDeprecated?: boolean;
310
328
  } & EventEmitterOptions;
311
329
  declare class Hookified extends Eventified {
312
330
  private readonly _hooks;
313
331
  private _throwHookErrors;
332
+ private _enforceBeforeAfter;
333
+ private _deprecatedHooks;
334
+ private _allowDeprecated;
314
335
  constructor(options?: HookifiedOptions);
315
336
  /**
316
337
  * Gets all hooks
@@ -327,6 +348,49 @@ declare class Hookified extends Eventified {
327
348
  * @param {boolean} value
328
349
  */
329
350
  set throwHookErrors(value: boolean);
351
+ /**
352
+ * Gets whether to enforce that all hook names start with 'before' or 'after'. Default is false.
353
+ * @returns {boolean}
354
+ * @default false
355
+ */
356
+ get enforceBeforeAfter(): boolean;
357
+ /**
358
+ * Sets whether to enforce that all hook names start with 'before' or 'after'. Default is false.
359
+ * @param {boolean} value
360
+ */
361
+ set enforceBeforeAfter(value: boolean);
362
+ /**
363
+ * Gets the map of deprecated hook names to deprecation messages.
364
+ * @returns {Map<string, string>}
365
+ */
366
+ get deprecatedHooks(): Map<string, string>;
367
+ /**
368
+ * Sets the map of deprecated hook names to deprecation messages.
369
+ * @param {Map<string, string>} value
370
+ */
371
+ set deprecatedHooks(value: Map<string, string>);
372
+ /**
373
+ * Gets whether deprecated hooks are allowed to be registered and executed. Default is true.
374
+ * @returns {boolean}
375
+ */
376
+ get allowDeprecated(): boolean;
377
+ /**
378
+ * Sets whether deprecated hooks are allowed to be registered and executed. Default is true.
379
+ * @param {boolean} value
380
+ */
381
+ set allowDeprecated(value: boolean);
382
+ /**
383
+ * Validates hook event name if enforceBeforeAfter is enabled
384
+ * @param {string} event - The event name to validate
385
+ * @throws {Error} If enforceBeforeAfter is true and event doesn't start with 'before' or 'after'
386
+ */
387
+ private validateHookName;
388
+ /**
389
+ * Checks if a hook is deprecated and emits a warning if it is
390
+ * @param {string} event - The event name to check
391
+ * @returns {boolean} - Returns true if the hook should proceed, false if it should be blocked
392
+ */
393
+ private checkDeprecatedHook;
330
394
  /**
331
395
  * Adds a handler function for a specific event
332
396
  * @param {string} event
@@ -1 +1,567 @@
1
- var o=class{_eventListeners;_maxListeners;_logger;_throwOnEmitError=!1;constructor(e){this._eventListeners=new Map,this._maxListeners=100,this._logger=e?.logger,e?.throwOnEmitError!==void 0&&(this._throwOnEmitError=e.throwOnEmitError)}get logger(){return this._logger}set logger(e){this._logger=e}get throwOnEmitError(){return this._throwOnEmitError}set throwOnEmitError(e){this._throwOnEmitError=e}once(e,t){let r=(...s)=>{this.off(e,r),t(...s)};return this.on(e,r),this}listenerCount(e){if(e===void 0)return this.getAllListeners().length;let t=this._eventListeners.get(e);return t?t.length:0}eventNames(){return[...this._eventListeners.keys()]}rawListeners(e){return e===void 0?this.getAllListeners():this._eventListeners.get(e)??[]}prependListener(e,t){let r=this._eventListeners.get(e)??[];return r.unshift(t),this._eventListeners.set(e,r),this}prependOnceListener(e,t){let r=(...s)=>{this.off(e,r),t(...s)};return this.prependListener(e,r),this}maxListeners(){return this._maxListeners}addListener(e,t){return this.on(e,t),this}on(e,t){this._eventListeners.has(e)||this._eventListeners.set(e,[]);let r=this._eventListeners.get(e);return r&&(r.length>=this._maxListeners&&console.warn(`MaxListenersExceededWarning: Possible event memory leak detected. ${r.length+1} ${e} listeners added. Use setMaxListeners() to increase limit.`),r.push(t)),this}removeListener(e,t){return this.off(e,t),this}off(e,t){let r=this._eventListeners.get(e)??[],s=r.indexOf(t);return s!==-1&&r.splice(s,1),r.length===0&&this._eventListeners.delete(e),this}emit(e,...t){let r=!1,s=this._eventListeners.get(e);if(s&&s.length>0)for(let n of s)n(...t),r=!0;if(e==="error"){let n=t[0]instanceof Error?t[0]:new Error(`${t[0]}`);if(this._throwOnEmitError&&!r)throw n}return r}listeners(e){return this._eventListeners.get(e)??[]}removeAllListeners(e){return e!==void 0?this._eventListeners.delete(e):this._eventListeners.clear(),this}setMaxListeners(e){this._maxListeners=e;for(let t of this._eventListeners.values())t.length>e&&t.splice(e)}getAllListeners(){let e=[];for(let t of this._eventListeners.values())e=[...e,...t];return e}};var l=class extends o{_hooks;_throwHookErrors=!1;constructor(e){super({logger:e?.logger}),this._hooks=new Map,e?.throwHookErrors!==void 0&&(this._throwHookErrors=e.throwHookErrors)}get hooks(){return this._hooks}get throwHookErrors(){return this._throwHookErrors}set throwHookErrors(e){this._throwHookErrors=e}onHook(e,t){let r=this._hooks.get(e);r?r.push(t):this._hooks.set(e,[t])}onHookEntry(e){this.onHook(e.event,e.handler)}addHook(e,t){this.onHook(e,t)}onHooks(e){for(let t of e)this.onHook(t.event,t.handler)}prependHook(e,t){let r=this._hooks.get(e);r?r.unshift(t):this._hooks.set(e,[t])}prependOnceHook(e,t){let r=async(...s)=>(this.removeHook(e,r),t(...s));this.prependHook(e,r)}onceHook(e,t){let r=async(...s)=>(this.removeHook(e,r),t(...s));this.onHook(e,r)}removeHook(e,t){let r=this._hooks.get(e);if(r){let s=r.indexOf(t);s!==-1&&r.splice(s,1)}}removeHooks(e){for(let t of e)this.removeHook(t.event,t.handler)}async hook(e,...t){let r=this._hooks.get(e);if(r)for(let s of r)try{await s(...t)}catch(n){let i=`${e}: ${n.message}`;if(this.emit("error",new Error(i)),this.logger&&this.logger.error(i),this._throwHookErrors)throw new Error(i)}}async beforeHook(e,...t){await this.hook(`before:${e}`,...t)}async afterHook(e,...t){await this.hook(`after:${e}`,...t)}async callHook(e,...t){await this.hook(e,...t)}getHooks(e){return this._hooks.get(e)}clearHooks(){this._hooks.clear()}};export{o as Eventified,l as Hookified};
1
+ // src/eventified.ts
2
+ var Eventified = class {
3
+ _eventListeners;
4
+ _maxListeners;
5
+ _logger;
6
+ _throwOnEmitError = false;
7
+ constructor(options) {
8
+ this._eventListeners = /* @__PURE__ */ new Map();
9
+ this._maxListeners = 100;
10
+ this._logger = options?.logger;
11
+ if (options?.throwOnEmitError !== void 0) {
12
+ this._throwOnEmitError = options.throwOnEmitError;
13
+ }
14
+ }
15
+ /**
16
+ * Gets the logger
17
+ * @returns {Logger}
18
+ */
19
+ get logger() {
20
+ return this._logger;
21
+ }
22
+ /**
23
+ * Sets the logger
24
+ * @param {Logger} logger
25
+ */
26
+ set logger(logger) {
27
+ this._logger = logger;
28
+ }
29
+ /**
30
+ * Gets whether an error should be thrown when an emit throws an error. Default is false and only emits an error event.
31
+ * @returns {boolean}
32
+ */
33
+ get throwOnEmitError() {
34
+ return this._throwOnEmitError;
35
+ }
36
+ /**
37
+ * Sets whether an error should be thrown when an emit throws an error. Default is false and only emits an error event.
38
+ * @param {boolean} value
39
+ */
40
+ set throwOnEmitError(value) {
41
+ this._throwOnEmitError = value;
42
+ }
43
+ /**
44
+ * Adds a handler function for a specific event that will run only once
45
+ * @param {string | symbol} eventName
46
+ * @param {EventListener} listener
47
+ * @returns {IEventEmitter} returns the instance of the class for chaining
48
+ */
49
+ once(eventName, listener) {
50
+ const onceListener = (...arguments_) => {
51
+ this.off(eventName, onceListener);
52
+ listener(...arguments_);
53
+ };
54
+ this.on(eventName, onceListener);
55
+ return this;
56
+ }
57
+ /**
58
+ * Gets the number of listeners for a specific event. If no event is provided, it returns the total number of listeners
59
+ * @param {string} eventName The event name. Not required
60
+ * @returns {number} The number of listeners
61
+ */
62
+ listenerCount(eventName) {
63
+ if (eventName === void 0) {
64
+ return this.getAllListeners().length;
65
+ }
66
+ const listeners = this._eventListeners.get(eventName);
67
+ return listeners ? listeners.length : 0;
68
+ }
69
+ /**
70
+ * Gets an array of event names
71
+ * @returns {Array<string | symbol>} An array of event names
72
+ */
73
+ eventNames() {
74
+ return [...this._eventListeners.keys()];
75
+ }
76
+ /**
77
+ * Gets an array of listeners for a specific event. If no event is provided, it returns all listeners
78
+ * @param {string} [event] (Optional) The event name
79
+ * @returns {EventListener[]} An array of listeners
80
+ */
81
+ rawListeners(event) {
82
+ if (event === void 0) {
83
+ return this.getAllListeners();
84
+ }
85
+ return this._eventListeners.get(event) ?? [];
86
+ }
87
+ /**
88
+ * Prepends a listener to the beginning of the listeners array for the specified event
89
+ * @param {string | symbol} eventName
90
+ * @param {EventListener} listener
91
+ * @returns {IEventEmitter} returns the instance of the class for chaining
92
+ */
93
+ prependListener(eventName, listener) {
94
+ const listeners = this._eventListeners.get(eventName) ?? [];
95
+ listeners.unshift(listener);
96
+ this._eventListeners.set(eventName, listeners);
97
+ return this;
98
+ }
99
+ /**
100
+ * Prepends a one-time listener to the beginning of the listeners array for the specified event
101
+ * @param {string | symbol} eventName
102
+ * @param {EventListener} listener
103
+ * @returns {IEventEmitter} returns the instance of the class for chaining
104
+ */
105
+ prependOnceListener(eventName, listener) {
106
+ const onceListener = (...arguments_) => {
107
+ this.off(eventName, onceListener);
108
+ listener(...arguments_);
109
+ };
110
+ this.prependListener(eventName, onceListener);
111
+ return this;
112
+ }
113
+ /**
114
+ * Gets the maximum number of listeners that can be added for a single event
115
+ * @returns {number} The maximum number of listeners
116
+ */
117
+ maxListeners() {
118
+ return this._maxListeners;
119
+ }
120
+ /**
121
+ * Adds a listener for a specific event. It is an alias for the on() method
122
+ * @param {string | symbol} event
123
+ * @param {EventListener} listener
124
+ * @returns {IEventEmitter} returns the instance of the class for chaining
125
+ */
126
+ addListener(event, listener) {
127
+ this.on(event, listener);
128
+ return this;
129
+ }
130
+ /**
131
+ * Adds a listener for a specific event
132
+ * @param {string | symbol} event
133
+ * @param {EventListener} listener
134
+ * @returns {IEventEmitter} returns the instance of the class for chaining
135
+ */
136
+ on(event, listener) {
137
+ if (!this._eventListeners.has(event)) {
138
+ this._eventListeners.set(event, []);
139
+ }
140
+ const listeners = this._eventListeners.get(event);
141
+ if (listeners) {
142
+ if (listeners.length >= this._maxListeners) {
143
+ console.warn(
144
+ `MaxListenersExceededWarning: Possible event memory leak detected. ${listeners.length + 1} ${event} listeners added. Use setMaxListeners() to increase limit.`
145
+ );
146
+ }
147
+ listeners.push(listener);
148
+ }
149
+ return this;
150
+ }
151
+ /**
152
+ * Removes a listener for a specific event. It is an alias for the off() method
153
+ * @param {string | symbol} event
154
+ * @param {EventListener} listener
155
+ * @returns {IEventEmitter} returns the instance of the class for chaining
156
+ */
157
+ removeListener(event, listener) {
158
+ this.off(event, listener);
159
+ return this;
160
+ }
161
+ /**
162
+ * Removes a listener for a specific event
163
+ * @param {string | symbol} event
164
+ * @param {EventListener} listener
165
+ * @returns {IEventEmitter} returns the instance of the class for chaining
166
+ */
167
+ off(event, listener) {
168
+ const listeners = this._eventListeners.get(event) ?? [];
169
+ const index = listeners.indexOf(listener);
170
+ if (index !== -1) {
171
+ listeners.splice(index, 1);
172
+ }
173
+ if (listeners.length === 0) {
174
+ this._eventListeners.delete(event);
175
+ }
176
+ return this;
177
+ }
178
+ /**
179
+ * Calls all listeners for a specific event
180
+ * @param {string | symbol} event
181
+ * @param arguments_ The arguments to pass to the listeners
182
+ * @returns {boolean} Returns true if the event had listeners, false otherwise
183
+ */
184
+ emit(event, ...arguments_) {
185
+ let result = false;
186
+ const listeners = this._eventListeners.get(event);
187
+ if (listeners && listeners.length > 0) {
188
+ for (const listener of listeners) {
189
+ listener(...arguments_);
190
+ result = true;
191
+ }
192
+ }
193
+ if (event === "error") {
194
+ const error = arguments_[0] instanceof Error ? arguments_[0] : new Error(`${arguments_[0]}`);
195
+ if (this._throwOnEmitError && !result) {
196
+ throw error;
197
+ }
198
+ }
199
+ return result;
200
+ }
201
+ /**
202
+ * Gets all listeners for a specific event. If no event is provided, it returns all listeners
203
+ * @param {string} [event] (Optional) The event name
204
+ * @returns {EventListener[]} An array of listeners
205
+ */
206
+ listeners(event) {
207
+ return this._eventListeners.get(event) ?? [];
208
+ }
209
+ /**
210
+ * Removes all listeners for a specific event. If no event is provided, it removes all listeners
211
+ * @param {string} [event] (Optional) The event name
212
+ * @returns {IEventEmitter} returns the instance of the class for chaining
213
+ */
214
+ removeAllListeners(event) {
215
+ if (event !== void 0) {
216
+ this._eventListeners.delete(event);
217
+ } else {
218
+ this._eventListeners.clear();
219
+ }
220
+ return this;
221
+ }
222
+ /**
223
+ * Sets the maximum number of listeners that can be added for a single event
224
+ * @param {number} n The maximum number of listeners
225
+ * @returns {void}
226
+ */
227
+ setMaxListeners(n) {
228
+ this._maxListeners = n;
229
+ for (const listeners of this._eventListeners.values()) {
230
+ if (listeners.length > n) {
231
+ listeners.splice(n);
232
+ }
233
+ }
234
+ }
235
+ /**
236
+ * Gets all listeners
237
+ * @returns {EventListener[]} An array of listeners
238
+ */
239
+ getAllListeners() {
240
+ let result = [];
241
+ for (const listeners of this._eventListeners.values()) {
242
+ result = [...result, ...listeners];
243
+ }
244
+ return result;
245
+ }
246
+ };
247
+
248
+ // src/index.ts
249
+ var Hookified = class extends Eventified {
250
+ _hooks;
251
+ _throwHookErrors = false;
252
+ _enforceBeforeAfter = false;
253
+ _deprecatedHooks;
254
+ _allowDeprecated = true;
255
+ constructor(options) {
256
+ super({ logger: options?.logger });
257
+ this._hooks = /* @__PURE__ */ new Map();
258
+ this._deprecatedHooks = options?.deprecatedHooks ? new Map(options.deprecatedHooks) : /* @__PURE__ */ new Map();
259
+ if (options?.throwHookErrors !== void 0) {
260
+ this._throwHookErrors = options.throwHookErrors;
261
+ }
262
+ if (options?.enforceBeforeAfter !== void 0) {
263
+ this._enforceBeforeAfter = options.enforceBeforeAfter;
264
+ }
265
+ if (options?.allowDeprecated !== void 0) {
266
+ this._allowDeprecated = options.allowDeprecated;
267
+ }
268
+ }
269
+ /**
270
+ * Gets all hooks
271
+ * @returns {Map<string, Hook[]>}
272
+ */
273
+ get hooks() {
274
+ return this._hooks;
275
+ }
276
+ /**
277
+ * Gets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
278
+ * @returns {boolean}
279
+ */
280
+ get throwHookErrors() {
281
+ return this._throwHookErrors;
282
+ }
283
+ /**
284
+ * Sets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
285
+ * @param {boolean} value
286
+ */
287
+ set throwHookErrors(value) {
288
+ this._throwHookErrors = value;
289
+ }
290
+ /**
291
+ * Gets whether to enforce that all hook names start with 'before' or 'after'. Default is false.
292
+ * @returns {boolean}
293
+ * @default false
294
+ */
295
+ get enforceBeforeAfter() {
296
+ return this._enforceBeforeAfter;
297
+ }
298
+ /**
299
+ * Sets whether to enforce that all hook names start with 'before' or 'after'. Default is false.
300
+ * @param {boolean} value
301
+ */
302
+ set enforceBeforeAfter(value) {
303
+ this._enforceBeforeAfter = value;
304
+ }
305
+ /**
306
+ * Gets the map of deprecated hook names to deprecation messages.
307
+ * @returns {Map<string, string>}
308
+ */
309
+ get deprecatedHooks() {
310
+ return this._deprecatedHooks;
311
+ }
312
+ /**
313
+ * Sets the map of deprecated hook names to deprecation messages.
314
+ * @param {Map<string, string>} value
315
+ */
316
+ set deprecatedHooks(value) {
317
+ this._deprecatedHooks = value;
318
+ }
319
+ /**
320
+ * Gets whether deprecated hooks are allowed to be registered and executed. Default is true.
321
+ * @returns {boolean}
322
+ */
323
+ get allowDeprecated() {
324
+ return this._allowDeprecated;
325
+ }
326
+ /**
327
+ * Sets whether deprecated hooks are allowed to be registered and executed. Default is true.
328
+ * @param {boolean} value
329
+ */
330
+ set allowDeprecated(value) {
331
+ this._allowDeprecated = value;
332
+ }
333
+ /**
334
+ * Validates hook event name if enforceBeforeAfter is enabled
335
+ * @param {string} event - The event name to validate
336
+ * @throws {Error} If enforceBeforeAfter is true and event doesn't start with 'before' or 'after'
337
+ */
338
+ validateHookName(event) {
339
+ if (this._enforceBeforeAfter) {
340
+ const eventValue = event.trim().toLocaleLowerCase();
341
+ if (!eventValue.startsWith("before") && !eventValue.startsWith("after")) {
342
+ throw new Error(
343
+ `Hook event "${event}" must start with "before" or "after" when enforceBeforeAfter is enabled`
344
+ );
345
+ }
346
+ }
347
+ }
348
+ /**
349
+ * Checks if a hook is deprecated and emits a warning if it is
350
+ * @param {string} event - The event name to check
351
+ * @returns {boolean} - Returns true if the hook should proceed, false if it should be blocked
352
+ */
353
+ checkDeprecatedHook(event) {
354
+ if (this._deprecatedHooks.has(event)) {
355
+ const message = this._deprecatedHooks.get(event);
356
+ const warningMessage = `Hook "${event}" is deprecated${message ? `: ${message}` : ""}`;
357
+ this.emit("warn", { hook: event, message: warningMessage });
358
+ if (this.logger?.warn) {
359
+ this.logger.warn(warningMessage);
360
+ }
361
+ return this._allowDeprecated;
362
+ }
363
+ return true;
364
+ }
365
+ /**
366
+ * Adds a handler function for a specific event
367
+ * @param {string} event
368
+ * @param {Hook} handler - this can be async or sync
369
+ * @returns {void}
370
+ */
371
+ onHook(event, handler) {
372
+ this.validateHookName(event);
373
+ if (!this.checkDeprecatedHook(event)) {
374
+ return;
375
+ }
376
+ const eventHandlers = this._hooks.get(event);
377
+ if (eventHandlers) {
378
+ eventHandlers.push(handler);
379
+ } else {
380
+ this._hooks.set(event, [handler]);
381
+ }
382
+ }
383
+ /**
384
+ * Adds a handler function for a specific event that runs before all other handlers
385
+ * @param {HookEntry} hookEntry
386
+ * @returns {void}
387
+ */
388
+ onHookEntry(hookEntry) {
389
+ this.onHook(hookEntry.event, hookEntry.handler);
390
+ }
391
+ /**
392
+ * Alias for onHook. This is provided for compatibility with other libraries that use the `addHook` method.
393
+ * @param {string} event
394
+ * @param {Hook} handler - this can be async or sync
395
+ * @returns {void}
396
+ */
397
+ addHook(event, handler) {
398
+ this.onHook(event, handler);
399
+ }
400
+ /**
401
+ * Adds a handler function for a specific event
402
+ * @param {Array<HookEntry>} hooks
403
+ * @returns {void}
404
+ */
405
+ onHooks(hooks) {
406
+ for (const hook of hooks) {
407
+ this.onHook(hook.event, hook.handler);
408
+ }
409
+ }
410
+ /**
411
+ * Adds a handler function for a specific event that runs before all other handlers
412
+ * @param {string} event
413
+ * @param {Hook} handler - this can be async or sync
414
+ * @returns {void}
415
+ */
416
+ prependHook(event, handler) {
417
+ this.validateHookName(event);
418
+ if (!this.checkDeprecatedHook(event)) {
419
+ return;
420
+ }
421
+ const eventHandlers = this._hooks.get(event);
422
+ if (eventHandlers) {
423
+ eventHandlers.unshift(handler);
424
+ } else {
425
+ this._hooks.set(event, [handler]);
426
+ }
427
+ }
428
+ /**
429
+ * Adds a handler that only executes once for a specific event before all other handlers
430
+ * @param event
431
+ * @param handler
432
+ */
433
+ prependOnceHook(event, handler) {
434
+ this.validateHookName(event);
435
+ if (!this.checkDeprecatedHook(event)) {
436
+ return;
437
+ }
438
+ const hook = async (...arguments_) => {
439
+ this.removeHook(event, hook);
440
+ return handler(...arguments_);
441
+ };
442
+ this.prependHook(event, hook);
443
+ }
444
+ /**
445
+ * Adds a handler that only executes once for a specific event
446
+ * @param event
447
+ * @param handler
448
+ */
449
+ onceHook(event, handler) {
450
+ this.validateHookName(event);
451
+ if (!this.checkDeprecatedHook(event)) {
452
+ return;
453
+ }
454
+ const hook = async (...arguments_) => {
455
+ this.removeHook(event, hook);
456
+ return handler(...arguments_);
457
+ };
458
+ this.onHook(event, hook);
459
+ }
460
+ /**
461
+ * Removes a handler function for a specific event
462
+ * @param {string} event
463
+ * @param {Hook} handler
464
+ * @returns {void}
465
+ */
466
+ removeHook(event, handler) {
467
+ this.validateHookName(event);
468
+ if (!this.checkDeprecatedHook(event)) {
469
+ return;
470
+ }
471
+ const eventHandlers = this._hooks.get(event);
472
+ if (eventHandlers) {
473
+ const index = eventHandlers.indexOf(handler);
474
+ if (index !== -1) {
475
+ eventHandlers.splice(index, 1);
476
+ }
477
+ }
478
+ }
479
+ /**
480
+ * Removes all handlers for a specific event
481
+ * @param {Array<HookEntry>} hooks
482
+ * @returns {void}
483
+ */
484
+ removeHooks(hooks) {
485
+ for (const hook of hooks) {
486
+ this.removeHook(hook.event, hook.handler);
487
+ }
488
+ }
489
+ /**
490
+ * Calls all handlers for a specific event
491
+ * @param {string} event
492
+ * @param {T[]} arguments_
493
+ * @returns {Promise<void>}
494
+ */
495
+ async hook(event, ...arguments_) {
496
+ this.validateHookName(event);
497
+ if (!this.checkDeprecatedHook(event)) {
498
+ return;
499
+ }
500
+ const eventHandlers = this._hooks.get(event);
501
+ if (eventHandlers) {
502
+ for (const handler of eventHandlers) {
503
+ try {
504
+ await handler(...arguments_);
505
+ } catch (error) {
506
+ const message = `${event}: ${error.message}`;
507
+ this.emit("error", new Error(message));
508
+ if (this.logger) {
509
+ this.logger.error(message);
510
+ }
511
+ if (this._throwHookErrors) {
512
+ throw new Error(message);
513
+ }
514
+ }
515
+ }
516
+ }
517
+ }
518
+ /**
519
+ * Prepends the word `before` to your hook. Example is event is `test`, the before hook is `before:test`.
520
+ * @param {string} event - The event name
521
+ * @param {T[]} arguments_ - The arguments to pass to the hook
522
+ */
523
+ async beforeHook(event, ...arguments_) {
524
+ await this.hook(`before:${event}`, ...arguments_);
525
+ }
526
+ /**
527
+ * Prepends the word `after` to your hook. Example is event is `test`, the after hook is `after:test`.
528
+ * @param {string} event - The event name
529
+ * @param {T[]} arguments_ - The arguments to pass to the hook
530
+ */
531
+ async afterHook(event, ...arguments_) {
532
+ await this.hook(`after:${event}`, ...arguments_);
533
+ }
534
+ /**
535
+ * Calls all handlers for a specific event. This is an alias for `hook` and is provided for
536
+ * compatibility with other libraries that use the `callHook` method.
537
+ * @param {string} event
538
+ * @param {T[]} arguments_
539
+ * @returns {Promise<void>}
540
+ */
541
+ async callHook(event, ...arguments_) {
542
+ await this.hook(event, ...arguments_);
543
+ }
544
+ /**
545
+ * Gets all hooks for a specific event
546
+ * @param {string} event
547
+ * @returns {Hook[]}
548
+ */
549
+ getHooks(event) {
550
+ this.validateHookName(event);
551
+ if (!this.checkDeprecatedHook(event)) {
552
+ return void 0;
553
+ }
554
+ return this._hooks.get(event);
555
+ }
556
+ /**
557
+ * Removes all hooks
558
+ * @returns {void}
559
+ */
560
+ clearHooks() {
561
+ this._hooks.clear();
562
+ }
563
+ };
564
+ export {
565
+ Eventified,
566
+ Hookified
567
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hookified",
3
- "version": "1.12.0",
3
+ "version": "1.12.2",
4
4
  "description": "Event Emitting and Middleware Hooks",
5
5
  "type": "module",
6
6
  "main": "dist/node/index.cjs",
@@ -17,9 +17,9 @@
17
17
  },
18
18
  "types": "dist/node/index.d.ts",
19
19
  "scripts": {
20
- "lint": "biome check --write",
20
+ "lint": "biome check --write --error-on-warnings",
21
21
  "test": "pnpm lint && vitest run --coverage",
22
- "test:ci": "biome check && vitest run --coverage",
22
+ "test:ci": "biome check --error-on-warnings && vitest run --coverage",
23
23
  "clean": "rimraf ./dist ./coverage ./site/dist",
24
24
  "build": "rimraf ./dist && tsup",
25
25
  "benchmark": "pnpm benchmark:hooks && pnpm benchmark:emit",
@@ -61,20 +61,20 @@
61
61
  },
62
62
  "homepage": "https://github.com/jaredwray/hookified#readme",
63
63
  "devDependencies": {
64
- "@biomejs/biome": "^2.2.0",
65
- "@monstermann/tinybench-pretty-printer": "^0.1.0",
66
- "@types/node": "^24.3.0",
64
+ "@biomejs/biome": "^2.2.6",
65
+ "@monstermann/tinybench-pretty-printer": "^0.2.0",
66
+ "@types/node": "^24.7.2",
67
67
  "@vitest/coverage-v8": "^3.2.4",
68
- "docula": "^0.20.0",
68
+ "docula": "^0.30.0",
69
69
  "emittery": "^1.2.0",
70
70
  "eventemitter3": "^5.0.1",
71
71
  "hookable": "^5.5.3",
72
- "pino": "^9.9.0",
72
+ "pino": "^10.0.0",
73
73
  "rimraf": "^6.0.1",
74
- "tinybench": "^5.0.0",
74
+ "tinybench": "^5.0.1",
75
75
  "tsup": "^8.5.0",
76
- "tsx": "^4.20.4",
77
- "typescript": "^5.9.2",
76
+ "tsx": "^4.20.6",
77
+ "typescript": "^5.9.3",
78
78
  "vitest": "^3.2.4"
79
79
  },
80
80
  "files": [
@@ -83,7 +83,6 @@
83
83
  ],
84
84
  "pnpm": {
85
85
  "onlyBuiltDependencies": [
86
- "esbuild",
87
86
  "unrs-resolver"
88
87
  ]
89
88
  }