UNPKG

emiterator

Version:

Adapter that turns EventEmitters into AsyncGenerators

85 lines 3.39 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.emiterator = void 0; /** * Makes an AsyncGenerator from an EventEmitter. * ```typescript * import { createReadStream } from 'node:fs'; * import { emiterator } from 'emiterator'; * * let iterator = emiterator( * createReadStream('file.txt', 'utf-8'), * ['data'], * ['end'] * ); * * for await (let chunk of iterator) { * // chunk is { event: 'data', args: [string] } * console.log(`Received ${chunk.args[0].length} bytes of data.`); * } * ``` * Behind the scenes, listeners are registered for each event specified. * They are removed when any of the `doneEvents` or `throwEvents` are emitted. * * @template L Mapping of event names to associated listener signatures. * Defaults to `{ [k: string]: (...args: any[]) => any; }` * @template DataEvent The names of events that will be iterated over. * @template DoneEvent The names of the events that signal iteration is done. * E.g. 'end' | 'finish' * @template ThrowEvent The names of events that signal an error. E.g. 'error'. * * @param emitter The EventEmitter. If emitter is a TypedEmitter, then the * elements yielded by the AsyncGenerator will typed accordingly. * @param dataEvents Events that will be yielded by the AsyncGenerator. * @param doneEvents Events that signal the end of iteration. * @param throwEvents Events that will cause the iterator to throw. * To handle these events yourself, add them to `dataEvents` instead. * @returns An AsyncGenerator that yields objects with string `event` and tuple * `args` properties that map to what would otherwise be emitter's * dataEvents and associated listener function arguments. * I.e. `on(event, (...args)=>{...})` */ async function* emiterator(emitter, dataEvents, doneEvents, throwEvents = []) { let results = []; let resolve; let reject; let promise = new Promise((...args) => [resolve, reject] = args); const listeners = new Map(); const addListener = (event, listener) => { emitter.on(event, listener); let eventListeners = listeners.get(event); if (null == eventListeners) { eventListeners = []; listeners.set(event, eventListeners); } eventListeners.push(listener); }; const removeListeners = () => listeners.forEach((eventListeners, event) => eventListeners.forEach(eventListener => //@ts-ignore emitter.removeListener(event, eventListener))); for (const dataEvent of dataEvents) { addListener(dataEvent, (...args) => { results.push({ event: dataEvent, args }); resolve(true); promise = new Promise((...args) => [resolve, reject] = args); }); } for (const doneEvent of doneEvents) { addListener(doneEvent, (..._args) => { removeListeners(); resolve(false); }); } for (const throwEvent of throwEvents) { addListener(throwEvent, (...errs) => { removeListeners(); const err = null == errs?.[0] ? new Error(String(throwEvent)) : errs[0]; reject(err); }); } while (await promise) { yield* results; results = []; } } exports.emiterator = emiterator; //# sourceMappingURL=index.js.map