/**
 * @packageDocumentation
 *
 * Merge several (async)iterables into one, yield values as they arrive.
 *
 * Nb. sources are iterated over in parallel so the order of emitted items is not guaranteed.
 *
 * @example
 *
 * ```javascript
 * import merge from 'it-merge'
 * import all from 'it-all'
 *
 * // This can also be an iterator, generator, etc
 * const values1 = [0, 1, 2, 3, 4]
 * const values2 = [5, 6, 7, 8, 9]
 *
 * const arr = all(merge(values1, values2))
 *
 * console.info(arr) // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
 * ```
 *
 * Async sources must be awaited:
 *
 * ```javascript
 * import merge from 'it-merge'
 * import all from 'it-all'
 *
 * // This can also be an iterator, async iterator, generator, etc
 * const values1 = async function * () {
 *   yield * [0, 1, 2, 3, 4]
 * }
 * const values2 = async function * () {
 *   yield * [5, 6, 7, 8, 9]
 * }
 *
 * const arr = await all(merge(values1(), values2()))
 *
 * console.info(arr) // 0, 1, 5, 6, 2, 3, 4, 7, 8, 9  <- nb. order is not guaranteed
 * ```
 */
import { queuelessPushable } from 'it-queueless-pushable';
function isAsyncIterable(thing) {
    return thing[Symbol.asyncIterator] != null;
}
async function addAllToPushable(sources, output, signal) {
    try {
        await Promise.all(sources.map(async (source) => {
            for await (const item of source) {
                await output.push(item, {
                    signal
                });
                signal.throwIfAborted();
            }
        }));
        await output.end(undefined, {
            signal
        });
    }
    catch (err) {
        await output.end(err, {
            signal
        })
            .catch(() => { });
    }
}
async function* mergeSources(sources) {
    const controller = new AbortController();
    const output = queuelessPushable();
    addAllToPushable(sources, output, controller.signal)
        .catch(() => { });
    try {
        yield* output;
    }
    finally {
        controller.abort();
    }
}
function* mergeSyncSources(syncSources) {
    for (const source of syncSources) {
        yield* source;
    }
}
function merge(...sources) {
    const syncSources = [];
    for (const source of sources) {
        if (!isAsyncIterable(source)) {
            syncSources.push(source);
        }
    }
    if (syncSources.length === sources.length) {
        // all sources are synchronous
        return mergeSyncSources(syncSources);
    }
    return mergeSources(sources);
}
export default merge;
//# sourceMappingURL=index.js.map