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 CHANGED
@@ -1,11 +1,11 @@
1
1
  /* eslint-disable no-redeclare */
2
2
 
3
3
  /**
4
- Emittery accepts strings and symbols as event names.
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 = string | symbol;
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<string, any>, // When https://github.com/microsoft/TypeScript/issues/1863 ships, we can switch this to have an index signature including Symbols. If you want to use symbol keys right now, you need to pass an interface with those symbol keys explicitly listed.
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 a symbol');
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 isListenerSymbol = symbol => symbol === listenerAdded || symbol === listenerRemoved;
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 (!isListenerSymbol(eventName)) {
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 (!isListenerSymbol(eventName)) {
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 = isListenerSymbol(eventName) ? [] : [...anyListeners];
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emittery",
3
- "version": "0.10.2",
3
+ "version": "0.11.0",
4
4
  "description": "Simple and modern async event emitter",
5
5
  "license": "MIT",
6
6
  "repository": "sindresorhus/emittery",
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 symbols as event names.
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 custom events that can be passed to `Emitter.on` and similar methods.
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.