UNPKG

@nasriya/atomix

Version:

Composable helper functions for building reliable systems

229 lines (228 loc) 8.94 kB
import { EventHandler, AddHandlerOptions } from './docs'; /** * A flexible and lightweight event emitter class that supports advanced features like: * - `beforeAll` and `afterAll` handler types * - One-time (`once`) handlers * - Handler limits with overflow detection * - Custom max-handler overflow behavior * * This implementation allows both standard event handlers and lifecycle-style hooks around them. * * @example * ```ts * const emitter = new atomix.tools.EventEmitter(); * * // Regular handler (called in the order added) * emitter.on('data', (value) => console.log('Received:', value)); * * // One-time handler * emitter.on('data', (value) => console.log('Once:', value), { once: true }); * * // Setup logic before all regular handlers * emitter.on('data', () => console.log('Before All'), { type: 'beforeAll' }); * * // Cleanup logic after all regular handlers * emitter.on('data', () => console.log('After All'), { type: 'afterAll' }); * * // Emit the event * await emitter.emit('data', 42); * ``` * * @example * ```ts * // Custom behavior when handler count exceeds limit * emitter.maxHandlers = 2; * emitter.onMaxHandlers((eventName) => { * throw new Error(`Handler overflow on ${eventName}`); * }); * * emitter.on('load', () => {}); * emitter.on('load', () => {}); * emitter.on('load', () => {}); // throws * ``` * * @since v1.0.8 */ export declare class EventEmitter { #private; /** * Emits an event, triggering all registered handlers for the given event name. * * Handlers are invoked in the following order for each `emit` call: * 1. The `beforeAll` handler (if set) runs before all `normal` handlers. * 2. All `normal` handlers (in the order they were registered). * 3. The `afterAll` handler (if set) runs after all `normal` handlers. * * `beforeAll` and `afterAll` are special singleton handlers — only one of each * may be set per event name. They are not removed automatically and are executed * on every `emit` call. * * `normal` handlers may be marked as `once`, in which case they will be removed * after their first invocation. * * Global (`'*'`) handlers are triggered on every emit and receive the actual event * name as their first argument. * * @async * @param eventName - The name of the event to emit. Must be a non-empty string. * @param args - Arguments to pass to all applicable handler functions. * * @throws {TypeError} If the event name is not a string. * @throws {RangeError} If the event name is an empty string. * * @example * ```ts * const emitter = new EventEmitter(); * * emitter.on('data', (value) => console.log('Normal:', value)); * emitter.on('data', () => console.log('Before All'), { type: 'beforeAll' }); * emitter.on('data', () => console.log('After All'), { type: 'afterAll' }); * * await emitter.emit('data', 123); * // Output: * // Before All * // Normal: 123 * // After All * ``` * * @example * ```ts * emitter.on('*', (event, ...args) => { * console.log(`Global handler: ${event}`, args); * }); * * await emitter.emit('load', true); * // Output: * // Global handler: load [true] * ``` * * @since v1.0.8 */ emit(eventName: string, ...args: any): Promise<void>; /** * Adds a handler to an event. * * @param eventName - The name of the event to add the handler to. * @param handler - The handler function to add. * @param options - (Optional) Additional configuration options for the handler. If not provided, defaults to `{ once: false, type: 'normal' }`. * @param options.once - (Optional) If true, the handler is removed after being called once. Defaults to false. * @param options.type - (Optional) The type of event handler to add. One of "before", "after", or "normal". Defaults to "normal". * * @throws {TypeError} Throws if the event name is not a string or the handler is not a function. * @throws {RangeError} Throws if the event name is an empty string or the type is not a valid event type. * * @returns The EventEmitter instance. * @since v1.0.8 */ on(eventName: string, handler: EventHandler, options?: AddHandlerOptions): this; /** * Registers a custom handler for the "max handlers exceeded" event. * * When the number of handlers for an event exceeds the maximum allowed, this handler is called with the event name as an argument. * * The handler is debounced to prevent excessive calls when the maximum number of handlers is exceeded multiple times in quick succession. * * @param handler - A function to call when the maximum number of handlers is exceeded or an error to throw. * @returns The EventEmitter instance. * @throws {TypeError} If the handler is not a function or an error. * @since v1.0.8 */ onMaxHandlers(handler: ((eventName: string) => any) | Error): this; /** * Cleans up any internal resources used by this instance. * * Specifically, cancels any pending debounced handlers (such as * warnings about maximum handlers) to prevent timers from * keeping the process alive or causing side effects after disposal. * * This method should be called when the instance is no longer needed, * such as during test teardown or object cleanup. * * @since v1.0.15 */ dispose(): void; /** * Retrieves the maximum number of event handlers allowed for this EventEmitter instance. * * The value is a positive integer or Infinity. If set to Infinity, there is no limit to the number of handlers. * * @returns {number} The maximum number of handlers. A positive integer or Infinity. * @since v1.0.8 */ get maxHandlers(): number; /** * Sets the maximum number of event handlers allowed for this EventEmitter instance. * * The value must be a positive integer or Infinity. If set to Infinity, there is no limit to the number of handlers. * * @param {number} value The maximum number of handlers. Must be a positive integer or Infinity. * @throws {TypeError} If the provided value is not a number or not an integer. * @throws {RangeError} If the provided value is not greater than 0. * @since v1.0.8 */ set maxHandlers(value: number); /** * Retrieves the total number of event handlers registered with this EventEmitter instance. * @returns {number} The total number of event handlers. * @since v1.0.8 */ get handlersCount(): number; /** * Retrieves the names of all registered events for this EventEmitter instance. * * @returns {string[]} An array of event names. * @since v1.0.8 */ get eventNames(): string[]; /** * A collection of methods to remove event handlers. * * This allows removing specific handlers or clearing all handlers from one or more events. * * @example * ```ts * const emitter = new EventEmitter(); * const handler = () => console.log('Hello'); * * emitter.on('greet', handler); * emitter.remove.handler('greet', handler); // Removes just this one * ``` * * @example * ```ts * emitter.on('load', () => {}); * emitter.on('error', () => {}); * emitter.remove.allHandlers(); // Removes everything * ``` * * @example * ```ts * emitter.remove.allHandlers('load'); // Removes all "load" handlers only * ``` * * @since v1.0.8 */ readonly remove: { /** * Removes a specified event handler for a given event name. * * @param eventName - The name of the event for which the handler should be removed. * @param handler - The handler function to remove. * @returns {boolean} True if the handler was successfully removed, otherwise false. * @throws {TypeError} Throws if the event name is not a string or the handler is not a function. * @since v1.0.8 */ handler: (eventName: string, handler: EventHandler) => boolean; /** * Removes all handlers for a given event name or all events if no name is specified. * * @param eventName - (Optional) The name of the event for which handlers should be removed. If not provided, handlers for all events are removed. * @returns {boolean} True if any handlers were removed, otherwise false. * @throws {TypeError} Throws if the event name is not a string. * @throws {RangeError} Throws if the event name is an empty string. * @since v1.0.8 */ allHandlers: (eventName?: string) => boolean; }; } export default EventEmitter;