@nasriya/atomix
Version:
Composable helper functions for building reliable systems
229 lines (228 loc) • 8.94 kB
TypeScript
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;