src/await/makeAwaitFunc.js
function getExtraInfo(traverse, topN) {
    return function await() {
        // Ensure this function is executing inside a fiber.
        if (!Fiber.current) {
            throw new Error('await functions, yield functions, and value-returning suspendable ' +
                'functions may only be called from inside a suspendable function. ');
        }
        // Parse argument(s). If not a single argument, treat it like an array was passed in.
        if (arguments.length === 1) {
            var expr = arguments[0];
        }
        else {
            expr = new Array(arguments.length);
            for (var i = 0; i < arguments.length; ++i)
                expr[i] = arguments[i];
            traverse = traverseInPlace;
        }
        // Handle each supported 'awaitable' appropriately...
        var fiber = Fiber.current;
        if (expr && _.isFunction(expr.then)) {
            // A promise: resume the coroutine with the resolved value, or throw the rejection value into it.
            // NB: ensure the handlers return null to avoid bluebird 3.x warning 'a promise was created in a
            //     handler but none were returned from it'. This occurs if the next resumption of the suspendable
            //     function (i.e. in the client's code) creates a bluebird 3.x promise and then awaits it.
            expr.then(function (val) { return (fiber.run(val), fiber = null); }, function (err) { return (fiber.throwInto(err), fiber = null); });
        }
        else if (_.isFunction(expr)) {
            // A thunk: resume the coroutine with the callback value, or throw the errback value into it.
            expr(function (err, val) { if (err)
                fiber.throwInto(err);
            else
                fiber.run(val); fiber = null; });
        }
        else if (_.isArray(expr) || _.isPlainObject(expr)) {
            // An array or plain object: resume the coroutine with a deep clone of the array/object,
            // where all contained promises and thunks have been replaced by their resolved values.
            // NB: ensure handlers return null (see similar comment above).
            var trackedPromises = [];
            expr = traverse(expr, trackAndReplaceWithResolvedValue(trackedPromises));
            if (!topN) {
                Promise.all(trackedPromises).then(function (val) { return (fiber.run(expr), fiber = null); }, function (err) { return (fiber.throwInto(err), fiber = null); });
            }
            else {
                Promise.some(trackedPromises, topN).then(function (val) { return (fiber.run(val), fiber = null); }, function (err) { return (fiber.throwInto(err), fiber = null); });
            }
        }
        else {
            // Anything else: resume the coroutine immediately with the value.
            setImmediate(function () { fiber.run(expr); fiber = null; });
        }
        // Suspend the current fiber until the one of the above handlers resumes it again.
        return Fiber.yield();
    };
}
function getExtraInfo(traverse, topN) {
    return function await() {
        // Ensure this function is executing inside a fiber.
        if (!Fiber.current) {
            throw new Error('await functions, yield functions, and value-returning suspendable ' +
                'functions may only be called from inside a suspendable function. ');
        }
        // Parse argument(s). If not a single argument, treat it like an array was passed in.
        if (arguments.length === 1) {
            var expr = arguments[0];
        }
        else {
            expr = new Array(arguments.length);
            for (var i = 0; i < arguments.length; ++i)
                expr[i] = arguments[i];
            traverse = traverseInPlace;
        }
        // Handle each supported 'awaitable' appropriately...
        var fiber = Fiber.current;
        if (expr && _.isFunction(expr.then)) {
            // A promise: resume the coroutine with the resolved value, or throw the rejection value into it.
            // NB: ensure the handlers return null to avoid bluebird 3.x warning 'a promise was created in a
            //     handler but none were returned from it'. This occurs if the next resumption of the suspendable
            //     function (i.e. in the client's code) creates a bluebird 3.x promise and then awaits it.
            expr.then(function (val) { return (fiber.run(val), fiber = null); }, function (err) { return (fiber.throwInto(err), fiber = null); });
        }
        else if (_.isFunction(expr)) {
            // A thunk: resume the coroutine with the callback value, or throw the errback value into it.
            expr(function (err, val) { if (err)
                fiber.throwInto(err);
            else
                fiber.run(val); fiber = null; });
        }
        else if (_.isArray(expr) || _.isPlainObject(expr)) {
            // An array or plain object: resume the coroutine with a deep clone of the array/object,
            // where all contained promises and thunks have been replaced by their resolved values.
            // NB: ensure handlers return null (see similar comment above).
            var trackedPromises = [];
            expr = traverse(expr, trackAndReplaceWithResolvedValue(trackedPromises));
            if (!topN) {
                Promise.all(trackedPromises).then(function (val) { return (fiber.run(expr), fiber = null); }, function (err) { return (fiber.throwInto(err), fiber = null); });
            }
            else {
                Promise.some(trackedPromises, topN).then(function (val) { return (fiber.run(val), fiber = null); }, function (err) { return (fiber.throwInto(err), fiber = null); });
            }
        }
        else {
            // Anything else: resume the coroutine immediately with the value.
            setImmediate(function () { fiber.run(expr); fiber = null; });
        }
        // Suspend the current fiber until the one of the above handlers resumes it again.
        return Fiber.yield();
    };
}
Helper function for makeAwaitFunc().