@supercat1337/event-emitter 1.0.10 → 1.0.11

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.
Files changed (4) hide show
  1. package/README.md +194 -65
  2. package/package.json +29 -29
  3. package/src/index.js +139 -32
  4. package/tests/test.js +50 -60
package/README.md CHANGED
@@ -1,92 +1,221 @@
1
- # event-emitter
1
+ # @supercat1337/event-emitter 🐈⚡
2
2
 
3
- ## Environment agnostic event emitter
3
+ A modern, feature-rich EventEmitter implementation for JavaScript and TypeScript with advanced capabilities and excellent type safety.
4
4
 
5
- This package allows you to create an event emitter that can be used in any environment.
6
- You can define types for the events that you want to emit and listen to.
5
+ ## Features
7
6
 
8
- ### Installation
9
- ```
10
- $ npm install @supercat1337/event-emitter
7
+ - ✅ **Full TypeScript support** with generics and complete type definitions
8
+ - 🎯 **Promise-based event waiting** with timeout support
9
+ - 📊 **Listener lifecycle tracking** - know when events gain/lose listeners
10
+ - 🛡️ **Memory safe** - automatic cleanup and unsubscribe functions
11
+ - ⚡ **High performance** - optimized for frequent events
12
+ - 🔒 **Immutable patterns** - listener arrays are copied during emission
13
+ - 🚀 **Modern ES2022+** - private fields, arrow functions, and more
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @supercat1337/event-emitter
11
19
  ```
12
20
 
13
- ### Methods
14
- - on(event, listener) - Add a callback function that's going to be executed when the event is triggered. Returns a function that can be used to unsubscribe from the event
15
- - emit(event) - Trigger an event.
16
- - once(event, listener) - Add a callback function that's going to be executed only once when the event is triggered. Returns a function that can be used to unsubscribe from the event
17
- - removeListener(event, listener) - Remove an event listener.
18
- - waitForEvent(event, max_wait_ms = 0) - Wait for an event to be emitted. If max_wait_ms is set to 0, the function will wait indefinitely.
19
- - waitForAnyEvent(events, max_wait_ms = 0) - Wait for any of the specified events to be emitted. If max_wait_ms is set to 0, the function will wait indefinitely.
20
- - clear() - Remove all event listeners
21
- - clearEventListeners(event) - Remove all listeners for a specified event
22
- - onHasEventListeners(callback) - Subscribe to the "#has-listeners" event. This event is emitted when the number of listeners for any event (except "#has-listeners" and "#no-listeners") goes from 0 to 1.
23
- - onNoEventListeners(callback) - Subscribe to the "#no-listeners" event. This event is emitted when the number of listeners for any event (except "#has-listeners" and "#no-listeners") goes from 1 to 0.
24
-
25
- ### Usage
26
-
27
- Basic example
28
- ```js
29
- import { EventEmitter } from "@supercat1337/event-emitter";
21
+ ## Quick Start
22
+
23
+ ```javascript
24
+ import { EventEmitter } from '@supercat1337/event-emitter';
30
25
 
31
- // Create an event emitter with a custom event type
32
- /** @type {EventEmitter<"foo">} */
33
- var ev = new EventEmitter();
26
+ // Define your event types
27
+ type AppEvents = 'user:created' | 'user:deleted' | 'notification:sent';
34
28
 
