1 | // Copyright Joyent, Inc. and other Node contributors.
|
---|
2 | //
|
---|
3 | // Permission is hereby granted, free of charge, to any person obtaining a
|
---|
4 | // copy of this software and associated documentation files (the
|
---|
5 | // "Software"), to deal in the Software without restriction, including
|
---|
6 | // without limitation the rights to use, copy, modify, merge, publish,
|
---|
7 | // distribute, sublicense, and/or sell copies of the Software, and to permit
|
---|
8 | // persons to whom the Software is furnished to do so, subject to the
|
---|
9 | // following conditions:
|
---|
10 | //
|
---|
11 | // The above copyright notice and this permission notice shall be included
|
---|
12 | // in all copies or substantial portions of the Software.
|
---|
13 | //
|
---|
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
---|
15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
---|
16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
---|
17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
---|
18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
---|
19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
---|
20 | // USE OR OTHER DEALINGS IN THE SOFTWARE.
|
---|
21 |
|
---|
22 | 'use strict';
|
---|
23 |
|
---|
24 | var R = typeof Reflect === 'object' ? Reflect : null
|
---|
25 | var ReflectApply = R && typeof R.apply === 'function'
|
---|
26 | ? R.apply
|
---|
27 | : function ReflectApply(target, receiver, args) {
|
---|
28 | return Function.prototype.apply.call(target, receiver, args);
|
---|
29 | }
|
---|
30 |
|
---|
31 | var ReflectOwnKeys
|
---|
32 | if (R && typeof R.ownKeys === 'function') {
|
---|
33 | ReflectOwnKeys = R.ownKeys
|
---|
34 | } else if (Object.getOwnPropertySymbols) {
|
---|
35 | ReflectOwnKeys = function ReflectOwnKeys(target) {
|
---|
36 | return Object.getOwnPropertyNames(target)
|
---|
37 | .concat(Object.getOwnPropertySymbols(target));
|
---|
38 | };
|
---|
39 | } else {
|
---|
40 | ReflectOwnKeys = function ReflectOwnKeys(target) {
|
---|
41 | return Object.getOwnPropertyNames(target);
|
---|
42 | };
|
---|
43 | }
|
---|
44 |
|
---|
45 | function ProcessEmitWarning(warning) {
|
---|
46 | if (console && console.warn) console.warn(warning);
|
---|
47 | }
|
---|
48 |
|
---|
49 | var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {
|
---|
50 | return value !== value;
|
---|
51 | }
|
---|
52 |
|
---|
53 | function EventEmitter() {
|
---|
54 | EventEmitter.init.call(this);
|
---|
55 | }
|
---|
56 | module.exports = EventEmitter;
|
---|
57 | module.exports.once = once;
|
---|
58 |
|
---|
59 | // Backwards-compat with node 0.10.x
|
---|
60 | EventEmitter.EventEmitter = EventEmitter;
|
---|
61 |
|
---|
62 | EventEmitter.prototype._events = undefined;
|
---|
63 | EventEmitter.prototype._eventsCount = 0;
|
---|
64 | EventEmitter.prototype._maxListeners = undefined;
|
---|
65 |
|
---|
66 | // By default EventEmitters will print a warning if more than 10 listeners are
|
---|
67 | // added to it. This is a useful default which helps finding memory leaks.
|
---|
68 | var defaultMaxListeners = 10;
|
---|
69 |
|
---|
70 | function checkListener(listener) {
|
---|
71 | if (typeof listener !== 'function') {
|
---|
72 | throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
|
---|
73 | }
|
---|
74 | }
|
---|
75 |
|
---|
76 | Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
|
---|
77 | enumerable: true,
|
---|
78 | get: function() {
|
---|
79 | return defaultMaxListeners;
|
---|
80 | },
|
---|
81 | set: function(arg) {
|
---|
82 | if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {
|
---|
83 | throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.');
|
---|
84 | }
|
---|
85 | defaultMaxListeners = arg;
|
---|
86 | }
|
---|
87 | });
|
---|
88 |
|
---|
89 | EventEmitter.init = function() {
|
---|
90 |
|
---|
91 | if (this._events === undefined ||
|
---|
92 | this._events === Object.getPrototypeOf(this)._events) {
|
---|
93 | this._events = Object.create(null);
|
---|
94 | this._eventsCount = 0;
|
---|
95 | }
|
---|
96 |
|
---|
97 | this._maxListeners = this._maxListeners || undefined;
|
---|
98 | };
|
---|
99 |
|
---|
100 | // Obviously not all Emitters should be limited to 10. This function allows
|
---|
101 | // that to be increased. Set to zero for unlimited.
|
---|
102 | EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
|
---|
103 | if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {
|
---|
104 | throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.');
|
---|
105 | }
|
---|
106 | this._maxListeners = n;
|
---|
107 | return this;
|
---|
108 | };
|
---|
109 |
|
---|
110 | function _getMaxListeners(that) {
|
---|
111 | if (that._maxListeners === undefined)
|
---|
112 | return EventEmitter.defaultMaxListeners;
|
---|
113 | return that._maxListeners;
|
---|
114 | }
|
---|
115 |
|
---|
116 | EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
|
---|
117 | return _getMaxListeners(this);
|
---|
118 | };
|
---|
119 |
|
---|
120 | EventEmitter.prototype.emit = function emit(type) {
|
---|
121 | var args = [];
|
---|
122 | for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);
|
---|
123 | var doError = (type === 'error');
|
---|
124 |
|
---|
125 | var events = this._events;
|
---|
126 | if (events !== undefined)
|
---|
127 | doError = (doError && events.error === undefined);
|
---|
128 | else if (!doError)
|
---|
129 | return false;
|
---|
130 |
|
---|
131 | // If there is no 'error' event listener then throw.
|
---|
132 | if (doError) {
|
---|
133 | var er;
|
---|
134 | if (args.length > 0)
|
---|
135 | er = args[0];
|
---|
136 | if (er instanceof Error) {
|
---|
137 | // Note: The comments on the `throw` lines are intentional, they show
|
---|
138 | // up in Node's output if this results in an unhandled exception.
|
---|
139 | throw er; // Unhandled 'error' event
|
---|
140 | }
|
---|
141 | // At least give some kind of context to the user
|
---|
142 | var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));
|
---|
143 | err.context = er;
|
---|
144 | throw err; // Unhandled 'error' event
|
---|
145 | }
|
---|
146 |
|
---|
147 | var handler = events[type];
|
---|
148 |
|
---|
149 | if (handler === undefined)
|
---|
150 | return false;
|
---|
151 |
|
---|
152 | if (typeof handler === 'function') {
|
---|
153 | ReflectApply(handler, this, args);
|
---|
154 | } else {
|
---|
155 | var len = handler.length;
|
---|
156 | var listeners = arrayClone(handler, len);
|
---|
157 | for (var i = 0; i < len; ++i)
|
---|
158 | ReflectApply(listeners[i], this, args);
|
---|
159 | }
|
---|
160 |
|
---|
161 | return true;
|
---|
162 | };
|
---|
163 |
|
---|
164 | function _addListener(target, type, listener, prepend) {
|
---|
165 | var m;
|
---|
166 | var events;
|
---|
167 | var existing;
|
---|
168 |
|
---|
169 | checkListener(listener);
|
---|
170 |
|
---|
171 | events = target._events;
|
---|
172 | if (events === undefined) {
|
---|
173 | events = target._events = Object.create(null);
|
---|
174 | target._eventsCount = 0;
|
---|
175 | } else {
|
---|
176 | // To avoid recursion in the case that type === "newListener"! Before
|
---|
177 | // adding it to the listeners, first emit "newListener".
|
---|
178 | if (events.newListener !== undefined) {
|
---|
179 | target.emit('newListener', type,
|
---|
180 | listener.listener ? listener.listener : listener);
|
---|
181 |
|
---|
182 | // Re-assign `events` because a newListener handler could have caused the
|
---|
183 | // this._events to be assigned to a new object
|
---|
184 | events = target._events;
|
---|
185 | }
|
---|
186 | existing = events[type];
|
---|
187 | }
|
---|
188 |
|
---|
189 | if (existing === undefined) {
|
---|
190 | // Optimize the case of one listener. Don't need the extra array object.
|
---|
191 | existing = events[type] = listener;
|
---|
192 | ++target._eventsCount;
|
---|
193 | } else {
|
---|
194 | if (typeof existing === 'function') {
|
---|
195 | // Adding the second element, need to change to array.
|
---|
196 | existing = events[type] =
|
---|
197 | prepend ? [listener, existing] : [existing, listener];
|
---|
198 | // If we've already got an array, just append.
|
---|
199 | } else if (prepend) {
|
---|
200 | existing.unshift(listener);
|
---|
201 | } else {
|
---|
202 | existing.push(listener);
|
---|
203 | }
|
---|
204 |
|
---|
205 | // Check for listener leak
|
---|
206 | m = _getMaxListeners(target);
|
---|
207 | if (m > 0 && existing.length > m && !existing.warned) {
|
---|
208 | existing.warned = true;
|
---|
209 | // No error code for this since it is a Warning
|
---|
210 | // eslint-disable-next-line no-restricted-syntax
|
---|
211 | var w = new Error('Possible EventEmitter memory leak detected. ' +
|
---|
212 | existing.length + ' ' + String(type) + ' listeners ' +
|
---|
213 | 'added. Use emitter.setMaxListeners() to ' +
|
---|
214 | 'increase limit');
|
---|
215 | w.name = 'MaxListenersExceededWarning';
|
---|
216 | w.emitter = target;
|
---|
217 | w.type = type;
|
---|
218 | w.count = existing.length;
|
---|
219 | ProcessEmitWarning(w);
|
---|
220 | }
|
---|
221 | }
|
---|
222 |
|
---|
223 | return target;
|
---|
224 | }
|
---|
225 |
|
---|
226 | EventEmitter.prototype.addListener = function addListener(type, listener) {
|
---|
227 | return _addListener(this, type, listener, false);
|
---|
228 | };
|
---|
229 |
|
---|
230 | EventEmitter.prototype.on = EventEmitter.prototype.addListener;
|
---|
231 |
|
---|
232 | EventEmitter.prototype.prependListener =
|
---|
233 | function prependListener(type, listener) {
|
---|
234 | return _addListener(this, type, listener, true);
|
---|
235 | };
|
---|
236 |
|
---|
237 | function onceWrapper() {
|
---|
238 | if (!this.fired) {
|
---|
239 | this.target.removeListener(this.type, this.wrapFn);
|
---|
240 | this.fired = true;
|
---|
241 | if (arguments.length === 0)
|
---|
242 | return this.listener.call(this.target);
|
---|
243 | return this.listener.apply(this.target, arguments);
|
---|
244 | }
|
---|
245 | }
|
---|
246 |
|
---|
247 | function _onceWrap(target, type, listener) {
|
---|
248 | var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };
|
---|
249 | var wrapped = onceWrapper.bind(state);
|
---|
250 | wrapped.listener = listener;
|
---|
251 | state.wrapFn = wrapped;
|
---|
252 | return wrapped;
|
---|
253 | }
|
---|
254 |
|
---|
255 | EventEmitter.prototype.once = function once(type, listener) {
|
---|
256 | checkListener(listener);
|
---|
257 | this.on(type, _onceWrap(this, type, listener));
|
---|
258 | return this;
|
---|
259 | };
|
---|
260 |
|
---|
261 | EventEmitter.prototype.prependOnceListener =
|
---|
262 | function prependOnceListener(type, listener) {
|
---|
263 | checkListener(listener);
|
---|
264 | this.prependListener(type, _onceWrap(this, type, listener));
|
---|
265 | return this;
|
---|
266 | };
|
---|
267 |
|
---|
268 | // Emits a 'removeListener' event if and only if the listener was removed.
|
---|
269 | EventEmitter.prototype.removeListener =
|
---|
270 | function removeListener(type, listener) {
|
---|
271 | var list, events, position, i, originalListener;
|
---|
272 |
|
---|
273 | checkListener(listener);
|
---|
274 |
|
---|
275 | events = this._events;
|
---|
276 | if (events === undefined)
|
---|
277 | return this;
|
---|
278 |
|
---|
279 | list = events[type];
|
---|
280 | if (list === undefined)
|
---|
281 | return this;
|
---|
282 |
|
---|
283 | if (list === listener || list.listener === listener) {
|
---|
284 | if (--this._eventsCount === 0)
|
---|
285 | this._events = Object.create(null);
|
---|
286 | else {
|
---|
287 | delete events[type];
|
---|
288 | if (events.removeListener)
|
---|
289 | this.emit('removeListener', type, list.listener || listener);
|
---|
290 | }
|
---|
291 | } else if (typeof list !== 'function') {
|
---|
292 | position = -1;
|
---|
293 |
|
---|
294 | for (i = list.length - 1; i >= 0; i--) {
|
---|
295 | if (list[i] === listener || list[i].listener === listener) {
|
---|
296 | originalListener = list[i].listener;
|
---|
297 | position = i;
|
---|
298 | break;
|
---|
299 | }
|
---|
300 | }
|
---|
301 |
|
---|
302 | if (position < 0)
|
---|
303 | return this;
|
---|
304 |
|
---|
305 | if (position === 0)
|
---|
306 | list.shift();
|
---|
307 | else {
|
---|
308 | spliceOne(list, position);
|
---|
309 | }
|
---|
310 |
|
---|
311 | if (list.length === 1)
|
---|
312 | events[type] = list[0];
|
---|
313 |
|
---|
314 | if (events.removeListener !== undefined)
|
---|
315 | this.emit('removeListener', type, originalListener || listener);
|
---|
316 | }
|
---|
317 |
|
---|
318 | return this;
|
---|
319 | };
|
---|
320 |
|
---|
321 | EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
|
---|
322 |
|
---|
323 | EventEmitter.prototype.removeAllListeners =
|
---|
324 | function removeAllListeners(type) {
|
---|
325 | var listeners, events, i;
|
---|
326 |
|
---|
327 | events = this._events;
|
---|
328 | if (events === undefined)
|
---|
329 | return this;
|
---|
330 |
|
---|
331 | // not listening for removeListener, no need to emit
|
---|
332 | if (events.removeListener === undefined) {
|
---|
333 | if (arguments.length === 0) {
|
---|
334 | this._events = Object.create(null);
|
---|
335 | this._eventsCount = 0;
|
---|
336 | } else if (events[type] !== undefined) {
|
---|
337 | if (--this._eventsCount === 0)
|
---|
338 | this._events = Object.create(null);
|
---|
339 | else
|
---|
340 | delete events[type];
|
---|
341 | }
|
---|
342 | return this;
|
---|
343 | }
|
---|
344 |
|
---|
345 | // emit removeListener for all listeners on all events
|
---|
346 | if (arguments.length === 0) {
|
---|
347 | var keys = Object.keys(events);
|
---|
348 | var key;
|
---|
349 | for (i = 0; i < keys.length; ++i) {
|
---|
350 | key = keys[i];
|
---|
351 | if (key === 'removeListener') continue;
|
---|
352 | this.removeAllListeners(key);
|
---|
353 | }
|
---|
354 | this.removeAllListeners('removeListener');
|
---|
355 | this._events = Object.create(null);
|
---|
356 | this._eventsCount = 0;
|
---|
357 | return this;
|
---|
358 | }
|
---|
359 |
|
---|
360 | listeners = events[type];
|
---|
361 |
|
---|
362 | if (typeof listeners === 'function') {
|
---|
363 | this.removeListener(type, listeners);
|
---|
364 | } else if (listeners !== undefined) {
|
---|
365 | // LIFO order
|
---|
366 | for (i = listeners.length - 1; i >= 0; i--) {
|
---|
367 | this.removeListener(type, listeners[i]);
|
---|
368 | }
|
---|
369 | }
|
---|
370 |
|
---|
371 | return this;
|
---|
372 | };
|
---|
373 |
|
---|
374 | function _listeners(target, type, unwrap) {
|
---|
375 | var events = target._events;
|
---|
376 |
|
---|
377 | if (events === undefined)
|
---|
378 | return [];
|
---|
379 |
|
---|
380 | var evlistener = events[type];
|
---|
381 | if (evlistener === undefined)
|
---|
382 | return [];
|
---|
383 |
|
---|
384 | if (typeof evlistener === 'function')
|
---|
385 | return unwrap ? [evlistener.listener || evlistener] : [evlistener];
|
---|
386 |
|
---|
387 | return unwrap ?
|
---|
388 | unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);
|
---|
389 | }
|
---|
390 |
|
---|
391 | EventEmitter.prototype.listeners = function listeners(type) {
|
---|
392 | return _listeners(this, type, true);
|
---|
393 | };
|
---|
394 |
|
---|
395 | EventEmitter.prototype.rawListeners = function rawListeners(type) {
|
---|
396 | return _listeners(this, type, false);
|
---|
397 | };
|
---|
398 |
|
---|
399 | EventEmitter.listenerCount = function(emitter, type) {
|
---|
400 | if (typeof emitter.listenerCount === 'function') {
|
---|
401 | return emitter.listenerCount(type);
|
---|
402 | } else {
|
---|
403 | return listenerCount.call(emitter, type);
|
---|
404 | }
|
---|
405 | };
|
---|
406 |
|
---|
407 | EventEmitter.prototype.listenerCount = listenerCount;
|
---|
408 | function listenerCount(type) {
|
---|
409 | var events = this._events;
|
---|
410 |
|
---|
411 | if (events !== undefined) {
|
---|
412 | var evlistener = events[type];
|
---|
413 |
|
---|
414 | if (typeof evlistener === 'function') {
|
---|
415 | return 1;
|
---|
416 | } else if (evlistener !== undefined) {
|
---|
417 | return evlistener.length;
|
---|
418 | }
|
---|
419 | }
|
---|
420 |
|
---|
421 | return 0;
|
---|
422 | }
|
---|
423 |
|
---|
424 | EventEmitter.prototype.eventNames = function eventNames() {
|
---|
425 | return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
|
---|
426 | };
|
---|
427 |
|
---|
428 | function arrayClone(arr, n) {
|
---|
429 | var copy = new Array(n);
|
---|
430 | for (var i = 0; i < n; ++i)
|
---|
431 | copy[i] = arr[i];
|
---|
432 | return copy;
|
---|
433 | }
|
---|
434 |
|
---|
435 | function spliceOne(list, index) {
|
---|
436 | for (; index + 1 < list.length; index++)
|
---|
437 | list[index] = list[index + 1];
|
---|
438 | list.pop();
|
---|
439 | }
|
---|
440 |
|
---|
441 | function unwrapListeners(arr) {
|
---|
442 | var ret = new Array(arr.length);
|
---|
443 | for (var i = 0; i < ret.length; ++i) {
|
---|
444 | ret[i] = arr[i].listener || arr[i];
|
---|
445 | }
|
---|
446 | return ret;
|
---|
447 | }
|
---|
448 |
|
---|
449 | function once(emitter, name) {
|
---|
450 | return new Promise(function (resolve, reject) {
|
---|
451 | function errorListener(err) {
|
---|
452 | emitter.removeListener(name, resolver);
|
---|
453 | reject(err);
|
---|
454 | }
|
---|
455 |
|
---|
456 | function resolver() {
|
---|
457 | if (typeof emitter.removeListener === 'function') {
|
---|
458 | emitter.removeListener('error', errorListener);
|
---|
459 | }
|
---|
460 | resolve([].slice.call(arguments));
|
---|
461 | };
|
---|
462 |
|
---|
463 | eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });
|
---|
464 | if (name !== 'error') {
|
---|
465 | addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });
|
---|
466 | }
|
---|
467 | });
|
---|
468 | }
|
---|
469 |
|
---|
470 | function addErrorHandlerIfEventEmitter(emitter, handler, flags) {
|
---|
471 | if (typeof emitter.on === 'function') {
|
---|
472 | eventTargetAgnosticAddListener(emitter, 'error', handler, flags);
|
---|
473 | }
|
---|
474 | }
|
---|
475 |
|
---|
476 | function eventTargetAgnosticAddListener(emitter, name, listener, flags) {
|
---|
477 | if (typeof emitter.on === 'function') {
|
---|
478 | if (flags.once) {
|
---|
479 | emitter.once(name, listener);
|
---|
480 | } else {
|
---|
481 | emitter.on(name, listener);
|
---|
482 | }
|
---|
483 | } else if (typeof emitter.addEventListener === 'function') {
|
---|
484 | // EventTarget does not have `error` event semantics like Node
|
---|
485 | // EventEmitters, we do not listen for `error` events here.
|
---|
486 | emitter.addEventListener(name, function wrapListener(arg) {
|
---|
487 | // IE does not have builtin `{ once: true }` support so we
|
---|
488 | // have to do it manually.
|
---|
489 | if (flags.once) {
|
---|
490 | emitter.removeEventListener(name, wrapListener);
|
---|
491 | }
|
---|
492 | listener(arg);
|
---|
493 | });
|
---|
494 | } else {
|
---|
495 | throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter);
|
---|
496 | }
|
---|
497 | }
|
---|