emittery 0.6.0 → 0.7.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.
Files changed (4) hide show
  1. package/index.d.ts +99 -9
  2. package/index.js +80 -52
  3. package/package.json +1 -1
  4. package/readme.md +79 -11
package/index.d.ts CHANGED
@@ -5,6 +5,11 @@ Symbol event names can be used to avoid name collisions when your classes are ex
5
5
  */
6
6
  type EventName = string | symbol;
7
7
 
8
+ /**
9
+ Emittery also accepts an array of strings and symbols as event names.
10
+ */
11
+ type EventNames = EventName | readonly EventName[];
12
+
8
13
  declare class Emittery {
9
14
  /**
10
15
  In TypeScript, it returns a decorator which mixins `Emittery` as property `emitteryPropertyName` and `methodNames`, or all `Emittery` methods if `methodNames` is not defined, into the target class.
@@ -78,14 +83,31 @@ declare class Emittery {
78
83
  static readonly listenerRemoved: unique symbol;
79
84
 
80
85
  /**
81
- Subscribe to an event.
86
+ Subscribe to one or more events.
82
87
 
83
88
  Using the same listener multiple times for the same event will result in only one method call per emitted event.
84
89
 
85
90
  @returns An unsubscribe method.
91
+
92
+ @example
93
+ ```
94
+ import Emittery = require('emittery');
95
+
96
+ const emitter = new Emittery();
97
+
98
+ emitter.on('🦄', data => {
99
+ console.log(data);
100
+ });
101
+ emitter.on(['🦄', '🐶'], data => {
102
+ console.log(data);
103
+ });
104
+
105
+ emitter.emit('🦄', '🌈'); // log => '🌈' x2
106
+ emitter.emit('🐶', '🍖'); // log => '🍖'
107
+ ```
86
108
  */
87
109
  on(eventName: typeof Emittery.listenerAdded | typeof Emittery.listenerRemoved, listener: (eventData: Emittery.ListenerChangedData) => void): Emittery.UnsubscribeFn
88
- on(eventName: EventName, listener: (eventData?: unknown) => void): Emittery.UnsubscribeFn;
110
+ on(eventName: EventNames, listener: (eventData?: unknown) => void): Emittery.UnsubscribeFn;
89
111
 
90
112
  /**
91
113
  Get an async iterator which buffers data each time an event is emitted.
@@ -139,22 +161,90 @@ declare class Emittery {
139
161
  }
140
162
  }
141
163
  ```
164
+
165
+ It accepts multiple event names.
166
+
167
+ @example
168
+ ```
169
+ import Emittery = require('emittery');
170
+
171
+ const emitter = new Emittery();
172
+ const iterator = emitter.events(['🦄', '🦊']);
173
+
174
+ emitter.emit('🦄', '🌈1'); // Buffered
175
+ emitter.emit('🦊', '🌈2'); // Buffered
176
+
177
+ iterator
178
+ .next()
179
+ .then(({value, done}) => {
180
+ // done === false
181
+ // value === '🌈1'
182
+ return iterator.next();
183
+ })
184
+ .then(({value, done}) => {
185
+ // done === false
186
+ // value === '🌈2'
187
+ // Revoke subscription
188
+ return iterator.return();
189
+ })
190
+ .then(({done}) => {
191
+ // done === true
192
+ });
193
+ ```
142
194
  */
143
- events(eventName: EventName): AsyncIterableIterator<unknown>
195
+ events(eventName: EventNames): AsyncIterableIterator<unknown>
144
196
 
145
197
  /**
146
- Remove an event subscription.
198
+ Remove one or more event subscriptions.
199
+
200
+ @example
201
+ ```
202
+ import Emittery = require('emittery');
203
+
204
+ const emitter = new Emittery();
205
+
206
+ const listener = data => console.log(data);
207
+ (async () => {
208
+ emitter.on(['🦄', '🐶', '🦊'], listener);
209
+ await emitter.emit('🦄', 'a');
210
+ await emitter.emit('🐶', 'b');
211
+ await emitter.emit('🦊', 'c');
212
+ emitter.off('🦄', listener);
213
+ emitter.off(['🐶', '🦊'], listener);
214
+ await emitter.emit('🦄', 'a'); // nothing happens
215
+ await emitter.emit('🐶', 'b'); // nothing happens
216
+ await emitter.emit('🦊', 'c'); // nothing happens
217
+ })();
218
+ ```
147
219
  */
148
- off(eventName: EventName, listener: (eventData?: unknown) => void): void;
220
+ off(eventName: EventNames, listener: (eventData?: unknown) => void): void;
149
221
 
150
222
  /**
151
- Subscribe to an event only once. It will be unsubscribed after the first
223
+ Subscribe to one or more events only once. It will be unsubscribed after the first
152
224
  event.
153
225
 
154
226
  @returns The event data when `eventName` is emitted.
227
+
228
+ @example
229
+ ```
230
+ import Emittery = require('emittery');
231
+
232
+ const emitter = new Emittery();
233
+
234
+ emitter.once('🦄').then(data => {
235
+ console.log(data);
236
+ //=> '🌈'
237
+ });
238
+ emitter.once(['🦄', '🐶']).then(data => {
239
+ console.log(data);
240
+ });
241
+
242
+ emitter.emit('🦄', '🌈'); // Logs `🌈` twice
243
+ emitter.emit('🐶', '🍖'); // Nothing happens
244
+ ```
155
245
  */
156
246
  once(eventName: typeof Emittery.listenerAdded | typeof Emittery.listenerRemoved): Promise<Emittery.ListenerChangedData>
157
- once(eventName: EventName): Promise<unknown>;
247
+ once(eventName: EventNames): Promise<unknown>;
158
248
 
159
249
  /**
160
250
  Trigger an event asynchronously, optionally with some data. Listeners are called in the order they were added, but executed concurrently.
@@ -225,12 +315,12 @@ declare class Emittery {
225
315
 
226
316
  If `eventName` is given, only the listeners for that event are cleared.
227
317
  */
228
- clearListeners(eventName?: EventName): void;
318
+ clearListeners(eventName?: EventNames): void;
229
319
 
230
320
  /**
231
321
  The number of listeners for the `eventName` or all events if not specified.
232
322
  */
233
- listenerCount(eventName?: EventName): number;
323
+ listenerCount(eventName?: EventNames): number;
234
324
 
235
325
  /**
236
326
  Bind the given `methodNames`, or all `Emittery` methods if `methodNames` is not defined, into the `target` object.
package/index.js CHANGED
@@ -56,7 +56,9 @@ function enqueueProducers(instance, eventName, eventData) {
56
56
  }
57
57
  }
58
58
 
59
- function iterator(instance, eventName) {
59
+ function iterator(instance, eventNames) {
60
+ eventNames = Array.isArray(eventNames) ? eventNames : [eventNames];
61
+
60
62
  let isFinished = false;
61
63
  let flush = () => {};
62
64
  let queue = [];
@@ -72,7 +74,9 @@ function iterator(instance, eventName) {
72
74
  }
73
75
  };
74
76
 
75
- getEventProducers(instance, eventName).add(producer);
77
+ for (const eventName of eventNames) {
78
+ getEventProducers(instance, eventName).add(producer);
79
+ }
76
80
 
77
81
  return {
78
82
  async next() {
@@ -101,7 +105,11 @@ function iterator(instance, eventName) {
101
105
 
102
106
  async return(value) {
103
107
  queue = undefined;
104
- getEventProducers(instance, eventName).delete(producer);
108
+
109
+ for (const eventName of eventNames) {
110
+ getEventProducers(instance, eventName).delete(producer);
111
+ }
112
+
105
113
  flush();
106
114
 
107
115
  return arguments.length > 0 ?
@@ -187,42 +195,52 @@ class Emittery {
187
195
  producersMap.set(this, new Map());
188
196
  }
189
197
 
190
- on(eventName, listener) {
191
- assertEventName(eventName);
198
+ on(eventNames, listener) {
192
199
  assertListener(listener);
193
- getListeners(this, eventName).add(listener);
194
200
 
195
- if (!isListenerSymbol(eventName)) {
196
- this.emit(listenerAdded, {eventName, listener});
201
+ eventNames = Array.isArray(eventNames) ? eventNames : [eventNames];
202
+ for (const eventName of eventNames) {
203
+ assertEventName(eventName);
204
+ getListeners(this, eventName).add(listener);
205
+
206
+ if (!isListenerSymbol(eventName)) {
207
+ this.emit(listenerAdded, {eventName, listener});
208
+ }
197
209
  }
198
210
 
199
- return this.off.bind(this, eventName, listener);
211
+ return this.off.bind(this, eventNames, listener);
200
212
  }
201
213
 
202
- off(eventName, listener) {
203
- assertEventName(eventName);
214
+ off(eventNames, listener) {
204
215
  assertListener(listener);
205
216
 
206
- if (!isListenerSymbol(eventName)) {
207
- this.emit(listenerRemoved, {eventName, listener});
208
- }
217
+ eventNames = Array.isArray(eventNames) ? eventNames : [eventNames];
218
+ for (const eventName of eventNames) {
219
+ assertEventName(eventName);
220
+ getListeners(this, eventName).delete(listener);
209
221
 
210
- getListeners(this, eventName).delete(listener);
222
+ if (!isListenerSymbol(eventName)) {
223
+ this.emit(listenerRemoved, {eventName, listener});
224
+ }
225
+ }
211
226
  }
212
227
 
213
- once(eventName) {
228
+ once(eventNames) {
214
229
  return new Promise(resolve => {
215
- assertEventName(eventName);
216
- const off = this.on(eventName, data => {
230
+ const off = this.on(eventNames, data => {
217
231
  off();
218
232
  resolve(data);
219
233
  });
220
234
  });
221
235
  }
222
236
 
223
- events(eventName) {
224
- assertEventName(eventName);
225
- return iterator(this, eventName);
237
+ events(eventNames) {
238
+ eventNames = Array.isArray(eventNames) ? eventNames : [eventNames];
239
+ for (const eventName of eventNames) {
240
+ assertEventName(eventName);
241
+ }
242
+
243
+ return iterator(this, eventNames);
226
244
  }
227
245
 
228
246
  async emit(eventName, eventData) {
@@ -236,7 +254,7 @@ class Emittery {
236
254
  const staticAnyListeners = isListenerSymbol(eventName) ? [] : [...anyListeners];
237
255
 
238
256
  await resolvedPromise;
239
- return Promise.all([
257
+ await Promise.all([
240
258
  ...staticListeners.map(async listener => {
241
259
  if (listeners.has(listener)) {
242
260
  return listener(eventData);
@@ -291,52 +309,62 @@ class Emittery {
291
309
  anyMap.get(this).delete(listener);
292
310
  }
293
311
 
294
- clearListeners(eventName) {
295
- if (typeof eventName === 'string') {
296
- getListeners(this, eventName).clear();
312
+ clearListeners(eventNames) {
313
+ eventNames = Array.isArray(eventNames) ? eventNames : [eventNames];
297
314
 
298
- const producers = getEventProducers(this, eventName);
315
+ for (const eventName of eventNames) {
316
+ if (typeof eventName === 'string') {
317
+ getListeners(this, eventName).clear();
299
318
 
300
- for (const producer of producers) {
301
- producer.finish();
302
- }
303
-
304
- producers.clear();
305
- } else {
306
- anyMap.get(this).clear();
319
+ const producers = getEventProducers(this, eventName);
307
320
 
308
- for (const listeners of eventsMap.get(this).values()) {
309
- listeners.clear();
310
- }
311
-
312
- for (const producers of producersMap.get(this).values()) {
313
321
  for (const producer of producers) {
314
322
  producer.finish();
315
323
  }
316
324
 
317
325
  producers.clear();
326
+ } else {
327
+ anyMap.get(this).clear();
328
+
329
+ for (const listeners of eventsMap.get(this).values()) {
330
+ listeners.clear();
331
+ }
332
+
333
+ for (const producers of producersMap.get(this).values()) {
334
+ for (const producer of producers) {
335
+ producer.finish();
336
+ }
337
+
338
+ producers.clear();
339
+ }
318
340
  }
319
341
  }
320
342
  }
321
343
 
322
- listenerCount(eventName) {
323
- if (typeof eventName === 'string') {
324
- return anyMap.get(this).size + getListeners(this, eventName).size +
325
- getEventProducers(this, eventName).size + getEventProducers(this).size;
326
- }
344
+ listenerCount(eventNames) {
345
+ eventNames = Array.isArray(eventNames) ? eventNames : [eventNames];
346
+ let count = 0;
327
347
 
328
- if (typeof eventName !== 'undefined') {
329
- assertEventName(eventName);
330
- }
348
+ for (const eventName of eventNames) {
349
+ if (typeof eventName === 'string') {
350
+ count += anyMap.get(this).size + getListeners(this, eventName).size +
351
+ getEventProducers(this, eventName).size + getEventProducers(this).size;
352
+ continue;
353
+ }
331
354
 
332
- let count = anyMap.get(this).size;
355
+ if (typeof eventName !== 'undefined') {
356
+ assertEventName(eventName);
357
+ }
333
358
 
334
- for (const value of eventsMap.get(this).values()) {
335
- count += value.size;
336
- }
359
+ count += anyMap.get(this).size;
360
+
361
+ for (const value of eventsMap.get(this).values()) {
362
+ count += value.size;
363
+ }
337
364
 
338
- for (const value of producersMap.get(this).values()) {
339
- count += value.size;
365
+ for (const value of producersMap.get(this).values()) {
366
+ count += value.size;
367
+ }
340
368
  }
341
369
 
342
370
  return count;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emittery",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Simple and modern async event emitter",
5
5
  "license": "MIT",
6
6
  "repository": "sindresorhus/emittery",
package/readme.md CHANGED
@@ -45,14 +45,30 @@ Symbol event names can be used to avoid name collisions when your classes are ex
45
45
 
46
46
  ### emitter = new Emittery()
47
47
 
48
- #### on(eventName, listener)
48
+ #### on(eventName | eventName[], listener)
49
49
 
50
- Subscribe to an event.
50
+ Subscribe to one or more events.
51
51
 
52
52
  Returns an unsubscribe method.
53
53
 
54
54
  Using the same listener multiple times for the same event will result in only one method call per emitted event.
55
55
 
56
+ ```js
57
+ const Emittery = require('emittery');
58
+
59
+ const emitter = new Emittery();
60
+
61
+ emitter.on('🦄', data => {
62
+ console.log(data);
63
+ });
64
+ emitter.on(['🦄', '🐶'], data => {
65
+ console.log(data);
66
+ });
67
+
68
+ emitter.emit('🦄', '🌈'); // log => '🌈' x2
69
+ emitter.emit('🐶', '🍖'); // log => '🍖'
70
+ ```
71
+
56
72
  ##### Custom subscribable events
57
73
 
58
74
  Emittery exports some symbols which represent custom events that can be passed to `Emitter.on` and similar methods.
@@ -87,15 +103,34 @@ Only events that are not of this type are able to trigger these events.
87
103
 
88
104
  ##### listener(data)
89
105
 
90
- #### off(eventName, listener)
106
+ #### off(eventName | eventName[], listener)
107
+
108
+ Remove one or more event subscriptions.
109
+
110
+ ```js
111
+ const Emittery = require('emittery');
112
+
113
+ const emitter = new Emittery();
91
114
 
92
- Remove an event subscription.
115
+ const listener = data => console.log(data);
116
+ (async () => {
117
+ emitter.on(['🦄', '🐶', '🦊'], listener);
118
+ await emitter.emit('🦄', 'a');
119
+ await emitter.emit('🐶', 'b');
120
+ await emitter.emit('🦊', 'c');
121
+ emitter.off('🦄', listener);
122
+ emitter.off(['🐶', '🦊'], listener);
123
+ await emitter.emit('🦄', 'a'); // nothing happens
124
+ await emitter.emit('🐶', 'b'); // nothing happens
125
+ await emitter.emit('🦊', 'c'); // nothing happens
126
+ })();
127
+ ```
93
128
 
94
129
  ##### listener(data)
95
130
 
96
- #### once(eventName)
131
+ #### once(eventName | eventName[])
97
132
 
98
- Subscribe to an event only once. It will be unsubscribed after the first event.
133
+ Subscribe to one or more events only once. It will be unsubscribed after the first event.
99
134
 
100
135
  Returns a promise for the event data when `eventName` is emitted.
101
136
 
@@ -108,8 +143,12 @@ emitter.once('🦄').then(data => {
108
143
  console.log(data);
109
144
  //=> '🌈'
110
145
  });
146
+ emitter.once(['🦄', '🐶']).then(data => {
147
+ console.log(data);
148
+ });
111
149
 
112
- emitter.emit('🦄', '🌈');
150
+ emitter.emit('🦄', '🌈'); // log => '🌈' x2
151
+ emitter.emit('🐶', '🍖'); // nothing happens
113
152
  ```
114
153
 
115
154
  #### events(eventName)
@@ -164,6 +203,35 @@ for await (const data of iterator) {
164
203
  }
165
204
  ```
166
205
 
206
+ It accepts multiple event names.
207
+
208
+ ```js
209
+ const Emittery = require('emittery');
210
+
211
+ const emitter = new Emittery();
212
+ const iterator = emitter.events(['🦄', '🦊']);
213
+
214
+ emitter.emit('🦄', '🌈1'); // Buffered
215
+ emitter.emit('🦊', '🌈2'); // Buffered
216
+
217
+ iterator
218
+ .next()
219
+ .then(({value, done}) => {
220
+ // done === false
221
+ // value === '🌈1'
222
+ return iterator.next();
223
+ })
224
+ .then(({value, done}) => {
225
+ // done === false
226
+ // value === '🌈2'
227
+ // Revoke subscription
228
+ return iterator.return();
229
+ })
230
+ .then(({done}) => {
231
+ // done === true
232
+ });
233
+ ```
234
+
167
235
  #### emit(eventName, data?)
168
236
 
169
237
  Trigger an event asynchronously, optionally with some data. Listeners are called in the order they were added, but executed concurrently.
@@ -222,15 +290,15 @@ iterator.next()
222
290
 
223
291
  In the same way as for `events`, you can subscribe by using the `for await` statement
224
292
 
225
- #### clearListeners()
293
+ #### clearListeners(eventNames?)
226
294
 
227
295
  Clear all event listeners on the instance.
228
296
 
229
- If `eventName` is given, only the listeners for that event are cleared.
297
+ If `eventNames` is given, only the listeners for that events are cleared.
230
298
 
231
- #### listenerCount(eventName?)
299
+ #### listenerCount(eventNames?)
232
300
 
233
- The number of listeners for the `eventName` or all events if not specified.
301
+ The number of listeners for the `eventNames` or all events if not specified.
234
302
 
235
303
  #### bindMethods(target, methodNames?)
236
304