| 100 | } |
| 101 | |
| 102 | async function* combiner(iterables: Some<T>[]) { |
| 103 | iterables.forEach((iterable, index) => iterators.set(index, awaitNext({ identity: index, iterator: asyncOf(iterable)[Symbol.asyncIterator]() }))); |
| 104 | |
| 105 | // Loop until all iterators are done, removing them as they complete |
| 106 | do { |
| 107 | if (!iterators.size && !completeWhenEmpty) { |
| 108 | await signal; // wait for a new item to be added, or for the complete signal |
| 109 | } |
| 110 | |
| 111 | while (iterators.size) { |
| 112 | const element = await race([...iterators.values()]); |
| 113 | |
| 114 | // Is that iterator done? |
| 115 | if (element.result!.done) { |
| 116 | iterators.delete(element.identity); |
| 117 | continue; |
| 118 | } |
| 119 | |
| 120 | // Yield the result from the iterator, and await the next item |
| 121 | const { value } = element.result!; |
| 122 | iterators.set(element.identity, awaitNext(element)); |
| 123 | if (value !== undefined && value !== null) { |
| 124 | yield value; |
| 125 | } |
| 126 | |
| 127 | } |
| 128 | |
| 129 | } while (!completeWhenEmpty); |
| 130 | signal.dispose(false); |
| 131 | |
| 132 | // prevent any more iterators from being added |
| 133 | result.add = () => { throw new Error('AsyncIterable is finished'); }; |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | export type Some<T> = T | Promise<T> | AsyncIterable<T | undefined> | AsyncIterable<Promise<T> | Promise<undefined>> | Iterable<T> | Iterable<Promise<T>>; |