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