diff --git a/index.js b/index.js index f244765..a3240b3 100644 --- a/index.js +++ b/index.js @@ -9,6 +9,7 @@ */ var eventListenerCount = require('./lib/compat').eventListenerCount +var wrapFunctionInner = require('./lib/compat').wrapFunctionInner var relative = require('path').relative /** @@ -65,20 +66,6 @@ function convertDataDescriptorToAccessor (obj, prop, message) { return descriptor } -/** - * Create arguments string to keep arity. - */ - -function createArgumentsString (arity) { - var str = '' - - for (var i = 0; i < arity; i++) { - str += ', arg' + i - } - - return str.substr(2) -} - /** * Create stack string from stack. */ @@ -398,21 +385,13 @@ function wrapfunction (fn, message) { throw new TypeError('argument fn must be a function') } - var args = createArgumentsString(fn.length) + var deprecate = this var stack = getStack() var site = callSiteLocation(stack[1]) site.name = fn.name - // eslint-disable-next-line no-new-func - var deprecatedfn = new Function('fn', 'log', 'deprecate', 'message', 'site', - '"use strict"\n' + - 'return function (' + args + ') {' + - 'log.call(deprecate, message, site)\n' + - 'return fn.apply(this, arguments)\n' + - '}')(fn, log, this, message, site) - - return deprecatedfn + return wrapFunctionInner(fn, log, deprecate, message, site) } /** diff --git a/lib/compat/index.js b/lib/compat/index.js index 181550c..0936b57 100644 --- a/lib/compat/index.js +++ b/lib/compat/index.js @@ -22,6 +22,10 @@ lazyProperty(module.exports, 'eventListenerCount', function eventListenerCount ( return EventEmitter.listenerCount || require('./event-listener-count') }) +lazyProperty(module.exports, 'wrapFunctionInner', function wrapFunctionInner () { + return require('./wrap-function-inner') +}) + /** * Define a lazy property. */ diff --git a/lib/compat/wrap-function-inner.js b/lib/compat/wrap-function-inner.js new file mode 100644 index 0000000..16ed457 --- /dev/null +++ b/lib/compat/wrap-function-inner.js @@ -0,0 +1,72 @@ +/*! + * depd + * Copyright(c) 2014-2018 Douglas Christopher Wilson + * MIT Licensed + */ + +'use strict' + +function canUseDefinePropertyOnFunctionLength () { + function detectfn () {} + + try { + // Node.js 3.3+. + Object.defineProperty(detectfn, 'length', { + configurable: true, + enumerable: false, + value: 1, + writable: false + }) + } catch (err) { + // Likely Node.js 2.5 or older. + } + + return detectfn.length === 1 +} + +/** + * Create arguments string to keep arity. + */ + +function createArgumentsString (arity) { + var str = '' + + for (var i = 0; i < arity; i++) { + str += ', arg' + i + } + + return str.substr(2) +} + +function wrapFunctionWithDefineProperty (fn, log, deprecate, message, site) { + var deprecatedfn = function () { + log.call(deprecate, message, site) + return fn.apply(this, arguments) + } + + // Preserve fn's arity. + Object.defineProperty(deprecatedfn, 'length', { + configurable: true, + enumerable: false, + value: fn.length, + writable: false + }) + + return deprecatedfn +} + +function wrapFunctionWithEval (fn, log, deprecate, message, site) { + // Preserve fn's arity by manually constructing an arguments string and + // eval'ing it into a new function. + var args = createArgumentsString(fn.length) + // eslint-disable-next-line no-new-func + return new Function('fn', 'log', 'deprecate', 'message', 'site', + '"use strict"\n' + + 'return function (' + args + ') {' + + 'log.call(deprecate, message, site)\n' + + 'return fn.apply(this, arguments)\n' + + '}')(fn, log, deprecate, message, site) +} + +module.exports = canUseDefinePropertyOnFunctionLength() + ? wrapFunctionWithDefineProperty : wrapFunctionWithEval