{"version":3,"sources":["../src/index.ts","../src/MemoryLeakError.ts","../src/Emitter.ts"],"sourcesContent":["export * from './Emitter'\nexport * from './MemoryLeakError'\n","import type { Emitter } from './Emitter'\n\nexport class MemoryLeakError extends Error {\n constructor(\n public readonly emitter: Emitter,\n public readonly type: string | number | symbol,\n public readonly count: number\n ) {\n super(\n `Possible EventEmitter memory leak detected. ${count} ${type.toString()} listeners added. Use emitter.setMaxListeners() to increase limit`\n )\n this.name = 'MaxListenersExceededWarning'\n }\n}\n","import { MemoryLeakError } from './MemoryLeakError'\n\nexport type EventMap = {\n [eventName: string]: Array\n}\n\nexport type InternalEventNames = 'newListener' | 'removeListener'\n\nexport type InternalListener = Listener<\n [eventName: keyof Events, listener: Listener>]\n>\n\nexport type Listener> = (...data: Data) => void\n\n/**\n * Node.js-compatible implementation of `EventEmitter`.\n *\n * @example\n * const emitter = new Emitter<{ hello: [string] }>()\n * emitter.on('hello', (name) => console.log(name))\n * emitter.emit('hello', 'John')\n */\nexport class Emitter {\n private events: Map>>\n private maxListeners: number\n private hasWarnedAboutPotentialMemoryLeak: boolean\n\n static defaultMaxListeners = 10\n\n static listenerCount(\n emitter: Emitter,\n eventName: keyof Events\n ): number {\n return emitter.listenerCount(eventName)\n }\n\n constructor() {\n this.events = new Map()\n this.maxListeners = Emitter.defaultMaxListeners\n this.hasWarnedAboutPotentialMemoryLeak = false\n }\n\n private _emitInternalEvent(\n internalEventName: InternalEventNames,\n eventName: keyof Events,\n listener: Listener>\n ): void {\n this.emit(\n internalEventName,\n // Anything to make TypeScript happy.\n ...([eventName, listener] as Events['newListener'] &\n Events['removeListener'])\n )\n }\n\n private _getListeners(\n eventName: EventName\n ): Array>> {\n // Always return a copy of the listeners array\n // so they are fixed at the time of the \"_getListeners\" call.\n return Array.prototype.concat.apply([], this.events.get(eventName)) || []\n }\n\n private _removeListener(\n listeners: Array>,\n listener: Listener\n ): Array> {\n const index = listeners.indexOf(listener)\n\n if (index > -1) {\n listeners.splice(index, 1)\n }\n\n return []\n }\n\n private _wrapOnceListener(\n eventName: EventName,\n listener: Listener\n ): Listener {\n const onceListener = (...data: Events[keyof Events]) => {\n this.removeListener(eventName, onceListener)\n\n /**\n * @note Return the result of the original listener.\n * This way this wrapped preserves listeners that are async.\n */\n return listener.apply(this, data)\n }\n\n // Inherit the name of the original listener.\n Object.defineProperty(onceListener, 'name', { value: listener.name })\n\n return onceListener\n }\n\n public setMaxListeners(maxListeners: number): this {\n this.maxListeners = maxListeners\n return this\n }\n\n /**\n * Returns the current max listener value for the `Emitter` which is\n * either set by `emitter.setMaxListeners(n)` or defaults to\n * `Emitter.defaultMaxListeners`.\n */\n public getMaxListeners(): number {\n return this.maxListeners\n }\n\n /**\n * Returns an array listing the events for which the emitter has registered listeners.\n * The values in the array will be strings or Symbols.\n */\n public eventNames(): Array {\n return Array.from(this.events.keys())\n }\n\n /**\n * Synchronously calls each of the listeners registered for the event named `eventName`,\n * in the order they were registered, passing the supplied arguments to each.\n * Returns `true` if the event has listeners, `false` otherwise.\n *\n * @example\n * const emitter = new Emitter<{ hello: [string] }>()\n * emitter.emit('hello', 'John')\n */\n public emit(\n eventName: EventName,\n ...data: Events[EventName]\n ): boolean {\n const listeners = this._getListeners(eventName)\n listeners.forEach((listener) => {\n listener.apply(this, data)\n })\n\n return listeners.length > 0\n }\n\n public addListener(\n eventName: InternalEventNames,\n listener: InternalListener\n ): this\n public addListener(\n eventName: EventName,\n listener: Listener\n ): this\n public addListener(\n eventName: InternalEventNames | keyof Events,\n listener: InternalListener | Listener\n ): this {\n // Emit the `newListener` event before adding the listener.\n this._emitInternalEvent('newListener', eventName, listener)\n\n const nextListeners = this._getListeners(eventName).concat(listener)\n this.events.set(eventName, nextListeners)\n\n if (\n this.maxListeners > 0 &&\n this.listenerCount(eventName) > this.maxListeners &&\n !this.hasWarnedAboutPotentialMemoryLeak\n ) {\n this.hasWarnedAboutPotentialMemoryLeak = true\n\n const memoryLeakWarning = new MemoryLeakError(\n this,\n eventName,\n this.listenerCount(eventName)\n )\n console.warn(memoryLeakWarning)\n }\n\n return this\n }\n\n public on(\n eventName: InternalEventNames,\n listener: InternalListener\n ): this\n public on(\n eventName: EventName,\n listener: Listener\n ): this\n public on(\n eventName: 'removeListener' | EventName,\n listener: Listener\n ): this {\n return this.addListener(eventName, listener)\n }\n\n public once(\n eventName: InternalEventNames,\n listener: InternalListener\n ): this\n public once(\n eventName: EventName,\n listener: Listener\n ): this\n public once(\n eventName: InternalEventNames | EventName,\n listener: Listener\n ): this {\n return this.addListener(\n eventName,\n this._wrapOnceListener(eventName, listener)\n )\n }\n\n public prependListener(\n eventName: InternalEventNames,\n listener: InternalListener\n ): this\n public prependListener(\n eventName: EventName,\n listener: Listener\n ): this\n public prependListener(\n eventName: InternalEventNames | keyof Events,\n listener: Listener\n ): this {\n const listeners = this._getListeners(eventName)\n\n if (listeners.length > 0) {\n const nextListeners = [listener].concat(listeners)\n this.events.set(eventName, nextListeners)\n } else {\n this.events.set(eventName, listeners.concat(listener))\n }\n\n return this\n }\n\n public prependOnceListener(\n eventName: InternalEventNames,\n listener: InternalListener\n ): this\n public prependOnceListener(\n eventName: EventName,\n listener: Listener\n ): this\n public prependOnceListener(\n eventName: InternalEventNames | keyof Events,\n listener: Listener\n ): this {\n return this.prependListener(\n eventName,\n this._wrapOnceListener(eventName, listener)\n )\n }\n\n public removeListener(\n eventName: InternalEventNames,\n listener: InternalListener\n ): this\n public removeListener(\n eventName: EventName,\n listener: Listener\n ): this\n public removeListener(\n eventName: InternalEventNames | keyof Events,\n listener: Listener\n ): this {\n const listeners = this._getListeners(eventName)\n\n if (listeners.length > 0) {\n this._removeListener(listeners, listener)\n this.events.set(eventName, listeners)\n\n // Emit the `removeListener` event after removing the listener.\n this._emitInternalEvent('removeListener', eventName, listener)\n }\n\n return this\n }\n\n public off(\n eventName: InternalEventNames,\n listener: InternalListener\n ): this\n public off(\n eventName: EventName,\n listener: Listener\n ): this\n /**\n * Alias for `emitter.removeListener()`.\n *\n * @example\n * emitter.off('hello', listener)\n */\n public off(\n eventName: InternalEventNames | keyof Events,\n listener: Listener\n ): this {\n return this.removeListener(eventName, listener)\n }\n\n public removeAllListeners(eventName?: InternalEventNames): this\n public removeAllListeners(\n eventName?: EventName\n ): this\n public removeAllListeners(\n eventName?: InternalEventNames | keyof Events\n ): this {\n if (eventName) {\n this.events.delete(eventName)\n } else {\n this.events.clear()\n }\n\n return this\n }\n\n public listeners(eventName: InternalEventNames): Array>\n public listeners(\n eventName: EventName\n ): Array>\n /**\n * Returns a copy of the array of listeners for the event named `eventName`.\n */\n public listeners(eventName: InternalEventNames | keyof Events) {\n return Array.from(this._getListeners(eventName))\n }\n\n public listenerCount(eventName: InternalEventNames): number\n public listenerCount(\n eventName: EventName\n ): number\n /**\n * Returns the number of listeners listening to the event named `eventName`.\n */\n public listenerCount(eventName: InternalEventNames | keyof Events): number {\n return this._getListeners(eventName).length\n }\n\n public rawListeners(\n eventName: EventName\n ): Array> {\n return this.listeners(eventName)\n }\n}\n"],"mappings":"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","names":[]}