You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
125 lines
2.1 KiB
125 lines
2.1 KiB
/** |
|
* Module Dependencies |
|
*/ |
|
|
|
var noop = function(){}; |
|
var co = require('co'); |
|
|
|
/** |
|
* Export `wrap-fn` |
|
*/ |
|
|
|
module.exports = wrap; |
|
|
|
/** |
|
* Wrap a function to support |
|
* sync, async, and gen functions. |
|
* |
|
* @param {Function} fn |
|
* @param {Function} done |
|
* @return {Function} |
|
* @api public |
|
*/ |
|
|
|
function wrap(fn, done) { |
|
done = once(done || noop); |
|
|
|
return function() { |
|
// prevents arguments leakage |
|
// see https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#3-managing-arguments |
|
var i = arguments.length; |
|
var args = new Array(i); |
|
while (i--) args[i] = arguments[i]; |
|
|
|
var ctx = this; |
|
|
|
// done |
|
if (!fn) { |
|
return done.apply(ctx, [null].concat(args)); |
|
} |
|
|
|
// async |
|
if (fn.length > args.length) { |
|
// NOTE: this only handles uncaught synchronous errors |
|
try { |
|
return fn.apply(ctx, args.concat(done)); |
|
} catch (e) { |
|
return done(e); |
|
} |
|
} |
|
|
|
// generator |
|
if (generator(fn)) { |
|
return co(fn).apply(ctx, args.concat(done)); |
|
} |
|
|
|
// sync |
|
return sync(fn, done).apply(ctx, args); |
|
} |
|
} |
|
|
|
/** |
|
* Wrap a synchronous function execution. |
|
* |
|
* @param {Function} fn |
|
* @param {Function} done |
|
* @return {Function} |
|
* @api private |
|
*/ |
|
|
|
function sync(fn, done) { |
|
return function () { |
|
var ret; |
|
|
|
try { |
|
ret = fn.apply(this, arguments); |
|
} catch (err) { |
|
return done(err); |
|
} |
|
|
|
if (promise(ret)) { |
|
ret.then(function (value) { done(null, value); }, done); |
|
} else { |
|
ret instanceof Error ? done(ret) : done(null, ret); |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* Is `value` a generator? |
|
* |
|
* @param {Mixed} value |
|
* @return {Boolean} |
|
* @api private |
|
*/ |
|
|
|
function generator(value) { |
|
return value |
|
&& value.constructor |
|
&& 'GeneratorFunction' == value.constructor.name; |
|
} |
|
|
|
|
|
/** |
|
* Is `value` a promise? |
|
* |
|
* @param {Mixed} value |
|
* @return {Boolean} |
|
* @api private |
|
*/ |
|
|
|
function promise(value) { |
|
return value && 'function' == typeof value.then; |
|
} |
|
|
|
/** |
|
* Once |
|
*/ |
|
|
|
function once(fn) { |
|
return function() { |
|
var ret = fn.apply(this, arguments); |
|
fn = noop; |
|
return ret; |
|
}; |
|
}
|
|
|