evnty 1.5.3 → 2.1.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 +57 -50
- package/build/index.cjs.map +1 -1
- package/build/index.d.ts +76 -63
- package/build/index.js +52 -48
- package/build/index.js.map +1 -1
- package/package.json +28 -21
- package/src/__tests__/example.js +45 -0
- package/src/index.ts +135 -112
package/src/index.ts
CHANGED
|
@@ -1,30 +1,37 @@
|
|
|
1
1
|
export type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;
|
|
2
2
|
|
|
3
|
-
export interface
|
|
4
|
-
():
|
|
3
|
+
export interface Callback<R = void> {
|
|
4
|
+
(): MaybePromise<R>;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
export interface Listener<T
|
|
8
|
-
(
|
|
7
|
+
export interface Listener<T, R = unknown> {
|
|
8
|
+
(event: T): MaybePromise<R | void>;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export interface
|
|
12
|
-
|
|
11
|
+
export interface Result<T, E> {
|
|
12
|
+
ok: boolean;
|
|
13
|
+
result: T | E;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
export interface
|
|
16
|
-
(
|
|
16
|
+
export interface FilterFunction<T> {
|
|
17
|
+
(event: T): MaybePromise<boolean>;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
export interface
|
|
20
|
-
(
|
|
20
|
+
export interface Predicate<T, P extends T> {
|
|
21
|
+
(event: T): event is P;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
export
|
|
24
|
-
|
|
24
|
+
export type Filter<T, P extends T> = Predicate<T, P> | FilterFunction<T>;
|
|
25
|
+
|
|
26
|
+
export interface Mapper<T, R> {
|
|
27
|
+
(event: T): MaybePromise<R>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface Reducer<T, R> {
|
|
31
|
+
(result: R, event: T): MaybePromise<R>;
|
|
25
32
|
}
|
|
26
33
|
|
|
27
|
-
export type Listeners<T
|
|
34
|
+
export type Listeners<T, R> = Listener<T, R>[];
|
|
28
35
|
|
|
29
36
|
/**
|
|
30
37
|
* An abstract class that extends the built-in Function class. It allows instances of the class
|
|
@@ -40,50 +47,55 @@ export abstract class FunctionExt extends Function {
|
|
|
40
47
|
}
|
|
41
48
|
|
|
42
49
|
export interface Dismiss {
|
|
43
|
-
():
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface Task {
|
|
47
|
-
(): MaybePromise<unknown>;
|
|
50
|
+
(): MaybePromise<void>;
|
|
48
51
|
}
|
|
49
52
|
|
|
50
53
|
/**
|
|
51
54
|
* @internal
|
|
52
55
|
*/
|
|
53
56
|
export class Dismiss extends FunctionExt {
|
|
54
|
-
constructor(callback:
|
|
57
|
+
constructor(callback: Callback) {
|
|
55
58
|
super(callback);
|
|
56
59
|
}
|
|
57
60
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
pre(callback: Callback): Dismiss {
|
|
62
|
+
return new Dismiss(async () => {
|
|
63
|
+
await callback();
|
|
64
|
+
await this();
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
post(callback: Callback): Dismiss {
|
|
69
|
+
return new Dismiss(async () => {
|
|
70
|
+
await this();
|
|
71
|
+
await callback();
|
|
72
|
+
});
|
|
61
73
|
}
|
|
62
74
|
|
|
63
|
-
|
|
64
|
-
return () => {
|
|
75
|
+
countdown(count: number): Dismiss {
|
|
76
|
+
return new Dismiss(async () => {
|
|
65
77
|
if (!--count) {
|
|
66
|
-
this();
|
|
78
|
+
await this();
|
|
67
79
|
}
|
|
68
|
-
};
|
|
80
|
+
});
|
|
69
81
|
}
|
|
70
82
|
}
|
|
71
83
|
|
|
72
|
-
const eventEmitter =
|
|
73
|
-
|
|
74
|
-
|
|
84
|
+
const eventEmitter = <A, R>(listeners: Listeners<A, R>, event: A): Promise<(void | R)[]> => Promise.all(listeners.map((listener) => listener(event)));
|
|
85
|
+
|
|
86
|
+
type EventType<T> = T extends undefined ? void : T;
|
|
75
87
|
|
|
76
|
-
export interface Event<T
|
|
77
|
-
(
|
|
88
|
+
export interface Event<T = unknown, R = void> {
|
|
89
|
+
(event?: EventType<T>): Promise<(R | undefined)[]>;
|
|
78
90
|
}
|
|
79
91
|
|
|
80
92
|
export type EventParameters<T> = T extends Event<infer P, unknown> ? P : never;
|
|
81
93
|
|
|
82
|
-
export type EventResult<T> = T extends Event<unknown
|
|
94
|
+
export type EventResult<T> = T extends Event<unknown, infer R> ? R : never;
|
|
83
95
|
|
|
84
|
-
export type AllEventsParameters<T extends Event<unknown
|
|
96
|
+
export type AllEventsParameters<T extends Event<unknown, unknown>[]> = { [K in keyof T]: EventParameters<T[K]> }[number];
|
|
85
97
|
|
|
86
|
-
export type AllEventsResults<T extends Event<unknown
|
|
98
|
+
export type AllEventsResults<T extends Event<unknown, unknown>[]> = { [K in keyof T]: EventResult<T[K]> }[number];
|
|
87
99
|
|
|
88
100
|
/**
|
|
89
101
|
* A class representing an anonymous event that can be listened to or triggered.
|
|
@@ -91,37 +103,7 @@ export type AllEventsResults<T extends Event<unknown[], unknown>[]> = { [K in ke
|
|
|
91
103
|
* @typeParam T - The tuple of arguments that the event takes.
|
|
92
104
|
* @typeParam R - The return type of the event.
|
|
93
105
|
*/
|
|
94
|
-
export class Event<T
|
|
95
|
-
/**
|
|
96
|
-
* Merges multiple events into a single event.
|
|
97
|
-
* @example
|
|
98
|
-
* const inputEvent = Event.merge(mouseEvent, keyboardEvent);
|
|
99
|
-
*
|
|
100
|
-
* @param events - The events to merge.
|
|
101
|
-
* @returns The merged event.
|
|
102
|
-
*/
|
|
103
|
-
static merge<Events extends Event<any[], any>[]>(...events: Events): Event<AllEventsParameters<Events>, AllEventsResults<Events>> {
|
|
104
|
-
const mergedEvent = new Event<AllEventsParameters<Events>, AllEventsResults<Events>>();
|
|
105
|
-
events.forEach((event) => event.on(mergedEvent));
|
|
106
|
-
return mergedEvent;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Creates an event that triggers at a specified interval.
|
|
111
|
-
* @example
|
|
112
|
-
* const tickEvent = Event.interval(1000);
|
|
113
|
-
* tickEvent.on((tickNumber) => console.log(tickNumber));
|
|
114
|
-
*
|
|
115
|
-
* @param interval - The interval at which to trigger the event.
|
|
116
|
-
* @returns The interval event.
|
|
117
|
-
*/
|
|
118
|
-
static interval(interval: number): Event<[number], void> {
|
|
119
|
-
let counter = 0;
|
|
120
|
-
const intervalEvent = new Event<[number], void>(() => clearInterval(timerId));
|
|
121
|
-
const timerId: ReturnType<typeof setInterval> = setInterval(() => intervalEvent(counter++), interval);
|
|
122
|
-
return intervalEvent;
|
|
123
|
-
}
|
|
124
|
-
|
|
106
|
+
export class Event<T, R> extends FunctionExt {
|
|
125
107
|
/**
|
|
126
108
|
* The array of listeners for the event.
|
|
127
109
|
*/
|
|
@@ -130,7 +112,7 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
|
|
|
130
112
|
/**
|
|
131
113
|
* A function that disposes of the event and its listeners.
|
|
132
114
|
*/
|
|
133
|
-
readonly dispose:
|
|
115
|
+
readonly dispose: Callback;
|
|
134
116
|
|
|
135
117
|
/**
|
|
136
118
|
* Creates a new event.
|
|
@@ -141,15 +123,15 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
|
|
|
141
123
|
*
|
|
142
124
|
* @param dispose - A function to call on the event disposal.
|
|
143
125
|
*/
|
|
144
|
-
constructor(dispose?:
|
|
126
|
+
constructor(dispose?: Callback) {
|
|
145
127
|
const listeners: Listeners<T, R> = [];
|
|
146
|
-
const fn = (
|
|
128
|
+
const fn = (event: T) => eventEmitter(listeners, event);
|
|
147
129
|
|
|
148
130
|
super(fn);
|
|
149
131
|
this.listeners = listeners;
|
|
150
|
-
this.dispose = () => {
|
|
132
|
+
this.dispose = async () => {
|
|
151
133
|
this.clear();
|
|
152
|
-
dispose?.();
|
|
134
|
+
await dispose?.();
|
|
153
135
|
};
|
|
154
136
|
}
|
|
155
137
|
|
|
@@ -206,26 +188,26 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
|
|
|
206
188
|
* @returns An object that can be used to remove the listener.
|
|
207
189
|
*/
|
|
208
190
|
once(listener: Listener<T, R>): Dismiss {
|
|
209
|
-
const oneTimeListener = (
|
|
191
|
+
const oneTimeListener = (event: T) => {
|
|
210
192
|
this.off(oneTimeListener);
|
|
211
|
-
return listener(
|
|
193
|
+
return listener(event);
|
|
212
194
|
};
|
|
213
195
|
return this.on(oneTimeListener);
|
|
214
196
|
}
|
|
215
197
|
|
|
216
198
|
/**
|
|
217
|
-
*
|
|
199
|
+
* Returns a Promise that resolves with the first emitted by the event arguments.
|
|
200
|
+
* @returns A Promise that resolves with the first emitted by the event.
|
|
218
201
|
*/
|
|
219
|
-
|
|
220
|
-
this.
|
|
202
|
+
onceAsync(): Promise<T> {
|
|
203
|
+
return new Promise((resolve) => this.once((event) => resolve(event)));
|
|
221
204
|
}
|
|
222
205
|
|
|
223
206
|
/**
|
|
224
|
-
*
|
|
225
|
-
* @returns A Promise that resolves with the first emitted by the event.
|
|
207
|
+
* Removes all listeners from the event.
|
|
226
208
|
*/
|
|
227
|
-
|
|
228
|
-
|
|
209
|
+
clear(): void {
|
|
210
|
+
this.listeners.splice(0);
|
|
229
211
|
}
|
|
230
212
|
|
|
231
213
|
/**
|
|
@@ -236,13 +218,15 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
|
|
|
236
218
|
* @param filter The filter function to apply to the event.
|
|
237
219
|
* @returns A new event that only triggers when the provided filter function returns `true`.
|
|
238
220
|
*/
|
|
239
|
-
filter<
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
221
|
+
filter<P extends T>(predicate: Predicate<T, P>): Event<P, R>;
|
|
222
|
+
filter<P extends T>(filter: FilterFunction<T>): Event<P, R>;
|
|
223
|
+
filter<P extends T>(filter: Filter<T, P>): Event<P, R> {
|
|
224
|
+
const dispose = this.on(async (event: T) => {
|
|
225
|
+
if (filteredEvent.size > 0 && (await filter(event))) {
|
|
226
|
+
await filteredEvent(event as EventType<P>);
|
|
243
227
|
}
|
|
244
228
|
});
|
|
245
|
-
const filteredEvent = new Event<
|
|
229
|
+
const filteredEvent = new Event<P, R>(dispose);
|
|
246
230
|
return filteredEvent;
|
|
247
231
|
}
|
|
248
232
|
|
|
@@ -255,17 +239,33 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
|
|
|
255
239
|
* @param filter - The filter function.
|
|
256
240
|
* @returns A new event that will only be triggered once the provided filter function returns `true`.
|
|
257
241
|
*/
|
|
258
|
-
first<
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
242
|
+
first<P extends T>(predicate: Predicate<T, P>): Event<P, R>;
|
|
243
|
+
first<P extends T>(filter: FilterFunction<T>): Event<P, R>;
|
|
244
|
+
first<P extends T>(filter: Filter<T, P>): Event<P, R> {
|
|
245
|
+
const dispose = this.on(async (event: T) => {
|
|
246
|
+
if (filteredEvent.size > 0 && (await filter(event))) {
|
|
247
|
+
await dispose();
|
|
248
|
+
await filteredEvent(event as EventType<P>);
|
|
263
249
|
}
|
|
264
250
|
});
|
|
265
|
-
const filteredEvent = new Event<
|
|
251
|
+
const filteredEvent = new Event<P, R>(dispose);
|
|
266
252
|
return filteredEvent;
|
|
267
253
|
}
|
|
268
254
|
|
|
255
|
+
/**
|
|
256
|
+
* Returns a new promise that will be resolved once the provided filter function returns `true`.
|
|
257
|
+
* @example
|
|
258
|
+
* const escPressEvent = await keyboardEvent.firstAsync((key) => key === 'Esc');
|
|
259
|
+
*
|
|
260
|
+
* @param filter - The filter function.
|
|
261
|
+
* @returns A new promise that will be resolved once the provided filter function returns `true`.
|
|
262
|
+
*/
|
|
263
|
+
firstAsync<P extends T>(predicate: Predicate<T, P>): Promise<P>;
|
|
264
|
+
firstAsync<P extends T>(filter: FilterFunction<T>): Promise<P>;
|
|
265
|
+
firstAsync<P extends T>(filter: Filter<T, P>): Promise<P> {
|
|
266
|
+
return this.first<P>(filter).onceAsync();
|
|
267
|
+
}
|
|
268
|
+
|
|
269
269
|
/**
|
|
270
270
|
* Returns a new event that maps the values of this event using the provided mapper function.
|
|
271
271
|
* @example
|
|
@@ -274,14 +274,14 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
|
|
|
274
274
|
* @param mapper A function that maps the values of this event to a new value.
|
|
275
275
|
* @returns A new event that emits the mapped values.
|
|
276
276
|
*/
|
|
277
|
-
map<M, MR =
|
|
278
|
-
const dispose = this.on(async (
|
|
277
|
+
map<M, MR = R>(mapper: Mapper<T, M>): Event<M, MR> {
|
|
278
|
+
const dispose = this.on(async (event) => {
|
|
279
279
|
if (mappedEvent.size > 0) {
|
|
280
|
-
const value = await mapper(
|
|
281
|
-
mappedEvent(value);
|
|
280
|
+
const value = await mapper(event);
|
|
281
|
+
await mappedEvent(value as EventType<M>);
|
|
282
282
|
}
|
|
283
283
|
});
|
|
284
|
-
const mappedEvent = new Event<
|
|
284
|
+
const mappedEvent = new Event<M, MR>(dispose);
|
|
285
285
|
return mappedEvent;
|
|
286
286
|
}
|
|
287
287
|
|
|
@@ -300,15 +300,15 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
|
|
|
300
300
|
* @param {A} init The initial value of the accumulated value.
|
|
301
301
|
* @returns {Event<[A], AR>} A new `Event` that emits the reduced value.
|
|
302
302
|
*/
|
|
303
|
-
reduce<A, AR =
|
|
303
|
+
reduce<A, AR = R>(reducer: Reducer<T, A>, init: A): Event<A, AR> {
|
|
304
304
|
let value = init;
|
|
305
|
-
const dispose = this.on(async (
|
|
305
|
+
const dispose = this.on(async (event) => {
|
|
306
306
|
if (reducedEvent.size > 0) {
|
|
307
|
-
value = await reducer(value,
|
|
308
|
-
reducedEvent(value);
|
|
307
|
+
value = await reducer(value, event);
|
|
308
|
+
await reducedEvent(value as EventType<A>);
|
|
309
309
|
}
|
|
310
310
|
});
|
|
311
|
-
const reducedEvent = new Event<
|
|
311
|
+
const reducedEvent = new Event<A, AR>(dispose);
|
|
312
312
|
return reducedEvent;
|
|
313
313
|
}
|
|
314
314
|
|
|
@@ -328,9 +328,9 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
|
|
|
328
328
|
*/
|
|
329
329
|
debounce(interval: number): Event<T, R> {
|
|
330
330
|
let timer: ReturnType<typeof setTimeout>;
|
|
331
|
-
const dispose = this.on((
|
|
331
|
+
const dispose = this.on((event) => {
|
|
332
332
|
clearTimeout(timer);
|
|
333
|
-
timer = setTimeout(() => debouncedEvent(
|
|
333
|
+
timer = setTimeout(() => debouncedEvent(event as EventType<T>), interval);
|
|
334
334
|
});
|
|
335
335
|
const debouncedEvent = new Event<T, R>(dispose);
|
|
336
336
|
return debouncedEvent;
|
|
@@ -338,15 +338,33 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
|
|
|
338
338
|
}
|
|
339
339
|
|
|
340
340
|
/**
|
|
341
|
-
*
|
|
341
|
+
* Merges multiple events into a single event.
|
|
342
342
|
* @example
|
|
343
|
-
* const
|
|
343
|
+
* const inputEvent = Event.merge(mouseEvent, keyboardEvent);
|
|
344
344
|
*
|
|
345
|
-
* @param
|
|
346
|
-
* @returns
|
|
345
|
+
* @param events - The events to merge.
|
|
346
|
+
* @returns The merged event.
|
|
347
347
|
*/
|
|
348
|
-
export const
|
|
349
|
-
|
|
348
|
+
export const merge = <Events extends Event<any, any>[]>(...events: Events): Event<AllEventsParameters<Events>, AllEventsResults<Events>> => {
|
|
349
|
+
const mergedEvent = new Event<AllEventsParameters<Events>, AllEventsResults<Events>>();
|
|
350
|
+
events.forEach((event) => event.on(mergedEvent));
|
|
351
|
+
return mergedEvent;
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Creates an event that triggers at a specified interval.
|
|
356
|
+
* @example
|
|
357
|
+
* const tickEvent = Event.interval(1000);
|
|
358
|
+
* tickEvent.on((tickNumber) => console.log(tickNumber));
|
|
359
|
+
*
|
|
360
|
+
* @param interval - The interval at which to trigger the event.
|
|
361
|
+
* @returns The interval event.
|
|
362
|
+
*/
|
|
363
|
+
export const createInterval = <R = void>(interval: number): Event<number, R> => {
|
|
364
|
+
let counter = 0;
|
|
365
|
+
const intervalEvent = new Event<number, R>(() => clearInterval(timerId));
|
|
366
|
+
const timerId: ReturnType<typeof setInterval> = setInterval(() => intervalEvent(counter++), interval);
|
|
367
|
+
return intervalEvent;
|
|
350
368
|
};
|
|
351
369
|
|
|
352
370
|
/**
|
|
@@ -361,9 +379,7 @@ export const once = <T extends unknown[], R = void>(event: Event<T, R>): Promise
|
|
|
361
379
|
* myEvent.on((str: string) => str.length);
|
|
362
380
|
* await myEvent('hello'); // [5]
|
|
363
381
|
*/
|
|
364
|
-
export const createEvent = <T
|
|
365
|
-
return new Event<T, R>();
|
|
366
|
-
};
|
|
382
|
+
export const createEvent = <T, R = void>(): Event<T, R> => new Event<T, R>();
|
|
367
383
|
|
|
368
384
|
export default createEvent;
|
|
369
385
|
|
|
@@ -379,7 +395,14 @@ export type EventHandler<E> = E extends Event<infer T, infer R> ? Listener<T, R>
|
|
|
379
395
|
*
|
|
380
396
|
* @typeParam E The event type to filter.
|
|
381
397
|
*/
|
|
382
|
-
export type EventFilter<E> =
|
|
398
|
+
export type EventFilter<E> = FilterFunction<EventParameters<E>>;
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* A type helper that extracts the event predicate type
|
|
402
|
+
*
|
|
403
|
+
* @typeParam E The event type to predicate.
|
|
404
|
+
*/
|
|
405
|
+
export type EventPredicate<E, P extends EventParameters<E>> = Predicate<EventParameters<E>, P>;
|
|
383
406
|
|
|
384
407
|
/**
|
|
385
408
|
* A type helper that extracts the event mapper type
|