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