merge.js

import {asAsyncIterator} from './lib/get_iterator'

/**
```
import {merge} from 'async_iter/pipeline/merge' # pipeline version
import {merge} from 'async_iter/merge' # conventional version
```

Merges the source iterables items into a single iterable.  Order is as they come.

If all source iterables are stopped, then the returned iteration is stopped

If the consumer stops the iteration, all source iterations are stopped.

 * @param  {Iterable}         sources        The source iterations
 * @return {Iterable} An iterable that combines all values from the sources
 * @function
 * @name merge
 * @memberof module:Operators
 */

export async function* merge(...sources) {
  let done = sources.length
  const items = sources
    .map(s => asAsyncIterator(s))
    .map((p, index) => p.next().then(d => ({...d, index})))

  try {
    while (done > 0) {
      const p = await Promise.race(items.filter(i => i))

      if (p.done) {
        done -= 1
        delete items[p.index]
      }
      else {
        items[p.index] = sources[p.index].next().then(d => ({...d, index: p.index}))
        yield p.value
      }
    }
  } finally {
    for (const item of sources.filter(i => i.return))
      item.return()
  }
}