hookified 1.15.0 → 2.0.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.
- package/README.md +958 -707
- package/dist/browser/index.global.js +283 -155
- package/dist/browser/index.global.js.map +1 -1
- package/dist/browser/index.js +286 -156
- package/dist/browser/index.js.map +1 -1
- package/dist/node/index.cjs +289 -157
- package/dist/node/index.d.cts +206 -79
- package/dist/node/index.d.ts +206 -79
- package/dist/node/index.js +286 -156
- package/package.json +10 -9
package/dist/browser/index.js
CHANGED
|
@@ -7,13 +7,13 @@ var Eventified = class {
|
|
|
7
7
|
constructor(options) {
|
|
8
8
|
__publicField(this, "_eventListeners");
|
|
9
9
|
__publicField(this, "_maxListeners");
|
|
10
|
-
__publicField(this, "
|
|
10
|
+
__publicField(this, "_eventLogger");
|
|
11
11
|
__publicField(this, "_throwOnEmitError", false);
|
|
12
|
-
__publicField(this, "_throwOnEmptyListeners",
|
|
12
|
+
__publicField(this, "_throwOnEmptyListeners", true);
|
|
13
13
|
__publicField(this, "_errorEvent", "error");
|
|
14
14
|
this._eventListeners = /* @__PURE__ */ new Map();
|
|
15
|
-
this._maxListeners =
|
|
16
|
-
this.
|
|
15
|
+
this._maxListeners = 0;
|
|
16
|
+
this._eventLogger = options?.eventLogger;
|
|
17
17
|
if (options?.throwOnEmitError !== void 0) {
|
|
18
18
|
this._throwOnEmitError = options.throwOnEmitError;
|
|
19
19
|
}
|
|
@@ -22,18 +22,18 @@ var Eventified = class {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
|
-
* Gets the logger
|
|
25
|
+
* Gets the event logger
|
|
26
26
|
* @returns {Logger}
|
|
27
27
|
*/
|
|
28
|
-
get
|
|
29
|
-
return this.
|
|
28
|
+
get eventLogger() {
|
|
29
|
+
return this._eventLogger;
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
32
|
-
* Sets the logger
|
|
33
|
-
* @param {Logger}
|
|
32
|
+
* Sets the event logger
|
|
33
|
+
* @param {Logger} eventLogger
|
|
34
34
|
*/
|
|
35
|
-
set
|
|
36
|
-
this.
|
|
35
|
+
set eventLogger(eventLogger) {
|
|
36
|
+
this._eventLogger = eventLogger;
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
39
|
* Gets whether an error should be thrown when an emit throws an error. Default is false and only emits an error event.
|
|
@@ -162,7 +162,7 @@ var Eventified = class {
|
|
|
162
162
|
}
|
|
163
163
|
const listeners = this._eventListeners.get(event);
|
|
164
164
|
if (listeners) {
|
|
165
|
-
if (listeners.length >= this._maxListeners) {
|
|
165
|
+
if (this._maxListeners > 0 && listeners.length >= this._maxListeners) {
|
|
166
166
|
console.warn(
|
|
167
167
|
`MaxListenersExceededWarning: Possible event memory leak detected. ${listeners.length + 1} ${event} listeners added. Use setMaxListeners() to increase limit.`
|
|
168
168
|
);
|
|
@@ -213,6 +213,7 @@ var Eventified = class {
|
|
|
213
213
|
result = true;
|
|
214
214
|
}
|
|
215
215
|
}
|
|
216
|
+
this.sendToEventLogger(event, arguments_);
|
|
216
217
|
if (event === this._errorEvent) {
|
|
217
218
|
const error = arguments_[0] instanceof Error ? arguments_[0] : new Error(`${arguments_[0]}`);
|
|
218
219
|
if (this._throwOnEmitError && !result) {
|
|
@@ -223,7 +224,6 @@ var Eventified = class {
|
|
|
223
224
|
}
|
|
224
225
|
}
|
|
225
226
|
}
|
|
226
|
-
this.sendLog(event, arguments_);
|
|
227
227
|
return result;
|
|
228
228
|
}
|
|
229
229
|
/**
|
|
@@ -253,12 +253,7 @@ var Eventified = class {
|
|
|
253
253
|
* @returns {void}
|
|
254
254
|
*/
|
|
255
255
|
setMaxListeners(n) {
|
|
256
|
-
this._maxListeners = n;
|
|
257
|
-
for (const listeners of this._eventListeners.values()) {
|
|
258
|
-
if (listeners.length > n) {
|
|
259
|
-
listeners.splice(n);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
256
|
+
this._maxListeners = n < 0 ? 0 : n;
|
|
262
257
|
}
|
|
263
258
|
/**
|
|
264
259
|
* Gets all listeners
|
|
@@ -276,8 +271,8 @@ var Eventified = class {
|
|
|
276
271
|
* @param {string | symbol} eventName - The event name that determines the log level
|
|
277
272
|
* @param {unknown} data - The data to log
|
|
278
273
|
*/
|
|
279
|
-
|
|
280
|
-
if (!this.
|
|
274
|
+
sendToEventLogger(eventName, data) {
|
|
275
|
+
if (!this._eventLogger) {
|
|
281
276
|
return;
|
|
282
277
|
}
|
|
283
278
|
let message;
|
|
@@ -294,38 +289,106 @@ var Eventified = class {
|
|
|
294
289
|
}
|
|
295
290
|
switch (eventName) {
|
|
296
291
|
case "error": {
|
|
297
|
-
this.
|
|
292
|
+
this._eventLogger.error?.(message, { event: eventName, data });
|
|
298
293
|
break;
|
|
299
294
|
}
|
|
300
295
|
case "warn": {
|
|
301
|
-
this.
|
|
296
|
+
this._eventLogger.warn?.(message, { event: eventName, data });
|
|
302
297
|
break;
|
|
303
298
|
}
|
|
304
299
|
case "trace": {
|
|
305
|
-
this.
|
|
300
|
+
this._eventLogger.trace?.(message, { event: eventName, data });
|
|
306
301
|
break;
|
|
307
302
|
}
|
|
308
303
|
case "debug": {
|
|
309
|
-
this.
|
|
304
|
+
this._eventLogger.debug?.(message, { event: eventName, data });
|
|
310
305
|
break;
|
|
311
306
|
}
|
|
312
307
|
case "fatal": {
|
|
313
|
-
this.
|
|
308
|
+
this._eventLogger.fatal?.(message, { event: eventName, data });
|
|
314
309
|
break;
|
|
315
310
|
}
|
|
316
311
|
default: {
|
|
317
|
-
this.
|
|
312
|
+
this._eventLogger.info?.(message, { event: eventName, data });
|
|
318
313
|
break;
|
|
319
314
|
}
|
|
320
315
|
}
|
|
321
316
|
}
|
|
322
317
|
};
|
|
323
318
|
|
|
319
|
+
// src/hooks/hook.ts
|
|
320
|
+
var Hook = class {
|
|
321
|
+
/**
|
|
322
|
+
* Creates a new Hook instance
|
|
323
|
+
* @param {string} event - The event name for the hook
|
|
324
|
+
* @param {HookFn} handler - The handler function for the hook
|
|
325
|
+
* @param {string} [id] - Optional unique identifier for the hook
|
|
326
|
+
*/
|
|
327
|
+
constructor(event, handler, id) {
|
|
328
|
+
__publicField(this, "id");
|
|
329
|
+
__publicField(this, "event");
|
|
330
|
+
__publicField(this, "handler");
|
|
331
|
+
this.id = id;
|
|
332
|
+
this.event = event;
|
|
333
|
+
this.handler = handler;
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
// src/hooks/waterfall-hook.ts
|
|
338
|
+
var WaterfallHook = class {
|
|
339
|
+
/**
|
|
340
|
+
* Creates a new WaterfallHook instance
|
|
341
|
+
* @param {string} event - The event name for the hook
|
|
342
|
+
* @param {WaterfallHookFn} finalHandler - The final handler function that receives the transformed result
|
|
343
|
+
* @param {string} [id] - Optional unique identifier for the hook
|
|
344
|
+
*/
|
|
345
|
+
constructor(event, finalHandler, id) {
|
|
346
|
+
__publicField(this, "id");
|
|
347
|
+
__publicField(this, "event");
|
|
348
|
+
__publicField(this, "handler");
|
|
349
|
+
__publicField(this, "hooks");
|
|
350
|
+
__publicField(this, "_finalHandler");
|
|
351
|
+
this.id = id;
|
|
352
|
+
this.event = event;
|
|
353
|
+
this.hooks = [];
|
|
354
|
+
this._finalHandler = finalHandler;
|
|
355
|
+
this.handler = async (...arguments_) => {
|
|
356
|
+
const initialArgs = arguments_.length === 1 ? arguments_[0] : arguments_;
|
|
357
|
+
const results = [];
|
|
358
|
+
for (const hook of this.hooks) {
|
|
359
|
+
const result = await hook({ initialArgs, results: [...results] });
|
|
360
|
+
results.push({ hook, result });
|
|
361
|
+
}
|
|
362
|
+
await this._finalHandler({ initialArgs, results: [...results] });
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Adds a hook function to the end of the waterfall chain
|
|
367
|
+
* @param {WaterfallHookFn} hook - The hook function to add
|
|
368
|
+
*/
|
|
369
|
+
addHook(hook) {
|
|
370
|
+
this.hooks.push(hook);
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Removes a specific hook function from the waterfall chain
|
|
374
|
+
* @param {WaterfallHookFn} hook - The hook function to remove
|
|
375
|
+
* @returns {boolean} true if the hook was found and removed
|
|
376
|
+
*/
|
|
377
|
+
removeHook(hook) {
|
|
378
|
+
const index = this.hooks.indexOf(hook);
|
|
379
|
+
if (index !== -1) {
|
|
380
|
+
this.hooks.splice(index, 1);
|
|
381
|
+
return true;
|
|
382
|
+
}
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
|
|
324
387
|
// src/index.ts
|
|
325
388
|
var Hookified = class extends Eventified {
|
|
326
389
|
constructor(options) {
|
|
327
390
|
super({
|
|
328
|
-
|
|
391
|
+
eventLogger: options?.eventLogger,
|
|
329
392
|
throwOnEmitError: options?.throwOnEmitError,
|
|
330
393
|
throwOnEmptyListeners: options?.throwOnEmptyListeners
|
|
331
394
|
});
|
|
@@ -334,12 +397,11 @@ var Hookified = class extends Eventified {
|
|
|
334
397
|
__publicField(this, "_enforceBeforeAfter", false);
|
|
335
398
|
__publicField(this, "_deprecatedHooks");
|
|
336
399
|
__publicField(this, "_allowDeprecated", true);
|
|
400
|
+
__publicField(this, "_useHookClone", true);
|
|
337
401
|
this._hooks = /* @__PURE__ */ new Map();
|
|
338
402
|
this._deprecatedHooks = options?.deprecatedHooks ? new Map(options.deprecatedHooks) : /* @__PURE__ */ new Map();
|
|
339
403
|
if (options?.throwOnHookError !== void 0) {
|
|
340
404
|
this._throwOnHookError = options.throwOnHookError;
|
|
341
|
-
} else if (options?.throwHookErrors !== void 0) {
|
|
342
|
-
this._throwOnHookError = options.throwHookErrors;
|
|
343
405
|
}
|
|
344
406
|
if (options?.enforceBeforeAfter !== void 0) {
|
|
345
407
|
this._enforceBeforeAfter = options.enforceBeforeAfter;
|
|
@@ -347,30 +409,17 @@ var Hookified = class extends Eventified {
|
|
|
347
409
|
if (options?.allowDeprecated !== void 0) {
|
|
348
410
|
this._allowDeprecated = options.allowDeprecated;
|
|
349
411
|
}
|
|
412
|
+
if (options?.useHookClone !== void 0) {
|
|
413
|
+
this._useHookClone = options.useHookClone;
|
|
414
|
+
}
|
|
350
415
|
}
|
|
351
416
|
/**
|
|
352
417
|
* Gets all hooks
|
|
353
|
-
* @returns {Map<string,
|
|
418
|
+
* @returns {Map<string, IHook[]>}
|
|
354
419
|
*/
|
|
355
420
|
get hooks() {
|
|
356
421
|
return this._hooks;
|
|
357
422
|
}
|
|
358
|
-
/**
|
|
359
|
-
* Gets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
|
|
360
|
-
* @returns {boolean}
|
|
361
|
-
* @deprecated - this will be deprecated in version 2. Please use throwOnHookError.
|
|
362
|
-
*/
|
|
363
|
-
get throwHookErrors() {
|
|
364
|
-
return this._throwOnHookError;
|
|
365
|
-
}
|
|
366
|
-
/**
|
|
367
|
-
* Sets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
|
|
368
|
-
* @param {boolean} value
|
|
369
|
-
* @deprecated - this will be deprecated in version 2. Please use throwOnHookError.
|
|
370
|
-
*/
|
|
371
|
-
set throwHookErrors(value) {
|
|
372
|
-
this._throwOnHookError = value;
|
|
373
|
-
}
|
|
374
423
|
/**
|
|
375
424
|
* Gets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
|
|
376
425
|
* @returns {boolean}
|
|
@@ -429,157 +478,153 @@ var Hookified = class extends Eventified {
|
|
|
429
478
|
this._allowDeprecated = value;
|
|
430
479
|
}
|
|
431
480
|
/**
|
|
432
|
-
*
|
|
433
|
-
* @
|
|
434
|
-
* @throws {Error} If enforceBeforeAfter is true and event doesn't start with 'before' or 'after'
|
|
435
|
-
*/
|
|
436
|
-
validateHookName(event) {
|
|
437
|
-
if (this._enforceBeforeAfter) {
|
|
438
|
-
const eventValue = event.trim().toLocaleLowerCase();
|
|
439
|
-
if (!eventValue.startsWith("before") && !eventValue.startsWith("after")) {
|
|
440
|
-
throw new Error(
|
|
441
|
-
`Hook event "${event}" must start with "before" or "after" when enforceBeforeAfter is enabled`
|
|
442
|
-
);
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
/**
|
|
447
|
-
* Checks if a hook is deprecated and emits a warning if it is
|
|
448
|
-
* @param {string} event - The event name to check
|
|
449
|
-
* @returns {boolean} - Returns true if the hook should proceed, false if it should be blocked
|
|
481
|
+
* Gets whether hook objects are cloned before storing. Default is true.
|
|
482
|
+
* @returns {boolean}
|
|
450
483
|
*/
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
const message = this._deprecatedHooks.get(event);
|
|
454
|
-
const warningMessage = `Hook "${event}" is deprecated${message ? `: ${message}` : ""}`;
|
|
455
|
-
this.emit("warn", { hook: event, message: warningMessage });
|
|
456
|
-
return this._allowDeprecated;
|
|
457
|
-
}
|
|
458
|
-
return true;
|
|
484
|
+
get useHookClone() {
|
|
485
|
+
return this._useHookClone;
|
|
459
486
|
}
|
|
460
487
|
/**
|
|
461
|
-
*
|
|
462
|
-
*
|
|
463
|
-
* @param {
|
|
464
|
-
* @returns {void}
|
|
488
|
+
* Sets whether hook objects are cloned before storing. Default is true.
|
|
489
|
+
* When false, the original IHook reference is stored directly.
|
|
490
|
+
* @param {boolean} value
|
|
465
491
|
*/
|
|
466
|
-
|
|
467
|
-
this.
|
|
492
|
+
set useHookClone(value) {
|
|
493
|
+
this._useHookClone = value;
|
|
468
494
|
}
|
|
469
495
|
/**
|
|
470
|
-
* Adds a handler function for a specific event
|
|
471
|
-
* @
|
|
472
|
-
* @
|
|
496
|
+
* Adds a handler function for a specific event.
|
|
497
|
+
* If you prefer the legacy `(event, handler)` signature, use {@link addHook} instead.
|
|
498
|
+
* To register multiple hooks at once, use {@link onHooks}.
|
|
499
|
+
* @param {IHook} hook - the hook containing event name and handler
|
|
500
|
+
* @param {OnHookOptions} [options] - optional per-call options (e.g., useHookClone override, position)
|
|
501
|
+
* @returns {IHook | undefined} the stored hook, or undefined if blocked by deprecation
|
|
473
502
|
*/
|
|
474
|
-
|
|
475
|
-
this.validateHookName(
|
|
476
|
-
if (!this.checkDeprecatedHook(
|
|
477
|
-
return;
|
|
503
|
+
onHook(hook, options) {
|
|
504
|
+
this.validateHookName(hook.event);
|
|
505
|
+
if (!this.checkDeprecatedHook(hook.event)) {
|
|
506
|
+
return void 0;
|
|
478
507
|
}
|
|
479
|
-
const
|
|
508
|
+
const shouldClone = options?.useHookClone ?? this._useHookClone;
|
|
509
|
+
const entry = shouldClone ? { id: hook.id, event: hook.event, handler: hook.handler } : hook;
|
|
510
|
+
entry.id = entry.id ?? crypto.randomUUID();
|
|
511
|
+
const eventHandlers = this._hooks.get(hook.event);
|
|
480
512
|
if (eventHandlers) {
|
|
481
|
-
eventHandlers.
|
|
513
|
+
const existingIndex = eventHandlers.findIndex((h) => h.id === entry.id);
|
|
514
|
+
if (existingIndex !== -1) {
|
|
515
|
+
eventHandlers[existingIndex] = entry;
|
|
516
|
+
} else {
|
|
517
|
+
const position = options?.position ?? "Bottom";
|
|
518
|
+
if (position === "Top") {
|
|
519
|
+
eventHandlers.unshift(entry);
|
|
520
|
+
} else if (position === "Bottom") {
|
|
521
|
+
eventHandlers.push(entry);
|
|
522
|
+
} else {
|
|
523
|
+
const index = Math.max(0, Math.min(position, eventHandlers.length));
|
|
524
|
+
eventHandlers.splice(index, 0, entry);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
482
527
|
} else {
|
|
483
|
-
this._hooks.set(
|
|
528
|
+
this._hooks.set(hook.event, [entry]);
|
|
484
529
|
}
|
|
530
|
+
return entry;
|
|
485
531
|
}
|
|
486
532
|
/**
|
|
487
533
|
* Alias for onHook. This is provided for compatibility with other libraries that use the `addHook` method.
|
|
488
|
-
* @param {string} event
|
|
489
|
-
* @param {
|
|
534
|
+
* @param {string} event - the event name
|
|
535
|
+
* @param {HookFn} handler - the handler function
|
|
490
536
|
* @returns {void}
|
|
491
537
|
*/
|
|
492
538
|
addHook(event, handler) {
|
|
493
|
-
this.
|
|
539
|
+
this.onHook({ event, handler });
|
|
494
540
|
}
|
|
495
541
|
/**
|
|
496
|
-
* Adds
|
|
497
|
-
* @param {Array<
|
|
542
|
+
* Adds handler functions for specific events
|
|
543
|
+
* @param {Array<IHook>} hooks
|
|
544
|
+
* @param {OnHookOptions} [options] - optional per-call options (e.g., useHookClone override, position)
|
|
498
545
|
* @returns {void}
|
|
499
546
|
*/
|
|
500
|
-
onHooks(hooks) {
|
|
547
|
+
onHooks(hooks, options) {
|
|
501
548
|
for (const hook of hooks) {
|
|
502
|
-
this.onHook(hook
|
|
549
|
+
this.onHook(hook, options);
|
|
503
550
|
}
|
|
504
551
|
}
|
|
505
552
|
/**
|
|
506
|
-
* Adds a handler function for a specific event that runs before all other handlers
|
|
507
|
-
*
|
|
508
|
-
* @param {
|
|
509
|
-
* @
|
|
553
|
+
* Adds a handler function for a specific event that runs before all other handlers.
|
|
554
|
+
* Equivalent to calling `onHook(hook, { position: "Top" })`.
|
|
555
|
+
* @param {IHook} hook - the hook containing event name and handler
|
|
556
|
+
* @param {PrependHookOptions} [options] - optional per-call options (e.g., useHookClone override)
|
|
557
|
+
* @returns {IHook | undefined} the stored hook, or undefined if blocked by deprecation
|
|
510
558
|
*/
|
|
511
|
-
prependHook(
|
|
512
|
-
this.
|
|
513
|
-
if (!this.checkDeprecatedHook(event)) {
|
|
514
|
-
return;
|
|
515
|
-
}
|
|
516
|
-
const eventHandlers = this._hooks.get(event);
|
|
517
|
-
if (eventHandlers) {
|
|
518
|
-
eventHandlers.unshift(handler);
|
|
519
|
-
} else {
|
|
520
|
-
this._hooks.set(event, [handler]);
|
|
521
|
-
}
|
|
559
|
+
prependHook(hook, options) {
|
|
560
|
+
return this.onHook(hook, { ...options, position: "Top" });
|
|
522
561
|
}
|
|
523
562
|
/**
|
|
524
|
-
* Adds a handler that only executes once for a specific event before all other handlers
|
|
525
|
-
*
|
|
526
|
-
* @param handler
|
|
563
|
+
* Adds a handler that only executes once for a specific event before all other handlers.
|
|
564
|
+
* Equivalent to calling `onHook` with a self-removing wrapper and `{ position: "Top" }`.
|
|
565
|
+
* @param {IHook} hook - the hook containing event name and handler
|
|
566
|
+
* @param {PrependHookOptions} [options] - optional per-call options (e.g., useHookClone override)
|
|
567
|
+
* @returns {IHook | undefined} the stored hook, or undefined if blocked by deprecation
|
|
527
568
|
*/
|
|
528
|
-
prependOnceHook(
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
return;
|
|
532
|
-
}
|
|
533
|
-
const hook = async (...arguments_) => {
|
|
534
|
-
this.removeHook(event, hook);
|
|
535
|
-
return handler(...arguments_);
|
|
569
|
+
prependOnceHook(hook, options) {
|
|
570
|
+
const wrappedHandler = async (...arguments_) => {
|
|
571
|
+
this.removeHook({ event: hook.event, handler: wrappedHandler });
|
|
572
|
+
return hook.handler(...arguments_);
|
|
536
573
|
};
|
|
537
|
-
this.
|
|
574
|
+
return this.onHook(
|
|
575
|
+
{ id: hook.id, event: hook.event, handler: wrappedHandler },
|
|
576
|
+
{ ...options, position: "Top" }
|
|
577
|
+
);
|
|
538
578
|
}
|
|
539
579
|
/**
|
|
540
580
|
* Adds a handler that only executes once for a specific event
|
|
541
|
-
* @param event
|
|
542
|
-
* @param handler
|
|
581
|
+
* @param {IHook} hook - the hook containing event name and handler
|
|
543
582
|
*/
|
|
544
|
-
onceHook(
|
|
545
|
-
this.validateHookName(event);
|
|
546
|
-
if (!this.checkDeprecatedHook(event)) {
|
|
583
|
+
onceHook(hook) {
|
|
584
|
+
this.validateHookName(hook.event);
|
|
585
|
+
if (!this.checkDeprecatedHook(hook.event)) {
|
|
547
586
|
return;
|
|
548
587
|
}
|
|
549
|
-
const
|
|
550
|
-
this.removeHook(event,
|
|
551
|
-
return handler(...arguments_);
|
|
588
|
+
const wrappedHandler = async (...arguments_) => {
|
|
589
|
+
this.removeHook({ event: hook.event, handler: wrappedHandler });
|
|
590
|
+
return hook.handler(...arguments_);
|
|
552
591
|
};
|
|
553
|
-
this.onHook(event,
|
|
592
|
+
this.onHook({ id: hook.id, event: hook.event, handler: wrappedHandler });
|
|
554
593
|
}
|
|
555
594
|
/**
|
|
556
595
|
* Removes a handler function for a specific event
|
|
557
|
-
* @param {
|
|
558
|
-
* @
|
|
559
|
-
* @returns {void}
|
|
596
|
+
* @param {IHook} hook - the hook containing event name and handler to remove
|
|
597
|
+
* @returns {IHook | undefined} the removed hook, or undefined if not found
|
|
560
598
|
*/
|
|
561
|
-
removeHook(
|
|
562
|
-
this.validateHookName(event);
|
|
563
|
-
|
|
564
|
-
return;
|
|
565
|
-
}
|
|
566
|
-
const eventHandlers = this._hooks.get(event);
|
|
599
|
+
removeHook(hook) {
|
|
600
|
+
this.validateHookName(hook.event);
|
|
601
|
+
const eventHandlers = this._hooks.get(hook.event);
|
|
567
602
|
if (eventHandlers) {
|
|
568
|
-
const index = eventHandlers.
|
|
603
|
+
const index = eventHandlers.findIndex((h) => h.handler === hook.handler);
|
|
569
604
|
if (index !== -1) {
|
|
570
605
|
eventHandlers.splice(index, 1);
|
|
606
|
+
if (eventHandlers.length === 0) {
|
|
607
|
+
this._hooks.delete(hook.event);
|
|
608
|
+
}
|
|
609
|
+
return { event: hook.event, handler: hook.handler };
|
|
571
610
|
}
|
|
572
611
|
}
|
|
612
|
+
return void 0;
|
|
573
613
|
}
|
|
574
614
|
/**
|
|
575
|
-
* Removes
|
|
576
|
-
* @param {Array<
|
|
577
|
-
* @returns {
|
|
615
|
+
* Removes multiple hook handlers
|
|
616
|
+
* @param {Array<IHook>} hooks
|
|
617
|
+
* @returns {IHook[]} the hooks that were successfully removed
|
|
578
618
|
*/
|
|
579
619
|
removeHooks(hooks) {
|
|
620
|
+
const removed = [];
|
|
580
621
|
for (const hook of hooks) {
|
|
581
|
-
this.removeHook(hook
|
|
622
|
+
const result = this.removeHook(hook);
|
|
623
|
+
if (result) {
|
|
624
|
+
removed.push(result);
|
|
625
|
+
}
|
|
582
626
|
}
|
|
627
|
+
return removed;
|
|
583
628
|
}
|
|
584
629
|
/**
|
|
585
630
|
* Calls all handlers for a specific event
|
|
@@ -594,9 +639,9 @@ var Hookified = class extends Eventified {
|
|
|
594
639
|
}
|
|
595
640
|
const eventHandlers = this._hooks.get(event);
|
|
596
641
|
if (eventHandlers) {
|
|
597
|
-
for (const
|
|
642
|
+
for (const hook of [...eventHandlers]) {
|
|
598
643
|
try {
|
|
599
|
-
await handler(...arguments_);
|
|
644
|
+
await hook.handler(...arguments_);
|
|
600
645
|
} catch (error) {
|
|
601
646
|
const message = `${event}: ${error.message}`;
|
|
602
647
|
this.emit("error", new Error(message));
|
|
@@ -624,12 +669,12 @@ var Hookified = class extends Eventified {
|
|
|
624
669
|
}
|
|
625
670
|
const eventHandlers = this._hooks.get(event);
|
|
626
671
|
if (eventHandlers) {
|
|
627
|
-
for (const
|
|
628
|
-
if (handler.constructor.name === "AsyncFunction") {
|
|
672
|
+
for (const hook of [...eventHandlers]) {
|
|
673
|
+
if (hook.handler.constructor.name === "AsyncFunction") {
|
|
629
674
|
continue;
|
|
630
675
|
}
|
|
631
676
|
try {
|
|
632
|
-
handler(...arguments_);
|
|
677
|
+
hook.handler(...arguments_);
|
|
633
678
|
} catch (error) {
|
|
634
679
|
const message = `${event}: ${error.message}`;
|
|
635
680
|
this.emit("error", new Error(message));
|
|
@@ -669,15 +714,54 @@ var Hookified = class extends Eventified {
|
|
|
669
714
|
/**
|
|
670
715
|
* Gets all hooks for a specific event
|
|
671
716
|
* @param {string} event
|
|
672
|
-
* @returns {
|
|
717
|
+
* @returns {IHook[]}
|
|
673
718
|
*/
|
|
674
719
|
getHooks(event) {
|
|
675
720
|
this.validateHookName(event);
|
|
676
|
-
if (!this.checkDeprecatedHook(event)) {
|
|
677
|
-
return void 0;
|
|
678
|
-
}
|
|
679
721
|
return this._hooks.get(event);
|
|
680
722
|
}
|
|
723
|
+
/**
|
|
724
|
+
* Gets a specific hook by id, searching across all events
|
|
725
|
+
* @param {string} id - the hook id
|
|
726
|
+
* @returns {IHook | undefined} the hook if found, or undefined
|
|
727
|
+
*/
|
|
728
|
+
getHook(id) {
|
|
729
|
+
for (const eventHandlers of this._hooks.values()) {
|
|
730
|
+
const found = eventHandlers.find((h) => h.id === id);
|
|
731
|
+
if (found) {
|
|
732
|
+
return found;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
return void 0;
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Removes one or more hooks by id, searching across all events
|
|
739
|
+
* @param {string | string[]} id - the hook id or array of hook ids to remove
|
|
740
|
+
* @returns {IHook | IHook[] | undefined} the removed hook(s), or undefined/empty array if not found
|
|
741
|
+
*/
|
|
742
|
+
removeHookById(id) {
|
|
743
|
+
if (Array.isArray(id)) {
|
|
744
|
+
const removed = [];
|
|
745
|
+
for (const singleId of id) {
|
|
746
|
+
const result = this.removeHookById(singleId);
|
|
747
|
+
if (result && !Array.isArray(result)) {
|
|
748
|
+
removed.push(result);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
return removed;
|
|
752
|
+
}
|
|
753
|
+
for (const [event, eventHandlers] of this._hooks.entries()) {
|
|
754
|
+
const index = eventHandlers.findIndex((h) => h.id === id);
|
|
755
|
+
if (index !== -1) {
|
|
756
|
+
const [removed] = eventHandlers.splice(index, 1);
|
|
757
|
+
if (eventHandlers.length === 0) {
|
|
758
|
+
this._hooks.delete(event);
|
|
759
|
+
}
|
|
760
|
+
return removed;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
return void 0;
|
|
764
|
+
}
|
|
681
765
|
/**
|
|
682
766
|
* Removes all hooks
|
|
683
767
|
* @returns {void}
|
|
@@ -685,10 +769,56 @@ var Hookified = class extends Eventified {
|
|
|
685
769
|
clearHooks() {
|
|
686
770
|
this._hooks.clear();
|
|
687
771
|
}
|
|
772
|
+
/**
|
|
773
|
+
* Removes all hooks for a specific event and returns the removed hooks.
|
|
774
|
+
* @param {string} event - The event name to remove hooks for.
|
|
775
|
+
* @returns {IHook[]} the hooks that were removed
|
|
776
|
+
*/
|
|
777
|
+
removeEventHooks(event) {
|
|
778
|
+
this.validateHookName(event);
|
|
779
|
+
const eventHandlers = this._hooks.get(event);
|
|
780
|
+
if (eventHandlers) {
|
|
781
|
+
const removed = [...eventHandlers];
|
|
782
|
+
this._hooks.delete(event);
|
|
783
|
+
return removed;
|
|
784
|
+
}
|
|
785
|
+
return [];
|
|
786
|
+
}
|
|
787
|
+
/**
|
|
788
|
+
* Validates hook event name if enforceBeforeAfter is enabled
|
|
789
|
+
* @param {string} event - The event name to validate
|
|
790
|
+
* @throws {Error} If enforceBeforeAfter is true and event doesn't start with 'before' or 'after'
|
|
791
|
+
*/
|
|
792
|
+
validateHookName(event) {
|
|
793
|
+
if (this._enforceBeforeAfter) {
|
|
794
|
+
const eventValue = event.trim().toLocaleLowerCase();
|
|
795
|
+
if (!eventValue.startsWith("before") && !eventValue.startsWith("after")) {
|
|
796
|
+
throw new Error(
|
|
797
|
+
`Hook event "${event}" must start with "before" or "after" when enforceBeforeAfter is enabled`
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
/**
|
|
803
|
+
* Checks if a hook is deprecated and emits a warning if it is
|
|
804
|
+
* @param {string} event - The event name to check
|
|
805
|
+
* @returns {boolean} - Returns true if the hook should proceed, false if it should be blocked
|
|
806
|
+
*/
|
|
807
|
+
checkDeprecatedHook(event) {
|
|
808
|
+
if (this._deprecatedHooks.has(event)) {
|
|
809
|
+
const message = this._deprecatedHooks.get(event);
|
|
810
|
+
const warningMessage = `Hook "${event}" is deprecated${message ? `: ${message}` : ""}`;
|
|
811
|
+
this.emit("warn", { hook: event, message: warningMessage });
|
|
812
|
+
return this._allowDeprecated;
|
|
813
|
+
}
|
|
814
|
+
return true;
|
|
815
|
+
}
|
|
688
816
|
};
|
|
689
817
|
export {
|
|
690
818
|
Eventified,
|
|
691
|
-
|
|
819
|
+
Hook,
|
|
820
|
+
Hookified,
|
|
821
|
+
WaterfallHook
|
|
692
822
|
};
|
|
693
823
|
/* v8 ignore next -- @preserve */
|
|
694
824
|
//# sourceMappingURL=index.js.map
|