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