UNPKG

asyncerator

Version:

Provide supporting types for AsyncIterable/AsyncIterableIterators, promisified stream.pipeline implementation, and Array-like utility operators, sources and sinks.

55 lines (46 loc) 2.14 kB
// source/merge.ts /* * Copyright (c) 2021-2024 Check Digit, LLC * * This code is licensed under the MIT license (see LICENSE.txt for details). */ import from, { type Asyncable, type Asyncerator } from '../asyncerator'; async function createPending<U>(asyncerator: Asyncerator<U>, index: number) { const iterator = asyncerator[Symbol.asyncIterator](); return { index, iterator, result: await iterator.next() }; } /** * Merge multiple asyncables into a single Asyncerator. If an iterator yields another Asyncerator, * merge its output into the stream. * * @param iterators */ export default async function* merge<T>(...iterators: Asyncable<T | Asyncable<T> | Promise<T>>[]): Asyncerator<T> { const wrappedIterators = iterators.map(from); const pending = wrappedIterators.map(createPending); const indexMap = wrappedIterators.map((_, index) => index); while (pending.length > 0) { // eslint-disable-next-line no-await-in-loop const { result, iterator, index } = await Promise.race(pending); if (result.done === true) { // delete this iterable from pending // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style,@typescript-eslint/no-floating-promises pending.splice(indexMap[index] as number, 1); for (let position = index + 1; position < indexMap.length; position++) { indexMap[position] = (indexMap[position] ?? 0) - 1; } } else { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if ((result.value as AsyncIterableIterator<T>)[Symbol.asyncIterator] === undefined) { yield result.value as T; } else { // this is another async iterable iterator, so merge its output into the pending pending.push(createPending(from(result.value as AsyncIterableIterator<T>), indexMap.length)); indexMap.push(pending.length - 1); } // start waiting for the next result from this iterable // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style pending[indexMap[index] as number] = createPending(iterator, index); } } }