evnty 1.4.2 → 1.5.0
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.
- package/build/index.cjs.map +1 -1
- package/build/index.d.ts +35 -17
- package/build/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +42 -21
package/build/index.cjs.map
CHANGED
|
@@ -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) {\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\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) {\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) {\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<F extends T>(filter: Filter<T>) {\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>) {\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>) {\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 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
|
|
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
|
|
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
|
|
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
|
|
48
|
-
type
|
|
49
|
-
type
|
|
50
|
-
[K in keyof T]:
|
|
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
|
|
53
|
-
[K in keyof T]:
|
|
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<
|
|
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<
|
|
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<
|
|
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
|
|
@@ -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
|
|
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>;
|
package/build/index.js.map
CHANGED
|
@@ -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":"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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) {\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\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) {\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) {\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<F extends T>(filter: Filter<T>) {\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>) {\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>) {\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 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":"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,OAAoBA,MAAiB,EAAE;QACrC,MAAMhB,UAAU,IAAI,CAACP,EAAE,CAAC,OAAO,GAAGX;YAChC,IAAImC,cAAcd,IAAI,GAAG,KAAM,MAAMa,UAAUlC,OAAQ;gBACrD,MAAMmC,iBAAkBnC;YAC1B;QACF;QACA,MAAMmC,gBAAgB,IAAI9B,MAAYa;QACtC,OAAOiB;IACT;IAWAC,MAAmBF,MAAiB,EAAE;QACpC,MAAMhB,UAAU,IAAI,CAACP,EAAE,CAAC,OAAO,GAAGX;YAChC,IAAImC,cAAcd,IAAI,GAAG,KAAM,MAAMa,UAAUlC,OAAQ;gBACrDkB;gBACA,MAAMiB,iBAAkBnC;YAC1B;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"}
|
package/package.json
CHANGED
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
|
|
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
|
|
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
|
|
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
|
|
@@ -77,13 +77,13 @@ export interface Event<T extends unknown[], R> {
|
|
|
77
77
|
(...args: T): Promise<(R | undefined)[]>;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
type
|
|
80
|
+
export type EventParameters<T> = T extends Event<infer P, unknown> ? P : never;
|
|
81
81
|
|
|
82
|
-
type
|
|
82
|
+
export type EventResult<T> = T extends Event<unknown[], infer R> ? R : never;
|
|
83
83
|
|
|
84
|
-
type
|
|
84
|
+
export type AllEventsParameters<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: EventParameters<T[K]> }[number];
|
|
85
85
|
|
|
86
|
-
type
|
|
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.
|
|
@@ -101,7 +101,7 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
|
|
|
101
101
|
* @returns The merged event.
|
|
102
102
|
*/
|
|
103
103
|
static merge<Events extends Event<any[], any>[]>(...events: Events) {
|
|
104
|
-
const mergedEvent = new Event<
|
|
104
|
+
const mergedEvent = new Event<AllEventsParameters<Events>, AllEventsResults<Events>>();
|
|
105
105
|
events.forEach((event) => event.on(mergedEvent));
|
|
106
106
|
return mergedEvent;
|
|
107
107
|
}
|
|
@@ -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>) {
|
|
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<
|
|
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>) {
|
|
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<
|
|
265
|
+
const filteredEvent = new Event<F, R>(dispose);
|
|
266
266
|
return filteredEvent;
|
|
267
267
|
}
|
|
268
268
|
|
|
@@ -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
|
|
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>;
|