evnty 1.2.5 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -57,67 +57,38 @@ Using npm:
57
57
  npm install evnty
58
58
  ```
59
59
 
60
- ## Interface
61
-
62
- ```typescript
63
- type Unsubscribe = () => void;
64
- type Listener = (...args: any[]) => void;
65
- type Dispose = () => void;
66
- type Filter = (...args: any[]) => boolean;
67
- type Mapper = <T = any>(...args: any[]) => T;
68
- type Reducer = <T = any>(value: any, ...args: any[]) => T;
69
-
70
- class Dismiss {
71
- async after(process: () => MaybePromise<any>): Promise<void>;
72
- afterTimes(count: number): () => void;
73
- }
74
-
75
- class Event {
76
- // Merges multiple events
77
- static merge(...events: Event[]): Event;
78
- // Emits event by interval
79
- static interval(interval: number): Event;
80
-
81
- readonly size: Number;
82
-
83
- constructor(dispose?: Dispose);
84
- lacks(listener: Listener): boolean;
85
- has(listener: Listener): boolean;
86
- off(listener: Listener): void;
87
- on(listener: Listener): Dismiss;
88
- once(listener: Listener): Dismiss;
89
- clear(): void;
90
- toPromise(): Promise<any[]>;
91
- filter(filter: Filter): Event;
92
- map(mapper: Mapper): Event;
93
- reduce(reducer: Reducer, init: any): Event;
94
- dispose(): Dispose;
95
- }
96
- ```
97
-
98
- ## Usage
60
+ ## Examples
99
61
 
100
62
  ```js
101
- import event, { once } from 'evnty';
63
+ import createEvent, { Event, once } from 'evnty';
102
64
 
103
- const handleClick = ({ button }) => console.log('Clicked button is', button);
104
- const clickEvent = event();
65
+ // Creates a click event
66
+ type Click = { button: string };
67
+ const clickEvent = createEvent<[Click]>();
68
+ const handleClick = ({ button }: Click) => console.log('Clicked button is', button);
105
69
  const unsubscribeClick = clickEvent.on(handleClick);
106
70
 
107
- const keyPressEvent = event();
108
- const handleKeyPress = ({ key }) => console.log('Key pressed', key);
71
+ // Creates a key press event
72
+ type KeyPress = { key: string };
73
+ const keyPressEvent = createEvent<[KeyPress]>();
74
+ const handleKeyPress = ({ key }: KeyPress) => console.log('Key pressed', key);
109
75
  const unsubscribeKeyPress = keyPressEvent.on(handleKeyPress);
110
76
 
111
- const handleInput = ({ button, key }) => {};
77
+ // Merges click and key press events into input event
78
+ type Input = Click | KeyPress;
79
+ const handleInput = (input: Input) => console.log('Input', input);;
112
80
  const inputEvent = Event.merge(clickEvent, keyPressEvent);
113
81
  inputEvent.on(handleInput);
114
82
 
83
+ // Filters a click event to only include left-click events.
115
84
  const handleLeftClick = () => console.log('Left button is clicked');
116
85
  const leftClickEvent = clickEvent.filter(({ button }) => button === 'left');
117
86
  leftClickEvent.on(handleLeftClick);
118
87
 
119
- setTimeout(() => keyPressEvent, 100, 'Enter');
120
- await once(keyPressEvent);
88
+ // Will press Enter after one second
89
+ setTimeout(keyPressEvent, 1000, { key: 'Enter' });
90
+ // Waits once the first Enter key press event occurs
91
+ await once(keyPressEvent.first(({ key }) => key === 'Enter'));
121
92
 
122
93
  keyPressEvent({ key: 'W' });
123
94
  keyPressEvent({ key: 'A' });
@@ -128,9 +99,14 @@ clickEvent({ button: 'right' });
128
99
  clickEvent({ button: 'left' });
129
100
  clickEvent({ button: 'middle' });
130
101
 
102
+ // Unsubscribe click listener
131
103
  unsubscribeClick();
132
- unsubscribeKeyPress.after(() => once(keyPressEvent));
104
+ // It does not log anything because of click listener is unsubscribed
133
105
  leftClickEvent.off(handleLeftClick);
106
+
107
+ // Unsubscribe key press listener once first Esc key press occur
108
+ unsubscribeKeyPress.after(() => once(keyPressEvent.first(({ key }) => key === 'Esc')));
109
+ // Press Esc to unsubscribe key press listener
134
110
  keyPressEvent({ key: 'Esc' });
