diff --git a/index.js b/index.js index 382d701a9..70cfc704a 100644 --- a/index.js +++ b/index.js @@ -49,6 +49,7 @@ exports.find = function (src, opts) { function visit(node, st, c) { var hasRequire = wordRe.test(src.slice(node.start, node.end)); if (!hasRequire) return; + if (isBundledDefinition(node)) return; walk.base[node.type](node, st, c); if (node.type !== 'CallExpression') return; if (isRequire(node)) { @@ -75,6 +76,20 @@ exports.find = function (src, opts) { Statement: visit, Expression: visit }); + + // Detect `require` redefinitions in function parameter lists, like + // in `{0:[function(require,module,exports){` generated by browser-pack. + // This is a simple way to address the 99% case without doing full scope analysis + function isBundledDefinition(node) { + if (node.type !== 'ObjectExpression') return false; + if (node.properties.length < 1) return false; + var arr = node.properties[0].value; + if (arr.type !== 'ArrayExpression') return false; + if (arr.elements.length < 2) return false; + if (arr.elements[0].type !== 'FunctionExpression') return false; + var fn = arr.elements[0]; + return fn.params.length > 0 && fn.params[0].type === 'Identifier' && fn.params[0].name === word; + } return modules; }; diff --git a/test/files/scope.js b/test/files/scope.js new file mode 100644 index 000000000..b94d787ac --- /dev/null +++ b/test/files/scope.js @@ -0,0 +1,12 @@ +(function(modules){ + modules[1](function(i){return modules[i]()}) +})({1:[function (require,module,exports) { + require('./y') // inside a bundle; should not be detected +},{'./y':2}],2:function(require,module,exports){ + console.log("abc") +}}) + +(function (require) { + require('./x'); // not inside a bundle; should be detected +}(require)); // (because someone might do this) +require('./z') diff --git a/test/scope.js b/test/scope.js new file mode 100644 index 000000000..3ffebca02 --- /dev/null +++ b/test/scope.js @@ -0,0 +1,9 @@ +var test = require('tap').test; +var detective = require('../'); +var fs = require('fs'); +var src = fs.readFileSync(__dirname + '/files/scope.js'); + +test('scope', function (t) { + t.plan(1); + t.deepEqual(detective(src), [ './x', './z' ]); +});