UNPKG

@hazae41/plume

Version:

Typed async events with sequenced and parallel dispatching

1 lines 7.51 kB
{"version":3,"file":"target.cjs","sources":["../../../../src/mods/target.ts"],"sourcesContent":["import { Pin } from \"@hazae41/box\";\nimport { Future } from \"@hazae41/future\";\nimport { None, Option, Some } from \"@hazae41/option\";\nimport { WeakParameters } from \"libs/parameters/index.js\";\nimport { Awaitable } from \"libs/promises/index.js\";\nimport { Voidable } from \"libs/voidable/index.js\";\n\nexport type SuperEventDescriptor =\n (...args: any) => any\n\nexport type SuperEventMap =\n Record<string, SuperEventDescriptor>\n\nexport type SuperEventListener<T extends SuperEventDescriptor> =\n (...params: WeakParameters<T>) => Awaitable<Voidable<Option<ReturnType<T>>>>\n\nexport type SuperEventWaiter<T extends SuperEventDescriptor, R> =\n (future: Future<R>, ...params: WeakParameters<T>) => Awaitable<Voidable<Option<ReturnType<T>>>>\n\nexport class SuperEventTarget<M extends SuperEventMap> {\n\n readonly #listeners = new Map<keyof M, Map<SuperEventListener<any>, AddEventListenerOptions & Disposable>>()\n\n get listeners() {\n return this.#listeners\n }\n\n /**\n * Add a listener to an event\n * @param type Event type // \"abort\", \"error\", \"message\", \"close\"\n * @param listener Event listener // (e) => new Some(123)\n * @param options Options // { passive: true }\n * @returns \n */\n on<K extends keyof M>(type: K, listener: SuperEventListener<M[K]>, options: AddEventListenerOptions = {}) {\n let listeners = this.#listeners.get(type)\n\n if (listeners === undefined) {\n listeners = new Map<SuperEventListener<any>, AddEventListenerOptions & Disposable>()\n this.#listeners.set(type, listeners)\n }\n\n const off = () => this.off(type, listener)\n\n options.signal?.addEventListener(\"abort\", off, { passive: true })\n const dispose = () => options.signal?.removeEventListener(\"abort\", off)\n\n listeners.set(listener, { ...options, [Symbol.dispose]: () => dispose() })\n\n return off\n }\n\n /**\n * Remove a listener from an event\n * @param type Event type // \"abort\", \"error\", \"message\", \"close\"\n * @param listener Event listener // (e) => console.log(\"hello\")\n * @param options Just to look like DOM's EventTarget\n * @returns \n */\n off<K extends keyof M>(type: K, listener: SuperEventListener<M[K]>) {\n const listeners = this.#listeners.get(type)\n\n if (!listeners)\n return\n\n using options = listeners.get(listener)\n\n if (!options)\n return\n\n listeners.delete(listener)\n\n if (listeners.size > 0)\n return\n\n this.#listeners.delete(type)\n }\n\n /**\n * Dispatch an event to its listeners\n * \n * - Dispatch to active listeners sequencially\n * - Return if one of the listeners returned something\n * - Dispatch to passive listeners concurrently\n * - Return if one of the listeners returned something\n * - Return nothing\n * @param params The object to emit\n * @returns `Some` if the event \n */\n async emit<K extends keyof M>(type: K, ...params: WeakParameters<M[K]>): Promise<Option<ReturnType<M[K]>>> {\n const listeners = this.#listeners.get(type) as Map<SuperEventListener<M[K]>, AddEventListenerOptions & Disposable> | undefined\n\n if (!listeners)\n return new None()\n\n const promises = new Array<Promise<Voidable<Option<ReturnType<M[K]>>>>>()\n\n for (const [listener, options] of listeners) {\n if (options.passive)\n continue\n if (options.once)\n this.off(type, listener)\n\n const returned = await listener(...params)\n\n if (returned == null)\n continue\n if (returned.isNone())\n continue\n\n return new Some(returned.get())\n }\n\n for (const [listener, options] of listeners) {\n if (!options.passive)\n continue\n if (options.once)\n this.off(type, listener)\n\n const promise = Promise.resolve().then(() => listener(...params))\n\n promises.push(promise)\n\n continue\n }\n\n const returneds = await Promise.all(promises)\n\n for (const returned of returneds) {\n if (returned == null)\n continue\n if (returned.isNone())\n continue\n\n return new Some(returned.get())\n }\n\n return new None()\n }\n\n /**\n * Like `.on`, but instead of returning to the target, capture the returned value in a future, and return nothing to the target\n * @param type \n * @param callback \n * @returns \n */\n wait<K extends keyof M, R>(type: K, callback: SuperEventWaiter<M[K], R>) {\n const future = new Future<R>()\n\n const dispose = this.on(type, async (...params: WeakParameters<M[K]>) => {\n return await callback(future, ...params)\n }, { passive: true })\n\n return Pin.with(future.promise, dispose)\n }\n\n}\n"],"names":["None","Some","future","Future","Pin"],"mappings":"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"}