From f727b28d0b20c30cb111a69a0062e3e93f5de6f7 Mon Sep 17 00:00:00 2001 From: Jacob Foster Date: Mon, 17 Jun 2024 17:33:12 -0500 Subject: [PATCH] events: replace EventEmitter with a more simple version with the same API --- lib/client.js | 15 +-- lib/events.js | 328 +++++++------------------------------------------- 2 files changed, 45 insertions(+), 298 deletions(-) diff --git a/lib/client.js b/lib/client.js index b3f00db..f44766c 100644 --- a/lib/client.js +++ b/lib/client.js @@ -1,6 +1,6 @@ const _global = typeof global !== 'undefined' ? global : typeof window !== 'undefined' ? window : {}; const _WebSocket = _global.WebSocket || require('ws'); -const EventEmitter = require('./events').EventEmitter; +const EventEmitter = require('./events'); const logger = require('./logger'); const parse = require('./parser'); const Queue = require('./timer'); @@ -60,19 +60,6 @@ class client extends EventEmitter { // Format the channel names.. this.opts.channels.forEach((n, i, a) => a[i] = _.channel(n)); - - EventEmitter.call(this); - this.setMaxListeners(0); - } - // Emit multiple events.. - emits(types, values) { - for(let i = 0; i < types.length; i++) { - const val = i < values.length ? values[i] : values[values.length - 1]; - this.emit.apply(this, [ types[i] ].concat(val)); - } - } - off(event, listener) { - this.removeListener(event, listener); } // Handle parsed chat server message.. handleMessage(message) { diff --git a/lib/events.js b/lib/events.js index 4e193f1..2961496 100644 --- a/lib/events.js +++ b/lib/events.js @@ -1,301 +1,61 @@ -/* istanbul ignore file */ -/* eslint-disable */ -/* - * Copyright Joyent, Inc. and other Node contributors. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to permit - * persons to whom the Software is furnished to do so, subject to the - * following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -function EventEmitter() { - this._events = this._events || {}; - this._maxListeners = this._maxListeners || undefined; -} - -module.exports = EventEmitter; - -// Backwards-compat with node 0.10.x -EventEmitter.EventEmitter = EventEmitter; - -EventEmitter.prototype._events = undefined; -EventEmitter.prototype._maxListeners = undefined; - -// By default EventEmitters will print a warning if more than 10 listeners are -// added to it. This is a useful default which helps finding memory leaks. -EventEmitter.defaultMaxListeners = 10; - -// Obviously not all Emitters should be limited to 10. This function allows -// that to be increased. Set to zero for unlimited. -EventEmitter.prototype.setMaxListeners = function(n) { - if (!isNumber(n) || n < 0 || isNaN(n)) { - throw TypeError("n must be a positive number"); +class EventEmitter { + constructor() { + this._events = new Map(); } - - this._maxListeners = n; - - return this; -}; - -EventEmitter.prototype.emit = function(type) { - var er, handler, len, args, i, listeners; - - if (!this._events) { this._events = {}; } - - // If there is no 'error' event listener then throw. - if (type === "error") { - if (!this._events.error || (isObject(this._events.error) && !this._events.error.length)) { - er = arguments[1]; - if (er instanceof Error) { throw er; } - throw TypeError("Uncaught, unspecified \"error\" event."); + emit(type, ...args) { + const listeners = this._events.get(type); + if(!listeners) { + return false; } - } - - handler = this._events[type]; - - if (isUndefined(handler)) { return false; } - - if (isFunction(handler)) { - switch (arguments.length) { - // fast cases - case 1: - handler.call(this); - break; - case 2: - handler.call(this, arguments[1]); - break; - case 3: - handler.call(this, arguments[1], arguments[2]); - break; - // slower - default: - args = Array.prototype.slice.call(arguments, 1); - handler.apply(this, args); + for(const listener of listeners) { + listener.apply(this, args); } - } else if (isObject(handler)) { - args = Array.prototype.slice.call(arguments, 1); - listeners = handler.slice(); - len = listeners.length; - for (i = 0; i < len; i++) { listeners[i].apply(this, args); } - } - - return true; -}; - -EventEmitter.prototype.addListener = function(type, listener) { - var m; - - if (!isFunction(listener)) { throw TypeError("listener must be a function"); } - - if (!this._events) { this._events = {}; } - - // To avoid recursion in the case that type === "newListener"! Before - // adding it to the listeners, first emit "newListener". - if (this._events.newListener) { - this.emit("newListener", type, isFunction(listener.listener) ? listener.listener : listener); + return true; } - - // Optimize the case of one listener. Don't need the extra array object. - if (!this._events[type]) { this._events[type] = listener; } - // If we've already got an array, just append. - else if (isObject(this._events[type])) { this._events[type].push(listener); } - // Adding the second element, need to change to array. - else { this._events[type] = [this._events[type], listener]; } - - // Check for listener leak - if (isObject(this._events[type]) && !this._events[type].warned) { - if (!isUndefined(this._maxListeners)) { - m = this._maxListeners; - } else { - m = EventEmitter.defaultMaxListeners; - } - - if (m && m > 0 && this._events[type].length > m) { - this._events[type].warned = true; - console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.", this._events[type].length); - // Not supported in IE 10 - if (typeof console.trace === "function") { - console.trace(); - } + emits(types, values) { + for(let i = 0; i < types.length; i++) { + const val = i < values.length ? values[i] : values[values.length - 1]; + this.emit.apply(this, [ types[i] ].concat(val)); } } - - return this; -}; - -EventEmitter.prototype.on = EventEmitter.prototype.addListener; - -// Modified to support multiple calls.. -EventEmitter.prototype.once = function(type, listener) { - if (!isFunction(listener)) { throw TypeError("listener must be a function"); } - - var fired = false; - - if (this._events.hasOwnProperty(type) && type.charAt(0) === "_") { - var count = 1; - var searchFor = type; - - for (var k in this._events){ - if (this._events.hasOwnProperty(k) && k.startsWith(searchFor)) { - count++; - } + addListener(type, listener) { + if(!this._events.has(type)) { + this._events.set(type, new Set()); } - type = type + count; + this._events.get(type).add(listener); } - - function g() { - if (type.charAt(0) === "_" && !isNaN(type.substr(type.length - 1))) { - type = type.substring(0, type.length - 1); - } - this.removeListener(type, g); - - if (!fired) { - fired = true; - listener.apply(this, arguments); - } + on(type, listener) { + this.addListener(type, listener); } - - g.listener = listener; - this.on(type, g); - - return this; -}; - -// Emits a "removeListener" event if the listener was removed.. -// Modified to support multiple calls from .once().. -EventEmitter.prototype.removeListener = function(type, listener) { - var list, position, length, i; - - if (!isFunction(listener)) { throw TypeError("listener must be a function"); } - - if (!this._events || !this._events[type]) { return this; } - - list = this._events[type]; - length = list.length; - position = -1; - if (list === listener || (isFunction(list.listener) && list.listener === listener)) { - delete this._events[type]; - - if (this._events.hasOwnProperty(type + "2") && type.charAt(0) === "_") { - var searchFor = type; - for (var k in this._events){ - if (this._events.hasOwnProperty(k) && k.startsWith(searchFor)) { - if (!isNaN(parseInt(k.substr(k.length - 1)))) { - this._events[type + parseInt(k.substr(k.length - 1) - 1)] = this._events[k]; - delete this._events[k]; - } - } - } - - this._events[type] = this._events[type + "1"]; - delete this._events[type + "1"]; - } - if (this._events.removeListener) { this.emit("removeListener", type, listener); } + once(type, listener) { + const wrapped = (...args) => { + this.removeListener(type, wrapped); + listener.apply(this, args); + }; + this.addListener(type, wrapped); } - else if (isObject(list)) { - for (i = length; i-- > 0;) { - if (list[i] === listener || - (list[i].listener && list[i].listener === listener)) { - position = i; - break; - } + removeListener(type, listener) { + if(!this._events.has(type)) { + return; } - - if (position < 0) { return this; } - - if (list.length === 1) { - list.length = 0; - delete this._events[type]; - } - else { list.splice(position, 1); } - - if (this._events.removeListener) { this.emit("removeListener", type, listener); } + this._events.get(type).delete(listener); } - - return this; -}; - -EventEmitter.prototype.removeAllListeners = function(type) { - var key, listeners; - - if (!this._events) { return this; } - - // not listening for removeListener, no need to emit - if (!this._events.removeListener) { - if (arguments.length === 0) { this._events = {}; } - else if (this._events[type]) { delete this._events[type]; } - return this; + off(type, listener) { + this.removeListener(type, listener); } - - // emit removeListener for all listeners on all events - if (arguments.length === 0) { - for (key in this._events) { - if (key === "removeListener") { continue; } - this.removeAllListeners(key); - } - this.removeAllListeners("removeListener"); - this._events = {}; - return this; + removeAllListeners(type) { + this._events.delete(type); } - - listeners = this._events[type]; - - if (isFunction(listeners)) { this.removeListener(type, listeners); } - else if (listeners) { while (listeners.length) { this.removeListener(type, listeners[listeners.length - 1]); } } - delete this._events[type]; - - return this; -}; - -EventEmitter.prototype.listeners = function(type) { - var ret; - if (!this._events || !this._events[type]) { ret = []; } - else if (isFunction(this._events[type])) { ret = [this._events[type]]; } - else { ret = this._events[type].slice(); } - return ret; -}; - -EventEmitter.prototype.listenerCount = function(type) { - if (this._events) { - var evlistener = this._events[type]; - - if (isFunction(evlistener)) { return 1; } - else if (evlistener) { return evlistener.length; } + listeners(type) { + return this._events.get(type); + } + listenerCount(type) { + const listeners = this._events.get(type); + if(!listeners) { + return 0; + } + return listeners.size; } - return 0; -}; - -EventEmitter.listenerCount = function(emitter, type) { - return emitter.listenerCount(type); -}; - -function isFunction(arg) { - return typeof arg === "function"; -} - -function isNumber(arg) { - return typeof arg === "number"; -} - -function isObject(arg) { - return typeof arg === "object" && arg !== null; } -function isUndefined(arg) { - return arg === void 0; -} +module.exports = EventEmitter;