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/src/index.ts CHANGED
@@ -1,30 +1,37 @@
1
1
  export type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;
2
2
 
3
- export interface Unsubscribe {
4
- (): void;
3
+ export interface Callback<R = void> {
4
+ (): MaybePromise<R>;
5
5
  }
6
6
 
7
- export interface Listener<T extends unknown[], R = unknown> {
8
- (...args: T): MaybePromise<R | void>;
7
+ export interface Listener<T, R = unknown> {
8
+ (event: T): MaybePromise<R | void>;
9
9
  }
10
10
 
11
- export interface Dispose {
12
- (): void;
11
+ export interface Result<T, E> {
12
+ ok: boolean;
13
+ result: T | E;
13
14
  }
14
15
 
15
- export interface Filter<T extends unknown[]> {
16
- (...args: T): MaybePromise<boolean>;
16
+ export interface FilterFunction<T> {
17
+ (event: T): MaybePromise<boolean>;
17
18
  }
18
19
 
19
- export interface Mapper<T extends unknown[], R> {
20
- (...args: T): MaybePromise<R>;
20
+ export interface Predicate<T, P extends T> {
21
+ (event: T): event is P;
21
22
  }
22
23
 
23
- export interface Reducer<T extends unknown[], R> {
24
- (value: R, ...args: T): MaybePromise<R>;
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 extends unknown[], R> = Listener<T, R>[];
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
- (): Promise<void> | void;
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: Unsubscribe) {
57
+ constructor(callback: Callback) {
55
58
  super(callback);
56
59
  }
57
60
 
58
- async after(task: Task): Promise<void> {
59
- await task();
60
- this();
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
- afterTimes(count: number): () => void {
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 = async <A extends unknown[], R>(listeners: Listeners<A, R>, ...args: A) => {
73
- return Promise.all(listeners.map((listener) => listener(...args)));
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 extends unknown[], R> {
77
- (...args: T): Promise<(R | undefined)[]>;
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[], infer R> ? R : never;
94
+ export type EventResult<T> = T extends Event<unknown, infer R> ? R : never;
83
95
 
84
- export type AllEventsParameters<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: EventParameters<T[K]> }[number];
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[], unknown>[]> = { [K in keyof T]: EventResult<T[K]> }[number];
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 extends unknown[], R = void> extends FunctionExt {
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: 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?: Dispose) {
126
+ constructor(dispose?: Callback) {
145
127
  const listeners: Listeners<T, R> = [];
146
- const fn = (...args: T) => eventEmitter(listeners, ...args);
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 = (...args: T) => {
191
+ const oneTimeListener = (event: T) => {
210
192
  this.off(oneTimeListener);
211
- return listener(...args);
193
+ return listener(event);
212
194
  };
213
195
  return this.on(oneTimeListener);
214
196
  }
215
197
 
216
198
  /**
217
- * Removes all listeners from the event.
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
- clear(): void {
220
- this.listeners.splice(0);
202
+ onceAsync(): Promise<T> {
203
+ return new Promise((resolve) => this.once((event) => resolve(event)));
221
204
  }
222
205
 
223
206
  /**
224
- * Returns a Promise that resolves with the first emitted by the event arguments.
225
- * @returns A Promise that resolves with the first emitted by the event.
207
+ * Removes all listeners from the event.
226
208
  */
227
- toPromise(): Promise<T> {
228
- return new Promise((resolve) => this.once((...args) => resolve(args)));
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<F extends T>(filter: Filter<T>): Event<F, R> {
240
- const dispose = this.on(async (...args: T) => {
241
- if (filteredEvent.size > 0 && (await filter(...args))) {
242
- await filteredEvent(...(args as F));
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<F, R>(dispose);
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<F extends T>(filter: Filter<T>): Event<F, R> {
259
- const dispose = this.on(async (...args: T) => {
260
- if (filteredEvent.size > 0 && (await filter(...args))) {
261
- dispose();
262
- await filteredEvent(...(args as F));
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<F, R>(dispose);
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 = unknown>(mapper: Mapper<T, M>): Event<[M], MR> {
278
- const dispose = this.on(async (...args) => {
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(...args);
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<[M], MR>(dispose);
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 = unknown>(reducer: Reducer<T, A>, init: A): Event<[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 (...args) => {
305
+ const dispose = this.on(async (event) => {
306
306
  if (reducedEvent.size > 0) {
307
- value = await reducer(value, ...args);
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<[A], AR>(dispose);
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((...args) => {
331
+ const dispose = this.on((event) => {
332
332
  clearTimeout(timer);
333
- timer = setTimeout(() => debouncedEvent(...args), interval);
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
- * Returns a promise that resolves with the arguments passed to the first invocation of the given event.
341
+ * Merges multiple events into a single event.
342
342
  * @example
343
- * const [x, y] = await once(mouseEvent);
343
+ * const inputEvent = Event.merge(mouseEvent, keyboardEvent);
344
344
  *
345
- * @param event The event to listen for.
346
- * @returns A promise that resolves with the arguments passed to the first invocation of the given event.
345
+ * @param events - The events to merge.
346
+ * @returns The merged event.
347
347
  */
348
- export const once = <T extends unknown[], R = void>(event: Event<T, R>): Promise<T> => {
349
- return new Promise((resolve) => event.once((...args) => resolve(args)));
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 extends unknown[], R = void>(): Event<T, R> => {
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> = Filter<EventParameters<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