UNPKG

@fimbul-works/observable

Version:

A lightweight, strongly-typed TypeScript library for reactive programming patterns, providing observable collections, values, and event handling.

125 lines (124 loc) 4.33 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EventEmitter = void 0; const map_js_1 = require("./map.js"); const signal_js_1 = require("./signal.js"); /** * A strongly-typed event emitter that manages event subscriptions and emissions. * Supports both synchronous and asynchronous event handlers. * * @template EventMap - Defines the mapping of event names to their data types. */ class EventEmitter { /** * Internal map of event signals, where each signal corresponds to an event type. * @private */ #signals = new map_js_1.ObservableMap(); /** * Subscribes to an event with a callback function. * The callback can be synchronous or asynchronous (return a Promise). * * @template K - The event key type. * @param event - The event to subscribe to. * @param fn - The function to be called when the event is emitted. * @returns A cleanup function that removes the handler when called. */ on(event, fn) { if (!this.#signals.has(event)) { this.#signals.set(event, new signal_js_1.Signal()); } const signal = this.#signals.get(event); if (signal) return signal.connect(fn); return () => { }; } /** * Unsubscribes a callback function from an event. * @template K - The event key type. * @param event - The event to unsubscribe from. * @param fn - The function to remove. */ off(event, fn) { const signal = this.#signals.get(event); if (signal) signal.disconnect(fn); } /** * Emits an event with the provided data. * This method runs synchronously and doesn't wait for any promises returned by handlers. * * @template K - The event key type. * @param event - The event to emit. * @param data - The data to pass to event handlers. * @returns {this} The event emitter instance for method chaining. */ emit(event, data) { const signal = this.#signals.get(event); if (signal) signal.emit(data); return this; } /** * Emits an event with the provided data and waits for all handlers to complete, * including any that return Promises. * * @template K - The event key type. * @param event - The event to emit. * @param data - The data to pass to event handlers. * @returns {Promise<this>} Promise resolving to the event emitter instance for method chaining. */ async emitAsync(event, data) { const signal = this.#signals.get(event); if (signal) await signal.emitAsync(data); return this; } /** * Registers an error handler for a specific event. * @template K - The event key type. * @param event - The event to handle errors for. * @param fn - The function to be called when an error occurs. * @returns A cleanup function that removes the error handler when called. */ onError(event, fn) { if (!this.#signals.has(event)) { this.#signals.set(event, new signal_js_1.Signal()); } const signal = this.#signals.get(event); if (signal) return signal.connectError(fn); return () => { }; } /** * Removes an error handler for a specific event. * @template K - The event key type. * @param event - The event to remove the error handler from. * @param fn - The error handler function to remove. * @returns {this} The event emitter instance for method chaining. */ offError(event, fn) { const signal = this.#signals.get(event); if (signal) signal.disconnectError(fn); return this; } /** * Returns an array of all registered event names. * @returns {Array<keyof EventMap>} An array containing all event names. */ getEvents() { return Array.from(this.#signals.keys()); } /** * Cleans up all event subscriptions and releases resources. * Call this method when the event emitter is no longer needed. */ destroy() { for (const [, signal] of this.#signals.entries()) { signal.destroy(); } this.#signals.clear(); } } exports.EventEmitter = EventEmitter;