import type { Disposable } from "./disposable.js"; import type { Event, EventListener, RemoveEventListener } from "./event.js"; export interface EventListenerInfo { listener: EventListener; thisArg: unknown; args: unknown[]; } export class EventEmitter implements Disposable { protected readonly listeners: EventListenerInfo[] = []; constructor() { this.event = this.event.bind(this); } protected addEventListener( info: EventListenerInfo, ): RemoveEventListener { this.listeners.push(info); const remove: RemoveEventListener = () => { const index = this.listeners.indexOf(info); if (index !== -1) { this.listeners.splice(index, 1); } }; remove.dispose = remove; return remove; } event: Event = ( listener: EventListener, thisArg?: TThis, ...args: TArgs ) => { const info: EventListenerInfo = { listener: listener as EventListener< TEvent, unknown, unknown[], TResult >, thisArg, args, }; return this.addEventListener(info); }; fire(e: TEvent) { for (const info of this.listeners.slice()) { info.listener.call(info.thisArg, e, ...info.args); } } dispose() { this.listeners.length = 0; } }