import { go, goGenerator } from '@blackglory/go' type Listener = (...args: Args) => | void | Generator export class GeneratorEmitter< EventToArgs extends Record = Record< string | number | symbol , unknown[] > , Event extends string | number | symbol = keyof EventToArgs , Yield = unknown , Next = unknown > { private map = new Map< Event , Set> >() get [Symbol.toStringTag](): string { return this.constructor.name } on( event: T , listener: Listener ): () => void { const set = go(() => { const set = this.map.get(event) if (set) { return set } else { const set = new Set>() this.map.set(event, set) return set } }) set.add(handler as Listener) return () => { const handlers = this.map.get(event) if (handlers) { const deleted = handlers.delete( handler as Listener ) if (deleted && handlers.size === 0) { this.map.delete(event) } } } function * handler( ...args: Parameters> ): Generator { yield* goGenerator(() => listener(...args)) } } once( event: T , listener: Listener ): () => void { const removeListener = this.on( event , function * ( ...args: Parameters> ): Generator { yield* goGenerator(() => listener(...args)) removeListener() } ) return removeListener } * emit( event: T , ...args: EventToArgs[T] ): Generator { const listeners = this.map.get(event) if (listeners) { for (const listener of listeners) { yield* goGenerator(() => listener(...args)) } } } removeAllListeners(event: T): void { this.map.get(event)?.clear() } }