import { EventHandler } from "./types" export class AGEventEmitter { private readonly _eventMap: Map[]> = new Map() once(evt: Key, cb: T[Key]) { const wrapper = (...args: any[]) => { this.off(evt, wrapper as any) ;(cb as any)(...args) } this.on(evt, wrapper as any) return this } on(evt: Key, cb: T[Key]) { const cbs = this._eventMap.get(evt) ?? [] cbs.push(cb as any) this._eventMap.set(evt, cbs) return this } off(evt: Key, cb: T[Key]) { const cbs = this._eventMap.get(evt) if (cbs) { this._eventMap.set( evt, cbs.filter((it) => it !== cb), ) } return this } removeAllEventListeners(): void { this._eventMap.clear() } emit(evt: Key, ...args: any[]) { const cbs = this._eventMap.get(evt) ?? [] for (const cb of cbs) { try { cb && cb(...args) } catch (e) { // cb exception should not affect other callbacks const error = e as Error const details = error.stack || error.message console.error( `[event] handling event ${evt.toString()} fail: ${details}`, ) } } return this } }