35
- ev.on("foo", () => {
36
- console.log("Hello!");
29
+ const emitter = new EventEmitter<AppEvents>();
30
+
31
+ // Subscribe to events
32
+ const unsubscribe = emitter.on('user:created', (userData) => {
33
+ console.log('User created:', userData);
37
34
  });
38
35
 
39
- // IDE will complain if we emit an event that doesn't exist
40
- ev.emit("bar"); // $ExpectError
41
- ev.emit("foo");
36
+ // Emit events
37
+ emitter.emit('user:created', { id: 1, name: 'John' });
38
+
39
+ // Unsubscribe when done
40
+ unsubscribe();
42
41
  ```
43
42
 
44
- Example of unsubscribing from an event
45
- ```js
46
- import { EventEmitter } from "@supercat1337/event-emitter";
43
+ ## API Reference
44
+
45
+ ### Core Methods
47
46
 
48
- /** @type {EventEmitter<"foo">} */
49
- var ev = new EventEmitter;
50
- var foo = 0
51
- var action = () => {
52
- foo++;
53
- };
47
+ #### `on(event, listener)`
54
48
 
55
- var unsubscriber = ev.on("foo", action);
49
+ Subscribe to an event. Returns an unsubscribe function.
56
50
 
57
- ev.emit("foo");
58
- unsubscriber();
51
+ ```javascript
52
+ const unsubscribe = emitter.on("user:created", (data) => {
53
+ console.log(data);
54
+ });
55
+
56
+ // Later...
57
+ unsubscribe();
58
+ ```
59
59
 
60
- ev.emit("foo");
60
+ #### `off(event, listener)`
61
61
 
62
- if (foo == 1) {
63
- console.log("Success!");
64
- } else {
65
- console.log("Fail!");
62
+ Remove a specific listener from an event.
63
+
64
+ ```javascript
65
+ function listener(data) {
66
+ /* ... */
66
67
  }
68
+ emitter.on("user:created", listener);
69
+ emitter.off("user:created", listener);
67
70
  ```
68
71
 
69
- Example of using the Once method
70
- ```js
71
- import { EventEmitter } from "@supercat1337/event-emitter";
72
+ #### `emit(event, ...args)`
73
+
74
+ Emit an event with optional arguments.
75
+
76
+ ```javascript
77
+ emitter.emit("user:created", { id: 1, name: "Alice" });
78
+ ```
79
+
80
+ #### `once(event, listener)`
72
81
 
73
- /** @type {EventEmitter<"foo">} */
74
- var ev = new EventEmitter;
82
+ Add a one-time listener that auto-removes after execution.
75
83
 
76
- var foo = 0
84
+ ```javascript
85
+ emitter.once("app:ready", () => {
86
+ console.log("App is ready!");
87
+ });
88
+ ```
89
+
90
+ ### Advanced Methods
91
+
92
+ #### `waitForEvent(event, [maxWaitMs])`
93
+
94
+ Wait for an event using Promises.
95
+
96
+ ```javascript
97
+ // Wait indefinitely
98
+ const result = await emitter.waitForEvent("data:loaded");
99
+
100
+ // Wait with timeout (returns false if timeout reached)
101
+ const success = await emitter.waitForEvent("data:loaded", 5000);
102
+ ```
103
+
104
+ #### `waitForAnyEvent(events, [maxWaitMs])`
77
105
 
78
- ev.once("foo", () => {
79
- foo++;
106
+ Wait for any of multiple events.
107
+
108
+ ```javascript
109
+ const events = ['success', 'error', 'timeout'] as const;
110
+ const result = await emitter.waitForAnyEvent(events, 3000);
111
+ ```
112
+
113
+ #### `onHasEventListeners(callback)`
114
+
115
+ Get notified when any event gains its first listener.
116
+
117
+ ```javascript
118
+ emitter.onHasEventListeners((eventName) => {
119
+ console.log(`Event ${eventName} now has listeners!`);
80
120
  });
121
+ ```
81
122
 
82
- ev.emit("foo");
83
- ev.emit("foo");
84
- ev.emit("foo");
123
+ #### `onNoEventListeners(callback)`
85
124
 
86
- if (foo == 1) {
87
- console.log("Success!");
88
- } else {
89
- console.log("Fail!");
90
- }
125
+ Get notified when any event loses its last listener.
126
+
127
+ ```javascript
128
+ emitter.onNoEventListeners((eventName) => {
129
+ console.log(`Event ${eventName} has no more listeners!`);
130
+ });
91
131
  ```
92
132
 
133
+ ### Lifecycle Management
134
+
135
+ #### `destroy()`
136
+
137
+ Completely destroy the emitter and clean up all resources.
138
+
139
+ ```javascript
140
+ emitter.destroy();
141
+ console.log(emitter.isDestroyed); // true
142
+ ```
143
+
144
+ #### `clear()`
145
+
146
+ Remove all listeners while keeping the emitter functional.
147
+
148
+ ```javascript
149
+ emitter.clear();
150
+ ```
151
+
152
+ #### `clearEventListeners(event)`
153
+
154
+ Remove all listeners for a specific event.
155
+
156
+ ```javascript
157
+ emitter.clearEventListeners("user:created");
158
+ ```
159
+
160
+ ## TypeScript Usage
161
+
162
+ ```typescript
163
+ import { EventEmitter } from "@supercat1337/event-emitter";
164
+
165
+ // Define your event types
166
+ type MyEvents =
167
+ | "user:created"
168
+ | "user:updated"
169
+ | { type: "user:deleted"; payload: { id: string; reason: string } };
170
+
171
+ const emitter = new EventEmitter<MyEvents>();
172
+
173
+ // Full type safety!
174
+ emitter.emit("user:created", { id: 1, name: "John" }); // ✅ Correct
175
+ emitter.emit("user:created", "invalid"); // ❌ Type error
176
+ ```
177
+
178
+ ## Error Handling
179
+
180
+ All listener errors are caught and logged to console, preventing emitter crashes:
181
+
182
+ ```javascript
183
+ emitter.on("data:received", () => {
184
+ throw new Error("Something went wrong!");
185
+ });
186
+
187
+ // Error is caught and logged, emitter continues working
188
+ emitter.emit("data:received");
189
+ ```
190
+
191
+ ## Performance Notes
192
+
193
+ - 🔄 Listener arrays are copied before iteration to allow safe modification during emission
194
+ - ⚡ Event existence checks are optimized with direct property access
195
+ - 🗑️ Automatic cleanup prevents memory leaks
196
+ - 📏 No external dependencies
197
+
198
+ ## Browser Support
199
+
200
+ | Feature | Support |
201
+ | ---------- | --------------- |
202
+ | ES2022+ | Modern browsers |
203
+ | TypeScript | 4.0+ |
204
+ | Node.js | 14+ |
205
+
206
+ ## License
207
+
208
+ MIT License - feel free to use in commercial projects.
209
+
210
+ ## Contributing
211
+
212
+ Contributions welcome! Please ensure:
213
+
214
+ - ✅ All tests pass
215
+ - ✅ TypeScript types are maintained
216
+ - ✅ New features include tests
217
+ - ✅ Code follows existing style
218
+
219
+ ---
220
+
221
+ **Made with ❤️ by [supercat1337](https://github.com/supercat1337)**
package/package.json CHANGED
@@ -1,32 +1,32 @@
1
1
  {
2
- "name": "@supercat1337/event-emitter",
3
- "version": "1.0.10",
4
- "description": "Event Emitter",
5
- "main": "index.js",
6
- "scripts": {
7
- "test": "c8 ava",
8
- "build": "npm run remove_type_files && npm run build_esm && npm run build_esm_min && npm run create_types",
9
- "build_esm": "rollup ./src/index.js --file ./dist/event-emitter.esm.js --format es",
10
- "build_esm_min": "esbuild --minify --bundle --platform=neutral --legal-comments=none ./src/index.js --outfile=./dist/event-emitter.esm.min.js",
11
- "create_types": "npx -p typescript tsc --project my.tsconfig.types.json",
12
- "remove_type_files": "del /q *.d.ts *.d.ts.map && cd dist && del /s /q *.d.ts *.d.ts.map && cd ../src && del /s /q *.d.ts *.d.ts.map && cd .."
2
+ "name": "@supercat1337/event-emitter",
3
+ "version": "1.0.11",
4
+ "description": "Event Emitter",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "c8 ava",
8
+ "build": "npm run remove_type_files && npm run build_esm && npm run build_esm_min && npm run create_types",
9
+ "build_esm": "rollup ./src/index.js --file ./dist/event-emitter.esm.js --format es",
10
+ "build_esm_min": "esbuild --minify --bundle --platform=neutral --legal-comments=none ./src/index.js --outfile=./dist/event-emitter.esm.min.js",
11
+ "create_types": "npx -p typescript tsc --project my.tsconfig.types.json",
12
+ "remove_type_files": "del /q *.d.ts *.d.ts.map && cd dist && del /s /q *.d.ts *.d.ts.map && cd ../src && del /s /q *.d.ts *.d.ts.map && cd .."
13
13
  },
14
- "author": "Supercat",
15
- "license": "MIT",
16
- "devDependencies": {
17
- "ava": "^6.1.2",
18
- "c8": "^9.1.0",
19
- "esbuild": "^0.20.2",
20
- "@types/node": "^20.12.2"
21
- },
22
- "type": "module",
23
- "moduleResolution": "nodenext",
24
- "keywords": [
25
- "typed event emitter",
26
- "typed event bus"
27
- ],
28
- "publishConfig": {
29
- "registry": "https://registry.npmjs.org"
30
- },
31
- "homepage": "https://github.com/supercat1337/event-emitter"
14
+ "author": "Supercat",
15
+ "license": "MIT",
16
+ "devDependencies": {
17
+ "ava": "^6.1.2",
18
+ "c8": "^9.1.0",
19
+ "esbuild": "^0.20.2",
20
+ "@types/node": "^20.12.2"
21
+ },
22
+ "type": "module",
23
+ "moduleResolution": "nodenext",
24
+ "keywords": [
25
+ "typed event emitter",
26
+ "typed event bus"
27
+ ],
28
+ "publishConfig": {
29
+ "registry": "https://registry.npmjs.org"
30
+ },
31
+ "homepage": "https://github.com/supercat1337/event-emitter"
32
32
  }
package/src/index.js CHANGED
@@ -8,15 +8,31 @@ class EventEmitter {
8
8
  /** @type {Object.<string, Function[]>} */
9
9
  events = {};
10
10
 
11
+ /** @type {Object.<"#has-listeners"|"#no-listeners", Function[]>} */
12
+ #internalEvents = { "#has-listeners": [], "#no-listeners": [] };
13
+
14
+ #isDestroyed = false;
15
+
16
+ /**
17
+ * Is the event emitter destroyed?
18
+ * @type {boolean}
19
+ */
20
+ get isDestroyed() {
21
+ return this.#isDestroyed;
22
+ }
23
+
11
24
  /**
12
25
  * on is used to add a callback function that's going to be executed when the event is triggered
13
- * @param {T|"#has-listeners"|"#no-listeners"} event
26
+ * @param {T} event
14
27
  * @param {Function} listener
15
28
  * @returns {()=>void}
16
29
  */
17
30
  on(event, listener) {
31
+ if (this.#isDestroyed) {
32
+ throw new Error("EventEmitter is destroyed");
33
+ }
18
34
 
19
- if (typeof this.events[event] !== 'object') {
35
+ if (typeof this.events[event] !== "object") {
20
36
  this.events[event] = [];
21
37
  }
22
38
 
@@ -28,61 +44,141 @@ class EventEmitter {
28
44
  that.removeListener(event, listener);
29
45
  };
30
46
 
31
- if (!/^(#has-listeners|#no-listeners)$/.test(event) && this.events[event].length == 1) {
32
- this.emit("#has-listeners", event);
47
+ if (this.events[event].length == 1) {
48
+ this.#emitInternal("#has-listeners", event);
33
49
  }
34
50
 
35
51
  return unsubscriber;
36
52
  }
53
+
54
+ /**
55
+ * Internal method to add a listener to an internal event
56
+ * @param {"#has-listeners"|"#no-listeners"} event
57
+ * @param {Function} listener
58
+ * @returns {()=>void}
59
+ */
60
+ #onInternalEvent(event, listener) {
61
+ if (typeof this.#internalEvents[event] !== "object") {
62
+ return;
63
+ }
64
+ this.#internalEvents[event].push(listener);
65
+
66
+ let that = this;
67
+
68
+ let unsubscriber = function () {
69
+ that.#removeInternalListener(event, listener);
70
+ };
71
+ return unsubscriber;
72
+ }
73
+
74
+ /**
75
+ * Internal method to remove a listener from an internal event
76
+ * @param {"#has-listeners"|"#no-listeners"} event
77
+ * @param {Function} listener
78
+ */
79
+ #removeInternalListener(event, listener) {
80
+ var idx;
81
+
82
+ if (typeof this.#internalEvents[event] === "object") {
83
+ idx = this.#internalEvents[event].indexOf(listener);
84
+
85
+ if (idx > -1) {
86
+ this.#internalEvents[event].splice(idx, 1);
87
+ }
88
+ }
89
+ }
90
+
91
+ /**
92
+ * off is an alias for removeListener
93
+ * @param {T} event
94
+ * @param {Function} listener
95
+ */
96
+ off(event, listener) {
97
+ return this.removeListener(event, listener);
98
+ }
99
+
37
100
  /**
38
101
  * Remove an event listener from an event
39
- * @param {T|"#has-listeners"|"#no-listeners"} event
102
+ * @param {T} event
40
103
  * @param {Function} listener
41
104
  */
42
105
  removeListener(event, listener) {
106
+ if (this.#isDestroyed) {
107
+ return;
108
+ }
43
109
  var idx;
44
110
 
45
- if (typeof this.events[event] === 'object') {
46
- idx = this.events[event].indexOf(listener);
111
+ if (!this.events[event]) return;
112
+ idx = this.events[event].indexOf(listener);
47
113
 
48
- if (idx > -1) {
49
- this.events[event].splice(idx, 1);
114
+ if (idx > -1) {
115
+ this.events[event].splice(idx, 1);
50
116
 
51
- if (!/^(#has-listeners|#no-listeners)$/.test(event) && this.events[event].length == 0) {
52
- this.emit("#no-listeners", event);
53
- }
117
+ if (this.events[event].length == 0) {
118
+ this.#emitInternal("#no-listeners", event);
54
119
  }
55
120
  }
56
-
57
121
  }
122
+
58
123
  /**
59
124
  * emit is used to trigger an event
60
- * @param {T|"#has-listeners"|"#no-listeners"} event
125
+ * @param {T} event
61
126
  */
62
127
  emit(event) {
63
- if (typeof this.events[event] !== 'object') return;
128
+ if (this.#isDestroyed) {
129
+ return;
130
+ }
131
+
132
+ if (typeof this.events[event] !== "object") return;
64
133
 
65
- var i, listeners, length, args = [].slice.call(arguments, 1);
134
+ var i,
135
+ listeners,
136
+ length,
137
+ args = [].slice.call(arguments, 1);
66
138
 
67
139
  listeners = this.events[event].slice();
68
140
  length = listeners.length;
69
141
 
70
142
  for (i = 0; i < length; i++) {
71
-
72
143
  try {
73
144
  listeners[i].apply(this, args);
74
- }
75
- catch (e) {
145
+ } catch (e) {
76
146
  console.error(event, args);
77
147
  console.error(e);
78
148
  }
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Internal function to emit an event
154
+ * @param {"#has-listeners"|"#no-listeners"} event
155
+ * @param {...any} args
156
+ */
157
+ #emitInternal(event, ...args) {
158
+ if (this.#isDestroyed) {
159
+ return;
160
+ }
79
161
 
162
+ if (typeof this.#internalEvents[event] !== "object") return;
163
+
164
+ var i, listeners, length;
165
+
166
+ listeners = this.#internalEvents[event].slice();
167
+ length = listeners.length;
168
+
169
+ for (i = 0; i < length; i++) {
170
+ try {
171
+ listeners[i].apply(this, args);
172
+ } catch (e) {
173
+ console.error(event, args);
174
+ console.error(e);
175
+ }
80
176
  }
81
177
  }
82
178
 
83
179
  /**
84
180
  * Add a one-time listener
85
- * @param {T|"#has-listeners"|"#no-listeners"} event
181
+ * @param {T} event
86
182
  * @param {Function} listener
87
183
  * @returns {()=>void}
88
184
  */
@@ -93,7 +189,6 @@ class EventEmitter {
93
189
  });
94
190
  }
95
191
 
96
-
97
192
  /**
98
193
  * Wait for an event to be emitted
99
194
  * @param {T} event
@@ -101,12 +196,14 @@ class EventEmitter {
101
196
  * @returns {Promise<boolean>} - Resolves with true if the event was emitted, false if the time ran out.
102
197
  */
103
198
  waitForEvent(event, max_wait_ms = 0) {
199
+ if (this.#isDestroyed) {
200
+ throw new Error("EventEmitter is destroyed");
201
+ }
104
202
 
105
203
  return new Promise((resolve) => {
106
204
  let timeout;
107
205
 
108
206
  let unsubscriber = this.on(event, () => {
109
-
110
207
  if (max_wait_ms > 0) {
111
208
  clearTimeout(timeout);
112
209
  }
@@ -120,13 +217,10 @@ class EventEmitter {
120
217
  unsubscriber();
121
218
  resolve(false);
122
219
  }, max_wait_ms);
123
-
124
220
  }
125
-
126
221
  });
127
222
  }
128
223
 
129
-
130
224
  /**
131
225
  * Wait for any of the specified events to be emitted
132
226
  * @param {T[]} events - Array of event names to wait for
@@ -134,6 +228,9 @@ class EventEmitter {
134
228
  * @returns {Promise<boolean>} - Resolves with true if any event was emitted, false if the time ran out.
135
229
  */
136
230
  waitForAnyEvent(events, max_wait_ms = 0) {
231
+ if (this.#isDestroyed) {
232
+ throw new Error("EventEmitter is destroyed");
233
+ }
137
234
 
138
235
  return new Promise((resolve) => {
139
236
  let timeout;
@@ -162,9 +259,7 @@ class EventEmitter {
162
259
  main_unsubscriber();
163
260
  resolve(false);
164
261
  }, max_wait_ms);
165
-
166
262
  }
167
-
168
263
  });
169
264
  }
170
265
 
@@ -180,12 +275,18 @@ class EventEmitter {
180
275
  * @alias clear
181
276
  */
182
277
  destroy() {
183
- this.clear();
278
+ if (this.#isDestroyed) {
279
+ return;
280
+ }
281
+
282
+ this.#isDestroyed = true;
283
+ this.#internalEvents = { "#has-listeners": [], "#no-listeners": [] };
284
+ this.events = {};
184
285
  }
185
286
 
186
287
  /**
187
288
  * Clears all listeners for a specified event.
188
- * @param {T|"#has-listeners"|"#no-listeners"} event - The event for which to clear all listeners.
289
+ * @param {T} event - The event for which to clear all listeners.
189
290
  */
190
291
  clearEventListeners(event) {
191
292
  let listeners = this.events[event] || [];
@@ -193,7 +294,7 @@ class EventEmitter {
193
294
 
194
295
  if (listenersCount > 0) {
195
296
  this.events[event] = [];
196
- this.emit("#no-listeners", event);
297
+ this.#emitInternal("#no-listeners", event);
197
298
  }
198
299
  }
199
300
 
@@ -203,7 +304,10 @@ class EventEmitter {
203
304
  * @returns {()=>void}
204
305
  */
205
306
  onHasEventListeners(callback) {
206
- return this.on("#has-listeners", callback);
307
+ if (this.#isDestroyed) {
308
+ throw new Error("EventEmitter is destroyed");
309
+ }
310
+ return this.#onInternalEvent("#has-listeners", callback);
207
311
  }
208
312
 
209
313
  /**
@@ -212,7 +316,10 @@ class EventEmitter {
212
316
  * @returns {()=>void}
213
317
  */
214
318
  onNoEventListeners(callback) {
215
- return this.on("#no-listeners", callback);
319
+ if (this.#isDestroyed) {
320
+ throw new Error("EventEmitter is destroyed");
321
+ }
322
+ return this.#onInternalEvent("#no-listeners", callback);
216
323
  }
217
324
  }
218
325
 
package/tests/test.js CHANGED
@@ -4,23 +4,21 @@
4
4
  import { EventEmitter } from "./../src/index.js";
5
5
  import test from "./../node_modules/ava/entrypoints/main.mjs";
6
6
 
7
-
8
- test("on(), emit()", t => {
7
+ test("on(), emit()", (t) => {
9
8
  /** @type {EventEmitter<"foo"|"bar">} */
10
- let ev = new EventEmitter;
9
+ let ev = new EventEmitter();
11
10
  ev.on("foo", () => {
12
11
  t.pass();
13
12
  });
14
13
 
15
14
  ev.emit("bar");
16
15
  ev.emit("foo");
17
-
18
16
  });
19
17
 
20
- test("once(), emit()", t => {
18
+ test("once(), emit()", (t) => {
21
19
  /** @type {EventEmitter<"foo">} */
22
- let ev = new EventEmitter;
23
- let foo = 0
20
+ let ev = new EventEmitter();
21
+ let foo = 0;
24
22
  ev.once("foo", () => {
25
23
  foo++;
26
24
  });
@@ -32,14 +30,14 @@ test("once(), emit()", t => {
32
30
  if (foo == 1) {
33
31
  t.pass();
34
32
  } else {
35
- t.fail()
33
+ t.fail();
36
34
  }
37
35
  });
38
36
 
39
- test("removeListener()", t => {
37
+ test("removeListener()", (t) => {
40
38
  /** @type {EventEmitter<"foo">} */
41
- let ev = new EventEmitter;
42
- let foo = 0
39
+ let ev = new EventEmitter();
40
+ let foo = 0;
43
41
  let action = () => {
44
42
  foo++;
45
43
  };
@@ -53,21 +51,20 @@ test("removeListener()", t => {
53
51
  if (foo == 0) {
54
52
  t.pass();
55
53
  } else {
56
- t.fail()
54
+ t.fail();
57
55
  }
58
56
  });
59
57
 
60
- test("Call unsubscriber", t => {
58
+ test("Call unsubscriber", (t) => {
61
59
  /** @type {EventEmitter<"foo">} */
62
- let ev = new EventEmitter;
63
- let foo = 0
60
+ let ev = new EventEmitter();
61
+ let foo = 0;
64
62
  let action = () => {
65
63
  foo++;
66
64
  };
67
65
 
68
66
  let unsubscriber = ev.on("foo", action);
69
67
 
70
-
71
68
  ev.emit("foo");
72
69
  unsubscriber();
73
70
 
@@ -76,23 +73,22 @@ test("Call unsubscriber", t => {
76
73
  if (foo == 1) {
77
74
  t.pass();
78
75
  } else {
79
- t.fail()
76
+ t.fail();
80
77
  }
81
78
  });
82
79
 
83
-
84
- test("on(), emit() with error", t => {
80
+ test("on(), emit() with error", (t) => {
85
81
  /** @type {EventEmitter<"foo">} */
86
- let ev = new EventEmitter;
82
+ let ev = new EventEmitter();
87
83
  let foo = 0;
88
84
 
89
85
  /**
90
- *
91
- * @param {number} bar
86
+ *
87
+ * @param {number} bar
92
88
  */
93
89
  function func(bar) {
94
90
  if (bar % 2) {
95
- throw new Error("Custom error")
91
+ throw new Error("Custom error");
96
92
  } else {
97
93
  foo++;
98
94
  }
@@ -109,15 +105,14 @@ test("on(), emit() with error", t => {
109
105
  if (foo == 1) {
110
106
  t.pass();
111
107
  } else {
112
- t.fail()
108
+ t.fail();
113
109
  }
114
-
115
110
  });
116
111
 
117
- test("waitForEvent()", async t => {
112
+ test("waitForEvent()", async (t) => {
118
113
  /** @type {EventEmitter<"foo">} */
119
- let ev = new EventEmitter;
120
- let foo = 0
114
+ let ev = new EventEmitter();
115
+ let foo = 0;
121
116
  let action = () => {
122
117
  foo++;
123
118
  };
@@ -132,14 +127,14 @@ test("waitForEvent()", async t => {
132
127
  if (foo == 1) {
133
128
  t.pass();
134
129
  } else {
135
- t.fail()
130
+ t.fail();
136
131
  }
137
132
  });
138
133
 
139
- test("waitForEvent() with timeout and no event", async t => {
134
+ test("waitForEvent() with timeout and no event", async (t) => {
140
135
  /** @type {EventEmitter<"foo">} */
141
- let ev = new EventEmitter;
142
- let foo = 0
136
+ let ev = new EventEmitter();
137
+ let foo = 0;
143
138
  let action = () => {
144
139
  foo++;
145
140
  };
@@ -154,15 +149,14 @@ test("waitForEvent() with timeout and no event", async t => {
154
149
  if (foo == 0) {
155
150
  t.pass();
156
151
  } else {
157
- t.fail()
152
+ t.fail();
158
153
  }
159
154
  });
160
155
 
161
-
162
- test("waitForEvent() with timeout", async t => {
156
+ test("waitForEvent() with timeout", async (t) => {
163
157
  /** @type {EventEmitter<"foo">} */
164
- let ev = new EventEmitter;
165
- let foo = 0
158
+ let ev = new EventEmitter();
159
+ let foo = 0;
166
160
  let action = () => {
167
161
  foo++;
168
162
  };
@@ -177,14 +171,13 @@ test("waitForEvent() with timeout", async t => {
177
171
  if (foo == 1) {
178
172
  t.pass();
179
173
  } else {
180
- t.fail()
174
+ t.fail();
181
175
  }
182
176
  });
183
177
 
184
-
185
- test("waitForAnyEvent()", async t => {
178
+ test("waitForAnyEvent()", async (t) => {
186
179
  /** @type {EventEmitter<"foo"|"bar">} */
187
- let ev = new EventEmitter;
180
+ let ev = new EventEmitter();
188
181
  let foo = 0;
189
182
  let bar = 0;
190
183
 
@@ -207,18 +200,17 @@ test("waitForAnyEvent()", async t => {
207
200
  }, 10);
208
201
 
209
202
  await ev.waitForAnyEvent(["foo", "bar"]);
210
-
203
+
211
204
  if (foo == 1 && bar == 1) {
212
205
  t.pass();
213
206
  } else {
214
- t.fail()
207
+ t.fail();
215
208
  }
216
209
  });
217
210
 
218
-
219
- test("waitForAnyEvent() with timeout and no event", async t => {
211
+ test("waitForAnyEvent() with timeout and no event", async (t) => {
220
212
  /** @type {EventEmitter<"foo"|"bar">} */
221
- let ev = new EventEmitter;
213
+ let ev = new EventEmitter();
222
214
  let foo = 0;
223
215
  let bar = 0;
224
216
 
@@ -243,13 +235,13 @@ test("waitForAnyEvent() with timeout and no event", async t => {
243
235
  if (foo == 1 && bar == 0) {
244
236
  t.pass();
245
237
  } else {
246
- t.fail()
238
+ t.fail();
247
239
  }
248
240
  });
249
241
 
250
- test("waitForAnyEvent() with timeout", async t => {
242
+ test("waitForAnyEvent() with timeout", async (t) => {
251
243
  /** @type {EventEmitter<"foo"|"bar">} */
252
- let ev = new EventEmitter;
244
+ let ev = new EventEmitter();
253
245
  let foo = 0;
254
246
  let bar = 0;
255
247
 
@@ -266,17 +258,17 @@ test("waitForAnyEvent() with timeout", async t => {
266
258
  }, 200);
267
259
 
268
260
  await ev.waitForAnyEvent(["foo", "bar"], 50);
269
-
261
+
270
262
  if (foo == 0 && bar == 0) {
271
263
  t.pass();
272
264
  } else {
273
- t.fail()
265
+ t.fail();
274
266
  }
275
267
  });
276
268
 
277
- test("clearEventListeners()", t => {
269
+ test("clearEventListeners()", (t) => {
278
270
  /** @type {EventEmitter<"foo"|"bar">} */
279
- let ev = new EventEmitter;
271
+ let ev = new EventEmitter();
280
272
  let foo = 0;
281
273
 
282
274
  ev.on("foo", () => {
@@ -293,12 +285,11 @@ test("clearEventListeners()", t => {
293
285
  ev.emit("foo");
294
286
 
295
287
  t.is(foo, 1);
296
- }
297
- );
288
+ });
298
289
 
299
- test("destroy()", t => {
290
+ test("destroy()", (t) => {
300
291
  /** @type {EventEmitter<"foo">} */
301
- let ev = new EventEmitter;
292
+ let ev = new EventEmitter();
302
293
  let foo = 0;
303
294
 
304
295
  ev.on("foo", () => {
@@ -315,8 +306,8 @@ test("destroy()", t => {
315
306
 
316
307
  ev.destroy();
317
308
 
318
- ev.on("foo", () => {
319
-
309
+ t.throws(() => {
310
+ ev.on("foo", () => {});
320
311
  });
321
312
 
322
313
  ev.emit("foo");
@@ -325,4 +316,3 @@ test("destroy()", t => {
325
316
 
326
317
  t.is(foo, 0);
327
318
  });
328
-