135
111
  ```
136
112
 
package/build/index.cjs CHANGED
@@ -9,6 +9,9 @@ function _export(target, all) {
9
9
  });
10
10
  }
11
11
  _export(exports, {
12
+ FunctionExt: function() {
13
+ return FunctionExt;
14
+ },
12
15
  Dismiss: function() {
13
16
  return Dismiss;
14
17
  },
@@ -18,8 +21,11 @@ _export(exports, {
18
21
  once: function() {
19
22
  return once;
20
23
  },
21
- default: function() {
24
+ createEvent: function() {
22
25
  return createEvent;
26
+ },
27
+ default: function() {
28
+ return _default;
23
29
  }
24
30
  });
25
31
  class FunctionExt extends Function {
@@ -29,11 +35,11 @@ class FunctionExt extends Function {
29
35
  }
30
36
  }
31
37
  class Dismiss extends FunctionExt {
32
- constructor(dismiss){
33
- super(dismiss);
38
+ constructor(callback){
39
+ super(callback);
34
40
  }
35
- async after(process) {
36
- await process();
41
+ async after(task) {
42
+ await task();
37
43
  this();
38
44
  }
39
45
  afterTimes(count) {
@@ -113,6 +119,16 @@ class Event extends FunctionExt {
113
119
  const filteredEvent = new Event(dispose);
114
120
  return filteredEvent;
115
121
  }
122
+ first(filter) {
123
+ const dispose = this.on(async (...args)=>{
124
+ if (filteredEvent.size > 0 && await filter(...args)) {
125
+ dispose();
126
+ await filteredEvent(...args);
127
+ }
128
+ });
129
+ const filteredEvent = new Event(dispose);
130
+ return filteredEvent;
131
+ }
116
132
  map(mapper) {
117
133
  const dispose = this.on(async (...args)=>{
118
134
  if (mappedEvent.size > 0) {
@@ -138,8 +154,9 @@ class Event extends FunctionExt {
138
154
  const once = (event)=>{
139
155
  return new Promise((resolve)=>event.once((...args)=>resolve(args)));
140
156
  };
141
- function createEvent() {
157
+ const createEvent = ()=>{
142
158
  return new Event();
143
- }
159
+ };
160
+ const _default = createEvent;
144
161
 
145
162
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;\n\nexport interface Unsubscribe {\n (): void;\n}\n\nexport interface Listener<T extends unknown[], R> {\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): R;\n}\n\nexport interface Reducer<T extends unknown[], R> {\n (value: R, ...args: T): R;\n}\n\nexport type Listeners<T extends unknown[], R> = Listener<T, R>[];\n\nclass 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 class Dismiss extends FunctionExt {\n constructor(dismiss: Unsubscribe) {\n super(dismiss);\n }\n async after(process: () => MaybePromise<unknown>) {\n await process();\n this();\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;\ntype UnpackReturn<T> = T extends Event<unknown[], infer R> ? R : never;\ntype UnpackAllParameters<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: UnpackParameters<T[K]> }[number];\ntype UnpackAllReturn<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: UnpackReturn<T[K]> }[number];\n\nexport class Event<T extends unknown[], R = void> extends FunctionExt {\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 static interval(interval: number) {\n let counter = 0;\n const intervalEvent = new Event<[number], void>(() => clearInterval(timerId));\n const timerId: NodeJS.Timeout = setInterval(() => intervalEvent(counter++), interval);\n return intervalEvent;\n }\n\n private listeners: Listeners<T, R>;\n readonly dispose: Dispose;\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 get size(): number {\n return this.listeners.length;\n }\n\n lacks(listener: Listener<T, R>): boolean {\n return this.listeners.indexOf(listener) === -1;\n }\n\n has(listener: Listener<T, R>): boolean {\n return this.listeners.indexOf(listener) !== -1;\n }\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 on(listener: Listener<T, R>): Dismiss {\n this.listeners.push(listener);\n return new Dismiss(() => this.off(listener));\n }\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 clear() {\n this.listeners.splice(0);\n }\n\n toPromise(): Promise<T> {\n return new Promise((resolve) => this.once((...args) => resolve(args)));\n }\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 map<R>(mapper: Mapper<T, R>) {\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(dispose);\n return mappedEvent;\n }\n\n reduce<R>(reducer: Reducer<T, R>, init: R) {\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(dispose);\n return reducedEvent;\n }\n}\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\nexport default function createEvent<T extends unknown[], R = void>() {\n return new Event<T, R>();\n}\n"],"names":["Dismiss","Event","once","createEvent","FunctionExt","Function","constructor","func","Object","setPrototypeOf","prototype","dismiss","after","process","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","mapper","mappedEvent","value","reduce","reducer","init","reducedEvent"],"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 = 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\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 * @example\n * // Create a click event.\n * const clickEvent = new Event<[x: number, y: number], void>();\n *\n * @template T - The tuple of arguments that the event takes.\n * @template 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 * @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 * @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: NodeJS.Timeout = 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 * @param dispose - A function to dispose of the event and its listeners.\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 * Converts the event to a promise that resolves with the event arguments.\n * @returns A promise that resolves with the event arguments.\n */\n toPromise(): Promise<T> {\n return new Promise((resolve) => this.once((...args) => resolve(args)));\n }\n\n /**\n * Creates a new event that only triggers if the filter function returns `true`.\n * @param filter - The filter function.\n * @returns The filtered event.\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 * Creates a new event that only triggers once if the filter function returns `true`.\n * @param filter - The filter function.\n * @returns The filtered event.\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 * Creates a new event that maps the event arguments to a new value.\n * @param mapper - The mapper function.\n * @returns The mapped event.\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 * Creates a new event that reduces the event arguments to a single value.\n * @param reducer - The reducer function.\n * @param init - The initial value for the reducer.\n * @returns The reduced event.\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/**\n * Returns a promise that resolves with the arguments passed to the first invocation of the given event.\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 instance of the Event class.\n * @returns {Event<T, R>} A new instance of the Event class.\n * @template T The type of the arguments passed to the event.\n * @template R The return type of the event.\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 * @template E - The event object type.\n * @template T - The event type extracted from the event object.\n * @template 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"],"mappings":";;;;;;;;;;;IAkCsBA,WAAW;eAAXA;;IAeTC,OAAO;eAAPA;;IA4CAC,KAAK;eAALA;;IAoMAC,IAAI;eAAJA;;IAUAC,WAAW;eAAXA;;IAIb,OAA2B;eAA3B;;;AA7QO,MAAeJ,oBAAoBK;IACxCC,YAAYC,IAAc,CAAE;QAC1B,KAAK;QACL,OAAOC,OAAOC,cAAc,CAACF,MAAM,WAAWG,SAAS;IACzD;AACF;AAUO,MAAMT,gBAAgBD;IAC3BM,YAAYK,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;AAuBO,MAAMhB,cAA6CF;IAMxD,OAAOuB,MAA0C,GAAGC,MAAc,EAAE;QAClE,MAAMC,cAAc,IAAIvB;QACxBsB,OAAOE,OAAO,CAAC,CAACC,QAAUA,MAAMC,EAAE,CAACH;QACnC,OAAOA;IACT;IAOA,OAAOI,SAASA,QAAgB,EAAE;QAChC,IAAIC,UAAU;QACd,MAAMC,gBAAgB,IAAI7B,MAAsB,IAAM8B,cAAcC;QACpE,MAAMA,UAA0BC,YAAY,IAAMH,cAAcD,YAAYD;QAC5E,OAAOE;IACT;IAKQd,UAA2B;IAK1BkB,QAAiB;IAM1B7B,YAAY6B,OAAiB,CAAE;QAC7B,MAAMlB,YAA6B,EAAE;QACrC,MAAMmB,KAAK,CAAC,GAAGlB,OAAYF,aAAaC,cAAcC;QAEtD,KAAK,CAACkB;QACN,IAAI,CAACnB,SAAS,GAAGA;QACjB,IAAI,CAACkB,OAAO,GAAG;YACb,IAAI,CAACE,KAAK;YACVF;QACF;IACF;IAKA,IAAIG,OAAe;QACjB,OAAO,IAAI,CAACrB,SAAS,CAACsB,MAAM;IAC9B;IAOAC,MAAMlB,QAAwB,EAAW;QACvC,OAAO,IAAI,CAACL,SAAS,CAACwB,OAAO,CAACnB,cAAc,CAAC;IAC/C;IAOAoB,IAAIpB,QAAwB,EAAW;QACrC,OAAO,IAAI,CAACL,SAAS,CAACwB,OAAO,CAACnB,cAAc,CAAC;IAC/C;IAMAqB,IAAIrB,QAAwB,EAAQ;QAClC,IAAIsB,QAAQ,IAAI,CAAC3B,SAAS,CAACwB,OAAO,CAACnB;QACnC,MAAO,CAACsB,MAAO;YACb,IAAI,CAAC3B,SAAS,CAAC4B,MAAM,CAACD,OAAO;YAC7BA,QAAQ,IAAI,CAAC3B,SAAS,CAACwB,OAAO,CAACnB;QACjC;IACF;IAOAM,GAAGN,QAAwB,EAAW;QACpC,IAAI,CAACL,SAAS,CAAC6B,IAAI,CAACxB;QACpB,OAAO,IAAIrB,QAAQ,IAAM,IAAI,CAAC0C,GAAG,CAACrB;IACpC;IAOAnB,KAAKmB,QAAwB,EAAW;QACtC,MAAMyB,kBAAkB,CAAC,GAAG7B;YAC1B,IAAI,CAACyB,GAAG,CAACI;YACT,OAAOzB,YAAYJ;QACrB;QACA,OAAO,IAAI,CAACU,EAAE,CAACmB;IACjB;IAKAV,QAAQ;QACN,IAAI,CAACpB,SAAS,CAAC4B,MAAM,CAAC;IACxB;IAMAG,YAAwB;QACtB,OAAO,IAAI7B,QAAQ,CAAC8B,UAAY,IAAI,CAAC9C,IAAI,CAAC,CAAC,GAAGe,OAAS+B,QAAQ/B;IACjE;IAOAgC,OAAOA,MAAiB,EAAE;QACxB,MAAMf,UAAU,IAAI,CAACP,EAAE,CAAC,OAAO,GAAGV;YAChC,IAAIiC,cAAcb,IAAI,GAAG,KAAM,MAAMY,UAAUhC,OAAQ;gBACrD,MAAMiC,iBAAiBjC;YACzB;QACF;QACA,MAAMiC,gBAAgB,IAAIjD,MAAYiC;QACtC,OAAOgB;IACT;IAOAC,MAAMF,MAAiB,EAAE;QACvB,MAAMf,UAAU,IAAI,CAACP,EAAE,CAAC,OAAO,GAAGV;YAChC,IAAIiC,cAAcb,IAAI,GAAG,KAAM,MAAMY,UAAUhC,OAAQ;gBACrDiB;gBACA,MAAMgB,iBAAiBjC;YACzB;QACF;QACA,MAAMiC,gBAAgB,IAAIjD,MAAYiC;QACtC,OAAOgB;IACT;IAOA9B,IAAqBgC,MAAoB,EAAE;QACzC,MAAMlB,UAAU,IAAI,CAACP,EAAE,CAAC,OAAO,GAAGV;YAChC,IAAIoC,YAAYhB,IAAI,GAAG,GAAG;gBACxB,MAAMiB,QAAQ,MAAMF,UAAUnC;gBAC9BoC,YAAYC;YACd;QACF;QACA,MAAMD,cAAc,IAAIpD,MAAeiC;QACvC,OAAOmB;IACT;IAQAE,OAAwBC,OAAsB,EAAEC,IAAO,EAAE;QACvD,IAAIH,QAAQG;QACZ,MAAMvB,UAAU,IAAI,CAACP,EAAE,CAAC,OAAO,GAAGV;YAChC,IAAIyC,aAAarB,IAAI,GAAG,GAAG;gBACzBiB,QAAQ,MAAME,QAAQF,UAAUrC;gBAChCyC,aAAaJ;YACf;QACF;QACA,MAAMI,eAAe,IAAIzD,MAAeiC;QACxC,OAAOwB;IACT;AACF;AAOO,MAAMxD,OAAO,CAAgCwB;IAClD,OAAO,IAAIR,QAAQ,CAAC8B,UAAYtB,MAAMxB,IAAI,CAAC,CAAC,GAAGe,OAAS+B,QAAQ/B;AAClE;AAQO,MAAMd,cAAc;IACzB,OAAO,IAAIF;AACb;MAEA,WAAeE"}
package/build/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;
1
+ export type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;
2
2
  export interface Unsubscribe {
3
3
  (): void;
4
4
  }
5
- export interface Listener<T extends unknown[], R> {
5
+ export interface Listener<T extends unknown[], R = unknown> {
6
6
  (...args: T): MaybePromise<R | void>;
7
7
  }
8
8
  export interface Dispose {
@@ -11,22 +11,31 @@ 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> {
14
+ export interface Mapper<T extends unknown[], R = unknown> {
15
15
  (...args: T): R;
16
16
  }
17
- export interface Reducer<T extends unknown[], R> {
17
+ export interface Reducer<T extends unknown[], R = unknown> {
18
18
  (value: R, ...args: T): R;
19
19
  }
20
- export type Listeners<T extends unknown[], R> = Listener<T, R>[];
21
- declare class FunctionExt extends Function {
20
+ export type Listeners<T extends unknown[], R = unknown> = Listener<T, R>[];
21
+ /**
22
+ * An abstract class that extends the built-in Function class. It allows instances of the class
23
+ * to be called as functions. When an instance of FunctionExt is called as a function, it will
24
+ * call the function passed to its constructor with the same arguments.
25
+ * @internal
26
+ */
27
+ export declare abstract class FunctionExt extends Function {
22
28
  constructor(func: Function);
23
29
  }
24
30
  export interface Dismiss {
25
31
  (): Promise<void> | void;
26
32
  }
33
+ export interface Task {
34
+ (): MaybePromise<unknown>;
35
+ }
27
36
  export declare class Dismiss extends FunctionExt {
28
- constructor(dismiss: Unsubscribe);
29
- after(process: () => MaybePromise<unknown>): Promise<void>;
37
+ constructor(callback: Unsubscribe);
38
+ after(task: Task): Promise<void>;
30
39
  afterTimes(count: number): () => void;
31
40
  }
32
41
  export interface Event<T extends unknown[], R> {
@@ -40,24 +49,128 @@ type UnpackAllParameters<T extends Event<unknown[], unknown>[]> = {
40
49
  type UnpackAllReturn<T extends Event<unknown[], unknown>[]> = {
41
50
  [K in keyof T]: UnpackReturn<T[K]>;
42
51
  }[number];
52
+ /**
53
+ * A class representing an anonymous event that can be listened to or triggered.
54
+ * @example
55
+ * // Create a click event.
56
+ * const clickEvent = new Event<[x: number, y: number], void>();
57
+ *
58
+ * @template T - The tuple of arguments that the event takes.
59
+ * @template R - The return type of the event.
60
+ */
43
61
  export declare class Event<T extends unknown[], R = void> extends FunctionExt {
62
+ /**
63
+ * Merges multiple events into a single event.
64
+ * @param events - The events to merge.
65
+ * @returns The merged event.
66
+ */
44
67
  static merge<Events extends Event<any[], any>[]>(...events: Events): Event<UnpackAllParameters<Events>, UnpackAllReturn<Events>>;
68
+ /**
69
+ * Creates an event that triggers at a specified interval.
70
+ * @param interval - The interval at which to trigger the event.
71
+ * @returns The interval event.
72
+ */
45
73
  static interval(interval: number): Event<[number], void>;
74
+ /**
75
+ * The array of listeners for the event.
76
+ */
46
77
  private listeners;
78
+ /**
79
+ * A function that disposes of the event and its listeners.
80
+ */
47
81
  readonly dispose: Dispose;
82
+ /**
83
+ * Creates a new event.
84
+ * @param dispose - A function to dispose of the event and its listeners.
85
+ */
48
86
  constructor(dispose?: Dispose);
87
+ /**
88
+ * The number of listeners for the event.
89
+ */
49
90
  get size(): number;
91
+ /**
92
+ * Checks if a listener is not registered for the event.
93
+ * @param listener - The listener to check.
94
+ * @returns `true` if the listener is not registered, `false` otherwise.
95
+ */
50
96
  lacks(listener: Listener<T, R>): boolean;
97
+ /**
98
+ * Checks if a listener is registered for the event.
99
+ * @param listener - The listener to check.
100
+ * @returns `true` if the listener is registered, `false` otherwise.
101
+ */
51
102
  has(listener: Listener<T, R>): boolean;
103
+ /**
104
+ * Removes a listener from the event.
105
+ * @param listener - The listener to remove.
106
+ */
52
107
  off(listener: Listener<T, R>): void;
108
+ /**
109
+ * Adds a listener to the event.
110
+ * @param listener - The listener to add.
111
+ * @returns An object that can be used to remove the listener.
112
+ */
53
113
  on(listener: Listener<T, R>): Dismiss;
114
+ /**
115
+ * Adds a listener to the event that will only be called once.
116
+ * @param listener - The listener to add.
117
+ * @returns An object that can be used to remove the listener.
118
+ */
54
119
  once(listener: Listener<T, R>): Dismiss;
120
+ /**
121
+ * Removes all listeners from the event.
122
+ */
55
123
  clear(): void;
124
+ /**
125
+ * Converts the event to a promise that resolves with the event arguments.
126
+ * @returns A promise that resolves with the event arguments.
127
+ */
56
128
  toPromise(): Promise<T>;
129
+ /**
130
+ * Creates a new event that only triggers if the filter function returns `true`.
131
+ * @param filter - The filter function.
132
+ * @returns The filtered event.
133
+ */
57
134
  filter(filter: Filter<T>): Event<T, R>;
58
- map<R>(mapper: Mapper<T, R>): Event<unknown[], void>;
59
- reduce<R>(reducer: Reducer<T, R>, init: R): Event<unknown[], void>;
135
+ /**
136
+ * Creates a new event that only triggers once if the filter function returns `true`.
137
+ * @param filter - The filter function.
138
+ * @returns The filtered event.
139
+ */
140
+ first(filter: Filter<T>): Event<T, R>;
141
+ /**
142
+ * Creates a new event that maps the event arguments to a new value.
143
+ * @param mapper - The mapper function.
144
+ * @returns The mapped event.
145
+ */
146
+ map<M, MR = unknown>(mapper: Mapper<T, M>): Event<[M], MR>;
147
+ /**
148
+ * Creates a new event that reduces the event arguments to a single value.
149
+ * @param reducer - The reducer function.
150
+ * @param init - The initial value for the reducer.
151
+ * @returns The reduced event.
152
+ */
153
+ reduce<A, AR = unknown>(reducer: Reducer<T, A>, init: A): Event<[A], AR>;
60
154
  }
155
+ /**
156
+ * Returns a promise that resolves with the arguments passed to the first invocation of the given event.
157
+ * @param event The event to listen for.
158
+ * @returns A promise that resolves with the arguments passed to the first invocation of the given event.
159
+ */
61
160
  export declare const once: <T extends unknown[], R = void>(event: Event<T, R>) => Promise<T>;
62
- export default function createEvent<T extends unknown[], R = void>(): Event<T, R>;
63
- export {};
161
+ /**
162
+ * Creates a new instance of the Event class.
163
+ * @returns {Event<T, R>} A new instance of the Event class.
164
+ * @template T The type of the arguments passed to the event.
165
+ * @template R The return type of the event.
166
+ */
167
+ export declare const createEvent: <T extends unknown[], R = void>() => Event<T, R>;
168
+ export default createEvent;
169
+ /**
170
+ * A type helper that extracts the event listener type
171
+ *
172
+ * @template E - The event object type.
173
+ * @template T - The event type extracted from the event object.
174
+ * @template R - The result type returned by the event handler function.
175
+ */
176
+ export type EventHandler<E> = E extends Event<infer T, infer R> ? Listener<T, R> : never;
package/build/index.js CHANGED
@@ -1,15 +1,15 @@
1
- class FunctionExt extends Function {
1
+ export class FunctionExt extends Function {
2
2
  constructor(func){
3
3
  super();
4
4
  return Object.setPrototypeOf(func, new.target.prototype);
5
5
  }
6
6
  }
7
7
  export class Dismiss extends FunctionExt {
8
- constructor(dismiss){
9
- super(dismiss);
8
+ constructor(callback){
9
+ super(callback);
10
10
  }
11
- async after(process) {
12
- await process();
11
+ async after(task) {
12
+ await task();
13
13
  this();
14
14
  }
15
15
  afterTimes(count) {
@@ -89,6 +89,16 @@ export class Event extends FunctionExt {
89
89
  const filteredEvent = new Event(dispose);
90
90
  return filteredEvent;
91
91
  }
92
+ first(filter) {
93
+ const dispose = this.on(async (...args)=>{
94
+ if (filteredEvent.size > 0 && await filter(...args)) {
95
+ dispose();
96
+ await filteredEvent(...args);
97
+ }
98
+ });
99
+ const filteredEvent = new Event(dispose);
100
+ return filteredEvent;
101
+ }
92
102
  map(mapper) {
93
103
  const dispose = this.on(async (...args)=>{
94
104
  if (mappedEvent.size > 0) {
@@ -114,8 +124,9 @@ export class Event extends FunctionExt {
114
124
  export const once = (event)=>{
115
125
  return new Promise((resolve)=>event.once((...args)=>resolve(args)));
116
126
  };
117
- export default function createEvent() {
127
+ export const createEvent = ()=>{
118
128
  return new Event();
119
- }
129
+ };
130
+ export default createEvent;
120
131
 
121
132
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;\n\nexport interface Unsubscribe {\n (): void;\n}\n\nexport interface Listener<T extends unknown[], R> {\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): R;\n}\n\nexport interface Reducer<T extends unknown[], R> {\n (value: R, ...args: T): R;\n}\n\nexport type Listeners<T extends unknown[], R> = Listener<T, R>[];\n\nclass 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 class Dismiss extends FunctionExt {\n constructor(dismiss: Unsubscribe) {\n super(dismiss);\n }\n async after(process: () => MaybePromise<unknown>) {\n await process();\n this();\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;\ntype UnpackReturn<T> = T extends Event<unknown[], infer R> ? R : never;\ntype UnpackAllParameters<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: UnpackParameters<T[K]> }[number];\ntype UnpackAllReturn<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: UnpackReturn<T[K]> }[number];\n\nexport class Event<T extends unknown[], R = void> extends FunctionExt {\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 static interval(interval: number) {\n let counter = 0;\n const intervalEvent = new Event<[number], void>(() => clearInterval(timerId));\n const timerId: NodeJS.Timeout = setInterval(() => intervalEvent(counter++), interval);\n return intervalEvent;\n }\n\n private listeners: Listeners<T, R>;\n readonly dispose: Dispose;\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 get size(): number {\n return this.listeners.length;\n }\n\n lacks(listener: Listener<T, R>): boolean {\n return this.listeners.indexOf(listener) === -1;\n }\n\n has(listener: Listener<T, R>): boolean {\n return this.listeners.indexOf(listener) !== -1;\n }\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 on(listener: Listener<T, R>): Dismiss {\n this.listeners.push(listener);\n return new Dismiss(() => this.off(listener));\n }\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 clear() {\n this.listeners.splice(0);\n }\n\n toPromise(): Promise<T> {\n return new Promise((resolve) => this.once((...args) => resolve(args)));\n }\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 map<R>(mapper: Mapper<T, R>) {\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(dispose);\n return mappedEvent;\n }\n\n reduce<R>(reducer: Reducer<T, R>, init: R) {\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(dispose);\n return reducedEvent;\n }\n}\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\nexport default function createEvent<T extends unknown[], R = void>() {\n return new Event<T, R>();\n}\n"],"names":["FunctionExt","Function","constructor","func","Object","setPrototypeOf","prototype","Dismiss","dismiss","after","process","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","mapper","mappedEvent","value","reduce","reducer","init","reducedEvent","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 = 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\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 * @example\n * // Create a click event.\n * const clickEvent = new Event<[x: number, y: number], void>();\n *\n * @template T - The tuple of arguments that the event takes.\n * @template 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 * @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 * @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: NodeJS.Timeout = 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 * @param dispose - A function to dispose of the event and its listeners.\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 * Converts the event to a promise that resolves with the event arguments.\n * @returns A promise that resolves with the event arguments.\n */\n toPromise(): Promise<T> {\n return new Promise((resolve) => this.once((...args) => resolve(args)));\n }\n\n /**\n * Creates a new event that only triggers if the filter function returns `true`.\n * @param filter - The filter function.\n * @returns The filtered event.\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 * Creates a new event that only triggers once if the filter function returns `true`.\n * @param filter - The filter function.\n * @returns The filtered event.\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 * Creates a new event that maps the event arguments to a new value.\n * @param mapper - The mapper function.\n * @returns The mapped event.\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 * Creates a new event that reduces the event arguments to a single value.\n * @param reducer - The reducer function.\n * @param init - The initial value for the reducer.\n * @returns The reduced event.\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/**\n * Returns a promise that resolves with the arguments passed to the first invocation of the given event.\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 instance of the Event class.\n * @returns {Event<T, R>} A new instance of the Event class.\n * @template T The type of the arguments passed to the event.\n * @template R The return type of the event.\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 * @template E - The event object type.\n * @template T - The event type extracted from the event object.\n * @template 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","createEvent"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "evnty",
3
3
  "description": "0-Deps, simple, fast, for browser and node js anonymous event library",
4
- "version": "1.2.5",
4
+ "version": "1.3.1",
5
5
  "type": "module",
6
6
  "types": "build/index.d.ts",
7
7
  "main": "build/index.cjs",
@@ -32,8 +32,11 @@
32
32
  "events",
33
33
  "emit",
34
34
  "emitter",
35
- "anonymous"
35
+ "anonymous",
36
+ "flow",
37
+ "event-driven"
36
38
  ],
39
+ "runkitExampleFilename": "src/__tests__/example.js",
37
40
  "funding": "https://github.com/sponsors/3axap4eHko",
38
41
  "author": {
39
42
  "name": "Ivan Zakharchanka",
package/src/index.ts CHANGED
@@ -1,10 +1,10 @@
1
- type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;
1
+ export type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;
2
2
 
3
3
  export interface Unsubscribe {
4
4
  (): void;
5
5
  }
6
6
 
7
- export interface Listener<T extends unknown[], R> {
7
+ export interface Listener<T extends unknown[], R = unknown> {
8
8
  (...args: T): MaybePromise<R | void>;
9
9
  }
10
10
 
@@ -16,17 +16,23 @@ export interface Filter<T extends unknown[]> {
16
16
  (...args: T): MaybePromise<boolean>;
17
17
  }
18
18
 
19
- export interface Mapper<T extends unknown[], R> {
19
+ export interface Mapper<T extends unknown[], R = unknown> {
20
20
  (...args: T): R;
21
21
  }
22
22
 
23
- export interface Reducer<T extends unknown[], R> {
23
+ export interface Reducer<T extends unknown[], R = unknown> {
24
24
  (value: R, ...args: T): R;
25
25
  }
26
26
 
27
- export type Listeners<T extends unknown[], R> = Listener<T, R>[];
27
+ export type Listeners<T extends unknown[], R = unknown> = Listener<T, R>[];
28
28
 
29
- class FunctionExt extends Function {
29
+ /**
30
+ * An abstract class that extends the built-in Function class. It allows instances of the class
31
+ * to be called as functions. When an instance of FunctionExt is called as a function, it will
32
+ * call the function passed to its constructor with the same arguments.
33
+ * @internal
34
+ */
35
+ export abstract class FunctionExt extends Function {
30
36
  constructor(func: Function) {
31
37
  super();
32
38
  return Object.setPrototypeOf(func, new.target.prototype);
@@ -37,14 +43,20 @@ export interface Dismiss {
37
43
  (): Promise<void> | void;
38
44
  }
39
45
 
46
+ export interface Task {
47
+ (): MaybePromise<unknown>;
48
+ }
49
+
40
50
  export class Dismiss extends FunctionExt {
41
- constructor(dismiss: Unsubscribe) {
42
- super(dismiss);
51
+ constructor(callback: Unsubscribe) {
52
+ super(callback);
43
53
  }
44
- async after(process: () => MaybePromise<unknown>) {
45
- await process();
54
+
55
+ async after(task: Task) {
56
+ await task();
46
57
  this();
47
58
  }
59
+
48
60
  afterTimes(count: number) {
49
61
  return () => {
50
62
  if (!--count) {
@@ -63,17 +75,39 @@ export interface Event<T extends unknown[], R> {
63
75
  }
64
76
 
65
77
  type UnpackParameters<T> = T extends Event<infer P, unknown> ? P : never;
78
+
66
79
  type UnpackReturn<T> = T extends Event<unknown[], infer R> ? R : never;
80
+
67
81
  type UnpackAllParameters<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: UnpackParameters<T[K]> }[number];
82
+
68
83
  type UnpackAllReturn<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: UnpackReturn<T[K]> }[number];
69
84
 
85
+ /**
86
+ * A class representing an anonymous event that can be listened to or triggered.
87
+ * @example
88
+ * // Create a click event.
89
+ * const clickEvent = new Event<[x: number, y: number], void>();
90
+ *
91
+ * @template T - The tuple of arguments that the event takes.
92
+ * @template R - The return type of the event.
93
+ */
70
94
  export class Event<T extends unknown[], R = void> extends FunctionExt {
95
+ /**
96
+ * Merges multiple events into a single event.
97
+ * @param events - The events to merge.
98
+ * @returns The merged event.
99
+ */
71
100
  static merge<Events extends Event<any[], any>[]>(...events: Events) {
72
101
  const mergedEvent = new Event<UnpackAllParameters<Events>, UnpackAllReturn<Events>>();
73
102
  events.forEach((event) => event.on(mergedEvent));
74
103
  return mergedEvent;
75
104
  }
76
105
 
106
+ /**
107
+ * Creates an event that triggers at a specified interval.
108
+ * @param interval - The interval at which to trigger the event.
109
+ * @returns The interval event.
110
+ */
77
111
  static interval(interval: number) {
78
112
  let counter = 0;
79
113
  const intervalEvent = new Event<[number], void>(() => clearInterval(timerId));
@@ -81,9 +115,20 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
81
115
  return intervalEvent;
82
116
  }
83
117
 
118
+ /**
119
+ * The array of listeners for the event.
120
+ */
84
121
  private listeners: Listeners<T, R>;
122
+
123
+ /**
124
+ * A function that disposes of the event and its listeners.
125
+ */
85
126
  readonly dispose: Dispose;
86
127
 
128
+ /**
129
+ * Creates a new event.
130
+ * @param dispose - A function to dispose of the event and its listeners.
131
+ */
87
132
  constructor(dispose?: Dispose) {
88
133
  const listeners: Listeners<T, R> = [];
89
134
  const fn = (...args: T) => eventEmitter(listeners, ...args);
@@ -96,18 +141,35 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
96
141
  };
97
142
  }
98
143
 
144
+ /**
145
+ * The number of listeners for the event.
146
+ */
99
147
  get size(): number {
100
148
  return this.listeners.length;
101
149
  }
102
150
 
151
+ /**
152
+ * Checks if a listener is not registered for the event.
153
+ * @param listener - The listener to check.
154
+ * @returns `true` if the listener is not registered, `false` otherwise.
155
+ */
103
156
  lacks(listener: Listener<T, R>): boolean {
104
157
  return this.listeners.indexOf(listener) === -1;
105
158
  }
106
159
 
160
+ /**
161
+ * Checks if a listener is registered for the event.
162
+ * @param listener - The listener to check.
163
+ * @returns `true` if the listener is registered, `false` otherwise.
164
+ */
107
165
  has(listener: Listener<T, R>): boolean {
108
166
  return this.listeners.indexOf(listener) !== -1;
109
167
  }
110
168
 
169
+ /**
170
+ * Removes a listener from the event.
171
+ * @param listener - The listener to remove.
172
+ */
111
173
  off(listener: Listener<T, R>): void {
112
174
  let index = this.listeners.indexOf(listener);
113
175
  while (~index) {
@@ -116,11 +178,21 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
116
178
  }
117
179
  }
118
180
 
181
+ /**
182
+ * Adds a listener to the event.
183
+ * @param listener - The listener to add.
184
+ * @returns An object that can be used to remove the listener.
185
+ */
119
186
  on(listener: Listener<T, R>): Dismiss {
120
187
  this.listeners.push(listener);
121
188
  return new Dismiss(() => this.off(listener));
122
189
  }
123
190
 
191
+ /**
192
+ * Adds a listener to the event that will only be called once.
193
+ * @param listener - The listener to add.
194
+ * @returns An object that can be used to remove the listener.
195
+ */
124
196
  once(listener: Listener<T, R>): Dismiss {
125
197
  const oneTimeListener = (...args: T) => {
126
198
  this.off(oneTimeListener);
@@ -129,14 +201,26 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
129
201
  return this.on(oneTimeListener);
130
202
  }
131
203
 
204
+ /**
205
+ * Removes all listeners from the event.
206
+ */
132
207
  clear() {
133
208
  this.listeners.splice(0);
134
209
  }
135
210
 
211
+ /**
212
+ * Converts the event to a promise that resolves with the event arguments.
213
+ * @returns A promise that resolves with the event arguments.
214
+ */
136
215
  toPromise(): Promise<T> {
137
216
  return new Promise((resolve) => this.once((...args) => resolve(args)));
138
217
  }
139
218
 
219
+ /**
220
+ * Creates a new event that only triggers if the filter function returns `true`.
221
+ * @param filter - The filter function.
222
+ * @returns The filtered event.
223
+ */
140
224
  filter(filter: Filter<T>) {
141
225
  const dispose = this.on(async (...args) => {
142
226
  if (filteredEvent.size > 0 && (await filter(...args))) {
@@ -147,18 +231,45 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
147
231
  return filteredEvent;
148
232
  }
149
233
 
150
- map<R>(mapper: Mapper<T, R>) {
234
+ /**
235
+ * Creates a new event that only triggers once if the filter function returns `true`.
236
+ * @param filter - The filter function.
237
+ * @returns The filtered event.
238
+ */
239
+ first(filter: Filter<T>) {
240
+ const dispose = this.on(async (...args) => {
241
+ if (filteredEvent.size > 0 && (await filter(...args))) {
242
+ dispose();
243
+ await filteredEvent(...args);
244
+ }
245
+ });
246
+ const filteredEvent = new Event<T, R>(dispose);
247
+ return filteredEvent;
248
+ }
249
+
250
+ /**
251
+ * Creates a new event that maps the event arguments to a new value.
252
+ * @param mapper - The mapper function.
253
+ * @returns The mapped event.
254
+ */
255
+ map<M, MR = unknown>(mapper: Mapper<T, M>) {
151
256
  const dispose = this.on(async (...args) => {
152
257
  if (mappedEvent.size > 0) {
153
258
  const value = await mapper(...args);
154
259
  mappedEvent(value);
155
260
  }
156
261
  });
157
- const mappedEvent = new Event(dispose);
262
+ const mappedEvent = new Event<[M], MR>(dispose);
158
263
  return mappedEvent;
159
264
  }
160
265
 
161
- reduce<R>(reducer: Reducer<T, R>, init: R) {
266
+ /**
267
+ * Creates a new event that reduces the event arguments to a single value.
268
+ * @param reducer - The reducer function.
269
+ * @param init - The initial value for the reducer.
270
+ * @returns The reduced event.
271
+ */
272
+ reduce<A, AR = unknown>(reducer: Reducer<T, A>, init: A) {
162
273
  let value = init;
163
274
  const dispose = this.on(async (...args) => {
164
275
  if (reducedEvent.size > 0) {
@@ -166,15 +277,37 @@ export class Event<T extends unknown[], R = void> extends FunctionExt {
166
277
  reducedEvent(value);
167
278
  }
168
279
  });
169
- const reducedEvent = new Event(dispose);
280
+ const reducedEvent = new Event<[A], AR>(dispose);
170
281
  return reducedEvent;
171
282
  }
172
283
  }
173
284
 
285
+ /**
286
+ * Returns a promise that resolves with the arguments passed to the first invocation of the given event.
287
+ * @param event The event to listen for.
288
+ * @returns A promise that resolves with the arguments passed to the first invocation of the given event.
289
+ */
174
290
  export const once = <T extends unknown[], R = void>(event: Event<T, R>): Promise<T> => {
175
291
  return new Promise((resolve) => event.once((...args) => resolve(args)));
176
292
  };
177
293
 
178
- export default function createEvent<T extends unknown[], R = void>() {
294
+ /**
295
+ * Creates a new instance of the Event class.
296
+ * @returns {Event<T, R>} A new instance of the Event class.
297
+ * @template T The type of the arguments passed to the event.
298
+ * @template R The return type of the event.
299
+ */
300
+ export const createEvent = <T extends unknown[], R = void>(): Event<T, R> => {
179
301
  return new Event<T, R>();
180
- }
302
+ };
303
+
304
+ export default createEvent;
305
+
306
+ /**
307
+ * A type helper that extracts the event listener type
308
+ *
309
+ * @template E - The event object type.
310
+ * @template T - The event type extracted from the event object.
311
+ * @template R - The result type returned by the event handler function.
312
+ */
313
+ export type EventHandler<E> = E extends Event<infer T, infer R> ? Listener<T, R> : never;