@homer0/events-hub 2.0.1 → 2.0.3

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
@@ -121,7 +121,7 @@ console.log(newUsersList);
121
121
 
122
122
  As this project is part of the `packages` monorepo, some of the tooling, like ESLint and Husky, are installed on the root's `package.json`.
123
123
 
124
- #### NPM tasks
124
+ #### Tasks
125
125
 
126
126
  | Task | Description |
127
127
  | ------- | -------------------- |
package/dist/esm/index.js CHANGED
@@ -8,15 +8,45 @@ var __publicField = (obj, key, value) => {
8
8
  // src/index.ts
9
9
  var EventsHub = class {
10
10
  constructor() {
11
+ /**
12
+ * A dictionary of the events and their listeners.
13
+ */
11
14
  __publicField(this, "events", {});
15
+ /**
16
+ * A dictionary of wrappers that were created for "one time subscriptions". This is
17
+ * used by the {@link EventsHub.off}: if it doesn't find the subscriber as it is, it
18
+ * will look for a wrapper and remove it.
19
+ */
12
20
  __publicField(this, "onceWrappers", {});
13
21
  }
22
+ /**
23
+ * Gets all the listeners for a specific event.
24
+ * The list is returned by reference, so it can be modified once obtained.
25
+ *
26
+ * @param event The name of the event.
27
+ */
14
28
  getSubscribers(event) {
15
29
  if (!this.events[event]) {
16
30
  this.events[event] = [];
17
31
  }
18
32
  return this.events[event];
19
33
  }
34
+ /**
35
+ * Adds a new event listener.
36
+ *
37
+ * @param event An event name or a list of them.
38
+ * @param listener The listener function.
39
+ * @returns An unsubscribe function to remove the listene(s).
40
+ * @template ListenerFn The type of the listener function.
41
+ * @example
42
+ *
43
+ * const events = new EventsHub();
44
+ * type Listener = (arg0: string) => void;
45
+ * const unsubscribe = events.on<Listener>('event', (arg0) => {
46
+ * console.log(`Event received: ${arg0}`);
47
+ * });
48
+ *
49
+ */
20
50
  on(event, listener) {
21
51
  const events = Array.isArray(event) ? event : [event];
22
52
  events.forEach((name) => {
@@ -27,6 +57,22 @@ var EventsHub = class {
27
57
  });
28
58
  return () => this.off(event, listener);
29
59
  }
60
+ /**
61
+ * Adds an event listener that will only be executed once.
62
+ *
63
+ * @param event An event name or a list of them.
64
+ * @param listener The listener function.
65
+ * @returns An unsubscribe function to remove the listener(s).
66
+ * @template ListenerFn The type of the listener function.
67
+ * @example
68
+ *
69
+ * const events = new EventsHub();
70
+ * type Listener = (arg0: string) => void;
71
+ * const unsubscribe = events.once<Listener>('event', (arg0) => {
72
+ * console.log(`Event received: ${arg0}`);
73
+ * });
74
+ *
75
+ */
30
76
  once(event, listener) {
31
77
  const events = Array.isArray(event) ? event : [event];
32
78
  let wrapper = events.reduce((acc, name) => {
@@ -56,6 +102,25 @@ var EventsHub = class {
56
102
  }
57
103
  return this.on(event, wrapper);
58
104
  }
105
+ /**
106
+ * Removes an event listener.
107
+ *
108
+ * @param event An event name or a list of them.
109
+ * @param listener The listener function.
110
+ * @returns If `event` was a `string`, it will return whether or not the listener was
111
+ * found and removed; but if `event`
112
+ * was an `Array`, it will return a list of boolean values.
113
+ * @template ListenerFn The type of the listener function.
114
+ * @example
115
+ *
116
+ * const events = new EventsHub();
117
+ * const listener = (arg0) => {
118
+ * console.log(`Event received: ${arg0}`);
119
+ * };
120
+ * events.on('event', listener); // subscribe.
121
+ * events.off('event', listener); // manually unsubscribe.
122
+ *
123
+ */
59
124
  off(event, listener) {
60
125
  const isArray = Array.isArray(event);
61
126
  const events = isArray ? event : [event];
@@ -86,6 +151,21 @@ var EventsHub = class {
86
151
  });
87
152
  return isArray ? result : result[0];
88
153
  }
154
+ /**
155
+ * Emits an event and call all its listeners.
156
+ *
157
+ * @param event An event name or a list of them.
158
+ * @param args A list of parameters to send to the listeners.
159
+ * @template Args The type of the parameters to send to the listeners.
160
+ * @example
161
+ *
162
+ * const events = new EventsHub();
163
+ * events.on('event', (arg0) => {
164
+ * console.log(`Event received: ${arg0}`);
165
+ * });
166
+ * events.emit('event', 'Hello'); // prints "Event received: Hello"
167
+ *
168
+ */
89
169
  emit(event, ...args) {
90
170
  const toClean = [];
91
171
  const events = Array.isArray(event) ? event : [event];
@@ -102,6 +182,28 @@ var EventsHub = class {
102
182
  });
103
183
  toClean.forEach((info) => this.off(info.event, info.listener));
104
184
  }
185
+ /**
186
+ * Asynchronously reduces a target using an event. It's like emit, but the events
187
+ * listener return a modified (or not) version of the `target`.
188
+ *
189
+ * @param event An event name or a list of them.
190
+ * @param target The variable to reduce with the reducers/listeners.
191
+ * @param args A list of parameters to send to the reducers/listeners.
192
+ * @returns A version of the `target` processed by the listeners.
193
+ * @template Target The type of the target.
194
+ * @template Args The type of the parameters to send to the reducers/listeners.
195
+ * @example
196
+ *
197
+ * const events = new EventsHub();
198
+ * events.on('event', async (target, arg0) => {
199
+ * const data = await fetch(`https://api.example.com/${arg0}`);
200
+ * target.push(data);
201
+ * return target;
202
+ * });
203
+ * const result = await events.reduce('event', [], 'Hello');
204
+ * // result would be a list of data fetched from the API.
205
+ *
206
+ */
105
207
  async reduce(event, target, ...args) {
106
208
  const events = Array.isArray(event) ? event : [event];
107
209
  const toClean = [];
@@ -135,6 +237,26 @@ var EventsHub = class {
135
237
  toClean.forEach((info) => this.off(info.event, info.listener));
136
238
  return result;
137
239
  }
240
+ /**
241
+ * Synchronously reduces a target using an event. It's like emit, but the events
242
+ * listener return a modified (or not) version of the `target`.
243
+ *
244
+ * @param event An event name or a list of them.
245
+ * @param target The variable to reduce with the reducers/listeners.
246
+ * @param args A list of parameters to send to the reducers/listeners.
247
+ * @returns A version of the `target` processed by the listeners.
248
+ * @template Target The type of the target.
249
+ * @template Args The type of the parameters to send to the reducers/listeners.
250
+ * @example
251
+ *
252
+ * const events = new EventsHub();
253
+ * events.on('event', (target, arg0) => {
254
+ * target.push(arg0);
255
+ * return target;
256
+ * });
257
+ * events.reduce('event', [], 'Hello'); // returns ['Hello']
258
+ *
259
+ */
138
260
  reduceSync(event, target, ...args) {
139
261
  const events = Array.isArray(event) ? event : [event];
140
262
  const toClean = [];
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/no-explicit-any -- It's a generic function.\ntype GenericFn = (...args: any[]) => any;\ntype GenericParams = Parameters<GenericFn>;\ntype OnceWrapperFn = GenericFn & {\n once: boolean;\n};\n/**\n * When the service receives a \"once subscription\", it needs to track the listener so it\n * gets removed after being called once, and to avoid modifying the original function, it\n * creates a wrapper function that has the \"once\" property set to true. The wrapper and\n * the original function are stored in case `off` is called before the wrapper gets\n * triggered; it will receive the original function, not the wrapper, so the class needs a\n * way to map them together.\n */\ntype OnceWrapper = {\n /**\n * A simple wrapper for the original listener, with the difference that it has a `once`\n * property set to `true`.\n */\n wrapper: OnceWrapperFn;\n /**\n * The original listener that will be called once.\n */\n original: GenericFn;\n};\n/**\n * A minimal implementation of an events handler service.\n */\nexport class EventsHub {\n /**\n * A dictionary of the events and their listeners.\n */\n protected events: Record<string, GenericFn[]> = {};\n /**\n * A dictionary of wrappers that were created for \"one time subscriptions\". This is\n * used by the {@link EventsHub.off}: if it doesn't find the subscriber as it is, it\n * will look for a wrapper and remove it.\n */\n protected onceWrappers: Record<string, OnceWrapper[]> = {};\n /**\n * Gets all the listeners for a specific event.\n * The list is returned by reference, so it can be modified once obtained.\n *\n * @param event The name of the event.\n */\n protected getSubscribers(event: string): (GenericFn | OnceWrapperFn)[] {\n if (!this.events[event]) {\n this.events[event] = [];\n }\n\n return this.events[event]!;\n }\n on<ListenerFn extends GenericFn = GenericFn>(\n event: string,\n listener: ListenerFn,\n ): () => boolean;\n on<ListenerFn extends GenericFn = GenericFn>(\n event: string[],\n listener: ListenerFn,\n ): () => boolean[];\n on<ListenerFn extends GenericFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): () => boolean | boolean[];\n /**\n * Adds a new event listener.\n *\n * @param event An event name or a list of them.\n * @param listener The listener function.\n * @returns An unsubscribe function to remove the listene(s).\n * @template ListenerFn The type of the listener function.\n * @example\n *\n * const events = new EventsHub();\n * type Listener = (arg0: string) => void;\n * const unsubscribe = events.on<Listener>('event', (arg0) => {\n * console.log(`Event received: ${arg0}`);\n * });\n *\n */\n on<ListenerFn extends GenericFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): () => boolean | boolean[] {\n const events = Array.isArray(event) ? event : [event];\n events.forEach((name) => {\n const subscribers = this.getSubscribers(name);\n if (!subscribers.includes(listener)) {\n subscribers.push(listener);\n }\n });\n\n return () => this.off<ListenerFn>(event, listener);\n }\n once<ListenerFn extends GenericFn = GenericFn>(\n event: string,\n listener: ListenerFn,\n ): () => boolean;\n once<ListenerFn extends GenericFn = GenericFn>(\n event: string[],\n listener: ListenerFn,\n ): () => boolean[];\n once<ListenerFn extends GenericFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): () => boolean | boolean[];\n /**\n * Adds an event listener that will only be executed once.\n *\n * @param event An event name or a list of them.\n * @param listener The listener function.\n * @returns An unsubscribe function to remove the listener(s).\n * @template ListenerFn The type of the listener function.\n * @example\n *\n * const events = new EventsHub();\n * type Listener = (arg0: string) => void;\n * const unsubscribe = events.once<Listener>('event', (arg0) => {\n * console.log(`Event received: ${arg0}`);\n * });\n *\n */\n once<ListenerFn extends GenericFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): () => boolean | boolean[] {\n const events = Array.isArray(event) ? event : [event];\n // Try to find an existing wrapper.\n let wrapper = events.reduce<OnceWrapperFn | null>((acc, name) => {\n // A previous iteration found a wrapper, so `continue`.\n if (acc) return acc;\n\n // A list of wrappers exists for the event, so, let's try an find one for this function.\n const onceWrapper = this.onceWrappers[name];\n if (Array.isArray(onceWrapper)) {\n const existing = onceWrapper.find((item) => item.original === listener);\n if (existing) {\n return existing.wrapper;\n }\n\n return null;\n }\n\n // The list didn't even exists, let's at least create it.\n this.onceWrappers[name] = [];\n return null;\n }, null);\n\n if (!wrapper) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- It's a generic function.\n const newWrapper = (...args: any[]) => listener(...args);\n newWrapper.once = true;\n wrapper = newWrapper;\n events.forEach((name) => {\n this.onceWrappers[name]!.push({\n wrapper: wrapper!,\n original: listener,\n });\n });\n }\n\n return this.on(event, wrapper);\n }\n off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(\n event: string[],\n listener: ListenerFn,\n ): boolean[];\n off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(\n event: string,\n listener: ListenerFn,\n ): boolean;\n off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): boolean | boolean[];\n /**\n * Removes an event listener.\n *\n * @param event An event name or a list of them.\n * @param listener The listener function.\n * @returns If `event` was a `string`, it will return whether or not the listener was\n * found and removed; but if `event`\n * was an `Array`, it will return a list of boolean values.\n * @template ListenerFn The type of the listener function.\n * @example\n *\n * const events = new EventsHub();\n * const listener = (arg0) => {\n * console.log(`Event received: ${arg0}`);\n * };\n * events.on('event', listener); // subscribe.\n * events.off('event', listener); // manually unsubscribe.\n *\n */\n off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): boolean | boolean[] {\n const isArray = Array.isArray(event);\n const events = isArray ? event : [event];\n const result = events.map((name) => {\n const subscribers = this.getSubscribers(name);\n const onceSubscribers = this.onceWrappers[name];\n let found = false;\n let index = subscribers.indexOf(listener);\n if (index > -1) {\n found = true;\n /**\n * If the listener had the `once` flag, then it's a wrapper, so it needs to remove\n * it from the wrappers list too.\n */\n if ('once' in listener && onceSubscribers) {\n const wrapperIndex = onceSubscribers.findIndex(\n (item) => item.wrapper === listener,\n );\n onceSubscribers.splice(wrapperIndex, 1);\n }\n subscribers.splice(index, 1);\n } else if (onceSubscribers) {\n /**\n * If it couldn't found the subscriber, maybe it's because it's the original\n * listener of a wrapper.\n */\n index = onceSubscribers.findIndex((item) => item.original === listener);\n if (index > -1) {\n found = true;\n const originalIndex = subscribers.indexOf(onceSubscribers[index]!.original);\n subscribers.splice(originalIndex, 1);\n onceSubscribers.splice(index, 1);\n }\n }\n\n return found;\n });\n\n return isArray ? result : result[0]!;\n }\n /**\n * Emits an event and call all its listeners.\n *\n * @param event An event name or a list of them.\n * @param args A list of parameters to send to the listeners.\n * @template Args The type of the parameters to send to the listeners.\n * @example\n *\n * const events = new EventsHub();\n * events.on('event', (arg0) => {\n * console.log(`Event received: ${arg0}`);\n * });\n * events.emit('event', 'Hello'); // prints \"Event received: Hello\"\n *\n */\n emit<Args extends GenericParams>(event: string | string[], ...args: Args): void {\n const toClean: { event: string; listener: GenericFn }[] = [];\n const events = Array.isArray(event) ? event : [event];\n events.forEach((name) => {\n this.getSubscribers(name).forEach((subscriber) => {\n subscriber(...args);\n if ('once' in subscriber) {\n toClean.push({\n event: name,\n listener: subscriber,\n });\n }\n });\n });\n\n toClean.forEach((info) => this.off(info.event, info.listener));\n }\n /**\n * Asynchronously reduces a target using an event. It's like emit, but the events\n * listener return a modified (or not) version of the `target`.\n *\n * @param event An event name or a list of them.\n * @param target The variable to reduce with the reducers/listeners.\n * @param args A list of parameters to send to the reducers/listeners.\n * @returns A version of the `target` processed by the listeners.\n * @template Target The type of the target.\n * @template Args The type of the parameters to send to the reducers/listeners.\n * @example\n *\n * const events = new EventsHub();\n * events.on('event', async (target, arg0) => {\n * const data = await fetch(`https://api.example.com/${arg0}`);\n * target.push(data);\n * return target;\n * });\n * const result = await events.reduce('event', [], 'Hello');\n * // result would be a list of data fetched from the API.\n *\n */\n async reduce<Target, Args extends GenericParams>(\n event: string | string[],\n target: Target,\n ...args: Args\n ): Promise<Target> {\n const events = Array.isArray(event) ? event : [event];\n const toClean: { event: string; listener: GenericFn }[] = [];\n const result = await events.reduce<Promise<Target>>(\n (eventAcc, name) =>\n eventAcc.then((eventCurrent) => {\n const subscribers = this.getSubscribers(name);\n return subscribers.reduce(\n (subAcc, subscriber) =>\n subAcc.then((subCurrent) => {\n let useCurrent;\n if (Array.isArray(subCurrent)) {\n useCurrent = subCurrent.slice();\n } else if (typeof subCurrent === 'object') {\n useCurrent = { ...subCurrent };\n } else {\n useCurrent = subCurrent;\n }\n\n const nextStep = subscriber(...[useCurrent, ...args]);\n if ('once' in subscriber) {\n toClean.push({\n event: name,\n listener: subscriber,\n });\n }\n\n return nextStep;\n }),\n Promise.resolve(eventCurrent),\n );\n }),\n Promise.resolve(target),\n );\n\n toClean.forEach((info) => this.off(info.event, info.listener));\n\n return result;\n }\n /**\n * Synchronously reduces a target using an event. It's like emit, but the events\n * listener return a modified (or not) version of the `target`.\n *\n * @param event An event name or a list of them.\n * @param target The variable to reduce with the reducers/listeners.\n * @param args A list of parameters to send to the reducers/listeners.\n * @returns A version of the `target` processed by the listeners.\n * @template Target The type of the target.\n * @template Args The type of the parameters to send to the reducers/listeners.\n * @example\n *\n * const events = new EventsHub();\n * events.on('event', (target, arg0) => {\n * target.push(arg0);\n * return target;\n * });\n * events.reduce('event', [], 'Hello'); // returns ['Hello']\n *\n */\n reduceSync<Target, ReducerArgs extends GenericParams>(\n event: string | string[],\n target: Target,\n ...args: ReducerArgs\n ): Target {\n const events = Array.isArray(event) ? event : [event];\n const toClean: { event: string; listener: GenericFn }[] = [];\n const result = events.reduce((eventAcc, name) => {\n const subscribers = this.getSubscribers(name);\n return subscribers.reduce((subAcc, subscriber) => {\n let useCurrent;\n if (Array.isArray(subAcc)) {\n useCurrent = subAcc.slice();\n } else if (typeof subAcc === 'object') {\n useCurrent = { ...subAcc };\n } else {\n useCurrent = subAcc;\n }\n\n const nextStep = subscriber(...[useCurrent, ...args]);\n if ('once' in subscriber) {\n toClean.push({\n event: name,\n listener: subscriber,\n });\n }\n\n return nextStep;\n }, eventAcc);\n }, target);\n\n toClean.forEach((info) => this.off(info.event, info.listener));\n return result;\n }\n}\n/**\n * Shorthand for `new EventsHub()`.\n *\n * @returns A new instance of {@link EventsHub}.\n */\nexport const eventsHub = () => new EventsHub();\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/no-explicit-any -- It's a generic function.\ntype GenericFn = (...args: any[]) => any;\ntype GenericParams = Parameters<GenericFn>;\ntype OnceWrapperFn = GenericFn & {\n once: boolean;\n};\n/**\n * When the service receives a \"once subscription\", it needs to track the listener so it\n * gets removed after being called once, and to avoid modifying the original function, it\n * creates a wrapper function that has the \"once\" property set to true. The wrapper and\n * the original function are stored in case `off` is called before the wrapper gets\n * triggered; it will receive the original function, not the wrapper, so the class needs a\n * way to map them together.\n */\ntype OnceWrapper = {\n /**\n * A simple wrapper for the original listener, with the difference that it has a `once`\n * property set to `true`.\n */\n wrapper: OnceWrapperFn;\n /**\n * The original listener that will be called once.\n */\n original: GenericFn;\n};\n/**\n * A minimal implementation of an events handler service.\n */\nexport class EventsHub {\n /**\n * A dictionary of the events and their listeners.\n */\n protected events: Record<string, GenericFn[]> = {};\n /**\n * A dictionary of wrappers that were created for \"one time subscriptions\". This is\n * used by the {@link EventsHub.off}: if it doesn't find the subscriber as it is, it\n * will look for a wrapper and remove it.\n */\n protected onceWrappers: Record<string, OnceWrapper[]> = {};\n /**\n * Gets all the listeners for a specific event.\n * The list is returned by reference, so it can be modified once obtained.\n *\n * @param event The name of the event.\n */\n protected getSubscribers(event: string): (GenericFn | OnceWrapperFn)[] {\n if (!this.events[event]) {\n this.events[event] = [];\n }\n\n return this.events[event]!;\n }\n on<ListenerFn extends GenericFn = GenericFn>(\n event: string,\n listener: ListenerFn,\n ): () => boolean;\n on<ListenerFn extends GenericFn = GenericFn>(\n event: string[],\n listener: ListenerFn,\n ): () => boolean[];\n on<ListenerFn extends GenericFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): () => boolean | boolean[];\n /**\n * Adds a new event listener.\n *\n * @param event An event name or a list of them.\n * @param listener The listener function.\n * @returns An unsubscribe function to remove the listene(s).\n * @template ListenerFn The type of the listener function.\n * @example\n *\n * const events = new EventsHub();\n * type Listener = (arg0: string) => void;\n * const unsubscribe = events.on<Listener>('event', (arg0) => {\n * console.log(`Event received: ${arg0}`);\n * });\n *\n */\n on<ListenerFn extends GenericFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): () => boolean | boolean[] {\n const events = Array.isArray(event) ? event : [event];\n events.forEach((name) => {\n const subscribers = this.getSubscribers(name);\n if (!subscribers.includes(listener)) {\n subscribers.push(listener);\n }\n });\n\n return () => this.off<ListenerFn>(event, listener);\n }\n once<ListenerFn extends GenericFn = GenericFn>(\n event: string,\n listener: ListenerFn,\n ): () => boolean;\n once<ListenerFn extends GenericFn = GenericFn>(\n event: string[],\n listener: ListenerFn,\n ): () => boolean[];\n once<ListenerFn extends GenericFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): () => boolean | boolean[];\n /**\n * Adds an event listener that will only be executed once.\n *\n * @param event An event name or a list of them.\n * @param listener The listener function.\n * @returns An unsubscribe function to remove the listener(s).\n * @template ListenerFn The type of the listener function.\n * @example\n *\n * const events = new EventsHub();\n * type Listener = (arg0: string) => void;\n * const unsubscribe = events.once<Listener>('event', (arg0) => {\n * console.log(`Event received: ${arg0}`);\n * });\n *\n */\n once<ListenerFn extends GenericFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): () => boolean | boolean[] {\n const events = Array.isArray(event) ? event : [event];\n // Try to find an existing wrapper.\n let wrapper = events.reduce<OnceWrapperFn | null>((acc, name) => {\n // A previous iteration found a wrapper, so `continue`.\n if (acc) return acc;\n\n // A list of wrappers exists for the event, so, let's try an find one for this function.\n const onceWrapper = this.onceWrappers[name];\n if (Array.isArray(onceWrapper)) {\n const existing = onceWrapper.find((item) => item.original === listener);\n if (existing) {\n return existing.wrapper;\n }\n\n return null;\n }\n\n // The list didn't even exists, let's at least create it.\n this.onceWrappers[name] = [];\n return null;\n }, null);\n\n if (!wrapper) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- It's a generic function.\n const newWrapper = (...args: any[]) => listener(...args);\n newWrapper.once = true;\n wrapper = newWrapper;\n events.forEach((name) => {\n this.onceWrappers[name]!.push({\n wrapper: wrapper!,\n original: listener,\n });\n });\n }\n\n return this.on(event, wrapper);\n }\n off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(\n event: string[],\n listener: ListenerFn,\n ): boolean[];\n off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(\n event: string,\n listener: ListenerFn,\n ): boolean;\n off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): boolean | boolean[];\n /**\n * Removes an event listener.\n *\n * @param event An event name or a list of them.\n * @param listener The listener function.\n * @returns If `event` was a `string`, it will return whether or not the listener was\n * found and removed; but if `event`\n * was an `Array`, it will return a list of boolean values.\n * @template ListenerFn The type of the listener function.\n * @example\n *\n * const events = new EventsHub();\n * const listener = (arg0) => {\n * console.log(`Event received: ${arg0}`);\n * };\n * events.on('event', listener); // subscribe.\n * events.off('event', listener); // manually unsubscribe.\n *\n */\n off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): boolean | boolean[] {\n const isArray = Array.isArray(event);\n const events = isArray ? event : [event];\n const result = events.map((name) => {\n const subscribers = this.getSubscribers(name);\n const onceSubscribers = this.onceWrappers[name];\n let found = false;\n let index = subscribers.indexOf(listener);\n if (index > -1) {\n found = true;\n /**\n * If the listener had the `once` flag, then it's a wrapper, so it needs to remove\n * it from the wrappers list too.\n */\n if ('once' in listener && onceSubscribers) {\n const wrapperIndex = onceSubscribers.findIndex(\n (item) => item.wrapper === listener,\n );\n onceSubscribers.splice(wrapperIndex, 1);\n }\n subscribers.splice(index, 1);\n } else if (onceSubscribers) {\n /**\n * If it couldn't found the subscriber, maybe it's because it's the original\n * listener of a wrapper.\n */\n index = onceSubscribers.findIndex((item) => item.original === listener);\n if (index > -1) {\n found = true;\n const originalIndex = subscribers.indexOf(onceSubscribers[index]!.original);\n subscribers.splice(originalIndex, 1);\n onceSubscribers.splice(index, 1);\n }\n }\n\n return found;\n });\n\n return isArray ? result : result[0]!;\n }\n /**\n * Emits an event and call all its listeners.\n *\n * @param event An event name or a list of them.\n * @param args A list of parameters to send to the listeners.\n * @template Args The type of the parameters to send to the listeners.\n * @example\n *\n * const events = new EventsHub();\n * events.on('event', (arg0) => {\n * console.log(`Event received: ${arg0}`);\n * });\n * events.emit('event', 'Hello'); // prints \"Event received: Hello\"\n *\n */\n emit<Args extends GenericParams>(event: string | string[], ...args: Args): void {\n const toClean: { event: string; listener: GenericFn }[] = [];\n const events = Array.isArray(event) ? event : [event];\n events.forEach((name) => {\n this.getSubscribers(name).forEach((subscriber) => {\n subscriber(...args);\n if ('once' in subscriber) {\n toClean.push({\n event: name,\n listener: subscriber,\n });\n }\n });\n });\n\n toClean.forEach((info) => this.off(info.event, info.listener));\n }\n /**\n * Asynchronously reduces a target using an event. It's like emit, but the events\n * listener return a modified (or not) version of the `target`.\n *\n * @param event An event name or a list of them.\n * @param target The variable to reduce with the reducers/listeners.\n * @param args A list of parameters to send to the reducers/listeners.\n * @returns A version of the `target` processed by the listeners.\n * @template Target The type of the target.\n * @template Args The type of the parameters to send to the reducers/listeners.\n * @example\n *\n * const events = new EventsHub();\n * events.on('event', async (target, arg0) => {\n * const data = await fetch(`https://api.example.com/${arg0}`);\n * target.push(data);\n * return target;\n * });\n * const result = await events.reduce('event', [], 'Hello');\n * // result would be a list of data fetched from the API.\n *\n */\n async reduce<Target, Args extends GenericParams>(\n event: string | string[],\n target: Target,\n ...args: Args\n ): Promise<Target> {\n const events = Array.isArray(event) ? event : [event];\n const toClean: { event: string; listener: GenericFn }[] = [];\n const result = await events.reduce<Promise<Target>>(\n (eventAcc, name) =>\n eventAcc.then((eventCurrent) => {\n const subscribers = this.getSubscribers(name);\n return subscribers.reduce(\n (subAcc, subscriber) =>\n subAcc.then((subCurrent) => {\n let useCurrent;\n if (Array.isArray(subCurrent)) {\n useCurrent = subCurrent.slice();\n } else if (typeof subCurrent === 'object') {\n useCurrent = { ...subCurrent };\n } else {\n useCurrent = subCurrent;\n }\n\n const nextStep = subscriber(...[useCurrent, ...args]);\n if ('once' in subscriber) {\n toClean.push({\n event: name,\n listener: subscriber,\n });\n }\n\n return nextStep;\n }),\n Promise.resolve(eventCurrent),\n );\n }),\n Promise.resolve(target),\n );\n\n toClean.forEach((info) => this.off(info.event, info.listener));\n\n return result;\n }\n /**\n * Synchronously reduces a target using an event. It's like emit, but the events\n * listener return a modified (or not) version of the `target`.\n *\n * @param event An event name or a list of them.\n * @param target The variable to reduce with the reducers/listeners.\n * @param args A list of parameters to send to the reducers/listeners.\n * @returns A version of the `target` processed by the listeners.\n * @template Target The type of the target.\n * @template Args The type of the parameters to send to the reducers/listeners.\n * @example\n *\n * const events = new EventsHub();\n * events.on('event', (target, arg0) => {\n * target.push(arg0);\n * return target;\n * });\n * events.reduce('event', [], 'Hello'); // returns ['Hello']\n *\n */\n reduceSync<Target, ReducerArgs extends GenericParams>(\n event: string | string[],\n target: Target,\n ...args: ReducerArgs\n ): Target {\n const events = Array.isArray(event) ? event : [event];\n const toClean: { event: string; listener: GenericFn }[] = [];\n const result = events.reduce((eventAcc, name) => {\n const subscribers = this.getSubscribers(name);\n return subscribers.reduce((subAcc, subscriber) => {\n let useCurrent;\n if (Array.isArray(subAcc)) {\n useCurrent = subAcc.slice();\n } else if (typeof subAcc === 'object') {\n useCurrent = { ...subAcc };\n } else {\n useCurrent = subAcc;\n }\n\n const nextStep = subscriber(...[useCurrent, ...args]);\n if ('once' in subscriber) {\n toClean.push({\n event: name,\n listener: subscriber,\n });\n }\n\n return nextStep;\n }, eventAcc);\n }, target);\n\n toClean.forEach((info) => this.off(info.event, info.listener));\n return result;\n }\n}\n/**\n * Shorthand for `new EventsHub()`.\n *\n * @returns A new instance of {@link EventsHub}.\n */\nexport const eventsHub = () => new EventsHub();\n"],"mappings":"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","names":[]}
package/dist/index.js CHANGED
@@ -31,15 +31,45 @@ __export(src_exports, {
31
31
  module.exports = __toCommonJS(src_exports);
32
32
  var EventsHub = class {
33
33
  constructor() {
34
+ /**
35
+ * A dictionary of the events and their listeners.
36
+ */
34
37
  __publicField(this, "events", {});
38
+ /**
39
+ * A dictionary of wrappers that were created for "one time subscriptions". This is
40
+ * used by the {@link EventsHub.off}: if it doesn't find the subscriber as it is, it
41
+ * will look for a wrapper and remove it.
42
+ */
35
43
  __publicField(this, "onceWrappers", {});
36
44
  }
45
+ /**
46
+ * Gets all the listeners for a specific event.
47
+ * The list is returned by reference, so it can be modified once obtained.
48
+ *
49
+ * @param event The name of the event.
50
+ */
37
51
  getSubscribers(event) {
38
52
  if (!this.events[event]) {
39
53
  this.events[event] = [];
40
54
  }
41
55
  return this.events[event];
42
56
  }
57
+ /**
58
+ * Adds a new event listener.
59
+ *
60
+ * @param event An event name or a list of them.
61
+ * @param listener The listener function.
62
+ * @returns An unsubscribe function to remove the listene(s).
63
+ * @template ListenerFn The type of the listener function.
64
+ * @example
65
+ *
66
+ * const events = new EventsHub();
67
+ * type Listener = (arg0: string) => void;
68
+ * const unsubscribe = events.on<Listener>('event', (arg0) => {
69
+ * console.log(`Event received: ${arg0}`);
70
+ * });
71
+ *
72
+ */
43
73
  on(event, listener) {
44
74
  const events = Array.isArray(event) ? event : [event];
45
75
  events.forEach((name) => {
@@ -50,6 +80,22 @@ var EventsHub = class {
50
80
  });
51
81
  return () => this.off(event, listener);
52
82
  }
83
+ /**
84
+ * Adds an event listener that will only be executed once.
85
+ *
86
+ * @param event An event name or a list of them.
87
+ * @param listener The listener function.
88
+ * @returns An unsubscribe function to remove the listener(s).
89
+ * @template ListenerFn The type of the listener function.
90
+ * @example
91
+ *
92
+ * const events = new EventsHub();
93
+ * type Listener = (arg0: string) => void;
94
+ * const unsubscribe = events.once<Listener>('event', (arg0) => {
95
+ * console.log(`Event received: ${arg0}`);
96
+ * });
97
+ *
98
+ */
53
99
  once(event, listener) {
54
100
  const events = Array.isArray(event) ? event : [event];
55
101
  let wrapper = events.reduce((acc, name) => {
@@ -79,6 +125,25 @@ var EventsHub = class {
79
125
  }
80
126
  return this.on(event, wrapper);
81
127
  }
128
+ /**
129
+ * Removes an event listener.
130
+ *
131
+ * @param event An event name or a list of them.
132
+ * @param listener The listener function.
133
+ * @returns If `event` was a `string`, it will return whether or not the listener was
134
+ * found and removed; but if `event`
135
+ * was an `Array`, it will return a list of boolean values.
136
+ * @template ListenerFn The type of the listener function.
137
+ * @example
138
+ *
139
+ * const events = new EventsHub();
140
+ * const listener = (arg0) => {
141
+ * console.log(`Event received: ${arg0}`);
142
+ * };
143
+ * events.on('event', listener); // subscribe.
144
+ * events.off('event', listener); // manually unsubscribe.
145
+ *
146
+ */
82
147
  off(event, listener) {
83
148
  const isArray = Array.isArray(event);
84
149
  const events = isArray ? event : [event];
@@ -109,6 +174,21 @@ var EventsHub = class {
109
174
  });
110
175
  return isArray ? result : result[0];
111
176
  }
177
+ /**
178
+ * Emits an event and call all its listeners.
179
+ *
180
+ * @param event An event name or a list of them.
181
+ * @param args A list of parameters to send to the listeners.
182
+ * @template Args The type of the parameters to send to the listeners.
183
+ * @example
184
+ *
185
+ * const events = new EventsHub();
186
+ * events.on('event', (arg0) => {
187
+ * console.log(`Event received: ${arg0}`);
188
+ * });
189
+ * events.emit('event', 'Hello'); // prints "Event received: Hello"
190
+ *
191
+ */
112
192
  emit(event, ...args) {
113
193
  const toClean = [];
114
194
  const events = Array.isArray(event) ? event : [event];
@@ -125,6 +205,28 @@ var EventsHub = class {
125
205
  });
126
206
  toClean.forEach((info) => this.off(info.event, info.listener));
127
207
  }
208
+ /**
209
+ * Asynchronously reduces a target using an event. It's like emit, but the events
210
+ * listener return a modified (or not) version of the `target`.
211
+ *
212
+ * @param event An event name or a list of them.
213
+ * @param target The variable to reduce with the reducers/listeners.
214
+ * @param args A list of parameters to send to the reducers/listeners.
215
+ * @returns A version of the `target` processed by the listeners.
216
+ * @template Target The type of the target.
217
+ * @template Args The type of the parameters to send to the reducers/listeners.
218
+ * @example
219
+ *
220
+ * const events = new EventsHub();
221
+ * events.on('event', async (target, arg0) => {
222
+ * const data = await fetch(`https://api.example.com/${arg0}`);
223
+ * target.push(data);
224
+ * return target;
225
+ * });
226
+ * const result = await events.reduce('event', [], 'Hello');
227
+ * // result would be a list of data fetched from the API.
228
+ *
229
+ */
128
230
  async reduce(event, target, ...args) {
129
231
  const events = Array.isArray(event) ? event : [event];
130
232
  const toClean = [];
@@ -158,6 +260,26 @@ var EventsHub = class {
158
260
  toClean.forEach((info) => this.off(info.event, info.listener));
159
261
  return result;
160
262
  }
263
+ /**
264
+ * Synchronously reduces a target using an event. It's like emit, but the events
265
+ * listener return a modified (or not) version of the `target`.
266
+ *
267
+ * @param event An event name or a list of them.
268
+ * @param target The variable to reduce with the reducers/listeners.
269
+ * @param args A list of parameters to send to the reducers/listeners.
270
+ * @returns A version of the `target` processed by the listeners.
271
+ * @template Target The type of the target.
272
+ * @template Args The type of the parameters to send to the reducers/listeners.
273
+ * @example
274
+ *
275
+ * const events = new EventsHub();
276
+ * events.on('event', (target, arg0) => {
277
+ * target.push(arg0);
278
+ * return target;
279
+ * });
280
+ * events.reduce('event', [], 'Hello'); // returns ['Hello']
281
+ *
282
+ */
161
283
  reduceSync(event, target, ...args) {
162
284
  const events = Array.isArray(event) ? event : [event];
163
285
  const toClean = [];
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/no-explicit-any -- It's a generic function.\ntype GenericFn = (...args: any[]) => any;\ntype GenericParams = Parameters<GenericFn>;\ntype OnceWrapperFn = GenericFn & {\n once: boolean;\n};\n/**\n * When the service receives a \"once subscription\", it needs to track the listener so it\n * gets removed after being called once, and to avoid modifying the original function, it\n * creates a wrapper function that has the \"once\" property set to true. The wrapper and\n * the original function are stored in case `off` is called before the wrapper gets\n * triggered; it will receive the original function, not the wrapper, so the class needs a\n * way to map them together.\n */\ntype OnceWrapper = {\n /**\n * A simple wrapper for the original listener, with the difference that it has a `once`\n * property set to `true`.\n */\n wrapper: OnceWrapperFn;\n /**\n * The original listener that will be called once.\n */\n original: GenericFn;\n};\n/**\n * A minimal implementation of an events handler service.\n */\nexport class EventsHub {\n /**\n * A dictionary of the events and their listeners.\n */\n protected events: Record<string, GenericFn[]> = {};\n /**\n * A dictionary of wrappers that were created for \"one time subscriptions\". This is\n * used by the {@link EventsHub.off}: if it doesn't find the subscriber as it is, it\n * will look for a wrapper and remove it.\n */\n protected onceWrappers: Record<string, OnceWrapper[]> = {};\n /**\n * Gets all the listeners for a specific event.\n * The list is returned by reference, so it can be modified once obtained.\n *\n * @param event The name of the event.\n */\n protected getSubscribers(event: string): (GenericFn | OnceWrapperFn)[] {\n if (!this.events[event]) {\n this.events[event] = [];\n }\n\n return this.events[event]!;\n }\n on<ListenerFn extends GenericFn = GenericFn>(\n event: string,\n listener: ListenerFn,\n ): () => boolean;\n on<ListenerFn extends GenericFn = GenericFn>(\n event: string[],\n listener: ListenerFn,\n ): () => boolean[];\n on<ListenerFn extends GenericFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): () => boolean | boolean[];\n /**\n * Adds a new event listener.\n *\n * @param event An event name or a list of them.\n * @param listener The listener function.\n * @returns An unsubscribe function to remove the listene(s).\n * @template ListenerFn The type of the listener function.\n * @example\n *\n * const events = new EventsHub();\n * type Listener = (arg0: string) => void;\n * const unsubscribe = events.on<Listener>('event', (arg0) => {\n * console.log(`Event received: ${arg0}`);\n * });\n *\n */\n on<ListenerFn extends GenericFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): () => boolean | boolean[] {\n const events = Array.isArray(event) ? event : [event];\n events.forEach((name) => {\n const subscribers = this.getSubscribers(name);\n if (!subscribers.includes(listener)) {\n subscribers.push(listener);\n }\n });\n\n return () => this.off<ListenerFn>(event, listener);\n }\n once<ListenerFn extends GenericFn = GenericFn>(\n event: string,\n listener: ListenerFn,\n ): () => boolean;\n once<ListenerFn extends GenericFn = GenericFn>(\n event: string[],\n listener: ListenerFn,\n ): () => boolean[];\n once<ListenerFn extends GenericFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): () => boolean | boolean[];\n /**\n * Adds an event listener that will only be executed once.\n *\n * @param event An event name or a list of them.\n * @param listener The listener function.\n * @returns An unsubscribe function to remove the listener(s).\n * @template ListenerFn The type of the listener function.\n * @example\n *\n * const events = new EventsHub();\n * type Listener = (arg0: string) => void;\n * const unsubscribe = events.once<Listener>('event', (arg0) => {\n * console.log(`Event received: ${arg0}`);\n * });\n *\n */\n once<ListenerFn extends GenericFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): () => boolean | boolean[] {\n const events = Array.isArray(event) ? event : [event];\n // Try to find an existing wrapper.\n let wrapper = events.reduce<OnceWrapperFn | null>((acc, name) => {\n // A previous iteration found a wrapper, so `continue`.\n if (acc) return acc;\n\n // A list of wrappers exists for the event, so, let's try an find one for this function.\n const onceWrapper = this.onceWrappers[name];\n if (Array.isArray(onceWrapper)) {\n const existing = onceWrapper.find((item) => item.original === listener);\n if (existing) {\n return existing.wrapper;\n }\n\n return null;\n }\n\n // The list didn't even exists, let's at least create it.\n this.onceWrappers[name] = [];\n return null;\n }, null);\n\n if (!wrapper) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- It's a generic function.\n const newWrapper = (...args: any[]) => listener(...args);\n newWrapper.once = true;\n wrapper = newWrapper;\n events.forEach((name) => {\n this.onceWrappers[name]!.push({\n wrapper: wrapper!,\n original: listener,\n });\n });\n }\n\n return this.on(event, wrapper);\n }\n off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(\n event: string[],\n listener: ListenerFn,\n ): boolean[];\n off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(\n event: string,\n listener: ListenerFn,\n ): boolean;\n off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): boolean | boolean[];\n /**\n * Removes an event listener.\n *\n * @param event An event name or a list of them.\n * @param listener The listener function.\n * @returns If `event` was a `string`, it will return whether or not the listener was\n * found and removed; but if `event`\n * was an `Array`, it will return a list of boolean values.\n * @template ListenerFn The type of the listener function.\n * @example\n *\n * const events = new EventsHub();\n * const listener = (arg0) => {\n * console.log(`Event received: ${arg0}`);\n * };\n * events.on('event', listener); // subscribe.\n * events.off('event', listener); // manually unsubscribe.\n *\n */\n off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): boolean | boolean[] {\n const isArray = Array.isArray(event);\n const events = isArray ? event : [event];\n const result = events.map((name) => {\n const subscribers = this.getSubscribers(name);\n const onceSubscribers = this.onceWrappers[name];\n let found = false;\n let index = subscribers.indexOf(listener);\n if (index > -1) {\n found = true;\n /**\n * If the listener had the `once` flag, then it's a wrapper, so it needs to remove\n * it from the wrappers list too.\n */\n if ('once' in listener && onceSubscribers) {\n const wrapperIndex = onceSubscribers.findIndex(\n (item) => item.wrapper === listener,\n );\n onceSubscribers.splice(wrapperIndex, 1);\n }\n subscribers.splice(index, 1);\n } else if (onceSubscribers) {\n /**\n * If it couldn't found the subscriber, maybe it's because it's the original\n * listener of a wrapper.\n */\n index = onceSubscribers.findIndex((item) => item.original === listener);\n if (index > -1) {\n found = true;\n const originalIndex = subscribers.indexOf(onceSubscribers[index]!.original);\n subscribers.splice(originalIndex, 1);\n onceSubscribers.splice(index, 1);\n }\n }\n\n return found;\n });\n\n return isArray ? result : result[0]!;\n }\n /**\n * Emits an event and call all its listeners.\n *\n * @param event An event name or a list of them.\n * @param args A list of parameters to send to the listeners.\n * @template Args The type of the parameters to send to the listeners.\n * @example\n *\n * const events = new EventsHub();\n * events.on('event', (arg0) => {\n * console.log(`Event received: ${arg0}`);\n * });\n * events.emit('event', 'Hello'); // prints \"Event received: Hello\"\n *\n */\n emit<Args extends GenericParams>(event: string | string[], ...args: Args): void {\n const toClean: { event: string; listener: GenericFn }[] = [];\n const events = Array.isArray(event) ? event : [event];\n events.forEach((name) => {\n this.getSubscribers(name).forEach((subscriber) => {\n subscriber(...args);\n if ('once' in subscriber) {\n toClean.push({\n event: name,\n listener: subscriber,\n });\n }\n });\n });\n\n toClean.forEach((info) => this.off(info.event, info.listener));\n }\n /**\n * Asynchronously reduces a target using an event. It's like emit, but the events\n * listener return a modified (or not) version of the `target`.\n *\n * @param event An event name or a list of them.\n * @param target The variable to reduce with the reducers/listeners.\n * @param args A list of parameters to send to the reducers/listeners.\n * @returns A version of the `target` processed by the listeners.\n * @template Target The type of the target.\n * @template Args The type of the parameters to send to the reducers/listeners.\n * @example\n *\n * const events = new EventsHub();\n * events.on('event', async (target, arg0) => {\n * const data = await fetch(`https://api.example.com/${arg0}`);\n * target.push(data);\n * return target;\n * });\n * const result = await events.reduce('event', [], 'Hello');\n * // result would be a list of data fetched from the API.\n *\n */\n async reduce<Target, Args extends GenericParams>(\n event: string | string[],\n target: Target,\n ...args: Args\n ): Promise<Target> {\n const events = Array.isArray(event) ? event : [event];\n const toClean: { event: string; listener: GenericFn }[] = [];\n const result = await events.reduce<Promise<Target>>(\n (eventAcc, name) =>\n eventAcc.then((eventCurrent) => {\n const subscribers = this.getSubscribers(name);\n return subscribers.reduce(\n (subAcc, subscriber) =>\n subAcc.then((subCurrent) => {\n let useCurrent;\n if (Array.isArray(subCurrent)) {\n useCurrent = subCurrent.slice();\n } else if (typeof subCurrent === 'object') {\n useCurrent = { ...subCurrent };\n } else {\n useCurrent = subCurrent;\n }\n\n const nextStep = subscriber(...[useCurrent, ...args]);\n if ('once' in subscriber) {\n toClean.push({\n event: name,\n listener: subscriber,\n });\n }\n\n return nextStep;\n }),\n Promise.resolve(eventCurrent),\n );\n }),\n Promise.resolve(target),\n );\n\n toClean.forEach((info) => this.off(info.event, info.listener));\n\n return result;\n }\n /**\n * Synchronously reduces a target using an event. It's like emit, but the events\n * listener return a modified (or not) version of the `target`.\n *\n * @param event An event name or a list of them.\n * @param target The variable to reduce with the reducers/listeners.\n * @param args A list of parameters to send to the reducers/listeners.\n * @returns A version of the `target` processed by the listeners.\n * @template Target The type of the target.\n * @template Args The type of the parameters to send to the reducers/listeners.\n * @example\n *\n * const events = new EventsHub();\n * events.on('event', (target, arg0) => {\n * target.push(arg0);\n * return target;\n * });\n * events.reduce('event', [], 'Hello'); // returns ['Hello']\n *\n */\n reduceSync<Target, ReducerArgs extends GenericParams>(\n event: string | string[],\n target: Target,\n ...args: ReducerArgs\n ): Target {\n const events = Array.isArray(event) ? event : [event];\n const toClean: { event: string; listener: GenericFn }[] = [];\n const result = events.reduce((eventAcc, name) => {\n const subscribers = this.getSubscribers(name);\n return subscribers.reduce((subAcc, subscriber) => {\n let useCurrent;\n if (Array.isArray(subAcc)) {\n useCurrent = subAcc.slice();\n } else if (typeof subAcc === 'object') {\n useCurrent = { ...subAcc };\n } else {\n useCurrent = subAcc;\n }\n\n const nextStep = subscriber(...[useCurrent, ...args]);\n if ('once' in subscriber) {\n toClean.push({\n event: name,\n listener: subscriber,\n });\n }\n\n return nextStep;\n }, eventAcc);\n }, target);\n\n toClean.forEach((info) => this.off(info.event, info.listener));\n return result;\n }\n}\n/**\n * Shorthand for `new EventsHub()`.\n *\n * @returns A new instance of {@link EventsHub}.\n */\nexport const eventsHub = () => new EventsHub();\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BO,IAAM,YAAN,MAAgB;AAAA,EAAhB;AAIL,wBAAU,UAAsC,CAAC;AAMjD,wBAAU,gBAA8C,CAAC;AAAA;AAAA,EAO/C,eAAe,OAA8C;AACrE,QAAI,CAAC,KAAK,OAAO,QAAQ;AACvB,WAAK,OAAO,SAAS,CAAC;AAAA,IACxB;AAEA,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA,EA6BA,GACE,OACA,UAC2B;AAC3B,UAAM,SAAS,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AACpD,WAAO,QAAQ,CAAC,SAAS;AACvB,YAAM,cAAc,KAAK,eAAe,IAAI;AAC5C,UAAI,CAAC,YAAY,SAAS,QAAQ,GAAG;AACnC,oBAAY,KAAK,QAAQ;AAAA,MAC3B;AAAA,IACF,CAAC;AAED,WAAO,MAAM,KAAK,IAAgB,OAAO,QAAQ;AAAA,EACnD;AAAA,EA6BA,KACE,OACA,UAC2B;AAC3B,UAAM,SAAS,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AAEpD,QAAI,UAAU,OAAO,OAA6B,CAAC,KAAK,SAAS;AAE/D,UAAI;AAAK,eAAO;AAGhB,YAAM,cAAc,KAAK,aAAa;AACtC,UAAI,MAAM,QAAQ,WAAW,GAAG;AAC9B,cAAM,WAAW,YAAY,KAAK,CAAC,SAAS,KAAK,aAAa,QAAQ;AACtE,YAAI,UAAU;AACZ,iBAAO,SAAS;AAAA,QAClB;AAEA,eAAO;AAAA,MACT;AAGA,WAAK,aAAa,QAAQ,CAAC;AAC3B,aAAO;AAAA,IACT,GAAG,IAAI;AAEP,QAAI,CAAC,SAAS;AAEZ,YAAM,aAAa,IAAI,SAAgB,SAAS,GAAG,IAAI;AACvD,iBAAW,OAAO;AAClB,gBAAU;AACV,aAAO,QAAQ,CAAC,SAAS;AACvB,aAAK,aAAa,MAAO,KAAK;AAAA,UAC5B;AAAA,UACA,UAAU;AAAA,QACZ,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAEA,WAAO,KAAK,GAAG,OAAO,OAAO;AAAA,EAC/B;AAAA,EAgCA,IACE,OACA,UACqB;AACrB,UAAM,UAAU,MAAM,QAAQ,KAAK;AACnC,UAAM,SAAS,UAAU,QAAQ,CAAC,KAAK;AACvC,UAAM,SAAS,OAAO,IAAI,CAAC,SAAS;AAClC,YAAM,cAAc,KAAK,eAAe,IAAI;AAC5C,YAAM,kBAAkB,KAAK,aAAa;AAC1C,UAAI,QAAQ;AACZ,UAAI,QAAQ,YAAY,QAAQ,QAAQ;AACxC,UAAI,QAAQ,IAAI;AACd,gBAAQ;AAKR,YAAI,UAAU,YAAY,iBAAiB;AACzC,gBAAM,eAAe,gBAAgB;AAAA,YACnC,CAAC,SAAS,KAAK,YAAY;AAAA,UAC7B;AACA,0BAAgB,OAAO,cAAc,CAAC;AAAA,QACxC;AACA,oBAAY,OAAO,OAAO,CAAC;AAAA,MAC7B,WAAW,iBAAiB;AAK1B,gBAAQ,gBAAgB,UAAU,CAAC,SAAS,KAAK,aAAa,QAAQ;AACtE,YAAI,QAAQ,IAAI;AACd,kBAAQ;AACR,gBAAM,gBAAgB,YAAY,QAAQ,gBAAgB,OAAQ,QAAQ;AAC1E,sBAAY,OAAO,eAAe,CAAC;AACnC,0BAAgB,OAAO,OAAO,CAAC;AAAA,QACjC;AAAA,MACF;AAEA,aAAO;AAAA,IACT,CAAC;AAED,WAAO,UAAU,SAAS,OAAO;AAAA,EACnC;AAAA,EAgBA,KAAiC,UAA6B,MAAkB;AAC9E,UAAM,UAAoD,CAAC;AAC3D,UAAM,SAAS,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AACpD,WAAO,QAAQ,CAAC,SAAS;AACvB,WAAK,eAAe,IAAI,EAAE,QAAQ,CAAC,eAAe;AAChD,mBAAW,GAAG,IAAI;AAClB,YAAI,UAAU,YAAY;AACxB,kBAAQ,KAAK;AAAA,YACX,OAAO;AAAA,YACP,UAAU;AAAA,UACZ,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAED,YAAQ,QAAQ,CAAC,SAAS,KAAK,IAAI,KAAK,OAAO,KAAK,QAAQ,CAAC;AAAA,EAC/D;AAAA,EAuBA,MAAM,OACJ,OACA,WACG,MACc;AACjB,UAAM,SAAS,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AACpD,UAAM,UAAoD,CAAC;AAC3D,UAAM,SAAS,MAAM,OAAO;AAAA,MAC1B,CAAC,UAAU,SACT,SAAS,KAAK,CAAC,iBAAiB;AAC9B,cAAM,cAAc,KAAK,eAAe,IAAI;AAC5C,eAAO,YAAY;AAAA,UACjB,CAAC,QAAQ,eACP,OAAO,KAAK,CAAC,eAAe;AAC1B,gBAAI;AACJ,gBAAI,MAAM,QAAQ,UAAU,GAAG;AAC7B,2BAAa,WAAW,MAAM;AAAA,YAChC,WAAW,OAAO,eAAe,UAAU;AACzC,2BAAa,EAAE,GAAG,WAAW;AAAA,YAC/B,OAAO;AACL,2BAAa;AAAA,YACf;AAEA,kBAAM,WAAW,WAAW,GAAG,CAAC,YAAY,GAAG,IAAI,CAAC;AACpD,gBAAI,UAAU,YAAY;AACxB,sBAAQ,KAAK;AAAA,gBACX,OAAO;AAAA,gBACP,UAAU;AAAA,cACZ,CAAC;AAAA,YACH;AAEA,mBAAO;AAAA,UACT,CAAC;AAAA,UACH,QAAQ,QAAQ,YAAY;AAAA,QAC9B;AAAA,MACF,CAAC;AAAA,MACH,QAAQ,QAAQ,MAAM;AAAA,IACxB;AAEA,YAAQ,QAAQ,CAAC,SAAS,KAAK,IAAI,KAAK,OAAO,KAAK,QAAQ,CAAC;AAE7D,WAAO;AAAA,EACT;AAAA,EAqBA,WACE,OACA,WACG,MACK;AACR,UAAM,SAAS,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AACpD,UAAM,UAAoD,CAAC;AAC3D,UAAM,SAAS,OAAO,OAAO,CAAC,UAAU,SAAS;AAC/C,YAAM,cAAc,KAAK,eAAe,IAAI;AAC5C,aAAO,YAAY,OAAO,CAAC,QAAQ,eAAe;AAChD,YAAI;AACJ,YAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,uBAAa,OAAO,MAAM;AAAA,QAC5B,WAAW,OAAO,WAAW,UAAU;AACrC,uBAAa,EAAE,GAAG,OAAO;AAAA,QAC3B,OAAO;AACL,uBAAa;AAAA,QACf;AAEA,cAAM,WAAW,WAAW,GAAG,CAAC,YAAY,GAAG,IAAI,CAAC;AACpD,YAAI,UAAU,YAAY;AACxB,kBAAQ,KAAK;AAAA,YACX,OAAO;AAAA,YACP,UAAU;AAAA,UACZ,CAAC;AAAA,QACH;AAEA,eAAO;AAAA,MACT,GAAG,QAAQ;AAAA,IACb,GAAG,MAAM;AAET,YAAQ,QAAQ,CAAC,SAAS,KAAK,IAAI,KAAK,OAAO,KAAK,QAAQ,CAAC;AAC7D,WAAO;AAAA,EACT;AACF;AAMO,IAAM,YAAY,MAAM,IAAI,UAAU;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/no-explicit-any -- It's a generic function.\ntype GenericFn = (...args: any[]) => any;\ntype GenericParams = Parameters<GenericFn>;\ntype OnceWrapperFn = GenericFn & {\n once: boolean;\n};\n/**\n * When the service receives a \"once subscription\", it needs to track the listener so it\n * gets removed after being called once, and to avoid modifying the original function, it\n * creates a wrapper function that has the \"once\" property set to true. The wrapper and\n * the original function are stored in case `off` is called before the wrapper gets\n * triggered; it will receive the original function, not the wrapper, so the class needs a\n * way to map them together.\n */\ntype OnceWrapper = {\n /**\n * A simple wrapper for the original listener, with the difference that it has a `once`\n * property set to `true`.\n */\n wrapper: OnceWrapperFn;\n /**\n * The original listener that will be called once.\n */\n original: GenericFn;\n};\n/**\n * A minimal implementation of an events handler service.\n */\nexport class EventsHub {\n /**\n * A dictionary of the events and their listeners.\n */\n protected events: Record<string, GenericFn[]> = {};\n /**\n * A dictionary of wrappers that were created for \"one time subscriptions\". This is\n * used by the {@link EventsHub.off}: if it doesn't find the subscriber as it is, it\n * will look for a wrapper and remove it.\n */\n protected onceWrappers: Record<string, OnceWrapper[]> = {};\n /**\n * Gets all the listeners for a specific event.\n * The list is returned by reference, so it can be modified once obtained.\n *\n * @param event The name of the event.\n */\n protected getSubscribers(event: string): (GenericFn | OnceWrapperFn)[] {\n if (!this.events[event]) {\n this.events[event] = [];\n }\n\n return this.events[event]!;\n }\n on<ListenerFn extends GenericFn = GenericFn>(\n event: string,\n listener: ListenerFn,\n ): () => boolean;\n on<ListenerFn extends GenericFn = GenericFn>(\n event: string[],\n listener: ListenerFn,\n ): () => boolean[];\n on<ListenerFn extends GenericFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): () => boolean | boolean[];\n /**\n * Adds a new event listener.\n *\n * @param event An event name or a list of them.\n * @param listener The listener function.\n * @returns An unsubscribe function to remove the listene(s).\n * @template ListenerFn The type of the listener function.\n * @example\n *\n * const events = new EventsHub();\n * type Listener = (arg0: string) => void;\n * const unsubscribe = events.on<Listener>('event', (arg0) => {\n * console.log(`Event received: ${arg0}`);\n * });\n *\n */\n on<ListenerFn extends GenericFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): () => boolean | boolean[] {\n const events = Array.isArray(event) ? event : [event];\n events.forEach((name) => {\n const subscribers = this.getSubscribers(name);\n if (!subscribers.includes(listener)) {\n subscribers.push(listener);\n }\n });\n\n return () => this.off<ListenerFn>(event, listener);\n }\n once<ListenerFn extends GenericFn = GenericFn>(\n event: string,\n listener: ListenerFn,\n ): () => boolean;\n once<ListenerFn extends GenericFn = GenericFn>(\n event: string[],\n listener: ListenerFn,\n ): () => boolean[];\n once<ListenerFn extends GenericFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): () => boolean | boolean[];\n /**\n * Adds an event listener that will only be executed once.\n *\n * @param event An event name or a list of them.\n * @param listener The listener function.\n * @returns An unsubscribe function to remove the listener(s).\n * @template ListenerFn The type of the listener function.\n * @example\n *\n * const events = new EventsHub();\n * type Listener = (arg0: string) => void;\n * const unsubscribe = events.once<Listener>('event', (arg0) => {\n * console.log(`Event received: ${arg0}`);\n * });\n *\n */\n once<ListenerFn extends GenericFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): () => boolean | boolean[] {\n const events = Array.isArray(event) ? event : [event];\n // Try to find an existing wrapper.\n let wrapper = events.reduce<OnceWrapperFn | null>((acc, name) => {\n // A previous iteration found a wrapper, so `continue`.\n if (acc) return acc;\n\n // A list of wrappers exists for the event, so, let's try an find one for this function.\n const onceWrapper = this.onceWrappers[name];\n if (Array.isArray(onceWrapper)) {\n const existing = onceWrapper.find((item) => item.original === listener);\n if (existing) {\n return existing.wrapper;\n }\n\n return null;\n }\n\n // The list didn't even exists, let's at least create it.\n this.onceWrappers[name] = [];\n return null;\n }, null);\n\n if (!wrapper) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- It's a generic function.\n const newWrapper = (...args: any[]) => listener(...args);\n newWrapper.once = true;\n wrapper = newWrapper;\n events.forEach((name) => {\n this.onceWrappers[name]!.push({\n wrapper: wrapper!,\n original: listener,\n });\n });\n }\n\n return this.on(event, wrapper);\n }\n off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(\n event: string[],\n listener: ListenerFn,\n ): boolean[];\n off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(\n event: string,\n listener: ListenerFn,\n ): boolean;\n off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): boolean | boolean[];\n /**\n * Removes an event listener.\n *\n * @param event An event name or a list of them.\n * @param listener The listener function.\n * @returns If `event` was a `string`, it will return whether or not the listener was\n * found and removed; but if `event`\n * was an `Array`, it will return a list of boolean values.\n * @template ListenerFn The type of the listener function.\n * @example\n *\n * const events = new EventsHub();\n * const listener = (arg0) => {\n * console.log(`Event received: ${arg0}`);\n * };\n * events.on('event', listener); // subscribe.\n * events.off('event', listener); // manually unsubscribe.\n *\n */\n off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(\n event: string | string[],\n listener: ListenerFn,\n ): boolean | boolean[] {\n const isArray = Array.isArray(event);\n const events = isArray ? event : [event];\n const result = events.map((name) => {\n const subscribers = this.getSubscribers(name);\n const onceSubscribers = this.onceWrappers[name];\n let found = false;\n let index = subscribers.indexOf(listener);\n if (index > -1) {\n found = true;\n /**\n * If the listener had the `once` flag, then it's a wrapper, so it needs to remove\n * it from the wrappers list too.\n */\n if ('once' in listener && onceSubscribers) {\n const wrapperIndex = onceSubscribers.findIndex(\n (item) => item.wrapper === listener,\n );\n onceSubscribers.splice(wrapperIndex, 1);\n }\n subscribers.splice(index, 1);\n } else if (onceSubscribers) {\n /**\n * If it couldn't found the subscriber, maybe it's because it's the original\n * listener of a wrapper.\n */\n index = onceSubscribers.findIndex((item) => item.original === listener);\n if (index > -1) {\n found = true;\n const originalIndex = subscribers.indexOf(onceSubscribers[index]!.original);\n subscribers.splice(originalIndex, 1);\n onceSubscribers.splice(index, 1);\n }\n }\n\n return found;\n });\n\n return isArray ? result : result[0]!;\n }\n /**\n * Emits an event and call all its listeners.\n *\n * @param event An event name or a list of them.\n * @param args A list of parameters to send to the listeners.\n * @template Args The type of the parameters to send to the listeners.\n * @example\n *\n * const events = new EventsHub();\n * events.on('event', (arg0) => {\n * console.log(`Event received: ${arg0}`);\n * });\n * events.emit('event', 'Hello'); // prints \"Event received: Hello\"\n *\n */\n emit<Args extends GenericParams>(event: string | string[], ...args: Args): void {\n const toClean: { event: string; listener: GenericFn }[] = [];\n const events = Array.isArray(event) ? event : [event];\n events.forEach((name) => {\n this.getSubscribers(name).forEach((subscriber) => {\n subscriber(...args);\n if ('once' in subscriber) {\n toClean.push({\n event: name,\n listener: subscriber,\n });\n }\n });\n });\n\n toClean.forEach((info) => this.off(info.event, info.listener));\n }\n /**\n * Asynchronously reduces a target using an event. It's like emit, but the events\n * listener return a modified (or not) version of the `target`.\n *\n * @param event An event name or a list of them.\n * @param target The variable to reduce with the reducers/listeners.\n * @param args A list of parameters to send to the reducers/listeners.\n * @returns A version of the `target` processed by the listeners.\n * @template Target The type of the target.\n * @template Args The type of the parameters to send to the reducers/listeners.\n * @example\n *\n * const events = new EventsHub();\n * events.on('event', async (target, arg0) => {\n * const data = await fetch(`https://api.example.com/${arg0}`);\n * target.push(data);\n * return target;\n * });\n * const result = await events.reduce('event', [], 'Hello');\n * // result would be a list of data fetched from the API.\n *\n */\n async reduce<Target, Args extends GenericParams>(\n event: string | string[],\n target: Target,\n ...args: Args\n ): Promise<Target> {\n const events = Array.isArray(event) ? event : [event];\n const toClean: { event: string; listener: GenericFn }[] = [];\n const result = await events.reduce<Promise<Target>>(\n (eventAcc, name) =>\n eventAcc.then((eventCurrent) => {\n const subscribers = this.getSubscribers(name);\n return subscribers.reduce(\n (subAcc, subscriber) =>\n subAcc.then((subCurrent) => {\n let useCurrent;\n if (Array.isArray(subCurrent)) {\n useCurrent = subCurrent.slice();\n } else if (typeof subCurrent === 'object') {\n useCurrent = { ...subCurrent };\n } else {\n useCurrent = subCurrent;\n }\n\n const nextStep = subscriber(...[useCurrent, ...args]);\n if ('once' in subscriber) {\n toClean.push({\n event: name,\n listener: subscriber,\n });\n }\n\n return nextStep;\n }),\n Promise.resolve(eventCurrent),\n );\n }),\n Promise.resolve(target),\n );\n\n toClean.forEach((info) => this.off(info.event, info.listener));\n\n return result;\n }\n /**\n * Synchronously reduces a target using an event. It's like emit, but the events\n * listener return a modified (or not) version of the `target`.\n *\n * @param event An event name or a list of them.\n * @param target The variable to reduce with the reducers/listeners.\n * @param args A list of parameters to send to the reducers/listeners.\n * @returns A version of the `target` processed by the listeners.\n * @template Target The type of the target.\n * @template Args The type of the parameters to send to the reducers/listeners.\n * @example\n *\n * const events = new EventsHub();\n * events.on('event', (target, arg0) => {\n * target.push(arg0);\n * return target;\n * });\n * events.reduce('event', [], 'Hello'); // returns ['Hello']\n *\n */\n reduceSync<Target, ReducerArgs extends GenericParams>(\n event: string | string[],\n target: Target,\n ...args: ReducerArgs\n ): Target {\n const events = Array.isArray(event) ? event : [event];\n const toClean: { event: string; listener: GenericFn }[] = [];\n const result = events.reduce((eventAcc, name) => {\n const subscribers = this.getSubscribers(name);\n return subscribers.reduce((subAcc, subscriber) => {\n let useCurrent;\n if (Array.isArray(subAcc)) {\n useCurrent = subAcc.slice();\n } else if (typeof subAcc === 'object') {\n useCurrent = { ...subAcc };\n } else {\n useCurrent = subAcc;\n }\n\n const nextStep = subscriber(...[useCurrent, ...args]);\n if ('once' in subscriber) {\n toClean.push({\n event: name,\n listener: subscriber,\n });\n }\n\n return nextStep;\n }, eventAcc);\n }, target);\n\n toClean.forEach((info) => this.off(info.event, info.listener));\n return result;\n }\n}\n/**\n * Shorthand for `new EventsHub()`.\n *\n * @returns A new instance of {@link EventsHub}.\n */\nexport const eventsHub = () => new EventsHub();\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@homer0/events-hub",
3
3
  "description": "A simple implementation of a pubsub service for handling events",
4
- "version": "2.0.1",
4
+ "version": "2.0.3",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/homer0/packages.git",
@@ -23,10 +23,12 @@
23
23
  "dist/"
24
24
  ],
25
25
  "devDependencies": {
26
- "jest": "^29.4.1",
27
- "ts-jest": "^29.0.5",
28
- "tsup": "^6.5.0",
29
- "typescript": "^4.9.4"
26
+ "@homer0/eslint-plugin": "10.2.2",
27
+ "@homer0/tsconfig": "1.0.8",
28
+ "jest": "^29.5.0",
29
+ "ts-jest": "^29.1.0",
30
+ "tsup": "^7.0.0",
31
+ "typescript": "^5.1.3"
30
32
  },
31
33
  "engine-strict": true,
32
34
  "engines": {
@@ -40,7 +42,7 @@
40
42
  "test": "jest -c ./.jestrc.js",
41
43
  "types:check": "tsc --noEmit && tsc --noEmit --project ./tests/tsconfig.json",
42
44
  "build": "tsup src/index.ts",
43
- "prepublishOnly": "npm run build"
45
+ "prepublishOnly": "pnpm run build"
44
46
  },
45
- "gitHead": "59c0f6af6901b9f4edb8d2ec36abaf11f6b0780d"
47
+ "gitHead": "e8c1e75555382d4cc23c78e7c4d1e2c62f8c06a2"
46
48
  }