From 12b649b914901ea0c92700288e57b68da55aafd4 Mon Sep 17 00:00:00 2001 From: Fathy Boundjadj Date: Wed, 28 Mar 2018 06:23:41 +0200 Subject: [PATCH] Ignore require if it is defined (#975) --- src/visitors/dependencies.js | 30 ++++++++++++++++++++- test/integration/require-scope/index.js | 35 +++++++++++++++++++++++++ test/javascript.js | 24 +++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 test/integration/require-scope/index.js diff --git a/src/visitors/dependencies.js b/src/visitors/dependencies.js index ee49ae88abc..e697db75343 100644 --- a/src/visitors/dependencies.js +++ b/src/visitors/dependencies.js @@ -37,7 +37,8 @@ module.exports = { types.isIdentifier(callee) && callee.name === 'require' && args.length === 1 && - types.isStringLiteral(args[0]); + types.isStringLiteral(args[0]) && + !hasBinding(ancestors, 'require'); if (isRequire) { let optional = ancestors.some(a => types.isTryStatement(a)) || undefined; @@ -88,6 +89,33 @@ module.exports = { } }; +function hasBinding(node, name) { + if (Array.isArray(node)) { + return node.some(ancestor => hasBinding(ancestor, name)); + } else if ( + types.isProgram(node) || + types.isBlockStatement(node) || + types.isBlock(node) + ) { + return node.body.some(statement => hasBinding(statement, name)); + } else if ( + types.isFunctionDeclaration(node) || + types.isFunctionExpression(node) || + types.isArrowFunctionExpression(node) + ) { + return ( + (node.id !== null && node.id.name === name) || + node.params.some( + param => types.isIdentifier(param) && param.name === name + ) + ); + } else if (types.isVariableDeclaration(node)) { + return node.declarations.some(declaration => declaration.id.name === name); + } + + return false; +} + function addDependency(asset, node, opts = {}) { if (asset.options.target !== 'browser') { const isRelativeImport = /^[/~.]/.test(node.value); diff --git a/test/integration/require-scope/index.js b/test/integration/require-scope/index.js new file mode 100644 index 00000000000..6af57ef0e4f --- /dev/null +++ b/test/integration/require-scope/index.js @@ -0,0 +1,35 @@ +const test = { + unaryFnExpr: 'test failed', + fnExpr: 'test failed', + fnDecl: 'test failed', + varDecl: 'test failed', + topVarDecl: 'test failed' +}; + +module.exports.test = test; + +function main(require) { + require('test passed'); +} + +main(x => test.fnDecl = x); + +(function(require) { + require('test passed') +})(x => test.fnExpr = x); + +void function main(require) { + require('test passed'); +}(x => test.unaryFnExpr = x); + +void function main() { + const require = x => test.varDecl = x + + require('test passed') +}() + +function require(x) { + return test.topVarDecl = x; +} + +require('test passed') diff --git a/test/javascript.js b/test/javascript.js index 20ab7533ffd..b512421f3bd 100644 --- a/test/javascript.js +++ b/test/javascript.js @@ -711,4 +711,28 @@ describe('javascript', function() { assert.deepEqual(output, err); }); + + it('should ignore require if it is defined in the scope', async function() { + let b = await bundle(__dirname + '/integration/require-scope/index.js'); + + assertBundleTree(b, { + name: 'index.js', + assets: ['index.js'], + childBundles: [ + { + type: 'map' + } + ] + }); + + let output = run(b); + + assert.equal(typeof output.test, 'object'); + + let failed = Object.keys(output.test).some( + key => output.test[key] !== 'test passed' + ); + + assert.equal(failed, false); + }); });