@homer0/events-hub 6.0.0 → 6.0.4
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/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/index.ts +40 -52
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\n * was 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":["EventsHub","event","listener","name","subscribers","events","wrapper","acc","onceWrapper","existing","item","newWrapper","args","isArray","result","onceSubscribers","found","index","wrapperIndex","originalIndex","toClean","subscriber","info","target","eventAcc","eventCurrent","subAcc","subCurrent","useCurrent","nextStep","eventsHub"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// oxlint-disable-next-line typescript/no-explicit-any -- Generic function arguments and return type must remain any for listener inference.\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 /** The original listener that will be called once. */\n original: GenericFn;\n};\n/** A minimal implementation of an events handler service. */\nexport class EventsHub {\n /** A dictionary of the events and their listeners. */\n protected events: Record<string, GenericFn[]> = {};\n /**\n * A dictionary of wrappers that were created for \"one time subscriptions\". This is used\n * by the {@link EventsHub.off}: if it doesn't find the subscriber as it is, it will look\n * for a wrapper and remove it.\n */\n protected onceWrappers: Record<string, OnceWrapper[]> = {};\n /**\n * Gets all the listeners for a specific event. The list is returned by reference, so it\n * 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 * @example\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 * @template ListenerFn The type of the listener function.\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 */\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 * @example\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 * @template ListenerFn The type of the listener function.\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 */\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 // oxlint-disable-next-line typescript/no-explicit-any -- The wrapper must retain any arguments for listener inference.\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 * @example\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 * @template ListenerFn The type of the listener function.\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` was an `Array`, it will return a list of boolean\n * values.\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 * @example\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 * @template Args The type of the parameters to send to the listeners.\n * @param event An event name or a list of them.\n * @param args A list of parameters to send to the listeners.\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 * @example\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 * @template Target The type of the target.\n * @template Args The type of the parameters to send to the reducers/listeners.\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 */\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 * @example\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 * @template Target The type of the target.\n * @template Args The type of the parameters to send to the reducers/listeners.\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 */\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":["EventsHub","event","listener","name","subscribers","events","wrapper","acc","onceWrapper","existing","item","newWrapper","args","isArray","result","onceSubscribers","found","index","wrapperIndex","originalIndex","toClean","subscriber","info","target","eventAcc","eventCurrent","subAcc","subCurrent","useCurrent","nextStep","eventsHub"]}
|
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": "6.0.
|
|
4
|
+
"version": "6.0.4",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/homer0/packages.git",
|
|
@@ -35,10 +35,10 @@
|
|
|
35
35
|
"src/"
|
|
36
36
|
],
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@homer0/
|
|
39
|
-
"@homer0/tsconfig": "5.0.
|
|
38
|
+
"@homer0/oxlint-config": "1.0.2",
|
|
39
|
+
"@homer0/tsconfig": "5.0.1",
|
|
40
40
|
"@vitest/coverage-v8": "catalog:",
|
|
41
|
-
"
|
|
41
|
+
"oxlint": "catalog:",
|
|
42
42
|
"tsup": "catalog:",
|
|
43
43
|
"typescript": "catalog:",
|
|
44
44
|
"unplugin-swc": "catalog:",
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
"node": ">=22"
|
|
50
50
|
},
|
|
51
51
|
"scripts": {
|
|
52
|
-
"lint": "
|
|
53
|
-
"lint:file": "
|
|
52
|
+
"lint": "oxlint .",
|
|
53
|
+
"lint:file": "oxlint $@",
|
|
54
54
|
"test": "vitest run $@",
|
|
55
55
|
"types:check": "tsc --noEmit && tsc --noEmit --project ./tests/tsconfig.json",
|
|
56
56
|
"build": "tsup",
|
|
57
57
|
"prepublishOnly": "pnpm run build"
|
|
58
58
|
},
|
|
59
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "e494ba08d9dd4fe6e5d3a9ef54201f3c1f748355"
|
|
60
60
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// oxlint-disable-next-line typescript/no-explicit-any -- Generic function arguments and return type must remain any for listener inference.
|
|
2
2
|
type GenericFn = (...args: any[]) => any;
|
|
3
3
|
type GenericParams = Parameters<GenericFn>;
|
|
4
4
|
type OnceWrapperFn = GenericFn & {
|
|
@@ -18,30 +18,24 @@ type OnceWrapper = {
|
|
|
18
18
|
* property set to `true`.
|
|
19
19
|
*/
|
|
20
20
|
wrapper: OnceWrapperFn;
|
|
21
|
-
/**
|
|
22
|
-
* The original listener that will be called once.
|
|
23
|
-
*/
|
|
21
|
+
/** The original listener that will be called once. */
|
|
24
22
|
original: GenericFn;
|
|
25
23
|
};
|
|
26
|
-
/**
|
|
27
|
-
* A minimal implementation of an events handler service.
|
|
28
|
-
*/
|
|
24
|
+
/** A minimal implementation of an events handler service. */
|
|
29
25
|
export class EventsHub {
|
|
30
|
-
/**
|
|
31
|
-
* A dictionary of the events and their listeners.
|
|
32
|
-
*/
|
|
26
|
+
/** A dictionary of the events and their listeners. */
|
|
33
27
|
protected events: Record<string, GenericFn[]> = {};
|
|
34
28
|
/**
|
|
35
|
-
* A dictionary of wrappers that were created for "one time subscriptions". This is
|
|
36
|
-
*
|
|
37
|
-
*
|
|
29
|
+
* A dictionary of wrappers that were created for "one time subscriptions". This is used
|
|
30
|
+
* by the {@link EventsHub.off}: if it doesn't find the subscriber as it is, it will look
|
|
31
|
+
* for a wrapper and remove it.
|
|
38
32
|
*/
|
|
39
33
|
protected onceWrappers: Record<string, OnceWrapper[]> = {};
|
|
40
34
|
/**
|
|
41
|
-
* Gets all the listeners for a specific event.
|
|
42
|
-
*
|
|
35
|
+
* Gets all the listeners for a specific event. The list is returned by reference, so it
|
|
36
|
+
* can be modified once obtained.
|
|
43
37
|
*
|
|
44
|
-
* @param event
|
|
38
|
+
* @param event The name of the event.
|
|
45
39
|
*/
|
|
46
40
|
protected getSubscribers(event: string): (GenericFn | OnceWrapperFn)[] {
|
|
47
41
|
if (!this.events[event]) {
|
|
@@ -65,18 +59,17 @@ export class EventsHub {
|
|
|
65
59
|
/**
|
|
66
60
|
* Adds a new event listener.
|
|
67
61
|
*
|
|
68
|
-
* @param event An event name or a list of them.
|
|
69
|
-
* @param listener The listener function.
|
|
70
|
-
* @returns An unsubscribe function to remove the listene(s).
|
|
71
|
-
* @template ListenerFn The type of the listener function.
|
|
72
62
|
* @example
|
|
73
|
-
*
|
|
74
63
|
* const events = new EventsHub();
|
|
75
64
|
* type Listener = (arg0: string) => void;
|
|
76
65
|
* const unsubscribe = events.on<Listener>('event', (arg0) => {
|
|
77
66
|
* console.log(`Event received: ${arg0}`);
|
|
78
67
|
* });
|
|
79
68
|
*
|
|
69
|
+
* @template ListenerFn The type of the listener function.
|
|
70
|
+
* @param event An event name or a list of them.
|
|
71
|
+
* @param listener The listener function.
|
|
72
|
+
* @returns An unsubscribe function to remove the listene(s).
|
|
80
73
|
*/
|
|
81
74
|
on<ListenerFn extends GenericFn = GenericFn>(
|
|
82
75
|
event: string | string[],
|
|
@@ -107,18 +100,17 @@ export class EventsHub {
|
|
|
107
100
|
/**
|
|
108
101
|
* Adds an event listener that will only be executed once.
|
|
109
102
|
*
|
|
110
|
-
* @param event An event name or a list of them.
|
|
111
|
-
* @param listener The listener function.
|
|
112
|
-
* @returns An unsubscribe function to remove the listener(s).
|
|
113
|
-
* @template ListenerFn The type of the listener function.
|
|
114
103
|
* @example
|
|
115
|
-
*
|
|
116
104
|
* const events = new EventsHub();
|
|
117
105
|
* type Listener = (arg0: string) => void;
|
|
118
106
|
* const unsubscribe = events.once<Listener>('event', (arg0) => {
|
|
119
107
|
* console.log(`Event received: ${arg0}`);
|
|
120
108
|
* });
|
|
121
109
|
*
|
|
110
|
+
* @template ListenerFn The type of the listener function.
|
|
111
|
+
* @param event An event name or a list of them.
|
|
112
|
+
* @param listener The listener function.
|
|
113
|
+
* @returns An unsubscribe function to remove the listener(s).
|
|
122
114
|
*/
|
|
123
115
|
once<ListenerFn extends GenericFn = GenericFn>(
|
|
124
116
|
event: string | string[],
|
|
@@ -147,7 +139,7 @@ export class EventsHub {
|
|
|
147
139
|
}, null);
|
|
148
140
|
|
|
149
141
|
if (!wrapper) {
|
|
150
|
-
//
|
|
142
|
+
// oxlint-disable-next-line typescript/no-explicit-any -- The wrapper must retain any arguments for listener inference.
|
|
151
143
|
const newWrapper = (...args: any[]) => listener(...args);
|
|
152
144
|
newWrapper.once = true;
|
|
153
145
|
wrapper = newWrapper;
|
|
@@ -176,14 +168,7 @@ export class EventsHub {
|
|
|
176
168
|
/**
|
|
177
169
|
* Removes an event listener.
|
|
178
170
|
*
|
|
179
|
-
* @param event An event name or a list of them.
|
|
180
|
-
* @param listener The listener function.
|
|
181
|
-
* @returns If `event` was a `string`, it will return whether or not the listener
|
|
182
|
-
* was found and removed; but if `event`
|
|
183
|
-
* was an `Array`, it will return a list of boolean values.
|
|
184
|
-
* @template ListenerFn The type of the listener function.
|
|
185
171
|
* @example
|
|
186
|
-
*
|
|
187
172
|
* const events = new EventsHub();
|
|
188
173
|
* const listener = (arg0) => {
|
|
189
174
|
* console.log(`Event received: ${arg0}`);
|
|
@@ -191,6 +176,12 @@ export class EventsHub {
|
|
|
191
176
|
* events.on('event', listener); // subscribe.
|
|
192
177
|
* events.off('event', listener); // manually unsubscribe.
|
|
193
178
|
*
|
|
179
|
+
* @template ListenerFn The type of the listener function.
|
|
180
|
+
* @param event An event name or a list of them.
|
|
181
|
+
* @param listener The listener function.
|
|
182
|
+
* @returns If `event` was a `string`, it will return whether or not the listener was
|
|
183
|
+
* found and removed; but if `event` was an `Array`, it will return a list of boolean
|
|
184
|
+
* values.
|
|
194
185
|
*/
|
|
195
186
|
off<ListenerFn extends GenericFn | OnceWrapperFn = GenericFn>(
|
|
196
187
|
event: string | string[],
|
|
@@ -238,17 +229,16 @@ export class EventsHub {
|
|
|
238
229
|
/**
|
|
239
230
|
* Emits an event and call all its listeners.
|
|
240
231
|
*
|
|
241
|
-
* @param event An event name or a list of them.
|
|
242
|
-
* @param args A list of parameters to send to the listeners.
|
|
243
|
-
* @template Args The type of the parameters to send to the listeners.
|
|
244
232
|
* @example
|
|
245
|
-
*
|
|
246
233
|
* const events = new EventsHub();
|
|
247
234
|
* events.on('event', (arg0) => {
|
|
248
235
|
* console.log(`Event received: ${arg0}`);
|
|
249
236
|
* });
|
|
250
237
|
* events.emit('event', 'Hello'); // prints "Event received: Hello"
|
|
251
238
|
*
|
|
239
|
+
* @template Args The type of the parameters to send to the listeners.
|
|
240
|
+
* @param event An event name or a list of them.
|
|
241
|
+
* @param args A list of parameters to send to the listeners.
|
|
252
242
|
*/
|
|
253
243
|
emit<Args extends GenericParams>(event: string | string[], ...args: Args): void {
|
|
254
244
|
const toClean: { event: string; listener: GenericFn }[] = [];
|
|
@@ -271,14 +261,7 @@ export class EventsHub {
|
|
|
271
261
|
* Asynchronously reduces a target using an event. It's like emit, but the events
|
|
272
262
|
* listener return a modified (or not) version of the `target`.
|
|
273
263
|
*
|
|
274
|
-
* @param event An event name or a list of them.
|
|
275
|
-
* @param target The variable to reduce with the reducers/listeners.
|
|
276
|
-
* @param args A list of parameters to send to the reducers/listeners.
|
|
277
|
-
* @returns A version of the `target` processed by the listeners.
|
|
278
|
-
* @template Target The type of the target.
|
|
279
|
-
* @template Args The type of the parameters to send to the reducers/listeners.
|
|
280
264
|
* @example
|
|
281
|
-
*
|
|
282
265
|
* const events = new EventsHub();
|
|
283
266
|
* events.on('event', async (target, arg0) => {
|
|
284
267
|
* const data = await fetch(`https://api.example.com/${arg0}`);
|
|
@@ -288,6 +271,12 @@ export class EventsHub {
|
|
|
288
271
|
* const result = await events.reduce('event', [], 'Hello');
|
|
289
272
|
* // result would be a list of data fetched from the API.
|
|
290
273
|
*
|
|
274
|
+
* @template Target The type of the target.
|
|
275
|
+
* @template Args The type of the parameters to send to the reducers/listeners.
|
|
276
|
+
* @param event An event name or a list of them.
|
|
277
|
+
* @param target The variable to reduce with the reducers/listeners.
|
|
278
|
+
* @param args A list of parameters to send to the reducers/listeners.
|
|
279
|
+
* @returns A version of the `target` processed by the listeners.
|
|
291
280
|
*/
|
|
292
281
|
async reduce<Target, Args extends GenericParams>(
|
|
293
282
|
event: string | string[],
|
|
@@ -336,14 +325,7 @@ export class EventsHub {
|
|
|
336
325
|
* Synchronously reduces a target using an event. It's like emit, but the events
|
|
337
326
|
* listener return a modified (or not) version of the `target`.
|
|
338
327
|
*
|
|
339
|
-
* @param event An event name or a list of them.
|
|
340
|
-
* @param target The variable to reduce with the reducers/listeners.
|
|
341
|
-
* @param args A list of parameters to send to the reducers/listeners.
|
|
342
|
-
* @returns A version of the `target` processed by the listeners.
|
|
343
|
-
* @template Target The type of the target.
|
|
344
|
-
* @template Args The type of the parameters to send to the reducers/listeners.
|
|
345
328
|
* @example
|
|
346
|
-
*
|
|
347
329
|
* const events = new EventsHub();
|
|
348
330
|
* events.on('event', (target, arg0) => {
|
|
349
331
|
* target.push(arg0);
|
|
@@ -351,6 +333,12 @@ export class EventsHub {
|
|
|
351
333
|
* });
|
|
352
334
|
* events.reduce('event', [], 'Hello'); // returns ['Hello']
|
|
353
335
|
*
|
|
336
|
+
* @template Target The type of the target.
|
|
337
|
+
* @template Args The type of the parameters to send to the reducers/listeners.
|
|
338
|
+
* @param event An event name or a list of them.
|
|
339
|
+
* @param target The variable to reduce with the reducers/listeners.
|
|
340
|
+
* @param args A list of parameters to send to the reducers/listeners.
|
|
341
|
+
* @returns A version of the `target` processed by the listeners.
|
|
354
342
|
*/
|
|
355
343
|
reduceSync<Target, ReducerArgs extends GenericParams>(
|
|
356
344
|
event: string | string[],
|