evnty 1.4.2 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;\n\nexport interface Unsubscribe {\n (): void;\n}\n\nexport interface Listener<T extends unknown[], R = unknown> {\n (...args: T): MaybePromise<R | void>;\n}\n\nexport interface Dispose {\n (): void;\n}\n\nexport interface Filter<T extends unknown[]> {\n (...args: T): MaybePromise<boolean>;\n}\n\nexport interface Mapper<T extends unknown[], R = unknown> {\n (...args: T): R;\n}\n\nexport interface Reducer<T extends unknown[], R = unknown> {\n (value: R, ...args: T): R;\n}\n\nexport type Listeners<T extends unknown[], R = unknown> = Listener<T, R>[];\n\n/**\n * An abstract class that extends the built-in Function class. It allows instances of the class\n * to be called as functions. When an instance of FunctionExt is called as a function, it will\n * call the function passed to its constructor with the same arguments.\n * @internal\n */\nexport abstract class FunctionExt extends Function {\n constructor(func: Function) {\n super();\n return Object.setPrototypeOf(func, new.target.prototype);\n }\n}\n\nexport interface Dismiss {\n (): Promise<void> | void;\n}\n\nexport interface Task {\n (): MaybePromise<unknown>;\n}\n\n/**\n * @internal\n */\nexport class Dismiss extends FunctionExt {\n constructor(callback: Unsubscribe) {\n super(callback);\n }\n\n async after(task: Task) {\n await task();\n this();\n }\n\n afterTimes(count: number) {\n return () => {\n if (!--count) {\n this();\n }\n };\n }\n}\n\nconst eventEmitter = async <A extends unknown[], R>(listeners: Listeners<A, R>, ...args: A) => {\n return Promise.all(listeners.map((listener) => listener(...args)));\n};\n\nexport interface Event<T extends unknown[], R> {\n (...args: T): Promise<(R | undefined)[]>;\n}\n\ntype UnpackParameters<T> = T extends Event<infer P, unknown> ? P : never;\n\ntype UnpackReturn<T> = T extends Event<unknown[], infer R> ? R : never;\n\ntype UnpackAllParameters<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: UnpackParameters<T[K]> }[number];\n\ntype UnpackAllReturn<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: UnpackReturn<T[K]> }[number];\n\n/**\n * A class representing an anonymous event that can be listened to or triggered.\n *\n * @typeParam T - The tuple of arguments that the event takes.\n * @typeParam R - The return type of the event.\n */\nexport class Event<T extends unknown[], R = void> extends FunctionExt {\n /**\n * Merges multiple events into a single event.\n * @example\n * const inputEvent = Event.merge(mouseEvent, keyboardEvent);\n *\n * @param events - The events to merge.\n * @returns The merged event.\n */\n static merge<Events extends Event<any[], any>[]>(...events: Events) {\n const mergedEvent = new Event<UnpackAllParameters<Events>, UnpackAllReturn<Events>>();\n events.forEach((event) => event.on(mergedEvent));\n return mergedEvent;\n }\n\n /**\n * Creates an event that triggers at a specified interval.\n * @example\n * const tickEvent = Event.interval(1000);\n * tickEvent.on((tickNumber) => console.log(tickNumber));\n *\n * @param interval - The interval at which to trigger the event.\n * @returns The interval event.\n */\n static interval(interval: number) {\n let counter = 0;\n const intervalEvent = new Event<[number], void>(() => clearInterval(timerId));\n const timerId: ReturnType<typeof setInterval> = setInterval(() => intervalEvent(counter++), interval);\n return intervalEvent;\n }\n\n /**\n * The array of listeners for the event.\n */\n private listeners: Listeners<T, R>;\n\n /**\n * A function that disposes of the event and its listeners.\n */\n readonly dispose: Dispose;\n\n /**\n * Creates a new event.\n * @example\n * // Create a click event.\n * const clickEvent = new Event<[x: number, y: number], void>();\n * clickEvent.on((x, y) => console.log(`Clicked at ${x}, ${y}`));\n *\n * @param dispose - A function to call on the event disposal.\n */\n constructor(dispose?: Dispose) {\n const listeners: Listeners<T, R> = [];\n const fn = (...args: T) => eventEmitter(listeners, ...args);\n\n super(fn);\n this.listeners = listeners;\n this.dispose = () => {\n this.clear();\n dispose?.();\n };\n }\n\n /**\n * The number of listeners for the event.\n */\n get size(): number {\n return this.listeners.length;\n }\n\n /**\n * Checks if a listener is not registered for the event.\n * @param listener - The listener to check.\n * @returns `true` if the listener is not registered, `false` otherwise.\n */\n lacks(listener: Listener<T, R>): boolean {\n return this.listeners.indexOf(listener) === -1;\n }\n\n /**\n * Checks if a listener is registered for the event.\n * @param listener - The listener to check.\n * @returns `true` if the listener is registered, `false` otherwise.\n */\n has(listener: Listener<T, R>): boolean {\n return this.listeners.indexOf(listener) !== -1;\n }\n\n /**\n * Removes a listener from the event.\n * @param listener - The listener to remove.\n */\n off(listener: Listener<T, R>): void {\n let index = this.listeners.indexOf(listener);\n while (~index) {\n this.listeners.splice(index, 1);\n index = this.listeners.indexOf(listener);\n }\n }\n\n /**\n * Adds a listener to the event.\n * @param listener - The listener to add.\n * @returns An object that can be used to remove the listener.\n */\n on(listener: Listener<T, R>): Dismiss {\n this.listeners.push(listener);\n return new Dismiss(() => this.off(listener));\n }\n\n /**\n * Adds a listener to the event that will only be called once.\n * @param listener - The listener to add.\n * @returns An object that can be used to remove the listener.\n */\n once(listener: Listener<T, R>): Dismiss {\n const oneTimeListener = (...args: T) => {\n this.off(oneTimeListener);\n return listener(...args);\n };\n return this.on(oneTimeListener);\n }\n\n /**\n * Removes all listeners from the event.\n */\n clear() {\n this.listeners.splice(0);\n }\n\n /**\n * Returns a Promise that resolves with the first emitted by the event arguments.\n * @returns A Promise that resolves with the first emitted by the event.\n */\n toPromise(): Promise<T> {\n return new Promise((resolve) => this.once((...args) => resolve(args)));\n }\n\n /**\n * Returns a new event that only triggers when the provided filter function returns `true`.\n * @example\n * const spacePressEvent = keyboardEvent.filter((key) => key === 'Space');\n *\n * @param filter The filter function to apply to the event.\n * @returns A new event that only triggers when the provided filter function returns `true`.\n */\n filter(filter: Filter<T>) {\n const dispose = this.on(async (...args) => {\n if (filteredEvent.size > 0 && (await filter(...args))) {\n await filteredEvent(...args);\n }\n });\n const filteredEvent = new Event<T, R>(dispose);\n return filteredEvent;\n }\n\n /**\n * Returns a new event that will only be triggered once the provided filter function returns `true`.\n * @example\n * const escPressEvent = keyboardEvent.first((key) => key === 'Esc');\n * await escPressEvent.toPromise();\n *\n * @param filter - The filter function.\n * @returns A new event that will only be triggered once the provided filter function returns `true`.\n */\n first(filter: Filter<T>) {\n const dispose = this.on(async (...args) => {\n if (filteredEvent.size > 0 && (await filter(...args))) {\n dispose();\n await filteredEvent(...args);\n }\n });\n const filteredEvent = new Event<T, R>(dispose);\n return filteredEvent;\n }\n\n /**\n * Returns a new event that maps the values of this event using the provided mapper function.\n * @example\n * const keyPressEvent = keyboardEvent.map((key) => key.toUpperCase()); // ['a'] -> ['A']\n *\n * @param mapper A function that maps the values of this event to a new value.\n * @returns A new event that emits the mapped values.\n */\n map<M, MR = unknown>(mapper: Mapper<T, M>) {\n const dispose = this.on(async (...args) => {\n if (mappedEvent.size > 0) {\n const value = await mapper(...args);\n mappedEvent(value);\n }\n });\n const mappedEvent = new Event<[M], MR>(dispose);\n return mappedEvent;\n }\n\n /**\n * Returns a new event that reduces the emitted values using the provided reducer function.\n * @example\n * const sumEvent = numberEvent.reduce((a, b) => a + b, 0);\n * sumEvent.on((sum) => console.log(sum)); // 1, 3, 6\n * sumEvent(1);\n * sumEvent(2);\n * sumEvent(3);\n *\n * @typeParam A The type of the accumulator value.\n * @typeParam AR The type of the reduced value.\n * @param {Reducer<T, A>} reducer The reducer function that reduces the emitted values.\n * @param {A} init The initial value of the accumulator.\n * @returns {Event<[A], AR>} A new event that reduces the emitted values using the provided reducer function.\n */\n reduce<A, AR = unknown>(reducer: Reducer<T, A>, init: A) {\n let value = init;\n const dispose = this.on(async (...args) => {\n if (reducedEvent.size > 0) {\n value = await reducer(value, ...args);\n reducedEvent(value);\n }\n });\n const reducedEvent = new Event<[A], AR>(dispose);\n return reducedEvent;\n }\n\n /**\n * Returns a new debounced event that will not fire until a certain amount of time has passed\n * since the last time it was triggered.\n * @example\n * const debouncedEvent = textInputEvent.debounce(100);\n * debouncedEvent.on((str) => console.log(str)); // 'test'\n * event('t');\n * event('te');\n * event('tes');\n * event('test');\n *\n * @param interval - The amount of time to wait before firing the debounced event, in milliseconds.\n * @returns A new debounced event.\n */\n debounce(interval: number) {\n let timer: ReturnType<typeof setTimeout>;\n const dispose = this.on((...args) => {\n clearTimeout(timer);\n timer = setTimeout(() => debouncedEvent(...args), interval);\n });\n const debouncedEvent = new Event<T, R>(dispose);\n return debouncedEvent;\n }\n}\n\n/**\n * Returns a promise that resolves with the arguments passed to the first invocation of the given event.\n * @example\n * const [x, y] = await once(mouseEvent);\n *\n * @param event The event to listen for.\n * @returns A promise that resolves with the arguments passed to the first invocation of the given event.\n */\nexport const once = <T extends unknown[], R = void>(event: Event<T, R>): Promise<T> => {\n return new Promise((resolve) => event.once((...args) => resolve(args)));\n};\n\n/**\n * Creates a new event instance.\n *\n * @typeParam T - An array of argument types that the event will accept.\n * @typeParam R - The return type of the event handler function.\n * @returns A new instance of the `Event` class.\n *\n * @example\n * const myEvent = createEvent<[string], number>();\n * myEvent.on((str: string) => str.length);\n * await myEvent('hello'); // [5]\n */\nexport const createEvent = <T extends unknown[], R = void>(): Event<T, R> => {\n return new Event<T, R>();\n};\n\nexport default createEvent;\n\n/**\n * A type helper that extracts the event listener type\n *\n * @typeParam E - The event object type.\n * @typeParam T - The event type extracted from the event object.\n * @typeParam R - The result type returned by the event handler function.\n */\nexport type EventHandler<E> = E extends Event<infer T, infer R> ? Listener<T, R> : never;\n"],"names":["FunctionExt","Dismiss","Event","once","createEvent","Function","constructor","func","Object","setPrototypeOf","prototype","callback","after","task","afterTimes","count","eventEmitter","listeners","args","Promise","all","map","listener","merge","events","mergedEvent","forEach","event","on","interval","counter","intervalEvent","clearInterval","timerId","setInterval","dispose","fn","clear","size","length","lacks","indexOf","has","off","index","splice","push","oneTimeListener","toPromise","resolve","filter","filteredEvent","first","mapper","mappedEvent","value","reduce","reducer","init","reducedEvent","debounce","timer","clearTimeout","setTimeout","debouncedEvent"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;\n\nexport interface Unsubscribe {\n (): void;\n}\n\nexport interface Listener<T extends unknown[], R = unknown> {\n (...args: T): MaybePromise<R | void>;\n}\n\nexport interface Dispose {\n (): void;\n}\n\nexport interface Filter<T extends unknown[]> {\n (...args: T): MaybePromise<boolean>;\n}\n\nexport interface Mapper<T extends unknown[], R> {\n (...args: T): MaybePromise<R>;\n}\n\nexport interface Reducer<T extends unknown[], R> {\n (value: R, ...args: T): MaybePromise<R>;\n}\n\nexport type Listeners<T extends unknown[], R> = Listener<T, R>[];\n\n/**\n * An abstract class that extends the built-in Function class. It allows instances of the class\n * to be called as functions. When an instance of FunctionExt is called as a function, it will\n * call the function passed to its constructor with the same arguments.\n * @internal\n */\nexport abstract class FunctionExt extends Function {\n constructor(func: Function) {\n super();\n return Object.setPrototypeOf(func, new.target.prototype);\n }\n}\n\nexport interface Dismiss {\n (): Promise<void> | void;\n}\n\nexport interface Task {\n (): MaybePromise<unknown>;\n}\n\n/**\n * @internal\n */\nexport class Dismiss extends FunctionExt {\n constructor(callback: Unsubscribe) {\n super(callback);\n }\n\n async after(task: Task): Promise<void> {\n await task();\n this();\n }\n\n afterTimes(count: number): () => void {\n return () => {\n if (!--count) {\n this();\n }\n };\n }\n}\n\nconst eventEmitter = async <A extends unknown[], R>(listeners: Listeners<A, R>, ...args: A) => {\n return Promise.all(listeners.map((listener) => listener(...args)));\n};\n\nexport interface Event<T extends unknown[], R> {\n (...args: T): Promise<(R | undefined)[]>;\n}\n\nexport type EventParameters<T> = T extends Event<infer P, unknown> ? P : never;\n\nexport type EventResult<T> = T extends Event<unknown[], infer R> ? R : never;\n\nexport type AllEventsParameters<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: EventParameters<T[K]> }[number];\n\nexport type AllEventsResults<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: EventResult<T[K]> }[number];\n\n/**\n * A class representing an anonymous event that can be listened to or triggered.\n *\n * @typeParam T - The tuple of arguments that the event takes.\n * @typeParam R - The return type of the event.\n */\nexport class Event<T extends unknown[], R = void> extends FunctionExt {\n /**\n * Merges multiple events into a single event.\n * @example\n * const inputEvent = Event.merge(mouseEvent, keyboardEvent);\n *\n * @param events - The events to merge.\n * @returns The merged event.\n */\n static merge<Events extends Event<any[], any>[]>(...events: Events): Event<AllEventsParameters<Events>, AllEventsResults<Events>> {\n const mergedEvent = new Event<AllEventsParameters<Events>, AllEventsResults<Events>>();\n events.forEach((event) => event.on(mergedEvent));\n return mergedEvent;\n }\n\n /**\n * Creates an event that triggers at a specified interval.\n * @example\n * const tickEvent = Event.interval(1000);\n * tickEvent.on((tickNumber) => console.log(tickNumber));\n *\n * @param interval - The interval at which to trigger the event.\n * @returns The interval event.\n */\n static interval(interval: number): Event<[number], void> {\n let counter = 0;\n const intervalEvent = new Event<[number], void>(() => clearInterval(timerId));\n const timerId: ReturnType<typeof setInterval> = setInterval(() => intervalEvent(counter++), interval);\n return intervalEvent;\n }\n\n /**\n * The array of listeners for the event.\n */\n private listeners: Listeners<T, R>;\n\n /**\n * A function that disposes of the event and its listeners.\n */\n readonly dispose: Dispose;\n\n /**\n * Creates a new event.\n * @example\n * // Create a click event.\n * const clickEvent = new Event<[x: number, y: number], void>();\n * clickEvent.on((x, y) => console.log(`Clicked at ${x}, ${y}`));\n *\n * @param dispose - A function to call on the event disposal.\n */\n constructor(dispose?: Dispose) {\n const listeners: Listeners<T, R> = [];\n const fn = (...args: T) => eventEmitter(listeners, ...args);\n\n super(fn);\n this.listeners = listeners;\n this.dispose = () => {\n this.clear();\n dispose?.();\n };\n }\n\n /**\n * The number of listeners for the event.\n */\n get size(): number {\n return this.listeners.length;\n }\n\n /**\n * Checks if a listener is not registered for the event.\n * @param listener - The listener to check.\n * @returns `true` if the listener is not registered, `false` otherwise.\n */\n lacks(listener: Listener<T, R>): boolean {\n return this.listeners.indexOf(listener) === -1;\n }\n\n /**\n * Checks if a listener is registered for the event.\n * @param listener - The listener to check.\n * @returns `true` if the listener is registered, `false` otherwise.\n */\n has(listener: Listener<T, R>): boolean {\n return this.listeners.indexOf(listener) !== -1;\n }\n\n /**\n * Removes a listener from the event.\n * @param listener - The listener to remove.\n */\n off(listener: Listener<T, R>): void {\n let index = this.listeners.indexOf(listener);\n while (~index) {\n this.listeners.splice(index, 1);\n index = this.listeners.indexOf(listener);\n }\n }\n\n /**\n * Adds a listener to the event.\n * @param listener - The listener to add.\n * @returns An object that can be used to remove the listener.\n */\n on(listener: Listener<T, R>): Dismiss {\n this.listeners.push(listener);\n return new Dismiss(() => this.off(listener));\n }\n\n /**\n * Adds a listener to the event that will only be called once.\n * @param listener - The listener to add.\n * @returns An object that can be used to remove the listener.\n */\n once(listener: Listener<T, R>): Dismiss {\n const oneTimeListener = (...args: T) => {\n this.off(oneTimeListener);\n return listener(...args);\n };\n return this.on(oneTimeListener);\n }\n\n /**\n * Removes all listeners from the event.\n */\n clear(): void {\n this.listeners.splice(0);\n }\n\n /**\n * Returns a Promise that resolves with the first emitted by the event arguments.\n * @returns A Promise that resolves with the first emitted by the event.\n */\n toPromise(): Promise<T> {\n return new Promise((resolve) => this.once((...args) => resolve(args)));\n }\n\n /**\n * Returns a new event that only triggers when the provided filter function returns `true`.\n * @example\n * const spacePressEvent = keyboardEvent.filter((key) => key === 'Space');\n *\n * @param filter The filter function to apply to the event.\n * @returns A new event that only triggers when the provided filter function returns `true`.\n */\n filter<F extends T>(filter: Filter<T>): Event<F, R> {\n const dispose = this.on(async (...args: T) => {\n if (filteredEvent.size > 0 && (await filter(...args))) {\n await filteredEvent(...(args as F));\n }\n });\n const filteredEvent = new Event<F, R>(dispose);\n return filteredEvent;\n }\n\n /**\n * Returns a new event that will only be triggered once the provided filter function returns `true`.\n * @example\n * const escPressEvent = keyboardEvent.first((key) => key === 'Esc');\n * await escPressEvent.toPromise();\n *\n * @param filter - The filter function.\n * @returns A new event that will only be triggered once the provided filter function returns `true`.\n */\n first<F extends T>(filter: Filter<T>): Event<F, R> {\n const dispose = this.on(async (...args: T) => {\n if (filteredEvent.size > 0 && (await filter(...args))) {\n dispose();\n await filteredEvent(...(args as F));\n }\n });\n const filteredEvent = new Event<F, R>(dispose);\n return filteredEvent;\n }\n\n /**\n * Returns a new event that maps the values of this event using the provided mapper function.\n * @example\n * const keyPressEvent = keyboardEvent.map((key) => key.toUpperCase()); // ['a'] -> ['A']\n *\n * @param mapper A function that maps the values of this event to a new value.\n * @returns A new event that emits the mapped values.\n */\n map<M, MR = unknown>(mapper: Mapper<T, M>): Event<[M], MR> {\n const dispose = this.on(async (...args) => {\n if (mappedEvent.size > 0) {\n const value = await mapper(...args);\n mappedEvent(value);\n }\n });\n const mappedEvent = new Event<[M], MR>(dispose);\n return mappedEvent;\n }\n\n /**\n * Returns a new event that reduces the emitted values using the provided reducer function.\n * @example\n * const sumEvent = numberEvent.reduce((a, b) => a + b, 0);\n * sumEvent.on((sum) => console.log(sum)); // 1, 3, 6\n * sumEvent(1);\n * sumEvent(2);\n * sumEvent(3);\n *\n * @typeParam A The type of the accumulated value.\n * @typeParam AR The type of the reduced value.\n * @param {Reducer<T, A>} reducer The reducer function that accumulates the values emitted by this `Event`.\n * @param {A} init The initial value of the accumulated value.\n * @returns {Event<[A], AR>} A new `Event` that emits the reduced value.\n */\n reduce<A, AR = unknown>(reducer: Reducer<T, A>, init: A): Event<[A], AR> {\n let value = init;\n const dispose = this.on(async (...args) => {\n if (reducedEvent.size > 0) {\n value = await reducer(value, ...args);\n reducedEvent(value);\n }\n });\n const reducedEvent = new Event<[A], AR>(dispose);\n return reducedEvent;\n }\n\n /**\n * Returns a new debounced event that will not fire until a certain amount of time has passed\n * since the last time it was triggered.\n * @example\n * const debouncedEvent = textInputEvent.debounce(100);\n * debouncedEvent.on((str) => console.log(str)); // 'test'\n * event('t');\n * event('te');\n * event('tes');\n * event('test');\n *\n * @param interval - The amount of time to wait before firing the debounced event, in milliseconds.\n * @returns A new debounced event.\n */\n debounce(interval: number): Event<T, R> {\n let timer: ReturnType<typeof setTimeout>;\n const dispose = this.on((...args) => {\n clearTimeout(timer);\n timer = setTimeout(() => debouncedEvent(...args), interval);\n });\n const debouncedEvent = new Event<T, R>(dispose);\n return debouncedEvent;\n }\n}\n\n/**\n * Returns a promise that resolves with the arguments passed to the first invocation of the given event.\n * @example\n * const [x, y] = await once(mouseEvent);\n *\n * @param event The event to listen for.\n * @returns A promise that resolves with the arguments passed to the first invocation of the given event.\n */\nexport const once = <T extends unknown[], R = void>(event: Event<T, R>): Promise<T> => {\n return new Promise((resolve) => event.once((...args) => resolve(args)));\n};\n\n/**\n * Creates a new event instance.\n *\n * @typeParam T - An array of argument types that the event will accept.\n * @typeParam R - The return type of the event handler function.\n * @returns A new instance of the `Event` class.\n *\n * @example\n * const myEvent = createEvent<[string], number>();\n * myEvent.on((str: string) => str.length);\n * await myEvent('hello'); // [5]\n */\nexport const createEvent = <T extends unknown[], R = void>(): Event<T, R> => {\n return new Event<T, R>();\n};\n\nexport default createEvent;\n\n/**\n * A type helper that extracts the event listener type\n *\n * @typeParam E - The event type.\n */\nexport type EventHandler<E> = E extends Event<infer T, infer R> ? Listener<T, R> : never;\n\n/**\n * A type helper that extracts the event filter type\n *\n * @typeParam E The event type to filter.\n */\nexport type EventFilter<E> = Filter<EventParameters<E>>;\n\n/**\n * A type helper that extracts the event mapper type\n *\n * @typeParam E The event type to map.\n * @typeParam M The new type to map `E` to.\n */\nexport type EventMapper<E, M> = Mapper<EventParameters<E>, M>;\n\n/**\n * A type helper that extracts the event mapper type\n *\n * @typeParam E The type of event to reduce.\n * @typeParam M The type of reduced event.\n */\nexport type EventReducer<E, R> = Reducer<EventParameters<E>, R>;\n"],"names":["FunctionExt","Dismiss","Event","once","createEvent","Function","constructor","func","Object","setPrototypeOf","prototype","callback","after","task","afterTimes","count","eventEmitter","listeners","args","Promise","all","map","listener","merge","events","mergedEvent","forEach","event","on","interval","counter","intervalEvent","clearInterval","timerId","setInterval","dispose","fn","clear","size","length","lacks","indexOf","has","off","index","splice","push","oneTimeListener","toPromise","resolve","filter","filteredEvent","first","mapper","mappedEvent","value","reduce","reducer","init","reducedEvent","debounce","timer","clearTimeout","setTimeout","debouncedEvent"],"mappings":"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"}
package/build/index.d.ts CHANGED
@@ -11,13 +11,13 @@ export interface Dispose {
11
11
  export interface Filter<T extends unknown[]> {
12
12
  (...args: T): MaybePromise<boolean>;
13
13
  }
14
- export interface Mapper<T extends unknown[], R = unknown> {
15
- (...args: T): R;
14
+ export interface Mapper<T extends unknown[], R> {
15
+ (...args: T): MaybePromise<R>;
16
16
  }
17
- export interface Reducer<T extends unknown[], R = unknown> {
18
- (value: R, ...args: T): R;
17
+ export interface Reducer<T extends unknown[], R> {
18
+ (value: R, ...args: T): MaybePromise<R>;
19
19
  }
20
- export type Listeners<T extends unknown[], R = unknown> = Listener<T, R>[];
20
+ export type Listeners<T extends unknown[], R> = Listener<T, R>[];
21
21
  /**
22
22
  * An abstract class that extends the built-in Function class. It allows instances of the class
23
23
  * to be called as functions. When an instance of FunctionExt is called as a function, it will
@@ -44,13 +44,13 @@ export declare class Dismiss extends FunctionExt {
44
44
  export interface Event<T extends unknown[], R> {
45
45
  (...args: T): Promise<(R | undefined)[]>;
46
46
  }
47
- type UnpackParameters<T> = T extends Event<infer P, unknown> ? P : never;
48
- type UnpackReturn<T> = T extends Event<unknown[], infer R> ? R : never;
49
- type UnpackAllParameters<T extends Event<unknown[], unknown>[]> = {
50
- [K in keyof T]: UnpackParameters<T[K]>;
47
+ export type EventParameters<T> = T extends Event<infer P, unknown> ? P : never;
48
+ export type EventResult<T> = T extends Event<unknown[], infer R> ? R : never;
49
+ export type AllEventsParameters<T extends Event<unknown[], unknown>[]> = {
50
+ [K in keyof T]: EventParameters<T[K]>;
51
51
  }[number];
52
- type UnpackAllReturn<T extends Event<unknown[], unknown>[]> = {
53
- [K in keyof T]: UnpackReturn<T[K]>;
52
+ export type AllEventsResults<T extends Event<unknown[], unknown>[]> = {
53
+ [K in keyof T]: EventResult<T[K]>;
54
54
  }[number];
55
55
  /**
56
56
  * A class representing an anonymous event that can be listened to or triggered.
@@ -67,7 +67,7 @@ export declare class Event<T extends unknown[], R = void> extends FunctionExt {
67
67
  * @param events - The events to merge.
68
68
  * @returns The merged event.
69
69
  */
70
- static merge<Events extends Event<any[], any>[]>(...events: Events): Event<UnpackAllParameters<Events>, UnpackAllReturn<Events>>;
70
+ static merge<Events extends Event<any[], any>[]>(...events: Events): Event<AllEventsParameters<Events>, AllEventsResults<Events>>;
71
71
  /**
72
72
  * Creates an event that triggers at a specified interval.
73
73
  * @example
@@ -146,7 +146,7 @@ export declare class Event<T extends unknown[], R = void> extends FunctionExt {
146
146
  * @param filter The filter function to apply to the event.
147
147
  * @returns A new event that only triggers when the provided filter function returns `true`.
148
148
  */
149
- filter(filter: Filter<T>): Event<T, R>;
149
+ filter<F extends T>(filter: Filter<T>): Event<F, R>;
150
150
  /**
151
151
  * Returns a new event that will only be triggered once the provided filter function returns `true`.
152
152
  * @example
@@ -156,7 +156,7 @@ export declare class Event<T extends unknown[], R = void> extends FunctionExt {
156
156
  * @param filter - The filter function.
157
157
  * @returns A new event that will only be triggered once the provided filter function returns `true`.
158
158
  */
159
- first(filter: Filter<T>): Event<T, R>;
159
+ first<F extends T>(filter: Filter<T>): Event<F, R>;
160
160
  /**
161
161
  * Returns a new event that maps the values of this event using the provided mapper function.
162
162
  * @example
@@ -175,11 +175,11 @@ export declare class Event<T extends unknown[], R = void> extends FunctionExt {
175
175
  * sumEvent(2);
176
176
  * sumEvent(3);
177
177
  *
178
- * @typeParam A The type of the accumulator value.
178
+ * @typeParam A The type of the accumulated value.
179
179
  * @typeParam AR The type of the reduced value.
180
- * @param {Reducer<T, A>} reducer The reducer function that reduces the emitted values.
181
- * @param {A} init The initial value of the accumulator.
182
- * @returns {Event<[A], AR>} A new event that reduces the emitted values using the provided reducer function.
180
+ * @param {Reducer<T, A>} reducer The reducer function that accumulates the values emitted by this `Event`.
181
+ * @param {A} init The initial value of the accumulated value.
182
+ * @returns {Event<[A], AR>} A new `Event` that emits the reduced value.
183
183
  */
184
184
  reduce<A, AR = unknown>(reducer: Reducer<T, A>, init: A): Event<[A], AR>;
185
185
  /**
@@ -224,8 +224,26 @@ export default createEvent;
224
224
  /**
225
225
  * A type helper that extracts the event listener type
226
226
  *
227
- * @typeParam E - The event object type.
228
- * @typeParam T - The event type extracted from the event object.
229
- * @typeParam R - The result type returned by the event handler function.
227
+ * @typeParam E - The event type.
230
228
  */
231
229
  export type EventHandler<E> = E extends Event<infer T, infer R> ? Listener<T, R> : never;
230
+ /**
231
+ * A type helper that extracts the event filter type
232
+ *
233
+ * @typeParam E The event type to filter.
234
+ */
235
+ export type EventFilter<E> = Filter<EventParameters<E>>;
236
+ /**
237
+ * A type helper that extracts the event mapper type
238
+ *
239
+ * @typeParam E The event type to map.
240
+ * @typeParam M The new type to map `E` to.
241
+ */
242
+ export type EventMapper<E, M> = Mapper<EventParameters<E>, M>;
243
+ /**
244
+ * A type helper that extracts the event mapper type
245
+ *
246
+ * @typeParam E The type of event to reduce.
247
+ * @typeParam M The type of reduced event.
248
+ */
249
+ export type EventReducer<E, R> = Reducer<EventParameters<E>, R>;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;\n\nexport interface Unsubscribe {\n (): void;\n}\n\nexport interface Listener<T extends unknown[], R = unknown> {\n (...args: T): MaybePromise<R | void>;\n}\n\nexport interface Dispose {\n (): void;\n}\n\nexport interface Filter<T extends unknown[]> {\n (...args: T): MaybePromise<boolean>;\n}\n\nexport interface Mapper<T extends unknown[], R = unknown> {\n (...args: T): R;\n}\n\nexport interface Reducer<T extends unknown[], R = unknown> {\n (value: R, ...args: T): R;\n}\n\nexport type Listeners<T extends unknown[], R = unknown> = Listener<T, R>[];\n\n/**\n * An abstract class that extends the built-in Function class. It allows instances of the class\n * to be called as functions. When an instance of FunctionExt is called as a function, it will\n * call the function passed to its constructor with the same arguments.\n * @internal\n */\nexport abstract class FunctionExt extends Function {\n constructor(func: Function) {\n super();\n return Object.setPrototypeOf(func, new.target.prototype);\n }\n}\n\nexport interface Dismiss {\n (): Promise<void> | void;\n}\n\nexport interface Task {\n (): MaybePromise<unknown>;\n}\n\n/**\n * @internal\n */\nexport class Dismiss extends FunctionExt {\n constructor(callback: Unsubscribe) {\n super(callback);\n }\n\n async after(task: Task) {\n await task();\n this();\n }\n\n afterTimes(count: number) {\n return () => {\n if (!--count) {\n this();\n }\n };\n }\n}\n\nconst eventEmitter = async <A extends unknown[], R>(listeners: Listeners<A, R>, ...args: A) => {\n return Promise.all(listeners.map((listener) => listener(...args)));\n};\n\nexport interface Event<T extends unknown[], R> {\n (...args: T): Promise<(R | undefined)[]>;\n}\n\ntype UnpackParameters<T> = T extends Event<infer P, unknown> ? P : never;\n\ntype UnpackReturn<T> = T extends Event<unknown[], infer R> ? R : never;\n\ntype UnpackAllParameters<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: UnpackParameters<T[K]> }[number];\n\ntype UnpackAllReturn<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: UnpackReturn<T[K]> }[number];\n\n/**\n * A class representing an anonymous event that can be listened to or triggered.\n *\n * @typeParam T - The tuple of arguments that the event takes.\n * @typeParam R - The return type of the event.\n */\nexport class Event<T extends unknown[], R = void> extends FunctionExt {\n /**\n * Merges multiple events into a single event.\n * @example\n * const inputEvent = Event.merge(mouseEvent, keyboardEvent);\n *\n * @param events - The events to merge.\n * @returns The merged event.\n */\n static merge<Events extends Event<any[], any>[]>(...events: Events) {\n const mergedEvent = new Event<UnpackAllParameters<Events>, UnpackAllReturn<Events>>();\n events.forEach((event) => event.on(mergedEvent));\n return mergedEvent;\n }\n\n /**\n * Creates an event that triggers at a specified interval.\n * @example\n * const tickEvent = Event.interval(1000);\n * tickEvent.on((tickNumber) => console.log(tickNumber));\n *\n * @param interval - The interval at which to trigger the event.\n * @returns The interval event.\n */\n static interval(interval: number) {\n let counter = 0;\n const intervalEvent = new Event<[number], void>(() => clearInterval(timerId));\n const timerId: ReturnType<typeof setInterval> = setInterval(() => intervalEvent(counter++), interval);\n return intervalEvent;\n }\n\n /**\n * The array of listeners for the event.\n */\n private listeners: Listeners<T, R>;\n\n /**\n * A function that disposes of the event and its listeners.\n */\n readonly dispose: Dispose;\n\n /**\n * Creates a new event.\n * @example\n * // Create a click event.\n * const clickEvent = new Event<[x: number, y: number], void>();\n * clickEvent.on((x, y) => console.log(`Clicked at ${x}, ${y}`));\n *\n * @param dispose - A function to call on the event disposal.\n */\n constructor(dispose?: Dispose) {\n const listeners: Listeners<T, R> = [];\n const fn = (...args: T) => eventEmitter(listeners, ...args);\n\n super(fn);\n this.listeners = listeners;\n this.dispose = () => {\n this.clear();\n dispose?.();\n };\n }\n\n /**\n * The number of listeners for the event.\n */\n get size(): number {\n return this.listeners.length;\n }\n\n /**\n * Checks if a listener is not registered for the event.\n * @param listener - The listener to check.\n * @returns `true` if the listener is not registered, `false` otherwise.\n */\n lacks(listener: Listener<T, R>): boolean {\n return this.listeners.indexOf(listener) === -1;\n }\n\n /**\n * Checks if a listener is registered for the event.\n * @param listener - The listener to check.\n * @returns `true` if the listener is registered, `false` otherwise.\n */\n has(listener: Listener<T, R>): boolean {\n return this.listeners.indexOf(listener) !== -1;\n }\n\n /**\n * Removes a listener from the event.\n * @param listener - The listener to remove.\n */\n off(listener: Listener<T, R>): void {\n let index = this.listeners.indexOf(listener);\n while (~index) {\n this.listeners.splice(index, 1);\n index = this.listeners.indexOf(listener);\n }\n }\n\n /**\n * Adds a listener to the event.\n * @param listener - The listener to add.\n * @returns An object that can be used to remove the listener.\n */\n on(listener: Listener<T, R>): Dismiss {\n this.listeners.push(listener);\n return new Dismiss(() => this.off(listener));\n }\n\n /**\n * Adds a listener to the event that will only be called once.\n * @param listener - The listener to add.\n * @returns An object that can be used to remove the listener.\n */\n once(listener: Listener<T, R>): Dismiss {\n const oneTimeListener = (...args: T) => {\n this.off(oneTimeListener);\n return listener(...args);\n };\n return this.on(oneTimeListener);\n }\n\n /**\n * Removes all listeners from the event.\n */\n clear() {\n this.listeners.splice(0);\n }\n\n /**\n * Returns a Promise that resolves with the first emitted by the event arguments.\n * @returns A Promise that resolves with the first emitted by the event.\n */\n toPromise(): Promise<T> {\n return new Promise((resolve) => this.once((...args) => resolve(args)));\n }\n\n /**\n * Returns a new event that only triggers when the provided filter function returns `true`.\n * @example\n * const spacePressEvent = keyboardEvent.filter((key) => key === 'Space');\n *\n * @param filter The filter function to apply to the event.\n * @returns A new event that only triggers when the provided filter function returns `true`.\n */\n filter(filter: Filter<T>) {\n const dispose = this.on(async (...args) => {\n if (filteredEvent.size > 0 && (await filter(...args))) {\n await filteredEvent(...args);\n }\n });\n const filteredEvent = new Event<T, R>(dispose);\n return filteredEvent;\n }\n\n /**\n * Returns a new event that will only be triggered once the provided filter function returns `true`.\n * @example\n * const escPressEvent = keyboardEvent.first((key) => key === 'Esc');\n * await escPressEvent.toPromise();\n *\n * @param filter - The filter function.\n * @returns A new event that will only be triggered once the provided filter function returns `true`.\n */\n first(filter: Filter<T>) {\n const dispose = this.on(async (...args) => {\n if (filteredEvent.size > 0 && (await filter(...args))) {\n dispose();\n await filteredEvent(...args);\n }\n });\n const filteredEvent = new Event<T, R>(dispose);\n return filteredEvent;\n }\n\n /**\n * Returns a new event that maps the values of this event using the provided mapper function.\n * @example\n * const keyPressEvent = keyboardEvent.map((key) => key.toUpperCase()); // ['a'] -> ['A']\n *\n * @param mapper A function that maps the values of this event to a new value.\n * @returns A new event that emits the mapped values.\n */\n map<M, MR = unknown>(mapper: Mapper<T, M>) {\n const dispose = this.on(async (...args) => {\n if (mappedEvent.size > 0) {\n const value = await mapper(...args);\n mappedEvent(value);\n }\n });\n const mappedEvent = new Event<[M], MR>(dispose);\n return mappedEvent;\n }\n\n /**\n * Returns a new event that reduces the emitted values using the provided reducer function.\n * @example\n * const sumEvent = numberEvent.reduce((a, b) => a + b, 0);\n * sumEvent.on((sum) => console.log(sum)); // 1, 3, 6\n * sumEvent(1);\n * sumEvent(2);\n * sumEvent(3);\n *\n * @typeParam A The type of the accumulator value.\n * @typeParam AR The type of the reduced value.\n * @param {Reducer<T, A>} reducer The reducer function that reduces the emitted values.\n * @param {A} init The initial value of the accumulator.\n * @returns {Event<[A], AR>} A new event that reduces the emitted values using the provided reducer function.\n */\n reduce<A, AR = unknown>(reducer: Reducer<T, A>, init: A) {\n let value = init;\n const dispose = this.on(async (...args) => {\n if (reducedEvent.size > 0) {\n value = await reducer(value, ...args);\n reducedEvent(value);\n }\n });\n const reducedEvent = new Event<[A], AR>(dispose);\n return reducedEvent;\n }\n\n /**\n * Returns a new debounced event that will not fire until a certain amount of time has passed\n * since the last time it was triggered.\n * @example\n * const debouncedEvent = textInputEvent.debounce(100);\n * debouncedEvent.on((str) => console.log(str)); // 'test'\n * event('t');\n * event('te');\n * event('tes');\n * event('test');\n *\n * @param interval - The amount of time to wait before firing the debounced event, in milliseconds.\n * @returns A new debounced event.\n */\n debounce(interval: number) {\n let timer: ReturnType<typeof setTimeout>;\n const dispose = this.on((...args) => {\n clearTimeout(timer);\n timer = setTimeout(() => debouncedEvent(...args), interval);\n });\n const debouncedEvent = new Event<T, R>(dispose);\n return debouncedEvent;\n }\n}\n\n/**\n * Returns a promise that resolves with the arguments passed to the first invocation of the given event.\n * @example\n * const [x, y] = await once(mouseEvent);\n *\n * @param event The event to listen for.\n * @returns A promise that resolves with the arguments passed to the first invocation of the given event.\n */\nexport const once = <T extends unknown[], R = void>(event: Event<T, R>): Promise<T> => {\n return new Promise((resolve) => event.once((...args) => resolve(args)));\n};\n\n/**\n * Creates a new event instance.\n *\n * @typeParam T - An array of argument types that the event will accept.\n * @typeParam R - The return type of the event handler function.\n * @returns A new instance of the `Event` class.\n *\n * @example\n * const myEvent = createEvent<[string], number>();\n * myEvent.on((str: string) => str.length);\n * await myEvent('hello'); // [5]\n */\nexport const createEvent = <T extends unknown[], R = void>(): Event<T, R> => {\n return new Event<T, R>();\n};\n\nexport default createEvent;\n\n/**\n * A type helper that extracts the event listener type\n *\n * @typeParam E - The event object type.\n * @typeParam T - The event type extracted from the event object.\n * @typeParam R - The result type returned by the event handler function.\n */\nexport type EventHandler<E> = E extends Event<infer T, infer R> ? Listener<T, R> : never;\n"],"names":["FunctionExt","Function","constructor","func","Object","setPrototypeOf","prototype","Dismiss","callback","after","task","afterTimes","count","eventEmitter","listeners","args","Promise","all","map","listener","Event","merge","events","mergedEvent","forEach","event","on","interval","counter","intervalEvent","clearInterval","timerId","setInterval","dispose","fn","clear","size","length","lacks","indexOf","has","off","index","splice","push","once","oneTimeListener","toPromise","resolve","filter","filteredEvent","first","mapper","mappedEvent","value","reduce","reducer","init","reducedEvent","debounce","timer","clearTimeout","setTimeout","debouncedEvent","createEvent"],"mappings":"AAkCA,OAAO,MAAeA,oBAAoBC;IACxCC,YAAYC,IAAc,CAAE;QAC1B,KAAK;QACL,OAAOC,OAAOC,cAAc,CAACF,MAAM,WAAWG,SAAS;IACzD;AACF;AAaA,OAAO,MAAMC,gBAAgBP;IAC3BE,YAAYM,QAAqB,CAAE;QACjC,KAAK,CAACA;IACR;IAEA,MAAMC,MAAMC,IAAU,EAAE;QACtB,MAAMA;QACN,IAAI;IACN;IAEAC,WAAWC,KAAa,EAAE;QACxB,OAAO;YACL,IAAI,CAAC,EAAEA,OAAO;gBACZ,IAAI;YACN;QACF;IACF;AACF;AAEA,MAAMC,eAAe,OAA+BC,WAA4B,GAAGC;IACjF,OAAOC,QAAQC,GAAG,CAACH,UAAUI,GAAG,CAAC,CAACC,WAAaA,YAAYJ;AAC7D;AAoBA,OAAO,MAAMK,cAA6CpB;IASxD,OAAOqB,MAA0C,GAAGC,MAAc,EAAE;QAClE,MAAMC,cAAc,IAAIH;QACxBE,OAAOE,OAAO,CAAC,CAACC,QAAUA,MAAMC,EAAE,CAACH;QACnC,OAAOA;IACT;IAWA,OAAOI,SAASA,QAAgB,EAAE;QAChC,IAAIC,UAAU;QACd,MAAMC,gBAAgB,IAAIT,MAAsB,IAAMU,cAAcC;QACpE,MAAMA,UAA0CC,YAAY,IAAMH,cAAcD,YAAYD;QAC5F,OAAOE;IACT;IAKQf,UAA2B;IAK1BmB,QAAiB;IAW1B/B,YAAY+B,OAAiB,CAAE;QAC7B,MAAMnB,YAA6B,EAAE;QACrC,MAAMoB,KAAK,CAAC,GAAGnB,OAAYF,aAAaC,cAAcC;QAEtD,KAAK,CAACmB;QACN,IAAI,CAACpB,SAAS,GAAGA;QACjB,IAAI,CAACmB,OAAO,GAAG;YACb,IAAI,CAACE,KAAK;YACVF;QACF;IACF;IAKA,IAAIG,OAAe;QACjB,OAAO,IAAI,CAACtB,SAAS,CAACuB,MAAM;IAC9B;IAOAC,MAAMnB,QAAwB,EAAW;QACvC,OAAO,IAAI,CAACL,SAAS,CAACyB,OAAO,CAACpB,cAAc,CAAC;IAC/C;IAOAqB,IAAIrB,QAAwB,EAAW;QACrC,OAAO,IAAI,CAACL,SAAS,CAACyB,OAAO,CAACpB,cAAc,CAAC;IAC/C;IAMAsB,IAAItB,QAAwB,EAAQ;QAClC,IAAIuB,QAAQ,IAAI,CAAC5B,SAAS,CAACyB,OAAO,CAACpB;QACnC,MAAO,CAACuB,MAAO;YACb,IAAI,CAAC5B,SAAS,CAAC6B,MAAM,CAACD,OAAO;YAC7BA,QAAQ,IAAI,CAAC5B,SAAS,CAACyB,OAAO,CAACpB;QACjC;IACF;IAOAO,GAAGP,QAAwB,EAAW;QACpC,IAAI,CAACL,SAAS,CAAC8B,IAAI,CAACzB;QACpB,OAAO,IAAIZ,QAAQ,IAAM,IAAI,CAACkC,GAAG,CAACtB;IACpC;IAOA0B,KAAK1B,QAAwB,EAAW;QACtC,MAAM2B,kBAAkB,CAAC,GAAG/B;YAC1B,IAAI,CAAC0B,GAAG,CAACK;YACT,OAAO3B,YAAYJ;QACrB;QACA,OAAO,IAAI,CAACW,EAAE,CAACoB;IACjB;IAKAX,QAAQ;QACN,IAAI,CAACrB,SAAS,CAAC6B,MAAM,CAAC;IACxB;IAMAI,YAAwB;QACtB,OAAO,IAAI/B,QAAQ,CAACgC,UAAY,IAAI,CAACH,IAAI,CAAC,CAAC,GAAG9B,OAASiC,QAAQjC;IACjE;IAUAkC,OAAOA,MAAiB,EAAE;QACxB,MAAMhB,UAAU,IAAI,CAACP,EAAE,CAAC,OAAO,GAAGX;YAChC,IAAImC,cAAcd,IAAI,GAAG,KAAM,MAAMa,UAAUlC,OAAQ;gBACrD,MAAMmC,iBAAiBnC;YACzB;QACF;QACA,MAAMmC,gBAAgB,IAAI9B,MAAYa;QACtC,OAAOiB;IACT;IAWAC,MAAMF,MAAiB,EAAE;QACvB,MAAMhB,UAAU,IAAI,CAACP,EAAE,CAAC,OAAO,GAAGX;YAChC,IAAImC,cAAcd,IAAI,GAAG,KAAM,MAAMa,UAAUlC,OAAQ;gBACrDkB;gBACA,MAAMiB,iBAAiBnC;YACzB;QACF;QACA,MAAMmC,gBAAgB,IAAI9B,MAAYa;QACtC,OAAOiB;IACT;IAUAhC,IAAqBkC,MAAoB,EAAE;QACzC,MAAMnB,UAAU,IAAI,CAACP,EAAE,CAAC,OAAO,GAAGX;YAChC,IAAIsC,YAAYjB,IAAI,GAAG,GAAG;gBACxB,MAAMkB,QAAQ,MAAMF,UAAUrC;gBAC9BsC,YAAYC;YACd;QACF;QACA,MAAMD,cAAc,IAAIjC,MAAea;QACvC,OAAOoB;IACT;IAiBAE,OAAwBC,OAAsB,EAAEC,IAAO,EAAE;QACvD,IAAIH,QAAQG;QACZ,MAAMxB,UAAU,IAAI,CAACP,EAAE,CAAC,OAAO,GAAGX;YAChC,IAAI2C,aAAatB,IAAI,GAAG,GAAG;gBACzBkB,QAAQ,MAAME,QAAQF,UAAUvC;gBAChC2C,aAAaJ;YACf;QACF;QACA,MAAMI,eAAe,IAAItC,MAAea;QACxC,OAAOyB;IACT;IAgBAC,SAAShC,QAAgB,EAAE;QACzB,IAAIiC;QACJ,MAAM3B,UAAU,IAAI,CAACP,EAAE,CAAC,CAAC,GAAGX;YAC1B8C,aAAaD;YACbA,QAAQE,WAAW,IAAMC,kBAAkBhD,OAAOY;QACpD;QACA,MAAMoC,iBAAiB,IAAI3C,MAAYa;QACvC,OAAO8B;IACT;AACF;AAUA,OAAO,MAAMlB,OAAO,CAAgCpB;IAClD,OAAO,IAAIT,QAAQ,CAACgC,UAAYvB,MAAMoB,IAAI,CAAC,CAAC,GAAG9B,OAASiC,QAAQjC;AAClE,EAAE;AAcF,OAAO,MAAMiD,cAAc;IACzB,OAAO,IAAI5C;AACb,EAAE;AAEF,eAAe4C,YAAY"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;\n\nexport interface Unsubscribe {\n (): void;\n}\n\nexport interface Listener<T extends unknown[], R = unknown> {\n (...args: T): MaybePromise<R | void>;\n}\n\nexport interface Dispose {\n (): void;\n}\n\nexport interface Filter<T extends unknown[]> {\n (...args: T): MaybePromise<boolean>;\n}\n\nexport interface Mapper<T extends unknown[], R> {\n (...args: T): MaybePromise<R>;\n}\n\nexport interface Reducer<T extends unknown[], R> {\n (value: R, ...args: T): MaybePromise<R>;\n}\n\nexport type Listeners<T extends unknown[], R> = Listener<T, R>[];\n\n/**\n * An abstract class that extends the built-in Function class. It allows instances of the class\n * to be called as functions. When an instance of FunctionExt is called as a function, it will\n * call the function passed to its constructor with the same arguments.\n * @internal\n */\nexport abstract class FunctionExt extends Function {\n constructor(func: Function) {\n super();\n return Object.setPrototypeOf(func, new.target.prototype);\n }\n}\n\nexport interface Dismiss {\n (): Promise<void> | void;\n}\n\nexport interface Task {\n (): MaybePromise<unknown>;\n}\n\n/**\n * @internal\n */\nexport class Dismiss extends FunctionExt {\n constructor(callback: Unsubscribe) {\n super(callback);\n }\n\n async after(task: Task): Promise<void> {\n await task();\n this();\n }\n\n afterTimes(count: number): () => void {\n return () => {\n if (!--count) {\n this();\n }\n };\n }\n}\n\nconst eventEmitter = async <A extends unknown[], R>(listeners: Listeners<A, R>, ...args: A) => {\n return Promise.all(listeners.map((listener) => listener(...args)));\n};\n\nexport interface Event<T extends unknown[], R> {\n (...args: T): Promise<(R | undefined)[]>;\n}\n\nexport type EventParameters<T> = T extends Event<infer P, unknown> ? P : never;\n\nexport type EventResult<T> = T extends Event<unknown[], infer R> ? R : never;\n\nexport type AllEventsParameters<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: EventParameters<T[K]> }[number];\n\nexport type AllEventsResults<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: EventResult<T[K]> }[number];\n\n/**\n * A class representing an anonymous event that can be listened to or triggered.\n *\n * @typeParam T - The tuple of arguments that the event takes.\n * @typeParam R - The return type of the event.\n */\nexport class Event<T extends unknown[], R = void> extends FunctionExt {\n /**\n * Merges multiple events into a single event.\n * @example\n * const inputEvent = Event.merge(mouseEvent, keyboardEvent);\n *\n * @param events - The events to merge.\n * @returns The merged event.\n */\n static merge<Events extends Event<any[], any>[]>(...events: Events): Event<AllEventsParameters<Events>, AllEventsResults<Events>> {\n const mergedEvent = new Event<AllEventsParameters<Events>, AllEventsResults<Events>>();\n events.forEach((event) => event.on(mergedEvent));\n return mergedEvent;\n }\n\n /**\n * Creates an event that triggers at a specified interval.\n * @example\n * const tickEvent = Event.interval(1000);\n * tickEvent.on((tickNumber) => console.log(tickNumber));\n *\n * @param interval - The interval at which to trigger the event.\n * @returns The interval event.\n */\n static interval(interval: number): Event<[number], void> {\n let counter = 0;\n const intervalEvent = new Event<[number], void>(() => clearInterval(timerId));\n const timerId: ReturnType<typeof setInterval> = setInterval(() => intervalEvent(counter++), interval);\n return intervalEvent;\n }\n\n /**\n * The array of listeners for the event.\n */\n private listeners: Listeners<T, R>;\n\n /**\n * A function that disposes of the event and its listeners.\n */\n readonly dispose: Dispose;\n\n /**\n * Creates a new event.\n * @example\n * // Create a click event.\n * const clickEvent = new Event<[x: number, y: number], void>();\n * clickEvent.on((x, y) => console.log(`Clicked at ${x}, ${y}`));\n *\n * @param dispose - A function to call on the event disposal.\n */\n constructor(dispose?: Dispose) {\n const listeners: Listeners<T, R> = [];\n const fn = (...args: T) => eventEmitter(listeners, ...args);\n\n super(fn);\n this.listeners = listeners;\n this.dispose = () => {\n this.clear();\n dispose?.();\n };\n }\n\n /**\n * The number of listeners for the event.\n */\n get size(): number {\n return this.listeners.length;\n }\n\n /**\n * Checks if a listener is not registered for the event.\n * @param listener - The listener to check.\n * @returns `true` if the listener is not registered, `false` otherwise.\n */\n lacks(listener: Listener<T, R>): boolean {\n return this.listeners.indexOf(listener) === -1;\n }\n\n /**\n * Checks if a listener is registered for the event.\n * @param listener - The listener to check.\n * @returns `true` if the listener is registered, `false` otherwise.\n */\n has(listener: Listener<T, R>): boolean {\n return this.listeners.indexOf(listener) !== -1;\n }\n\n /**\n * Removes a listener from the event.\n * @param listener - The listener to remove.\n */\n off(listener: Listener<T, R>): void {\n let index = this.listeners.indexOf(listener);\n while (~index) {\n this.listeners.splice(index, 1);\n index = this.listeners.indexOf(listener);\n }\n }\n\n /**\n * Adds a listener to the event.\n * @param listener - The listener to add.\n * @returns An object that can be used to remove the listener.\n */\n on(listener: Listener<T, R>): Dismiss {\n this.listeners.push(listener);\n return new Dismiss(() => this.off(listener));\n }\n\n /**\n * Adds a listener to the event that will only be called once.\n * @param listener - The listener to add.\n * @returns An object that can be used to remove the listener.\n */\n once(listener: Listener<T, R>): Dismiss {\n const oneTimeListener = (...args: T) => {\n this.off(oneTimeListener);\n return listener(...args);\n };\n return this.on(oneTimeListener);\n }\n\n /**\n * Removes all listeners from the event.\n */\n clear(): void {\n this.listeners.splice(0);\n }\n\n /**\n * Returns a Promise that resolves with the first emitted by the event arguments.\n * @returns A Promise that resolves with the first emitted by the event.\n */\n toPromise(): Promise<T> {\n return new Promise((resolve) => this.once((...args) => resolve(args)));\n }\n\n /**\n * Returns a new event that only triggers when the provided filter function returns `true`.\n * @example\n * const spacePressEvent = keyboardEvent.filter((key) => key === 'Space');\n *\n * @param filter The filter function to apply to the event.\n * @returns A new event that only triggers when the provided filter function returns `true`.\n */\n filter<F extends T>(filter: Filter<T>): Event<F, R> {\n const dispose = this.on(async (...args: T) => {\n if (filteredEvent.size > 0 && (await filter(...args))) {\n await filteredEvent(...(args as F));\n }\n });\n const filteredEvent = new Event<F, R>(dispose);\n return filteredEvent;\n }\n\n /**\n * Returns a new event that will only be triggered once the provided filter function returns `true`.\n * @example\n * const escPressEvent = keyboardEvent.first((key) => key === 'Esc');\n * await escPressEvent.toPromise();\n *\n * @param filter - The filter function.\n * @returns A new event that will only be triggered once the provided filter function returns `true`.\n */\n first<F extends T>(filter: Filter<T>): Event<F, R> {\n const dispose = this.on(async (...args: T) => {\n if (filteredEvent.size > 0 && (await filter(...args))) {\n dispose();\n await filteredEvent(...(args as F));\n }\n });\n const filteredEvent = new Event<F, R>(dispose);\n return filteredEvent;\n }\n\n /**\n * Returns a new event that maps the values of this event using the provided mapper function.\n * @example\n * const keyPressEvent = keyboardEvent.map((key) => key.toUpperCase()); // ['a'] -> ['A']\n *\n * @param mapper A function that maps the values of this event to a new value.\n * @returns A new event that emits the mapped values.\n */\n map<M, MR = unknown>(mapper: Mapper<T, M>): Event<[M], MR> {\n const dispose = this.on(async (...args) => {\n if (mappedEvent.size > 0) {\n const value = await mapper(...args);\n mappedEvent(value);\n }\n });\n const mappedEvent = new Event<[M], MR>(dispose);\n return mappedEvent;\n }\n\n /**\n * Returns a new event that reduces the emitted values using the provided reducer function.\n * @example\n * const sumEvent = numberEvent.reduce((a, b) => a + b, 0);\n * sumEvent.on((sum) => console.log(sum)); // 1, 3, 6\n * sumEvent(1);\n * sumEvent(2);\n * sumEvent(3);\n *\n * @typeParam A The type of the accumulated value.\n * @typeParam AR The type of the reduced value.\n * @param {Reducer<T, A>} reducer The reducer function that accumulates the values emitted by this `Event`.\n * @param {A} init The initial value of the accumulated value.\n * @returns {Event<[A], AR>} A new `Event` that emits the reduced value.\n */\n reduce<A, AR = unknown>(reducer: Reducer<T, A>, init: A): Event<[A], AR> {\n let value = init;\n const dispose = this.on(async (...args) => {\n if (reducedEvent.size > 0) {\n value = await reducer(value, ...args);\n reducedEvent(value);\n }\n });\n const reducedEvent = new Event<[A], AR>(dispose);\n return reducedEvent;\n }\n\n /**\n * Returns a new debounced event that will not fire until a certain amount of time has passed\n * since the last time it was triggered.\n * @example\n * const debouncedEvent = textInputEvent.debounce(100);\n * debouncedEvent.on((str) => console.log(str)); // 'test'\n * event('t');\n * event('te');\n * event('tes');\n * event('test');\n *\n * @param interval - The amount of time to wait before firing the debounced event, in milliseconds.\n * @returns A new debounced event.\n */\n debounce(interval: number): Event<T, R> {\n let timer: ReturnType<typeof setTimeout>;\n const dispose = this.on((...args) => {\n clearTimeout(timer);\n timer = setTimeout(() => debouncedEvent(...args), interval);\n });\n const debouncedEvent = new Event<T, R>(dispose);\n return debouncedEvent;\n }\n}\n\n/**\n * Returns a promise that resolves with the arguments passed to the first invocation of the given event.\n * @example\n * const [x, y] = await once(mouseEvent);\n *\n * @param event The event to listen for.\n * @returns A promise that resolves with the arguments passed to the first invocation of the given event.\n */\nexport const once = <T extends unknown[], R = void>(event: Event<T, R>): Promise<T> => {\n return new Promise((resolve) => event.once((...args) => resolve(args)));\n};\n\n/**\n * Creates a new event instance.\n *\n * @typeParam T - An array of argument types that the event will accept.\n * @typeParam R - The return type of the event handler function.\n * @returns A new instance of the `Event` class.\n *\n * @example\n * const myEvent = createEvent<[string], number>();\n * myEvent.on((str: string) => str.length);\n * await myEvent('hello'); // [5]\n */\nexport const createEvent = <T extends unknown[], R = void>(): Event<T, R> => {\n return new Event<T, R>();\n};\n\nexport default createEvent;\n\n/**\n * A type helper that extracts the event listener type\n *\n * @typeParam E - The event type.\n */\nexport type EventHandler<E> = E extends Event<infer T, infer R> ? Listener<T, R> : never;\n\n/**\n * A type helper that extracts the event filter type\n *\n * @typeParam E The event type to filter.\n */\nexport type EventFilter<E> = Filter<EventParameters<E>>;\n\n/**\n * A type helper that extracts the event mapper type\n *\n * @typeParam E The event type to map.\n * @typeParam M The new type to map `E` to.\n */\nexport type EventMapper<E, M> = Mapper<EventParameters<E>, M>;\n\n/**\n * A type helper that extracts the event mapper type\n *\n * @typeParam E The type of event to reduce.\n * @typeParam M The type of reduced event.\n */\nexport type EventReducer<E, R> = Reducer<EventParameters<E>, R>;\n"],"names":["FunctionExt","Function","constructor","func","Object","setPrototypeOf","prototype","Dismiss","callback","after","task","afterTimes","count","eventEmitter","listeners","args","Promise","all","map","listener","Event","merge","events","mergedEvent","forEach","event","on","interval","counter","intervalEvent","clearInterval","timerId","setInterval","dispose","fn","clear","size","length","lacks","indexOf","has","off","index","splice","push","once","oneTimeListener","toPromise","resolve","filter","filteredEvent","first","mapper","mappedEvent","value","reduce","reducer","init","reducedEvent","debounce","timer","clearTimeout","setTimeout","debouncedEvent","createEvent"],"mappings":"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"}
package/package.json CHANGED
@@ -1,16 +1,14 @@
1
1
  {
2
2
  "name": "evnty",
3
3
  "description": "0-Deps, simple, fast, for browser and node js anonymous event library",
4
- "version": "1.4.2",
4
+ "version": "1.5.1",
5
5
  "type": "module",
6
6
  "types": "build/index.d.ts",
7
7
  "main": "build/index.cjs",
8
8
  "module": "build/index.js",
9
9
  "exports": {
10
- ".": {
11
- "require": "./build/index.cjs",
12
- "import": "./build/index.js"
13
- }
10
+ "require": "./build/index.cjs",
11
+ "import": "./build/index.js"
14
12
  },
15
13
  "files": [
16
14
  "build",
package/src/index.ts CHANGED
@@ -16,15 +16,15 @@ export interface Filter<T extends unknown[]> {
16
16
  (...args: T): MaybePromise<boolean>;
17
17
  }
18
18
 
19
- export interface Mapper<T extends unknown[], R = unknown> {
20
- (...args: T): R;
19
+ export interface Mapper<T extends unknown[], R> {
20
+ (...args: T): MaybePromise<R>;
21
21
  }
22
22
 
23
- export interface Reducer<T extends unknown[], R = unknown> {
24
- (value: R, ...args: T): R;
23
+ export interface Reducer<T extends unknown[], R> {
24
+ (value: R, ...args: T): MaybePromise<R>;
25
25
  }
26
26
 
27
- export type Listeners<T extends unknown[], R = unknown> = Listener<T, R>[];
27
+ export type Listeners<T extends unknown[], R> = Listener<T, R>[];
28
28
 
29
29
  /**
30
30
  * An abstract class that extends the built-in Function class. It allows instances of the class
@@ -55,12 +55,12 @@ export class Dismiss extends FunctionExt {
55
55
  super(callback);
56
56
  }
57
57
 
58
- async after(task: Task) {
58
+ async after(task: Task): Promise<void> {
59
59
  await task();
60
60
  this();
61
61
  }
62
62
 
63
- afterTimes(count: number) {
63
+ afterTimes(count: number): () => void {
64
64
  return () => {
65
65
  if (!--count) {
66
66
  this();
@@ -77,13 +77,13 @@ export interface Event<T extends unknown[], R> {
77
77
  (...args: T): Promise<(R | undefined)[]>;
78
78
  }
79
79
 
80
- type UnpackParameters<T> = T extends Event<infer P, unknown> ? P : never;
80
+ export type EventParameters<T> = T extends Event<infer P, unknown> ? P : never;
81
81
 
82
- type UnpackReturn<T> = T extends Event<unknown[], infer R> ? R : never;
82
+ export type EventResult<T> = T extends Event<unknown[], infer R> ? R : never;
83
83
 
84
- type UnpackAllParameters<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: UnpackParameters<T[K]> }[number];
84
+ export type AllEventsParameters<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: EventParameters<T[K]> }[number];
85
85
 
86
- type UnpackAllReturn<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: UnpackReturn<T[K]> }[number];
86
+ export type AllEventsResults<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: EventResult<T[K]> }[number];
87
87
 
88
88
  /**
89
89
  * A class representing an anonymous event that can be listened to or triggered.
@@ -100,8 +100,8 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
100
100
  * @param events - The events to merge.
101
101
  * @returns The merged event.
102
102
  */
103
- static merge<Events extends Event<any[], any>[]>(...events: Events) {
104
- const mergedEvent = new Event<UnpackAllParameters<Events>, UnpackAllReturn<Events>>();
103
+ static merge<Events extends Event<any[], any>[]>(...events: Events): Event<AllEventsParameters<Events>, AllEventsResults<Events>> {
104
+ const mergedEvent = new Event<AllEventsParameters<Events>, AllEventsResults<Events>>();
105
105
  events.forEach((event) => event.on(mergedEvent));
106
106
  return mergedEvent;
107
107
  }
@@ -115,7 +115,7 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
115
115
  * @param interval - The interval at which to trigger the event.
116
116
  * @returns The interval event.
117
117
  */
118
- static interval(interval: number) {
118
+ static interval(interval: number): Event<[number], void> {
119
119
  let counter = 0;
120
120
  const intervalEvent = new Event<[number], void>(() => clearInterval(timerId));
121
121
  const timerId: ReturnType<typeof setInterval> = setInterval(() => intervalEvent(counter++), interval);
@@ -216,7 +216,7 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
216
216
  /**
217
217
  * Removes all listeners from the event.
218
218
  */
219
- clear() {
219
+ clear(): void {
220
220
  this.listeners.splice(0);
221
221
  }
222
222
 
@@ -236,13 +236,13 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
236
236
  * @param filter The filter function to apply to the event.
237
237
  * @returns A new event that only triggers when the provided filter function returns `true`.
238
238
  */
239
- filter(filter: Filter<T>) {
240
- const dispose = this.on(async (...args) => {
239
+ filter<F extends T>(filter: Filter<T>): Event<F, R> {
240
+ const dispose = this.on(async (...args: T) => {
241
241
  if (filteredEvent.size > 0 && (await filter(...args))) {
242
- await filteredEvent(...args);
242
+ await filteredEvent(...(args as F));
243
243
  }
244
244
  });
245
- const filteredEvent = new Event<T, R>(dispose);
245
+ const filteredEvent = new Event<F, R>(dispose);
246
246
  return filteredEvent;
247
247
  }
248
248
 
@@ -255,14 +255,14 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
255
255
  * @param filter - The filter function.
256
256
  * @returns A new event that will only be triggered once the provided filter function returns `true`.
257
257
  */
258
- first(filter: Filter<T>) {
259
- const dispose = this.on(async (...args) => {
258
+ first<F extends T>(filter: Filter<T>): Event<F, R> {
259
+ const dispose = this.on(async (...args: T) => {
260
260
  if (filteredEvent.size > 0 && (await filter(...args))) {
261
261
  dispose();
262
- await filteredEvent(...args);
262
+ await filteredEvent(...(args as F));
263
263
  }
264
264
  });
265
- const filteredEvent = new Event<T, R>(dispose);
265
+ const filteredEvent = new Event<F, R>(dispose);
266
266
  return filteredEvent;
267
267
  }
268
268
 
@@ -274,7 +274,7 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
274
274
  * @param mapper A function that maps the values of this event to a new value.
275
275
  * @returns A new event that emits the mapped values.
276
276
  */
277
- map<M, MR = unknown>(mapper: Mapper<T, M>) {
277
+ map<M, MR = unknown>(mapper: Mapper<T, M>): Event<[M], MR> {
278
278
  const dispose = this.on(async (...args) => {
279
279
  if (mappedEvent.size > 0) {
280
280
  const value = await mapper(...args);
@@ -294,13 +294,13 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
294
294
  * sumEvent(2);
295
295
  * sumEvent(3);
296
296
  *
297
- * @typeParam A The type of the accumulator value.
297
+ * @typeParam A The type of the accumulated value.
298
298
  * @typeParam AR The type of the reduced value.
299
- * @param {Reducer<T, A>} reducer The reducer function that reduces the emitted values.
300
- * @param {A} init The initial value of the accumulator.
301
- * @returns {Event<[A], AR>} A new event that reduces the emitted values using the provided reducer function.
299
+ * @param {Reducer<T, A>} reducer The reducer function that accumulates the values emitted by this `Event`.
300
+ * @param {A} init The initial value of the accumulated value.
301
+ * @returns {Event<[A], AR>} A new `Event` that emits the reduced value.
302
302
  */
303
- reduce<A, AR = unknown>(reducer: Reducer<T, A>, init: A) {
303
+ reduce<A, AR = unknown>(reducer: Reducer<T, A>, init: A): Event<[A], AR> {
304
304
  let value = init;
305
305
  const dispose = this.on(async (...args) => {
306
306
  if (reducedEvent.size > 0) {
@@ -326,7 +326,7 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
326
326
  * @param interval - The amount of time to wait before firing the debounced event, in milliseconds.
327
327
  * @returns A new debounced event.
328
328
  */
329
- debounce(interval: number) {
329
+ debounce(interval: number): Event<T, R> {
330
330
  let timer: ReturnType<typeof setTimeout>;
331
331
  const dispose = this.on((...args) => {
332
332
  clearTimeout(timer);
@@ -370,8 +370,29 @@ export default createEvent;
370
370
  /**
371
371
  * A type helper that extracts the event listener type
372
372
  *
373
- * @typeParam E - The event object type.
374
- * @typeParam T - The event type extracted from the event object.
375
- * @typeParam R - The result type returned by the event handler function.
373
+ * @typeParam E - The event type.
376
374
  */
377
375
  export type EventHandler<E> = E extends Event<infer T, infer R> ? Listener<T, R> : never;
376
+
377
+ /**
378
+ * A type helper that extracts the event filter type
379
+ *
380
+ * @typeParam E The event type to filter.
381
+ */
382
+ export type EventFilter<E> = Filter<EventParameters<E>>;
383
+
384
+ /**
385
+ * A type helper that extracts the event mapper type
386
+ *
387
+ * @typeParam E The event type to map.
388
+ * @typeParam M The new type to map `E` to.
389
+ */
390
+ export type EventMapper<E, M> = Mapper<EventParameters<E>, M>;
391
+
392
+ /**
393
+ * A type helper that extracts the event mapper type
394
+ *
395
+ * @typeParam E The type of event to reduce.
396
+ * @typeParam M The type of reduced event.
397
+ */
398
+ export type EventReducer<E, R> = Reducer<EventParameters<E>, R>;