hookified 1.8.0 → 1.8.1

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 CHANGED
@@ -16,7 +16,8 @@
16
16
  - Browser Support and Delivered via CDN
17
17
  - Ability to throw errors in hooks
18
18
  - Ability to pass in a logger (such as Pino) for errors
19
- - No package dependencies
19
+ - No package dependencies and only 100KB in size
20
+ - Fast and Efficient with [Benchmarks](#benchmarks)
20
21
  - Maintained on a regular basis!
21
22
 
22
23
  # Table of Contents
@@ -48,6 +49,7 @@
48
49
  - [.listenerCount(eventName?)](#listenercounteventname)
49
50
  - [.rawListeners(eventName?)](#rawlistenerseventname)
50
51
  - [Development and Testing](#development-and-testing)
52
+ - [Benchmarks](#benchmarks)
51
53
  - [License](#license)
52
54
 
53
55
  # Installation
@@ -809,6 +811,29 @@ npm i && npm test
809
811
 
810
812
  To contribute follow the [Contributing Guidelines](CONTRIBUTING.md) and [Code of Conduct](CODE_OF_CONDUCT.md).
811
813
 
814
+ # Benchmarks
815
+
816
+ We are doing very simple benchmarking to see how this compares to other libraries using `tinybench`. This is not a full benchmark but just a simple way to see how it performs. Our goal is to be as close or better than the other libraries including native (EventEmitter).
817
+
818
+ ## Hooks
819
+ | name | summary | ops/sec | time/op | margin | samples |
820
+ |-------------------|:---------:|----------:|----------:|:--------:|----------:|
821
+ | Hookified 1.8.0 | 🥇 | 4M | 306ns | ±2.46% | 3M |
822
+ | Hookable ^5.5.3 | -71% | 1M | 1µs | ±2.93% | 826K |
823
+
824
+ ## Emits
825
+
826
+ This shows how close the native `EventEmitter` is to `hookified` and `eventemitter3`. We are using the same test as above but just emitting events. It is not a fair comparison but it is interesting to see how close they are.
827
+
828
+ | name | summary | ops/sec | time/op | margin | samples |
829
+ |-------------------------|:---------:|----------:|----------:|:--------:|----------:|
830
+ | Hookified 1.8.0 | 🥇 | 10M | 112ns | ±1.13% | 9M |
831
+ | EventEmitter3 5.0.1 | -1.3% | 10M | 114ns | ±1.84% | 9M |
832
+ | EventEmitter v22.12.0 | -1.5% | 9M | 114ns | ±1.18% | 9M |
833
+ | Emittery 1.1.0 | -92% | 785K | 1µs | ±0.45% | 761K |
834
+
835
+ _Note: the `EventEmitter` version is Nodejs versioning._
836
+
812
837
  # License
813
838
 
814
839
  [MIT & © Jared Wray](LICENSE)
@@ -1,393 +1 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var index_exports = {};
22
- __export(index_exports, {
23
- Eventified: () => Eventified,
24
- Hookified: () => Hookified
25
- });
26
- module.exports = __toCommonJS(index_exports);
27
-
28
- // src/eventified.ts
29
- var Eventified = class {
30
- _eventListeners;
31
- _maxListeners;
32
- _logger;
33
- constructor(options) {
34
- this._eventListeners = /* @__PURE__ */ new Map();
35
- this._maxListeners = 100;
36
- this._logger = options?.logger;
37
- }
38
- /**
39
- * Adds a handler function for a specific event that will run only once
40
- * @param {string | symbol} eventName
41
- * @param {EventListener} listener
42
- * @returns {IEventEmitter} returns the instance of the class for chaining
43
- */
44
- once(eventName, listener) {
45
- const onceListener = (...arguments_) => {
46
- this.off(eventName, onceListener);
47
- listener(...arguments_);
48
- };
49
- this.on(eventName, onceListener);
50
- return this;
51
- }
52
- /**
53
- * Gets the number of listeners for a specific event. If no event is provided, it returns the total number of listeners
54
- * @param {string} eventName The event name. Not required
55
- * @returns {number} The number of listeners
56
- */
57
- listenerCount(eventName) {
58
- if (!eventName) {
59
- return this.getAllListeners().length;
60
- }
61
- const listeners = this._eventListeners.get(eventName);
62
- return listeners ? listeners.length : 0;
63
- }
64
- /**
65
- * Gets an array of event names
66
- * @returns {Array<string | symbol>} An array of event names
67
- */
68
- eventNames() {
69
- return Array.from(this._eventListeners.keys());
70
- }
71
- /**
72
- * Gets an array of listeners for a specific event. If no event is provided, it returns all listeners
73
- * @param {string} [event] (Optional) The event name
74
- * @returns {EventListener[]} An array of listeners
75
- */
76
- rawListeners(event) {
77
- if (!event) {
78
- return this.getAllListeners();
79
- }
80
- return this._eventListeners.get(event) ?? [];
81
- }
82
- /**
83
- * Prepends a listener to the beginning of the listeners array for the specified event
84
- * @param {string | symbol} eventName
85
- * @param {EventListener} listener
86
- * @returns {IEventEmitter} returns the instance of the class for chaining
87
- */
88
- prependListener(eventName, listener) {
89
- const listeners = this._eventListeners.get(eventName) ?? [];
90
- listeners.unshift(listener);
91
- this._eventListeners.set(eventName, listeners);
92
- return this;
93
- }
94
- /**
95
- * Prepends a one-time listener to the beginning of the listeners array for the specified event
96
- * @param {string | symbol} eventName
97
- * @param {EventListener} listener
98
- * @returns {IEventEmitter} returns the instance of the class for chaining
99
- */
100
- prependOnceListener(eventName, listener) {
101
- const onceListener = (...arguments_) => {
102
- this.off(eventName, onceListener);
103
- listener(...arguments_);
104
- };
105
- this.prependListener(eventName, onceListener);
106
- return this;
107
- }
108
- /**
109
- * Gets the maximum number of listeners that can be added for a single event
110
- * @returns {number} The maximum number of listeners
111
- */
112
- maxListeners() {
113
- return this._maxListeners;
114
- }
115
- /**
116
- * Adds a listener for a specific event. It is an alias for the on() method
117
- * @param {string | symbol} event
118
- * @param {EventListener} listener
119
- * @returns {IEventEmitter} returns the instance of the class for chaining
120
- */
121
- addListener(event, listener) {
122
- this.on(event, listener);
123
- return this;
124
- }
125
- /**
126
- * Adds a listener for a specific event
127
- * @param {string | symbol} event
128
- * @param {EventListener} listener
129
- * @returns {IEventEmitter} returns the instance of the class for chaining
130
- */
131
- on(event, listener) {
132
- if (!this._eventListeners.has(event)) {
133
- this._eventListeners.set(event, []);
134
- }
135
- const listeners = this._eventListeners.get(event);
136
- if (listeners) {
137
- if (listeners.length >= this._maxListeners) {
138
- console.warn(`MaxListenersExceededWarning: Possible event memory leak detected. ${listeners.length + 1} ${event} listeners added. Use setMaxListeners() to increase limit.`);
139
- }
140
- listeners.push(listener);
141
- }
142
- return this;
143
- }
144
- /**
145
- * Removes a listener for a specific event. It is an alias for the off() method
146
- * @param {string | symbol} event
147
- * @param {EventListener} listener
148
- * @returns {IEventEmitter} returns the instance of the class for chaining
149
- */
150
- removeListener(event, listener) {
151
- this.off(event, listener);
152
- return this;
153
- }
154
- /**
155
- * Removes a listener for a specific event
156
- * @param {string | symbol} event
157
- * @param {EventListener} listener
158
- * @returns {IEventEmitter} returns the instance of the class for chaining
159
- */
160
- off(event, listener) {
161
- const listeners = this._eventListeners.get(event) ?? [];
162
- const index = listeners.indexOf(listener);
163
- if (index !== -1) {
164
- listeners.splice(index, 1);
165
- }
166
- if (listeners.length === 0) {
167
- this._eventListeners.delete(event);
168
- }
169
- return this;
170
- }
171
- /**
172
- * Calls all listeners for a specific event
173
- * @param {string | symbol} event
174
- * @param arguments_ The arguments to pass to the listeners
175
- * @returns {boolean} Returns true if the event had listeners, false otherwise
176
- */
177
- emit(event, ...arguments_) {
178
- let result = false;
179
- const listeners = this._eventListeners.get(event);
180
- if (listeners && listeners.length > 0) {
181
- for (const listener of listeners) {
182
- listener(...arguments_);
183
- result = true;
184
- }
185
- }
186
- return result;
187
- }
188
- /**
189
- * Gets all listeners for a specific event. If no event is provided, it returns all listeners
190
- * @param {string} [event] (Optional) The event name
191
- * @returns {EventListener[]} An array of listeners
192
- */
193
- listeners(event) {
194
- return this._eventListeners.get(event) ?? [];
195
- }
196
- /**
197
- * Removes all listeners for a specific event. If no event is provided, it removes all listeners
198
- * @param {string} [event] (Optional) The event name
199
- * @returns {IEventEmitter} returns the instance of the class for chaining
200
- */
201
- removeAllListeners(event) {
202
- if (event) {
203
- this._eventListeners.delete(event);
204
- } else {
205
- this._eventListeners.clear();
206
- }
207
- return this;
208
- }
209
- /**
210
- * Sets the maximum number of listeners that can be added for a single event
211
- * @param {number} n The maximum number of listeners
212
- * @returns {void}
213
- */
214
- setMaxListeners(n) {
215
- this._maxListeners = n;
216
- for (const listeners of this._eventListeners.values()) {
217
- if (listeners.length > n) {
218
- listeners.splice(n);
219
- }
220
- }
221
- }
222
- /**
223
- * Gets all listeners
224
- * @returns {EventListener[]} An array of listeners
225
- */
226
- getAllListeners() {
227
- let result = new Array();
228
- for (const listeners of this._eventListeners.values()) {
229
- result = result.concat(listeners);
230
- }
231
- return result;
232
- }
233
- };
234
-
235
- // src/index.ts
236
- var Hookified = class extends Eventified {
237
- _hooks;
238
- _throwHookErrors = false;
239
- constructor(options) {
240
- super({ logger: options?.logger });
241
- this._hooks = /* @__PURE__ */ new Map();
242
- if (options?.throwHookErrors !== void 0) {
243
- this._throwHookErrors = options.throwHookErrors;
244
- }
245
- }
246
- /**
247
- * Gets all hooks
248
- * @returns {Map<string, Hook[]>}
249
- */
250
- get hooks() {
251
- return this._hooks;
252
- }
253
- /**
254
- * Gets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
255
- * @returns {boolean}
256
- */
257
- get throwHookErrors() {
258
- return this._throwHookErrors;
259
- }
260
- /**
261
- * Sets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
262
- * @param {boolean} value
263
- */
264
- set throwHookErrors(value) {
265
- this._throwHookErrors = value;
266
- }
267
- /**
268
- * Gets the logger
269
- * @returns {Logger}
270
- */
271
- get logger() {
272
- return this._logger;
273
- }
274
- /**
275
- * Sets the logger
276
- * @param {Logger} logger
277
- */
278
- set logger(logger) {
279
- this._logger = logger;
280
- }
281
- /**
282
- * Adds a handler function for a specific event
283
- * @param {string} event
284
- * @param {Hook} handler - this can be async or sync
285
- * @returns {void}
286
- */
287
- onHook(event, handler) {
288
- const eventHandlers = this._hooks.get(event);
289
- if (eventHandlers) {
290
- eventHandlers.push(handler);
291
- } else {
292
- this._hooks.set(event, [handler]);
293
- }
294
- }
295
- /**
296
- * Adds a handler function for a specific event that runs before all other handlers
297
- * @param {string} event
298
- * @param {Hook} handler - this can be async or sync
299
- * @returns {void}
300
- */
301
- prependHook(event, handler) {
302
- const eventHandlers = this._hooks.get(event);
303
- if (eventHandlers) {
304
- eventHandlers.unshift(handler);
305
- } else {
306
- this._hooks.set(event, [handler]);
307
- }
308
- }
309
- /**
310
- * Adds a handler that only executes once for a specific event before all other handlers
311
- * @param event
312
- * @param handler
313
- */
314
- prependOnceHook(event, handler) {
315
- const hook = async (...arguments_) => {
316
- this.removeHook(event, hook);
317
- return handler(...arguments_);
318
- };
319
- this.prependHook(event, hook);
320
- }
321
- /**
322
- * Adds a handler that only executes once for a specific event
323
- * @param event
324
- * @param handler
325
- */
326
- onceHook(event, handler) {
327
- const hook = async (...arguments_) => {
328
- this.removeHook(event, hook);
329
- return handler(...arguments_);
330
- };
331
- this.onHook(event, hook);
332
- }
333
- /**
334
- * Removes a handler function for a specific event
335
- * @param {string} event
336
- * @param {Hook} handler
337
- * @returns {void}
338
- */
339
- removeHook(event, handler) {
340
- const eventHandlers = this._hooks.get(event);
341
- if (eventHandlers) {
342
- const index = eventHandlers.indexOf(handler);
343
- if (index !== -1) {
344
- eventHandlers.splice(index, 1);
345
- }
346
- }
347
- }
348
- /**
349
- * Calls all handlers for a specific event
350
- * @param {string} event
351
- * @param {T[]} arguments_
352
- * @returns {Promise<void>}
353
- */
354
- async hook(event, ...arguments_) {
355
- const eventHandlers = this._hooks.get(event);
356
- if (eventHandlers) {
357
- for (const handler of eventHandlers) {
358
- try {
359
- await handler(...arguments_);
360
- } catch (error) {
361
- const message = `${event}: ${error.message}`;
362
- this.emit("error", new Error(message));
363
- if (this._logger) {
364
- this._logger.error(message);
365
- }
366
- if (this._throwHookErrors) {
367
- throw new Error(message);
368
- }
369
- }
370
- }
371
- }
372
- }
373
- /**
374
- * Gets all hooks for a specific event
375
- * @param {string} event
376
- * @returns {Hook[]}
377
- */
378
- getHooks(event) {
379
- return this._hooks.get(event);
380
- }
381
- /**
382
- * Removes all hooks
383
- * @returns {void}
384
- */
385
- clearHooks() {
386
- this._hooks.clear();
387
- }
388
- };
389
- // Annotate the CommonJS export names for ESM import in node:
390
- 0 && (module.exports = {
391
- Eventified,
392
- Hookified
393
- });
1
+ "use strict";var g=Object.defineProperty;var a=Object.getOwnPropertyDescriptor;var h=Object.getOwnPropertyNames;var u=Object.prototype.hasOwnProperty;var v=(n,e)=>{for(var t in e)g(n,t,{get:e[t],enumerable:!0})},c=(n,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of h(e))!u.call(n,r)&&r!==t&&g(n,r,{get:()=>e[r],enumerable:!(s=a(e,r))||s.enumerable});return n};var p=n=>c(g({},"__esModule",{value:!0}),n);var E={};v(E,{Eventified:()=>i,Hookified:()=>m});module.exports=p(E);var i=class{_eventListeners;_maxListeners;_logger;constructor(e){this._eventListeners=new Map,this._maxListeners=100,this._logger=e?.logger}once(e,t){let s=(...r)=>{this.off(e,s),t(...r)};return this.on(e,s),this}listenerCount(e){if(!e)return this.getAllListeners().length;let t=this._eventListeners.get(e);return t?t.length:0}eventNames(){return Array.from(this._eventListeners.keys())}rawListeners(e){return e?this._eventListeners.get(e)??[]:this.getAllListeners()}prependListener(e,t){let s=this._eventListeners.get(e)??[];return s.unshift(t),this._eventListeners.set(e,s),this}prependOnceListener(e,t){let s=(...r)=>{this.off(e,s),t(...r)};return this.prependListener(e,s),this}maxListeners(){return this._maxListeners}addListener(e,t){return this.on(e,t),this}on(e,t){this._eventListeners.has(e)||this._eventListeners.set(e,[]);let s=this._eventListeners.get(e);return s&&(s.length>=this._maxListeners&&console.warn(`MaxListenersExceededWarning: Possible event memory leak detected. ${s.length+1} ${e} listeners added. Use setMaxListeners() to increase limit.`),s.push(t)),this}removeListener(e,t){return this.off(e,t),this}off(e,t){let s=this._eventListeners.get(e)??[],r=s.indexOf(t);return r!==-1&&s.splice(r,1),s.length===0&&this._eventListeners.delete(e),this}emit(e,...t){let s=!1,r=this._eventListeners.get(e);if(r&&r.length>0)for(let o of r)o(...t),s=!0;return s}listeners(e){return this._eventListeners.get(e)??[]}removeAllListeners(e){return e?this._eventListeners.delete(e):this._eventListeners.clear(),this}setMaxListeners(e){this._maxListeners=e;for(let t of this._eventListeners.values())t.length>e&&t.splice(e)}getAllListeners(){let e=new Array;for(let t of this._eventListeners.values())e=e.concat(t);return e}};var m=class extends i{_hooks;_throwHookErrors=!1;constructor(e){super({logger:e?.logger}),this._hooks=new Map,e?.throwHookErrors!==void 0&&(this._throwHookErrors=e.throwHookErrors)}get hooks(){return this._hooks}get throwHookErrors(){return this._throwHookErrors}set throwHookErrors(e){this._throwHookErrors=e}get logger(){return this._logger}set logger(e){this._logger=e}onHook(e,t){let s=this._hooks.get(e);s?s.push(t):this._hooks.set(e,[t])}prependHook(e,t){let s=this._hooks.get(e);s?s.unshift(t):this._hooks.set(e,[t])}prependOnceHook(e,t){let s=async(...r)=>(this.removeHook(e,s),t(...r));this.prependHook(e,s)}onceHook(e,t){let s=async(...r)=>(this.removeHook(e,s),t(...r));this.onHook(e,s)}removeHook(e,t){let s=this._hooks.get(e);if(s){let r=s.indexOf(t);r!==-1&&s.splice(r,1)}}async hook(e,...t){let s=this._hooks.get(e);if(s)for(let r of s)try{await r(...t)}catch(o){let l=`${e}: ${o.message}`;if(this.emit("error",new Error(l)),this._logger&&this._logger.error(l),this._throwHookErrors)throw new Error(l)}}getHooks(e){return this._hooks.get(e)}clearHooks(){this._hooks.clear()}};0&&(module.exports={Eventified,Hookified});
@@ -1,365 +1 @@
1
- // src/eventified.ts
2
- var Eventified = class {
3
- _eventListeners;
4
- _maxListeners;
5
- _logger;
6
- constructor(options) {
7
- this._eventListeners = /* @__PURE__ */ new Map();
8
- this._maxListeners = 100;
9
- this._logger = options?.logger;
10
- }
11
- /**
12
- * Adds a handler function for a specific event that will run only once
13
- * @param {string | symbol} eventName
14
- * @param {EventListener} listener
15
- * @returns {IEventEmitter} returns the instance of the class for chaining
16
- */
17
- once(eventName, listener) {
18
- const onceListener = (...arguments_) => {
19
- this.off(eventName, onceListener);
20
- listener(...arguments_);
21
- };
22
- this.on(eventName, onceListener);
23
- return this;
24
- }
25
- /**
26
- * Gets the number of listeners for a specific event. If no event is provided, it returns the total number of listeners
27
- * @param {string} eventName The event name. Not required
28
- * @returns {number} The number of listeners
29
- */
30
- listenerCount(eventName) {
31
- if (!eventName) {
32
- return this.getAllListeners().length;
33
- }
34
- const listeners = this._eventListeners.get(eventName);
35
- return listeners ? listeners.length : 0;
36
- }
37
- /**
38
- * Gets an array of event names
39
- * @returns {Array<string | symbol>} An array of event names
40
- */
41
- eventNames() {
42
- return Array.from(this._eventListeners.keys());
43
- }
44
- /**
45
- * Gets an array of listeners for a specific event. If no event is provided, it returns all listeners
46
- * @param {string} [event] (Optional) The event name
47
- * @returns {EventListener[]} An array of listeners
48
- */
49
- rawListeners(event) {
50
- if (!event) {
51
- return this.getAllListeners();
52
- }
53
- return this._eventListeners.get(event) ?? [];
54
- }
55
- /**
56
- * Prepends a listener to the beginning of the listeners array for the specified event
57
- * @param {string | symbol} eventName
58
- * @param {EventListener} listener
59
- * @returns {IEventEmitter} returns the instance of the class for chaining
60
- */
61
- prependListener(eventName, listener) {
62
- const listeners = this._eventListeners.get(eventName) ?? [];
63
- listeners.unshift(listener);
64
- this._eventListeners.set(eventName, listeners);
65
- return this;
66
- }
67
- /**
68
- * Prepends a one-time listener to the beginning of the listeners array for the specified event
69
- * @param {string | symbol} eventName
70
- * @param {EventListener} listener
71
- * @returns {IEventEmitter} returns the instance of the class for chaining
72
- */
73
- prependOnceListener(eventName, listener) {
74
- const onceListener = (...arguments_) => {
75
- this.off(eventName, onceListener);
76
- listener(...arguments_);
77
- };
78
- this.prependListener(eventName, onceListener);
79
- return this;
80
- }
81
- /**
82
- * Gets the maximum number of listeners that can be added for a single event
83
- * @returns {number} The maximum number of listeners
84
- */
85
- maxListeners() {
86
- return this._maxListeners;
87
- }
88
- /**
89
- * Adds a listener for a specific event. It is an alias for the on() method
90
- * @param {string | symbol} event
91
- * @param {EventListener} listener
92
- * @returns {IEventEmitter} returns the instance of the class for chaining
93
- */
94
- addListener(event, listener) {
95
- this.on(event, listener);
96
- return this;
97
- }
98
- /**
99
- * Adds a listener for a specific event
100
- * @param {string | symbol} event
101
- * @param {EventListener} listener
102
- * @returns {IEventEmitter} returns the instance of the class for chaining
103
- */
104
- on(event, listener) {
105
- if (!this._eventListeners.has(event)) {
106
- this._eventListeners.set(event, []);
107
- }
108
- const listeners = this._eventListeners.get(event);
109
- if (listeners) {
110
- if (listeners.length >= this._maxListeners) {
111
- console.warn(`MaxListenersExceededWarning: Possible event memory leak detected. ${listeners.length + 1} ${event} listeners added. Use setMaxListeners() to increase limit.`);
112
- }
113
- listeners.push(listener);
114
- }
115
- return this;
116
- }
117
- /**
118
- * Removes a listener for a specific event. It is an alias for the off() method
119
- * @param {string | symbol} event
120
- * @param {EventListener} listener
121
- * @returns {IEventEmitter} returns the instance of the class for chaining
122
- */
123
- removeListener(event, listener) {
124
- this.off(event, listener);
125
- return this;
126
- }
127
- /**
128
- * Removes a listener for a specific event
129
- * @param {string | symbol} event
130
- * @param {EventListener} listener
131
- * @returns {IEventEmitter} returns the instance of the class for chaining
132
- */
133
- off(event, listener) {
134
- const listeners = this._eventListeners.get(event) ?? [];
135
- const index = listeners.indexOf(listener);
136
- if (index !== -1) {
137
- listeners.splice(index, 1);
138
- }
139
- if (listeners.length === 0) {
140
- this._eventListeners.delete(event);
141
- }
142
- return this;
143
- }
144
- /**
145
- * Calls all listeners for a specific event
146
- * @param {string | symbol} event
147
- * @param arguments_ The arguments to pass to the listeners
148
- * @returns {boolean} Returns true if the event had listeners, false otherwise
149
- */
150
- emit(event, ...arguments_) {
151
- let result = false;
152
- const listeners = this._eventListeners.get(event);
153
- if (listeners && listeners.length > 0) {
154
- for (const listener of listeners) {
155
- listener(...arguments_);
156
- result = true;
157
- }
158
- }
159
- return result;
160
- }
161
- /**
162
- * Gets all listeners for a specific event. If no event is provided, it returns all listeners
163
- * @param {string} [event] (Optional) The event name
164
- * @returns {EventListener[]} An array of listeners
165
- */
166
- listeners(event) {
167
- return this._eventListeners.get(event) ?? [];
168
- }
169
- /**
170
- * Removes all listeners for a specific event. If no event is provided, it removes all listeners
171
- * @param {string} [event] (Optional) The event name
172
- * @returns {IEventEmitter} returns the instance of the class for chaining
173
- */
174
- removeAllListeners(event) {
175
- if (event) {
176
- this._eventListeners.delete(event);
177
- } else {
178
- this._eventListeners.clear();
179
- }
180
- return this;
181
- }
182
- /**
183
- * Sets the maximum number of listeners that can be added for a single event
184
- * @param {number} n The maximum number of listeners
185
- * @returns {void}
186
- */
187
- setMaxListeners(n) {
188
- this._maxListeners = n;
189
- for (const listeners of this._eventListeners.values()) {
190
- if (listeners.length > n) {
191
- listeners.splice(n);
192
- }
193
- }
194
- }
195
- /**
196
- * Gets all listeners
197
- * @returns {EventListener[]} An array of listeners
198
- */
199
- getAllListeners() {
200
- let result = new Array();
201
- for (const listeners of this._eventListeners.values()) {
202
- result = result.concat(listeners);
203
- }
204
- return result;
205
- }
206
- };
207
-
208
- // src/index.ts
209
- var Hookified = class extends Eventified {
210
- _hooks;
211
- _throwHookErrors = false;
212
- constructor(options) {
213
- super({ logger: options?.logger });
214
- this._hooks = /* @__PURE__ */ new Map();
215
- if (options?.throwHookErrors !== void 0) {
216
- this._throwHookErrors = options.throwHookErrors;
217
- }
218
- }
219
- /**
220
- * Gets all hooks
221
- * @returns {Map<string, Hook[]>}
222
- */
223
- get hooks() {
224
- return this._hooks;
225
- }
226
- /**
227
- * Gets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
228
- * @returns {boolean}
229
- */
230
- get throwHookErrors() {
231
- return this._throwHookErrors;
232
- }
233
- /**
234
- * Sets whether an error should be thrown when a hook throws an error. Default is false and only emits an error event.
235
- * @param {boolean} value
236
- */
237
- set throwHookErrors(value) {
238
- this._throwHookErrors = value;
239
- }
240
- /**
241
- * Gets the logger
242
- * @returns {Logger}
243
- */
244
- get logger() {
245
- return this._logger;
246
- }
247
- /**
248
- * Sets the logger
249
- * @param {Logger} logger
250
- */
251
- set logger(logger) {
252
- this._logger = logger;
253
- }
254
- /**
255
- * Adds a handler function for a specific event
256
- * @param {string} event
257
- * @param {Hook} handler - this can be async or sync
258
- * @returns {void}
259
- */
260
- onHook(event, handler) {
261
- const eventHandlers = this._hooks.get(event);
262
- if (eventHandlers) {
263
- eventHandlers.push(handler);
264
- } else {
265
- this._hooks.set(event, [handler]);
266
- }
267
- }
268
- /**
269
- * Adds a handler function for a specific event that runs before all other handlers
270
- * @param {string} event
271
- * @param {Hook} handler - this can be async or sync
272
- * @returns {void}
273
- */
274
- prependHook(event, handler) {
275
- const eventHandlers = this._hooks.get(event);
276
- if (eventHandlers) {
277
- eventHandlers.unshift(handler);
278
- } else {
279
- this._hooks.set(event, [handler]);
280
- }
281
- }
282
- /**
283
- * Adds a handler that only executes once for a specific event before all other handlers
284
- * @param event
285
- * @param handler
286
- */
287
- prependOnceHook(event, handler) {
288
- const hook = async (...arguments_) => {
289
- this.removeHook(event, hook);
290
- return handler(...arguments_);
291
- };
292
- this.prependHook(event, hook);
293
- }
294
- /**
295
- * Adds a handler that only executes once for a specific event
296
- * @param event
297
- * @param handler
298
- */
299
- onceHook(event, handler) {
300
- const hook = async (...arguments_) => {
301
- this.removeHook(event, hook);
302
- return handler(...arguments_);
303
- };
304
- this.onHook(event, hook);
305
- }
306
- /**
307
- * Removes a handler function for a specific event
308
- * @param {string} event
309
- * @param {Hook} handler
310
- * @returns {void}
311
- */
312
- removeHook(event, handler) {
313
- const eventHandlers = this._hooks.get(event);
314
- if (eventHandlers) {
315
- const index = eventHandlers.indexOf(handler);
316
- if (index !== -1) {
317
- eventHandlers.splice(index, 1);
318
- }
319
- }
320
- }
321
- /**
322
- * Calls all handlers for a specific event
323
- * @param {string} event
324
- * @param {T[]} arguments_
325
- * @returns {Promise<void>}
326
- */
327
- async hook(event, ...arguments_) {
328
- const eventHandlers = this._hooks.get(event);
329
- if (eventHandlers) {
330
- for (const handler of eventHandlers) {
331
- try {
332
- await handler(...arguments_);
333
- } catch (error) {
334
- const message = `${event}: ${error.message}`;
335
- this.emit("error", new Error(message));
336
- if (this._logger) {
337
- this._logger.error(message);
338
- }
339
- if (this._throwHookErrors) {
340
- throw new Error(message);
341
- }
342
- }
343
- }
344
- }
345
- }
346
- /**
347
- * Gets all hooks for a specific event
348
- * @param {string} event
349
- * @returns {Hook[]}
350
- */
351
- getHooks(event) {
352
- return this._hooks.get(event);
353
- }
354
- /**
355
- * Removes all hooks
356
- * @returns {void}
357
- */
358
- clearHooks() {
359
- this._hooks.clear();
360
- }
361
- };
362
- export {
363
- Eventified,
364
- Hookified
365
- };
1
+ var n=class{_eventListeners;_maxListeners;_logger;constructor(e){this._eventListeners=new Map,this._maxListeners=100,this._logger=e?.logger}once(e,s){let t=(...r)=>{this.off(e,t),s(...r)};return this.on(e,t),this}listenerCount(e){if(!e)return this.getAllListeners().length;let s=this._eventListeners.get(e);return s?s.length:0}eventNames(){return Array.from(this._eventListeners.keys())}rawListeners(e){return e?this._eventListeners.get(e)??[]:this.getAllListeners()}prependListener(e,s){let t=this._eventListeners.get(e)??[];return t.unshift(s),this._eventListeners.set(e,t),this}prependOnceListener(e,s){let t=(...r)=>{this.off(e,t),s(...r)};return this.prependListener(e,t),this}maxListeners(){return this._maxListeners}addListener(e,s){return this.on(e,s),this}on(e,s){this._eventListeners.has(e)||this._eventListeners.set(e,[]);let t=this._eventListeners.get(e);return t&&(t.length>=this._maxListeners&&console.warn(`MaxListenersExceededWarning: Possible event memory leak detected. ${t.length+1} ${e} listeners added. Use setMaxListeners() to increase limit.`),t.push(s)),this}removeListener(e,s){return this.off(e,s),this}off(e,s){let t=this._eventListeners.get(e)??[],r=t.indexOf(s);return r!==-1&&t.splice(r,1),t.length===0&&this._eventListeners.delete(e),this}emit(e,...s){let t=!1,r=this._eventListeners.get(e);if(r&&r.length>0)for(let i of r)i(...s),t=!0;return t}listeners(e){return this._eventListeners.get(e)??[]}removeAllListeners(e){return e?this._eventListeners.delete(e):this._eventListeners.clear(),this}setMaxListeners(e){this._maxListeners=e;for(let s of this._eventListeners.values())s.length>e&&s.splice(e)}getAllListeners(){let e=new Array;for(let s of this._eventListeners.values())e=e.concat(s);return e}};var l=class extends n{_hooks;_throwHookErrors=!1;constructor(e){super({logger:e?.logger}),this._hooks=new Map,e?.throwHookErrors!==void 0&&(this._throwHookErrors=e.throwHookErrors)}get hooks(){return this._hooks}get throwHookErrors(){return this._throwHookErrors}set throwHookErrors(e){this._throwHookErrors=e}get logger(){return this._logger}set logger(e){this._logger=e}onHook(e,s){let t=this._hooks.get(e);t?t.push(s):this._hooks.set(e,[s])}prependHook(e,s){let t=this._hooks.get(e);t?t.unshift(s):this._hooks.set(e,[s])}prependOnceHook(e,s){let t=async(...r)=>(this.removeHook(e,t),s(...r));this.prependHook(e,t)}onceHook(e,s){let t=async(...r)=>(this.removeHook(e,t),s(...r));this.onHook(e,t)}removeHook(e,s){let t=this._hooks.get(e);if(t){let r=t.indexOf(s);r!==-1&&t.splice(r,1)}}async hook(e,...s){let t=this._hooks.get(e);if(t)for(let r of t)try{await r(...s)}catch(i){let o=`${e}: ${i.message}`;if(this.emit("error",new Error(o)),this._logger&&this._logger.error(o),this._throwHookErrors)throw new Error(o)}}getHooks(e){return this._hooks.get(e)}clearHooks(){this._hooks.clear()}};export{n as Eventified,l as Hookified};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hookified",
3
- "version": "1.8.0",
3
+ "version": "1.8.1",
4
4
  "description": "Event Emitting and Middleware Hooks",
5
5
  "type": "module",
6
6
  "main": "dist/node/index.cjs",
@@ -21,6 +21,9 @@
21
21
  "test:ci": "xo && vitest run --coverage",
22
22
  "clean": "rimraf ./dist ./coverage ./site/dist",
23
23
  "build": "rimraf ./dist && tsup",
24
+ "benchmark": "pnpm benchmark:hooks && pnpm benchmark:emit",
25
+ "benchmark:hooks": "pnpm tsx benchmark/hook.ts",
26
+ "benchmark:emit": "pnpm tsx benchmark/emit.ts",
24
27
  "website:build": "docula build",
25
28
  "website:serve": "docula serve",
26
29
  "prepare": "npm run build"
@@ -57,11 +60,17 @@
57
60
  },
58
61
  "homepage": "https://github.com/jaredwray/hookified#readme",
59
62
  "devDependencies": {
63
+ "@monstermann/tinybench-pretty-printer": "^0.0.0",
60
64
  "@vitest/coverage-v8": "^3.0.8",
61
65
  "docula": "^0.10.1",
66
+ "emittery": "^1.1.0",
67
+ "eventemitter3": "^5.0.1",
68
+ "hookable": "^5.5.3",
62
69
  "pino": "^9.6.0",
63
70
  "rimraf": "^6.0.1",
71
+ "tinybench": "^3.1.1",
64
72
  "tsup": "^8.4.0",
73
+ "tsx": "^4.19.3",
65
74
  "typescript": "^5.8.2",
66
75
  "vitest": "^3.0.8",
67
76
  "xo": "^0.60.0"