emittery 0.10.2 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +6 -6
- package/index.js +30 -22
- package/package.json +1 -1
- package/readme.md +4 -4
package/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/* eslint-disable no-redeclare */
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
Emittery accepts strings and
|
|
4
|
+
Emittery accepts strings, symbols, and numbers as event names.
|
|
5
5
|
|
|
6
|
-
Symbol event names can be used to avoid name collisions when your classes are extended, especially for internal events.
|
|
6
|
+
Symbol event names are preferred given that they can be used to avoid name collisions when your classes are extended, especially for internal events.
|
|
7
7
|
*/
|
|
8
|
-
type EventName =
|
|
8
|
+
type EventName = PropertyKey;
|
|
9
9
|
|
|
10
10
|
// Helper type for turning the passed `EventData` type map into a list of string keys that don't require data alongside the event name when emitting. Uses the same trick that `Omit` does internally to filter keys by building a map of keys to keys we want to keep, and then accessing all the keys to return just the list of keys we want to keep.
|
|
11
11
|
type DatalessEventNames<EventData> = {
|
|
@@ -90,7 +90,7 @@ interface DebugOptions<EventData> {
|
|
|
90
90
|
(type, debugName, eventName, eventData) => {
|
|
91
91
|
eventData = JSON.stringify(eventData);
|
|
92
92
|
|
|
93
|
-
if (typeof eventName === 'symbol') {
|
|
93
|
+
if (typeof eventName === 'symbol' || typeof eventName === 'number') {
|
|
94
94
|
eventName = eventName.toString();
|
|
95
95
|
}
|
|
96
96
|
|
|
@@ -142,7 +142,7 @@ Emittery is a strictly typed, fully async EventEmitter implementation. Event lis
|
|
|
142
142
|
import Emittery = require('emittery');
|
|
143
143
|
|
|
144
144
|
const emitter = new Emittery<
|
|
145
|
-
// Pass `{[eventName: <string | symbol>]: undefined | <eventArg>}` as the first type argument for events that pass data to their listeners.
|
|
145
|
+
// Pass `{[eventName: <string | symbol | number>]: undefined | <eventArg>}` as the first type argument for events that pass data to their listeners.
|
|
146
146
|
// A value of `undefined` in this map means the event listeners should expect no data, and a type other than `undefined` means the listeners will receive one argument of that type.
|
|
147
147
|
{
|
|
148
148
|
open: string,
|
|
@@ -164,7 +164,7 @@ emitter.emit('other');
|
|
|
164
164
|
```
|
|
165
165
|
*/
|
|
166
166
|
declare class Emittery<
|
|
167
|
-
EventData = Record<
|
|
167
|
+
EventData = Record<EventName, any>,
|
|
168
168
|
AllEventData = EventData & _OmnipresentEventData,
|
|
169
169
|
DatalessEvents = DatalessEventNames<EventData>
|
|
170
170
|
> {
|
package/index.js
CHANGED
|
@@ -6,14 +6,22 @@ const producersMap = new WeakMap();
|
|
|
6
6
|
const anyProducer = Symbol('anyProducer');
|
|
7
7
|
const resolvedPromise = Promise.resolve();
|
|
8
8
|
|
|
9
|
+
// Define symbols for "meta" events.
|
|
9
10
|
const listenerAdded = Symbol('listenerAdded');
|
|
10
11
|
const listenerRemoved = Symbol('listenerRemoved');
|
|
11
12
|
|
|
13
|
+
// Define a symbol that allows internal code to emit meta events, but prevents userland from doing so.
|
|
14
|
+
const metaEventsAllowed = Symbol('metaEventsAllowed');
|
|
15
|
+
|
|
12
16
|
let isGlobalDebugEnabled = false;
|
|
13
17
|
|
|
14
|
-
function assertEventName(eventName) {
|
|
15
|
-
if (typeof eventName !== 'string' && typeof eventName !== 'symbol') {
|
|
16
|
-
throw new TypeError('eventName must be a string or
|
|
18
|
+
function assertEventName(eventName, allowMetaEvents) {
|
|
19
|
+
if (typeof eventName !== 'string' && typeof eventName !== 'symbol' && typeof eventName !== 'number') {
|
|
20
|
+
throw new TypeError('`eventName` must be a string, symbol, or number');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (isMetaEvent(eventName) && allowMetaEvents !== metaEventsAllowed) {
|
|
24
|
+
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`');
|
|
17
25
|
}
|
|
18
26
|
}
|
|
19
27
|
|
|
@@ -33,7 +41,7 @@ function getListeners(instance, eventName) {
|
|
|
33
41
|
}
|
|
34
42
|
|
|
35
43
|
function getEventProducers(instance, eventName) {
|
|
36
|
-
const key = typeof eventName === 'string' || typeof eventName === 'symbol' ? eventName : anyProducer;
|
|
44
|
+
const key = typeof eventName === 'string' || typeof eventName === 'symbol' || typeof eventName === 'number' ? eventName : anyProducer;
|
|
37
45
|
const producers = producersMap.get(instance);
|
|
38
46
|
if (!producers.has(key)) {
|
|
39
47
|
producers.set(key, new Set());
|
|
@@ -147,7 +155,7 @@ function defaultMethodNamesOrAssert(methodNames) {
|
|
|
147
155
|
return methodNames;
|
|
148
156
|
}
|
|
149
157
|
|
|
150
|
-
const
|
|
158
|
+
const isMetaEvent = eventName => eventName === listenerAdded || eventName === listenerRemoved;
|
|
151
159
|
|
|
152
160
|
class Emittery {
|
|
153
161
|
static mixin(emitteryPropertyName, methodNames) {
|
|
@@ -223,7 +231,7 @@ class Emittery {
|
|
|
223
231
|
eventData = `Object with the following keys failed to stringify: ${Object.keys(eventData).join(',')}`;
|
|
224
232
|
}
|
|
225
233
|
|
|
226
|
-
if (typeof eventName === 'symbol') {
|
|
234
|
+
if (typeof eventName === 'symbol' || typeof eventName === 'number') {
|
|
227
235
|
eventName = eventName.toString();
|
|
228
236
|
}
|
|
229
237
|
|
|
@@ -245,13 +253,13 @@ class Emittery {
|
|
|
245
253
|
|
|
246
254
|
eventNames = Array.isArray(eventNames) ? eventNames : [eventNames];
|
|
247
255
|
for (const eventName of eventNames) {
|
|
248
|
-
assertEventName(eventName);
|
|
256
|
+
assertEventName(eventName, metaEventsAllowed);
|
|
249
257
|
getListeners(this, eventName).add(listener);
|
|
250
258
|
|
|
251
259
|
this.logIfDebugEnabled('subscribe', eventName, undefined);
|
|
252
260
|
|
|
253
|
-
if (!
|
|
254
|
-
this.emit(listenerAdded, {eventName, listener});
|
|
261
|
+
if (!isMetaEvent(eventName)) {
|
|
262
|
+
this.emit(listenerAdded, {eventName, listener}, metaEventsAllowed);
|
|
255
263
|
}
|
|
256
264
|
}
|
|
257
265
|
|
|
@@ -263,13 +271,13 @@ class Emittery {
|
|
|
263
271
|
|
|
264
272
|
eventNames = Array.isArray(eventNames) ? eventNames : [eventNames];
|
|
265
273
|
for (const eventName of eventNames) {
|
|
266
|
-
assertEventName(eventName);
|
|
274
|
+
assertEventName(eventName, metaEventsAllowed);
|
|
267
275
|
getListeners(this, eventName).delete(listener);
|
|
268
276
|
|
|
269
277
|
this.logIfDebugEnabled('unsubscribe', eventName, undefined);
|
|
270
278
|
|
|
271
|
-
if (!
|
|
272
|
-
this.emit(listenerRemoved, {eventName, listener});
|
|
279
|
+
if (!isMetaEvent(eventName)) {
|
|
280
|
+
this.emit(listenerRemoved, {eventName, listener}, metaEventsAllowed);
|
|
273
281
|
}
|
|
274
282
|
}
|
|
275
283
|
}
|
|
@@ -286,14 +294,14 @@ class Emittery {
|
|
|
286
294
|
events(eventNames) {
|
|
287
295
|
eventNames = Array.isArray(eventNames) ? eventNames : [eventNames];
|
|
288
296
|
for (const eventName of eventNames) {
|
|
289
|
-
assertEventName(eventName);
|
|
297
|
+
assertEventName(eventName, metaEventsAllowed);
|
|
290
298
|
}
|
|
291
299
|
|
|
292
300
|
return iterator(this, eventNames);
|
|
293
301
|
}
|
|
294
302
|
|
|
295
|
-
async emit(eventName, eventData) {
|
|
296
|
-
assertEventName(eventName);
|
|
303
|
+
async emit(eventName, eventData, allowMetaEvents) {
|
|
304
|
+
assertEventName(eventName, allowMetaEvents);
|
|
297
305
|
|
|
298
306
|
this.logIfDebugEnabled('emit', eventName, eventData);
|
|
299
307
|
|
|
@@ -302,7 +310,7 @@ class Emittery {
|
|
|
302
310
|
const listeners = getListeners(this, eventName);
|
|
303
311
|
const anyListeners = anyMap.get(this);
|
|
304
312
|
const staticListeners = [...listeners];
|
|
305
|
-
const staticAnyListeners =
|
|
313
|
+
const staticAnyListeners = isMetaEvent(eventName) ? [] : [...anyListeners];
|
|
306
314
|
|
|
307
315
|
await resolvedPromise;
|
|
308
316
|
await Promise.all([
|
|
@@ -319,8 +327,8 @@ class Emittery {
|
|
|
319
327
|
]);
|
|
320
328
|
}
|
|
321
329
|
|
|
322
|
-
async emitSerial(eventName, eventData) {
|
|
323
|
-
assertEventName(eventName);
|
|
330
|
+
async emitSerial(eventName, eventData, allowMetaEvents) {
|
|
331
|
+
assertEventName(eventName, allowMetaEvents);
|
|
324
332
|
|
|
325
333
|
this.logIfDebugEnabled('emitSerial', eventName, eventData);
|
|
326
334
|
|
|
@@ -351,7 +359,7 @@ class Emittery {
|
|
|
351
359
|
this.logIfDebugEnabled('subscribeAny', undefined, undefined);
|
|
352
360
|
|
|
353
361
|
anyMap.get(this).add(listener);
|
|
354
|
-
this.emit(listenerAdded, {listener});
|
|
362
|
+
this.emit(listenerAdded, {listener}, metaEventsAllowed);
|
|
355
363
|
return this.offAny.bind(this, listener);
|
|
356
364
|
}
|
|
357
365
|
|
|
@@ -364,7 +372,7 @@ class Emittery {
|
|
|
364
372
|
|
|
365
373
|
this.logIfDebugEnabled('unsubscribeAny', undefined, undefined);
|
|
366
374
|
|
|
367
|
-
this.emit(listenerRemoved, {listener});
|
|
375
|
+
this.emit(listenerRemoved, {listener}, metaEventsAllowed);
|
|
368
376
|
anyMap.get(this).delete(listener);
|
|
369
377
|
}
|
|
370
378
|
|
|
@@ -374,7 +382,7 @@ class Emittery {
|
|
|
374
382
|
for (const eventName of eventNames) {
|
|
375
383
|
this.logIfDebugEnabled('clear', eventName, undefined);
|
|
376
384
|
|
|
377
|
-
if (typeof eventName === 'string' || typeof eventName === 'symbol') {
|
|
385
|
+
if (typeof eventName === 'string' || typeof eventName === 'symbol' || typeof eventName === 'number') {
|
|
378
386
|
getListeners(this, eventName).clear();
|
|
379
387
|
|
|
380
388
|
const producers = getEventProducers(this, eventName);
|
|
@@ -414,7 +422,7 @@ class Emittery {
|
|
|
414
422
|
}
|
|
415
423
|
|
|
416
424
|
if (typeof eventName !== 'undefined') {
|
|
417
|
-
assertEventName(eventName);
|
|
425
|
+
assertEventName(eventName, metaEventsAllowed);
|
|
418
426
|
}
|
|
419
427
|
|
|
420
428
|
count += anyMap.get(this).size;
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -40,9 +40,9 @@ emitter.emit(myUnicorn, '🦋'); // Will trigger printing 'Unicorns love 🦋'
|
|
|
40
40
|
|
|
41
41
|
### eventName
|
|
42
42
|
|
|
43
|
-
Emittery accepts strings and
|
|
43
|
+
Emittery accepts strings, symbols, and numbers as event names.
|
|
44
44
|
|
|
45
|
-
Symbol event names can be used to avoid name collisions when your classes are extended, especially for internal events.
|
|
45
|
+
Symbol event names are preferred given that they can be used to avoid name collisions when your classes are extended, especially for internal events.
|
|
46
46
|
|
|
47
47
|
### isDebugEnabled
|
|
48
48
|
|
|
@@ -160,7 +160,7 @@ Default:
|
|
|
160
160
|
eventData = JSON.stringify(eventData);
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
if (typeof eventName === 'symbol') {
|
|
163
|
+
if (typeof eventName === 'symbol' || typeof eventName === 'number') {
|
|
164
164
|
eventName = eventName.toString();
|
|
165
165
|
}
|
|
166
166
|
|
|
@@ -222,7 +222,7 @@ emitter.emit('🐶', '🍖'); // log => '🍖'
|
|
|
222
222
|
|
|
223
223
|
##### Custom subscribable events
|
|
224
224
|
|
|
225
|
-
Emittery exports some symbols which represent
|
|
225
|
+
Emittery exports some symbols which represent "meta" events that can be passed to `Emitter.on` and similar methods.
|
|
226
226
|
|
|
227
227
|
- `Emittery.listenerAdded` - Fires when an event listener was added.
|
|
228
228
|
- `Emittery.listenerRemoved` - Fires when an event listener was removed.
|