diff --git a/docs/src/pages/docs/crocks/Async.md b/docs/src/pages/docs/crocks/Async.md index 3a9173bd7..9606b7e39 100644 --- a/docs/src/pages/docs/crocks/Async.md +++ b/docs/src/pages/docs/crocks/Async.md @@ -379,8 +379,17 @@ As such, the need for binding may arise. `fromNode` provides a second, optional argument that takes the context that will be used to bind the function being wrapped. -Any curried interface will not be respected and if a curried interface is needed -then [`nAry`][nary] can be used. +The function returned from `fromNode` will be automatically curried, allowing you +to partially apply the function up to its penultimate parameter[1], so long as the +arity of the original function given to `fromNode` can be determined via its `.length` property. + +In practice this means that functions defined via `compose` or those making use +of `arguments`, spread args (`...args`) or default values for parameters, will not be +good candidates for partial application. + +[1] The final parameter to the incoming function is provided to you by`fromNode` rather +than being part of the parameters that can be partially applied. + diff --git a/src/Async/Async.spec.js b/src/Async/Async.spec.js index 4f963472f..8830622dd 100644 --- a/src/Async/Async.spec.js +++ b/src/Async/Async.spec.js @@ -225,6 +225,21 @@ test('Async fromNode resolution', t => { Async.fromNode(resCPS)(val).fork(rej(val), res(val)) }) +test('Async fromNode partially applied', t => { + t.plan(2) + + const val = 'super fun' + + const rejCPS = (x, y, cf) => cf(x, y) + const resCPS = (x, y, cf) => cf(null, x, y) + + const rej = y => x => t.equal(x, y, 'rejects an erred CPS') + const res = y => x => t.equal(x, y, 'resolves a good CPS') + + Async.fromNode(rejCPS)(val)(val).fork(rej(val), res(val)) + Async.fromNode(resCPS)(val)(val).fork(rej(val), res(val)) +}) + test('Async all', t => { const all = bindFunc(Async.all) diff --git a/src/Async/index.js b/src/Async/index.js index d902de6d4..f72bd2a04 100644 --- a/src/Async/index.js +++ b/src/Async/index.js @@ -48,14 +48,22 @@ function fromNode(fn, ctx) { throw new TypeError('Async.fromNode: CPS function required') } - return (...args) => - Async((reject, resolve) => { + const _fn = curry(fn) + + return (...args) => { + + if (args.length < _fn.length - 1) { + return fromNode(_fn(...args), ctx) + } + + return Async((reject, resolve) => { fn.apply(ctx, args.concat( (err, data) => err ? reject(err) : resolve(data) ) ) }) + } } function fromPromise(fn) {