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