Website/node_modules/wrap-fn/index.js
2015-12-02 18:21:44 -05:00

126 lines
2.1 KiB
JavaScript

/**
* 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;
};
}