import { type AsyncSubscription, AsyncTeardownManager, type Subscription } from "../teardown-manager.js"; import { Event, type EventArgs, type EventKeys, type EventListener, type EventOptions, type EventReturnType, type IEvent } from "./shared.js"; /** * Represents special events with a dispose symbol. * @typedef {Object} SpecialEvents * @property {Event<[]>} [Symbol.dispose] - The dispose event. */ export type SpecialEvents = { [Symbol.dispose]: IEvent<[], void> } export type EventMap = { [key in EventKeys]?: T[key] } /** * Represents all event keys, including special events. * @template T * @typedef {EventKeys | keyof SpecialEvents} AllEventKeys */ export type AllEventKeys = EventKeys | keyof SpecialEvents; /** * EventBus interface to manage events and listeners. * @template T * @implements {Disposable} */ export interface EventBus = Record>> extends AsyncTeardownManager { /** * Checks if there are listeners for a given event. * @template TKey * @param {TKey} name - The name of the event. * @returns {boolean} - True if there are listeners, false otherwise. */ hasListener>(name: TKey): boolean; /** * Gets the defined events. * @returns {string[]} - An array of defined event names. */ get definedEvents(): (EventKeys)[]; /** * Emits an event. * @template TEvent * @param {TEvent} event - The event to emit. * @param {...EventArgs} args - The arguments to pass to the event listeners. * @returns {false | EventReturnType} - The return value of the event listeners or false if the event does not exist. */ emit>(event: TEvent, ...args: EventArgs): false | EventReturnType; /** * Adds a listener for an event. * @template TEvent * @param {TEvent} event - The event to listen to. * @param {EventListener[TEvent]>} handler - The event handler. * @param {EventOptions[TEvent]>} [options] - The event options. * @returns {Subscription} - The subscription. */ on>(event: TEvent, handler: EventListener, options?: EventOptions): Subscription; /** * Adds a one-time listener for an event. * @template TEvent * @param {TEvent} event - The event to listen to. * @param {EventListener[TEvent]>} handler - The event handler. * @param {Omit[TEvent]>, 'once'>} [options] - The event options. * @returns {Subscription} - The subscription. */ once>(event: TEvent, handler: EventListener, options?: Omit, 'once'>): Subscription; /** * Removes a listener for an event. * @template TEvent * @param {TEvent} event - The event to remove the listener from. * @param {EventListener[TEvent]>} handler - The event handler. * @returns {boolean} - True if the listener was removed, false otherwise. */ off>(event: TEvent, handler?: EventListener): boolean; } /** * AsyncEventBus interface to manage events and listeners. * @template T * @implements {Disposable} */ export interface AsyncEventBus } = Record>> extends AsyncTeardownManager { /** * Checks if there are listeners for a given event. * @template TKey * @param {TKey} name - The name of the event. * @returns {Promise} - True if there are listeners, false otherwise. */ hasListener>(name: TKey): Promise; /** * Gets the defined events. * @returns {Promise} - An array of defined event names. */ get definedEvents(): Promise<(EventKeys)[]>; /** * Emits an event. * @template TEvent * @param {TEvent} event - The event to emit. * @param {...EventArgs} args - The arguments to pass to the event listeners. * @returns {Promise>} - The return value of the event listeners or false if the event does not exist. */ emit>(event: TEvent, ...args: EventArgs): Promise>; /** * Adds a listener for an event. * @template TEvent * @param {TEvent} event - The event to listen to. * @param {EventListener[TEvent]>} handler - The event handler. * @param {EventOptions[TEvent]>} [options] - The event options. * @returns {Promise} - The subscription. */ on>(event: TEvent, handler: EventListener, options?: EventOptions): Promise; /** * Adds a one-time listener for an event. * @template TEvent * @param {TEvent} event - The event to listen to. * @param {EventListener[TEvent]>} handler - The event handler. * @param {Omit[TEvent]>, 'once'>} [options] - The event options. * @returns {Promise} - The subscription. */ once>(event: TEvent, handler: EventListener, options?: Omit, 'once'>): Promise; /** * Removes a listener for an event. * @template TEvent * @param {TEvent} event - The event to remove the listener from. * @param {EventListener[TEvent]>} handler - The event handler. * @returns {Promise} - True if the listener was removed, false otherwise. */ off>(event: TEvent, handler?: EventListener): Promise; } /** * Wrapper class for EventEmitter to manage subscriptions. * @template T * @implements {Disposable} */ export class EventBusWrapper> = Record>> extends AsyncTeardownManager implements EventBus { constructor(private readonly emitter: EventBus) { super(); emitter.once(Symbol.dispose as EventKeys, (() => this[Symbol.dispose]()) as EventListener]>); } public readonly subscriptions: Subscription[] = [] /** * Checks if there are listeners for a given event. * @template TKey * @param {TKey} name - The name of the event. * @returns {boolean} - True if there are listeners, false otherwise. */ hasListener>(name: TKey): boolean { return this.emitter.hasListener(name); } /** * Gets the defined events. * @returns {string[]} - An array of defined event names. */ public get definedEvents(): EventKeys[] { return this.emitter.definedEvents; } /** * Emits an event. * @template TEvent * @param {TEvent} event - The event to emit. * @param {...EventArgs} args - The arguments to pass to the event listeners. * @returns {false | EventReturnType} - The return value of the event listeners or false if the event does not exist. */ emit>(event: TEvent, ...args: EventArgs): false | EventReturnType { return this.emitter.emit(event, ...args); } /** * Adds a listener for an event. * @template TEvent * @param {TEvent} event - The event to listen to. * @param {EventListener[TEvent]>} handler - The event handler. * @param {EventOptions[TEvent]>} [options] - The event options. * @returns {Subscription} - The subscription. */ on>(event: TEvent, handler: EventListener, options?: EventOptions): Subscription { const sub = this.emitter.on(event, handler, options); this.subscriptions.push(sub); return sub; } /** * Adds a one-time listener for an event. * @template TEvent * @param {TEvent} event - The event to listen to. * @param {EventListener[TEvent]>} handler - The event handler. * @param {Omit[TEvent]>, "once">} [options] - The event options. * @returns {Subscription} - The subscription. */ once>(event: TEvent, handler: EventListener, options?: Omit, "once">): Subscription { const sub = this.emitter.once(event, handler, options); this.subscriptions.push(sub); return sub; } /** * Removes a listener for an event. * @template TEvent * @param {TEvent} event - The event to remove the listener from. * @param {EventListener[TEvent]>} handler - The event handler. * @returns {boolean} - True if the listener was removed, false otherwise. */ off>(event: TEvent, handler: EventListener): boolean { return this.emitter.off(event, handler); } } /** * Wrapper class to make a sync event bus async. * @template T * @implements {Disposable} */ export class EventBus2AsyncEventBus> = Record>> extends AsyncTeardownManager implements AsyncEventBus { constructor(private readonly emitter: EventBus) { super(); emitter.once(Symbol.dispose as EventKeys, (() => this[Symbol.asyncDispose]()) as EventListener]>); } public readonly subscriptions: Subscription[] = [] /** * Checks if there are listeners for a given event. * @template TKey * @param {TKey} name - The name of the event. * @returns {boolean} - True if there are listeners, false otherwise. */ hasListener>(name: TKey): Promise { return Promise.resolve(this.emitter.hasListener(name)); } /** * Gets the defined events. * @returns {string[]} - An array of defined event names. */ public get definedEvents(): Promise[]> { return Promise.resolve(this.emitter.definedEvents); } /** * Emits an event. * @template TEvent * @param {TEvent} event - The event to emit. * @param {...EventArgs} args - The arguments to pass to the event listeners. * @returns {false | EventReturnType} - The return value of the event listeners or false if the event does not exist. */ emit>(event: TEvent, ...args: EventArgs): Promise> { return Promise.resolve(this.emitter.emit(event, ...args)); } /** * Adds a listener for an event. * @template TEvent * @param {TEvent} event - The event to listen to. * @param {EventListener[TEvent]>} handler - The event handler. * @param {EventOptions[TEvent]>} [options] - The event options. * @returns {Subscription} - The subscription. */ on>(event: TEvent, handler: EventListener, options?: EventOptions): Promise { const sub = this.emitter.on(event, handler, options); this.subscriptions.push(sub); return Promise.resolve(() => Promise.resolve(sub())); } /** * Adds a one-time listener for an event. * @template TEvent * @param {TEvent} event - The event to listen to. * @param {EventListener[TEvent]>} handler - The event handler. * @param {Omit[TEvent]>, "once">} [options] - The event options. * @returns {Subscription} - The subscription. */ once>(event: TEvent, handler: EventListener, options?: Omit, "once">): Promise { const sub = this.emitter.once(event, handler, options); this.subscriptions.push(sub); return Promise.resolve(() => Promise.resolve(sub())); } /** * Removes a listener for an event. * @template TEvent * @param {TEvent} event - The event to remove the listener from. * @param {EventListener[TEvent]>} handler - The event handler. * @returns {boolean} - True if the listener was removed, false otherwise. */ off>(event: TEvent, handler: EventListener): Promise { return Promise.resolve(this.emitter.off(event, handler)); } }