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