evnty 1.5.2 → 2.0.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/README.md +139 -16
- package/build/index.cjs +39 -43
- package/build/index.cjs.map +1 -1
- package/build/index.d.ts +58 -47
- package/build/index.js +34 -41
- package/build/index.js.map +1 -1
- package/package.json +21 -13
- package/src/__tests__/example.js +45 -0
- package/src/__tests__/index.ts +383 -0
- package/src/index.ts +102 -90
package/build/index.js
CHANGED
|
@@ -10,36 +10,23 @@ export class Dismiss extends FunctionExt {
|
|
|
10
10
|
}
|
|
11
11
|
async after(task) {
|
|
12
12
|
await task();
|
|
13
|
-
this();
|
|
13
|
+
await this();
|
|
14
14
|
}
|
|
15
15
|
afterTimes(count) {
|
|
16
|
-
return ()=>{
|
|
16
|
+
return async ()=>{
|
|
17
17
|
if (!--count) {
|
|
18
|
-
this();
|
|
18
|
+
await this();
|
|
19
19
|
}
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
-
const eventEmitter =
|
|
24
|
-
return Promise.all(listeners.map((listener)=>listener(...args)));
|
|
25
|
-
};
|
|
23
|
+
const eventEmitter = (listeners, event)=>Promise.all(listeners.map((listener)=>listener(event)));
|
|
26
24
|
export class Event extends FunctionExt {
|
|
27
|
-
static merge(...events) {
|
|
28
|
-
const mergedEvent = new Event();
|
|
29
|
-
events.forEach((event)=>event.on(mergedEvent));
|
|
30
|
-
return mergedEvent;
|
|
31
|
-
}
|
|
32
|
-
static interval(interval) {
|
|
33
|
-
let counter = 0;
|
|
34
|
-
const intervalEvent = new Event(()=>clearInterval(timerId));
|
|
35
|
-
const timerId = setInterval(()=>intervalEvent(counter++), interval);
|
|
36
|
-
return intervalEvent;
|
|
37
|
-
}
|
|
38
25
|
listeners;
|
|
39
26
|
dispose;
|
|
40
27
|
constructor(dispose){
|
|
41
28
|
const listeners = [];
|
|
42
|
-
const fn = (
|
|
29
|
+
const fn = (event)=>eventEmitter(listeners, event);
|
|
43
30
|
super(fn);
|
|
44
31
|
this.listeners = listeners;
|
|
45
32
|
this.dispose = ()=>{
|
|
@@ -68,42 +55,42 @@ export class Event extends FunctionExt {
|
|
|
68
55
|
return new Dismiss(()=>this.off(listener));
|
|
69
56
|
}
|
|
70
57
|
once(listener) {
|
|
71
|
-
const oneTimeListener = (
|
|
58
|
+
const oneTimeListener = (event)=>{
|
|
72
59
|
this.off(oneTimeListener);
|
|
73
|
-
return listener(
|
|
60
|
+
return listener(event);
|
|
74
61
|
};
|
|
75
62
|
return this.on(oneTimeListener);
|
|
76
63
|
}
|
|
77
64
|
clear() {
|
|
78
65
|
this.listeners.splice(0);
|
|
79
66
|
}
|
|
80
|
-
|
|
81
|
-
return new Promise((resolve)=>this.once((
|
|
67
|
+
onceAsync() {
|
|
68
|
+
return new Promise((resolve)=>this.once((event)=>resolve(event)));
|
|
82
69
|
}
|
|
83
70
|
filter(filter) {
|
|
84
|
-
const dispose = this.on(async (
|
|
85
|
-
if (filteredEvent.size > 0 && await filter(
|
|
86
|
-
await filteredEvent(
|
|
71
|
+
const dispose = this.on(async (event)=>{
|
|
72
|
+
if (filteredEvent.size > 0 && await filter(event)) {
|
|
73
|
+
await filteredEvent(event);
|
|
87
74
|
}
|
|
88
75
|
});
|
|
89
76
|
const filteredEvent = new Event(dispose);
|
|
90
77
|
return filteredEvent;
|
|
91
78
|
}
|
|
92
79
|
first(filter) {
|
|
93
|
-
const dispose = this.on(async (
|
|
94
|
-
if (filteredEvent.size > 0 && await filter(
|
|
95
|
-
dispose();
|
|
96
|
-
await filteredEvent(
|
|
80
|
+
const dispose = this.on(async (event)=>{
|
|
81
|
+
if (filteredEvent.size > 0 && await filter(event)) {
|
|
82
|
+
await dispose();
|
|
83
|
+
await filteredEvent(event);
|
|
97
84
|
}
|
|
98
85
|
});
|
|
99
86
|
const filteredEvent = new Event(dispose);
|
|
100
87
|
return filteredEvent;
|
|
101
88
|
}
|
|
102
89
|
map(mapper) {
|
|
103
|
-
const dispose = this.on(async (
|
|
90
|
+
const dispose = this.on(async (event)=>{
|
|
104
91
|
if (mappedEvent.size > 0) {
|
|
105
|
-
const value = await mapper(
|
|
106
|
-
mappedEvent(value);
|
|
92
|
+
const value = await mapper(event);
|
|
93
|
+
await mappedEvent(value);
|
|
107
94
|
}
|
|
108
95
|
});
|
|
109
96
|
const mappedEvent = new Event(dispose);
|
|
@@ -111,10 +98,10 @@ export class Event extends FunctionExt {
|
|
|
111
98
|
}
|
|
112
99
|
reduce(reducer, init) {
|
|
113
100
|
let value = init;
|
|
114
|
-
const dispose = this.on(async (
|
|
101
|
+
const dispose = this.on(async (event)=>{
|
|
115
102
|
if (reducedEvent.size > 0) {
|
|
116
|
-
value = await reducer(value,
|
|
117
|
-
reducedEvent(value);
|
|
103
|
+
value = await reducer(value, event);
|
|
104
|
+
await reducedEvent(value);
|
|
118
105
|
}
|
|
119
106
|
});
|
|
120
107
|
const reducedEvent = new Event(dispose);
|
|
@@ -122,20 +109,26 @@ export class Event extends FunctionExt {
|
|
|
122
109
|
}
|
|
123
110
|
debounce(interval) {
|
|
124
111
|
let timer;
|
|
125
|
-
const dispose = this.on((
|
|
112
|
+
const dispose = this.on((event)=>{
|
|
126
113
|
clearTimeout(timer);
|
|
127
|
-
timer = setTimeout(()=>debouncedEvent(
|
|
114
|
+
timer = setTimeout(()=>debouncedEvent(event), interval);
|
|
128
115
|
});
|
|
129
116
|
const debouncedEvent = new Event(dispose);
|
|
130
117
|
return debouncedEvent;
|
|
131
118
|
}
|
|
132
119
|
}
|
|
133
|
-
export const
|
|
134
|
-
|
|
120
|
+
export const merge = (...events)=>{
|
|
121
|
+
const mergedEvent = new Event();
|
|
122
|
+
events.forEach((event)=>event.on(mergedEvent));
|
|
123
|
+
return mergedEvent;
|
|
135
124
|
};
|
|
136
|
-
export const
|
|
137
|
-
|
|
125
|
+
export const createInterval = (interval)=>{
|
|
126
|
+
let counter = 0;
|
|
127
|
+
const intervalEvent = new Event(()=>clearInterval(timerId));
|
|
128
|
+
const timerId = setInterval(()=>intervalEvent(counter++), interval);
|
|
129
|
+
return intervalEvent;
|
|
138
130
|
};
|
|
131
|
+
export const createEvent = ()=>new Event();
|
|
139
132
|
export default createEvent;
|
|
140
133
|
|
|
141
134
|
//# sourceMappingURL=index.js.map
|
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> {\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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"}
|
|
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, R = unknown> {\n (event: T): MaybePromise<R | void>;\n}\n\nexport interface Dispose {\n (): void;\n}\n\nexport interface Result<T, E> {\n ok: boolean;\n result: T | E;\n}\n\nexport interface Resolver<T, P> {\n (event: T): Promise<P>;\n}\n\nexport interface FilterFunction<T> {\n (event: T): MaybePromise<boolean>;\n}\n\nexport interface Predicate<T, P extends T> {\n (event: T): event is P;\n}\n\nexport type Filter<T, P extends T> = Predicate<T, P> | FilterFunction<T>;\n\nexport interface Mapper<T, R> {\n (event: T): MaybePromise<R>;\n}\n\nexport interface Reducer<T, R> {\n (result: R, event: T): MaybePromise<R>;\n}\n\nexport type Listeners<T, 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 await this();\n }\n\n afterTimes(count: number): () => Promise<void> {\n return async () => {\n if (!--count) {\n await this();\n }\n };\n }\n}\n\nconst eventEmitter = <A, R>(listeners: Listeners<A, R>, event: A): Promise<(void | R)[]> => Promise.all(listeners.map((listener) => listener(event)));\n\ntype EventType<T> = T extends undefined ? void : T;\n\nexport interface Event<T = unknown, R = void> {\n (event?: EventType<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, R> extends FunctionExt {\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 = (event: T) => eventEmitter(listeners, event);\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 = (event: T) => {\n this.off(oneTimeListener);\n return listener(event);\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 onceAsync(): Promise<T> {\n return new Promise((resolve) => this.once((event) => resolve(event)));\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<P extends T>(predicate: Predicate<T, P>): Event<P, R>;\n filter<P extends T>(filter: FilterFunction<T>): Event<P, R>;\n filter<P extends T>(filter: Filter<T, P>): Event<P, R> {\n const dispose = this.on(async (event: T) => {\n if (filteredEvent.size > 0 && (await filter(event))) {\n await filteredEvent(event as EventType<P>);\n }\n });\n const filteredEvent = new Event<P, 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<P extends T>(predicate: Predicate<T, P>): Event<P, R>;\n first<P extends T>(filter: FilterFunction<T>): Event<P, R>;\n first<P extends T>(filter: Filter<T, P>): Event<P, R> {\n const dispose = this.on(async (event: T) => {\n if (filteredEvent.size > 0 && (await filter(event))) {\n await dispose();\n await filteredEvent(event as EventType<P>);\n }\n });\n const filteredEvent = new Event<P, 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 = R>(mapper: Mapper<T, M>): Event<M, MR> {\n const dispose = this.on(async (event) => {\n if (mappedEvent.size > 0) {\n const value = await mapper(event);\n await mappedEvent(value as EventType<M>);\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 = R>(reducer: Reducer<T, A>, init: A): Event<A, AR> {\n let value = init;\n const dispose = this.on(async (event) => {\n if (reducedEvent.size > 0) {\n value = await reducer(value, event);\n await reducedEvent(value as EventType<A>);\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((event) => {\n clearTimeout(timer);\n timer = setTimeout(() => debouncedEvent(event as EventType<T>), interval);\n });\n const debouncedEvent = new Event<T, R>(dispose);\n return debouncedEvent;\n }\n}\n\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 */\nexport const 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 */\nexport const createInterval = <R = void>(interval: number): Event<number, R> => {\n let counter = 0;\n const intervalEvent = new Event<number, R>(() => clearInterval(timerId));\n const timerId: ReturnType<typeof setInterval> = setInterval(() => intervalEvent(counter++), interval);\n return intervalEvent;\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, R = void>(): Event<T, R> => new Event<T, R>();\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> = FilterFunction<EventParameters<E>>;\n\n/**\n * A type helper that extracts the event predicate type\n *\n * @typeParam E The event type to predicate.\n */\nexport type EventPredicate<E, P extends EventParameters<E>> = Predicate<EventParameters<E>, P>;\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","event","Promise","all","map","listener","Event","dispose","fn","clear","size","length","lacks","indexOf","has","off","index","splice","on","push","once","oneTimeListener","onceAsync","resolve","filter","filteredEvent","first","mapper","mappedEvent","value","reduce","reducer","init","reducedEvent","debounce","interval","timer","clearTimeout","setTimeout","debouncedEvent","merge","events","mergedEvent","forEach","createInterval","counter","intervalEvent","clearInterval","timerId","setInterval","createEvent"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "evnty",
|
|
3
|
-
"description": "0-Deps, simple, fast, for browser and node js anonymous event library",
|
|
4
|
-
"version": "
|
|
3
|
+
"description": "0-Deps, simple, fast, for browser and node js reactive anonymous event library",
|
|
4
|
+
"version": "2.0.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
7
7
|
"main": "build/index.cjs",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"build",
|
|
15
|
-
"src/index.ts"
|
|
15
|
+
"src/index.ts",
|
|
16
|
+
"src/__tests__/example.js"
|
|
16
17
|
],
|
|
17
18
|
"sideEffects": false,
|
|
18
19
|
"scripts": {
|
|
@@ -34,7 +35,13 @@
|
|
|
34
35
|
"emitter",
|
|
35
36
|
"anonymous",
|
|
36
37
|
"flow",
|
|
37
|
-
"event-driven"
|
|
38
|
+
"event-driven",
|
|
39
|
+
"reactive",
|
|
40
|
+
"reactivity",
|
|
41
|
+
"react",
|
|
42
|
+
"signal",
|
|
43
|
+
"functional",
|
|
44
|
+
"stream"
|
|
38
45
|
],
|
|
39
46
|
"runkitExampleFilename": "src/__tests__/example.js",
|
|
40
47
|
"funding": "https://github.com/sponsors/3axap4eHko",
|
|
@@ -49,19 +56,20 @@
|
|
|
49
56
|
},
|
|
50
57
|
"homepage": "https://github.com/3axap4eHko/evnty#readme",
|
|
51
58
|
"devDependencies": {
|
|
52
|
-
"@swc/jest": "^0.2.
|
|
53
|
-
"@types/jest": "^29.5.
|
|
54
|
-
"@
|
|
55
|
-
"@typescript-eslint/
|
|
56
|
-
"eslint": "^
|
|
59
|
+
"@swc/jest": "^0.2.29",
|
|
60
|
+
"@types/jest": "^29.5.5",
|
|
61
|
+
"@types/node": "^20.7.0",
|
|
62
|
+
"@typescript-eslint/eslint-plugin": "^6.7.3",
|
|
63
|
+
"@typescript-eslint/parser": "^6.7.3",
|
|
64
|
+
"eslint": "^8.50.0",
|
|
57
65
|
"eslint-config-airbnb-base": "^15.0.0",
|
|
58
66
|
"eslint-config-prettier": "^9.0.0",
|
|
59
|
-
"eslint-plugin-import": "^2.
|
|
67
|
+
"eslint-plugin-import": "^2.28.1",
|
|
60
68
|
"eslint-plugin-prettier": "^5.0.0",
|
|
61
69
|
"husky": "^8.0.3",
|
|
62
70
|
"inop": "^0.4.2",
|
|
63
|
-
"jest": "^29.
|
|
64
|
-
"prettier": "^3.0.
|
|
65
|
-
"typescript": "^5.0.
|
|
71
|
+
"jest": "^29.7.0",
|
|
72
|
+
"prettier": "^3.0.3",
|
|
73
|
+
"typescript": "^5.0.4"
|
|
66
74
|
}
|
|
67
75
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const { createEvent, Event, once } = require('evnty');
|
|
2
|
+
|
|
3
|
+
// Creates a click event
|
|
4
|
+
const clickEvent = createEvent();
|
|
5
|
+
const handleClick = ({ button }) => console.log('Clicked button is', button);
|
|
6
|
+
const unsubscribeClick = clickEvent.on(handleClick);
|
|
7
|
+
|
|
8
|
+
// Creates a key press event
|
|
9
|
+
const keyPressEvent = createEvent();
|
|
10
|
+
const handleKeyPress = ({ key }) => console.log('Key pressed', key);
|
|
11
|
+
const unsubscribeKeyPress = keyPressEvent.on(handleKeyPress);
|
|
12
|
+
|
|
13
|
+
// Merges click and key press events into input event
|
|
14
|
+
const handleInput = (input) => console.log('Input', input);;
|
|
15
|
+
const inputEvent = Event.merge(clickEvent, keyPressEvent);
|
|
16
|
+
inputEvent.on(handleInput);
|
|
17
|
+
|
|
18
|
+
// Filters a click event to only include left-click events.
|
|
19
|
+
const handleLeftClick = () => console.log('Left button is clicked');
|
|
20
|
+
const leftClickEvent = clickEvent.filter(({ button }) => button === 'left');
|
|
21
|
+
leftClickEvent.on(handleLeftClick);
|
|
22
|
+
|
|
23
|
+
// Will press Enter after one second
|
|
24
|
+
setTimeout(keyPressEvent, 1000, { key: 'Enter' });
|
|
25
|
+
// Waits once the first Enter key press event occurs
|
|
26
|
+
await once(keyPressEvent.first(({ key }) => key === 'Enter'));
|
|
27
|
+
|
|
28
|
+
keyPressEvent({ key: 'W' });
|
|
29
|
+
keyPressEvent({ key: 'A' });
|
|
30
|
+
keyPressEvent({ key: 'S' });
|
|
31
|
+
keyPressEvent({ key: 'D' });
|
|
32
|
+
|
|
33
|
+
clickEvent({ button: 'right' });
|
|
34
|
+
clickEvent({ button: 'left' });
|
|
35
|
+
clickEvent({ button: 'middle' });
|
|
36
|
+
|
|
37
|
+
// Unsubscribe click listener
|
|
38
|
+
unsubscribeClick();
|
|
39
|
+
// It does not log anything because of click listener is unsubscribed
|
|
40
|
+
leftClickEvent.off(handleLeftClick);
|
|
41
|
+
|
|
42
|
+
// Unsubscribe key press listener once first Esc key press occur
|
|
43
|
+
unsubscribeKeyPress.after(() => once(keyPressEvent.first(({ key }) => key === 'Esc')));
|
|
44
|
+
// Press Esc to unsubscribe key press listener
|
|
45
|
+
keyPressEvent({ key: 'Esc' });
|