@irrelon/emitter
Version:
Simple JavaScript event emitter with some powerful features.
269 lines (268 loc) • 14.5 kB
TypeScript
export type AnyFunction<ReturnType = any> = (...args: any[]) => ReturnType;
export type AnyConstructor = new (...args: any[]) => any;
export declare enum ListenerReturnFlag {
none = "!+_NONE",
cancel = "!+_CANCEL"
}
export type EventListenerCallback<EventCallbackFunctionSignature extends AnyFunction = AnyFunction> = (...args: Parameters<EventCallbackFunctionSignature>) => ReturnType<EventCallbackFunctionSignature>;
export interface EventStaticEmitterObject<EventCallbackFunctionSignature extends AnyFunction = AnyFunction> {
id: string;
args: Parameters<EventCallbackFunctionSignature>;
}
export interface EmitterAnyEventsInterface {
[key: string]: AnyFunction;
}
export type EmitterEventsInterface<T> = {
[K in keyof T]: T[K];
};
interface WithStar {
"*"?: (eventName: string, ...args: any[]) => void;
}
export type EmitterEventsWithStar<T> = EmitterEventsInterface<T> & WithStar;
/**
* Creates a new class with the capability to emit events.
*/
export declare class Emitter<EventsInterface extends EmitterEventsWithStar<EventsInterface> = EmitterAnyEventsInterface> {
_eventsEmitting: boolean;
_eventRemovalQueue: any[];
_eventListeners?: {
[EventName in keyof EventsInterface]?: Record<string, EventListenerCallback<EventsInterface[EventName]>[]>;
};
_eventStaticEmitters: {
[EventName in keyof EventsInterface]?: EventStaticEmitterObject<EventsInterface[EventName]>[];
};
_eventsAllowDefer: boolean;
_eventsDeferTimeouts: Record<any, number>;
/**
* Attach an event listener to the passed event only if the passed
* id matches the id for the event being fired.
* @param eventName The name of the event to listen for.
* @param id The id to match against.
* @param listener The method to call when the event is fired.
* @returns The emitter instance.
*/
_on<EventName extends keyof EventsInterface>(eventName: EventName, id: string, listener: EventListenerCallback<EventsInterface[EventName]>): this;
/**
* Attach an event listener to the passed event only if the passed
* id matches the document id for the event being fired.
* @param eventName The name of the event to listen for.
* @param id The id to match against.
* @param listener The method to call when the event is fired.
* @returns The emitter instance.
*/
_once<EventName extends keyof EventsInterface>(eventName: EventName, id: string, listener: EventListenerCallback<EventsInterface[EventName]>): this;
/**
* Cancels an event listener based on an event name, id and listener function.
* @param eventName The event to cancel listener for.
* @param id The ID of the event to cancel listening for.
* @param listener The event listener function used in the on()
* or once() call to cancel.
* @returns The emitter instance.
*/
_off<EventName extends keyof EventsInterface>(eventName: EventName, id: string, listener?: EventListenerCallback<EventsInterface[EventName]>): this;
/**
* Creates an event listener that listens for any and all events
* emitted.
*/
onAny(listener: EventListenerCallback): void;
/**
* Attach an event listener to the passed event only if the passed
* id matches the document id for the event being fired.
* @param eventName The name of the event to listen for.
* @param id The id to match against.
* @param listener The method to call when the event is fired.
* @returns The emitter instance.
*/
on<EventName extends keyof EventsInterface>(eventName: EventName, id: string, listener: EventListenerCallback<EventsInterface[EventName]>): this;
on<EventName extends keyof EventsInterface>(eventName: EventName, listener: EventListenerCallback<EventsInterface[EventName]>): this;
/**
* Attach an event listener to the passed event only if the passed
* id matches the document id for the event being fired.
* @param eventName The name of the event to listen for.
* @param id The id to match against.
* @param listener
* @returns The emitter instance.
*/
once<EventName extends keyof EventsInterface>(eventName: EventName, id: string, listener: EventListenerCallback<EventsInterface[EventName]>): this;
once<EventName extends keyof EventsInterface>(eventName: EventName, listener: EventListenerCallback<EventsInterface[EventName]>): this;
/**
* Overwrites any previous event listeners so that if the event fires, only
* the listener you pass will be called. If you pass an id along with the
* listener, only listeners for the id will be overwritten. This is similar
* to calling `.off(eventName)` then `on(eventName, listener)` since
* `off(eventName)` will cancel any previous event listeners for the passed
* event name.
* @param eventName The name of the event to listen for.
* @param id The id to match against.
* @param listener The method to call when the event is fired.
* @returns The emitter instance.
*/
overwrite<EventName extends keyof EventsInterface>(eventName: EventName, id: string, listener: EventListenerCallback<EventsInterface[EventName]>): this;
overwrite<EventName extends keyof EventsInterface>(eventName: EventName, listener: EventListenerCallback<EventsInterface[EventName]>): this;
/**
* Removes an event listener that listens for any and all events
* emitted.
*/
offAny(listener: EventListenerCallback): void;
/**
* Cancels an event listener based on an event name, id and listener function.
* @param eventName The event to cancel listener for.
* @param id The ID of the event to cancel listening for.
* @param listener The event listener function used in the on()
* or once() call to cancel.
* @returns The emitter instance.
*/
off<EventName extends keyof EventsInterface>(eventName: EventName, id: string, listener?: EventListenerCallback<EventsInterface[EventName]>): this;
off<EventName extends keyof EventsInterface>(eventName: EventName, listener?: EventListenerCallback<EventsInterface[EventName]>): this;
off<EventName extends keyof EventsInterface>(eventName: EventName): this;
_emitToSingleListener<EventName extends keyof EventsInterface>(listener: EventListenerCallback<EventsInterface[EventName]>, data: Parameters<EventsInterface[EventName]>): ReturnType<EventsInterface[EventName]> | ListenerReturnFlag;
_emitToArrayOfListeners<EventName extends keyof EventsInterface>(arr: EventListenerCallback<EventsInterface[EventName]>[], data: Parameters<EventsInterface[EventName]>): (ReturnType<EventsInterface[EventName]> | ListenerReturnFlag)[];
/**
* Call an event listener by name. The `rpc()` function differs from `emit()` in
* that it will only call and return data from the first event listener for the
* event rather than all event listeners. If you have more than one event listener
* assigned to the event, all others except the first will be ignored and will
* not receive the event.
* @param eventName The name of the event to call the listener for.
* @param {...any} data The arguments to send to the listening method.
* If you are sending multiple arguments, separate them with a comma so
* that they are received by the function as separate arguments.
* @return {number}
* @example #Call the Event Listener
* // Emit the event named "hello"
* myEntity.emit('hello');
* @example #Call the Event Listener With Data Object
* // Emit the event named "hello"
* myEntity.emit('hello', {moo: true});
* @example #Call the Event Listener With Multiple Data Values
* // Emit the event named "hello"
* myEntity.emit('hello', {moo: true}, 'someString');
* @example #Register the Listener for Event Data
* // Set a listener to listen for the data (multiple values emitted
* // from an event are passed as function arguments)
* myEntity.on('hello', function (arg1, arg2) {
* console.log("Arguments:", arg1, arg2);
* return "foo";
* }
*
* // Emit the event named "hello"
* const result = myEntity.emit('hello', 'data1', 'data2');
* console.log("Result:", result);
*
* // The console output is:
* // Arguments: data1 data2
* // Result: "foo"
*/
rpc<EventName extends keyof EventsInterface>(eventName: EventName, ...data: Parameters<EventsInterface[EventName]>): ReturnType<EventsInterface[EventName]> | ListenerReturnFlag;
rpcId<EventName extends keyof EventsInterface>(eventName: EventName, id: string, ...data: Parameters<EventsInterface[EventName]>): ReturnType<EventsInterface[EventName]> | ListenerReturnFlag;
/**
* Emit an event by name.
* @param eventName The name of the event to emit.
* @param {...any} data The arguments to send to any listening methods.
* If you are sending multiple arguments, separate them with a comma so
* that they are received by the function as separate arguments.
* @return {number}
* @example #Emit an Event
* // Emit the event named "hello"
* myEntity.emit('hello');
* @example #Emit an Event With Data Object
* // Emit the event named "hello"
* myEntity.emit('hello', {moo: true});
* @example #Emit an Event With Multiple Data Values
* // Emit the event named "hello"
* myEntity.emit('hello', {moo: true}, 'someString');
* @example #Listen for Event Data
* // Set a listener to listen for the data (multiple values emitted
* // from an event are passed as function arguments)
* myEntity.on('hello', function (arg1, arg2) {
* console.log("Arguments:", arg1, arg2);
* return "foo";
* }
*
* // Emit the event named "hello"
* // The result is returned as an array of all return values
* // from all the listeners for the event
* const result = myEntity.emit('hello', 'data1', 'data2');
* console.log("Result:", result);
*
* // The console output is:
* // Arguments: data1 data2
* // Result: ["foo"]
*/
emit<EventName extends keyof EventsInterface>(eventName: EventName, ...data: Parameters<EventsInterface[EventName]>): (ReturnType<EventsInterface[EventName]> | ListenerReturnFlag)[];
emitId<EventName extends keyof EventsInterface>(eventName: EventName, id: string, ...data: Parameters<EventsInterface[EventName]>): (ReturnType<EventsInterface[EventName]> | ListenerReturnFlag)[];
/**
* Creates a persistent emitter record that will fire a listener if
* one is added for this event after the emitStatic() call has been
* made.
* @param eventName The name of the event to emit.
* @param {...any} data Optional arguments to emit with the event.
* @returns The emitter instance.
* @private
*/
emitStatic<EventName extends keyof EventsInterface>(eventName: EventName, ...data: Parameters<EventsInterface[EventName]>): this;
/**
* Creates a persistent emitter record that will fire a listener if
* one is added for this event after the emitStatic() call has been
* made.
* @param eventName The name of the event to emit.
* @param id The id of the event to emit.
* @param {...any} data Optional arguments to emit with the event.
* @returns The emitter instance.
* @private
*/
emitStaticId<EventName extends keyof EventsInterface>(eventName: EventName, id: string, ...data: Parameters<EventsInterface[EventName]>): this;
/**
* Handles removing emitters, is an internal method not called directly.
* @param eventName The event to remove static emitter for.
* @returns The emitter instance.
* @private
*/
cancelStatic<EventName extends keyof EventsInterface>(eventName: EventName): this;
/**
* Checks if an event has any event listeners or not.
* @param eventName The name of the event to check for.
* @returns True if one or more event listeners are registered for
* the event. False if none are found.
*/
willEmit<EventName extends keyof EventsInterface>(eventName: EventName): boolean;
/**
* Checks if an event has any event listeners or not based on the passed id.
* @param eventName The name of the event to check for.
* @param id The event ID to check for.
* @returns True if one or more event listeners are registered for
* the event. False if none are found.
*/
willEmitId<EventName extends keyof EventsInterface>(eventName: EventName, id: string): boolean;
/**
* Queues an event to be fired. This has automatic de-bouncing so that any
* events of the same type that occur within 100 milliseconds of a previous
* one will all be wrapped into a single emit rather than emitting tons of
* events for lots of chained inserts etc. Only the data from the last
* de-bounced event will be emitted.
* @param eventName The name of the event to emit.
* @param {...any} data Optional arguments to emit with the event.
* @returns The emitter instance.
*/
deferEmit<EventName extends keyof EventsInterface>(eventName: EventName, ...data: Parameters<EventsInterface[EventName]>): this;
/**
* Returns true if the result from an emit() call passed as the first
* argument contains a cancellation flag.
* @param resultArr
*/
didCancel(resultArr: (unknown | ListenerReturnFlag)[]): boolean;
/**
* If events are cleared with the off() method while the event emitter is
* actively processing any events then the off() calls get added to a
* queue to be executed after the event emitter is finished. This stops
* errors that might occur by potentially mutating the event listener array
* while the emitter is running through them. This method is called after
* the event emitter is finished processing.
* @private
*/
_processRemovalQueue(): void;
}
export declare function makeEmitter(obj: AnyConstructor, prototypeMode: boolean): Emitter;
export declare function makeEmitter(obj: boolean): Emitter;
export declare function makeEmitter(obj: Record<string, unknown>, prototypeMode: boolean): Emitter;
export {};