diff --git a/lib/dependencies/AMDDefineDependencyParserPlugin.js b/lib/dependencies/AMDDefineDependencyParserPlugin.js index c6959acd3..3ecf54b67 100644 --- a/lib/dependencies/AMDDefineDependencyParserPlugin.js +++ b/lib/dependencies/AMDDefineDependencyParserPlugin.js @@ -40,272 +40,275 @@ class AMDDefineDependencyParserPlugin { this.options = options; } - newDefineDependency( - range, - arrayRange, - functionRange, - objectRange, - namedModule - ) { - return new AMDDefineDependency( - range, - arrayRange, - functionRange, - objectRange, - namedModule + apply(parser) { + this.parser = parser; + parser.hooks.call.for("define").tap( + "AMDDefineDependencyParserPlugin", + this.processCallDefine.bind( + Object.create(this, { + parser: { value: parser } + }) + ) ); } - apply(parser) { - const options = this.options; - - const processArray = (expr, param, identifiers, namedModule) => { - if (param.isArray()) { - param.items.forEach((param, idx) => { - if ( - param.isString() && - ["require", "module", "exports"].includes(param.string) - ) - identifiers[idx] = param.string; - const result = processItem(expr, param, namedModule); - if (result === undefined) { - processContext(expr, param); - } - }); - return true; - } else if (param.isConstArray()) { - const deps = []; - param.array.forEach((request, idx) => { - let dep; - let localModule; - if (request === "require") { - identifiers[idx] = request; - dep = "__webpack_require__"; - } else if (["exports", "module"].includes(request)) { - identifiers[idx] = request; - dep = request; - } else if ( - (localModule = LocalModulesHelpers.getLocalModule( - parser.state, - request - )) - ) { - // eslint-disable-line no-cond-assign - dep = new LocalModuleDependency(localModule); - dep.loc = expr.loc; - parser.state.current.addDependency(dep); - } else { - dep = new AMDRequireItemDependency(request); - dep.loc = expr.loc; - dep.optional = !!parser.scope.inTry; - parser.state.current.addDependency(dep); - } - deps.push(dep); - }); - const dep = new AMDRequireArrayDependency(deps, param.range); - dep.loc = expr.loc; - dep.optional = !!parser.scope.inTry; - parser.state.current.addDependency(dep); - return true; - } - }; - const processItem = (expr, param, namedModule) => { - if (param.isConditional()) { - param.options.forEach(param => { - const result = processItem(expr, param); - if (result === undefined) { - processContext(expr, param); - } - }); - return true; - } else if (param.isString()) { - let dep, localModule; - if (param.string === "require") { - dep = new ConstDependency("__webpack_require__", param.range); - } else if (["require", "exports", "module"].includes(param.string)) { - dep = new ConstDependency(param.string, param.range); + processArray(expr, param, identifiers, namedModule) { + const parser = this.parser; + if (param.isArray()) { + param.items.forEach((param, idx) => { + if ( + param.isString() && + ["require", "module", "exports"].includes(param.string) + ) + identifiers[idx] = param.string; + const result = this.processItem(expr, param, namedModule); + if (result === undefined) { + this.processContext(expr, param); + } + }); + return true; + } else if (param.isConstArray()) { + const deps = []; + param.array.forEach((request, idx) => { + let dep; + let localModule; + if (request === "require") { + identifiers[idx] = request; + dep = "__webpack_require__"; + } else if (["exports", "module"].includes(request)) { + identifiers[idx] = request; + dep = request; } else if ( (localModule = LocalModulesHelpers.getLocalModule( parser.state, - param.string, - namedModule + request )) ) { // eslint-disable-line no-cond-assign - dep = new LocalModuleDependency(localModule, param.range); + dep = new LocalModuleDependency(localModule); + dep.loc = expr.loc; + parser.state.current.addDependency(dep); } else { - dep = new AMDRequireItemDependency(param.string, param.range); + dep = this.newRequireItemDependency(request); + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + parser.state.current.addDependency(dep); } - dep.loc = expr.loc; - dep.optional = !!parser.scope.inTry; - parser.state.current.addDependency(dep); - return true; - } - }; - const processContext = (expr, param) => { - const dep = ContextDependencyHelpers.create( - AMDRequireContextDependency, - param.range, - param, - expr, - options - ); - if (!dep) return; + deps.push(dep); + }); + const dep = this.newRequireArrayDependency(deps, param.range); dep.loc = expr.loc; dep.optional = !!parser.scope.inTry; parser.state.current.addDependency(dep); return true; - }; - - parser.hooks.call - .for("define") - .tap("AMDDefineDependencyParserPlugin", expr => { - let array, fn, obj, namedModule; - switch (expr.arguments.length) { - case 1: - if (isCallable(expr.arguments[0])) { - // define(f() {...}) - fn = expr.arguments[0]; - } else if (expr.arguments[0].type === "ObjectExpression") { - // define({...}) - obj = expr.arguments[0]; - } else { - // define(expr) - // unclear if function or object - obj = fn = expr.arguments[0]; - } - break; - case 2: - if (expr.arguments[0].type === "Literal") { - namedModule = expr.arguments[0].value; - // define("...", ...) - if (isCallable(expr.arguments[1])) { - // define("...", f() {...}) - fn = expr.arguments[1]; - } else if (expr.arguments[1].type === "ObjectExpression") { - // define("...", {...}) - obj = expr.arguments[1]; - } else { - // define("...", expr) - // unclear if function or object - obj = fn = expr.arguments[1]; - } - } else { - array = expr.arguments[0]; - if (isCallable(expr.arguments[1])) { - // define([...], f() {}) - fn = expr.arguments[1]; - } else if (expr.arguments[1].type === "ObjectExpression") { - // define([...], {...}) - obj = expr.arguments[1]; - } else { - // define([...], expr) - // unclear if function or object - obj = fn = expr.arguments[1]; - } - } - break; - case 3: - // define("...", [...], f() {...}) - namedModule = expr.arguments[0].value; - array = expr.arguments[1]; - if (isCallable(expr.arguments[2])) { - // define("...", [...], f() {}) - fn = expr.arguments[2]; - } else if (expr.arguments[2].type === "ObjectExpression") { - // define("...", [...], {...}) - obj = expr.arguments[2]; - } else { - // define("...", [...], expr) - // unclear if function or object - obj = fn = expr.arguments[2]; - } - break; - default: - return; + } + } + processItem(expr, param, namedModule) { + const parser = this.parser; + if (param.isConditional()) { + param.options.forEach(param => { + const result = this.processItem(expr, param); + if (result === undefined) { + this.processContext(expr, param); } - let fnParams = null; - let fnParamsOffset = 0; - if (fn) { - if (isUnboundFunctionExpression(fn)) fnParams = fn.params; - else if (isBoundFunctionExpression(fn)) { - fnParams = fn.callee.object.params; - fnParamsOffset = fn.arguments.length - 1; - if (fnParamsOffset < 0) fnParamsOffset = 0; + }); + return true; + } else if (param.isString()) { + let dep, localModule; + if (param.string === "require") { + dep = new ConstDependency("__webpack_require__", param.range); + } else if (["require", "exports", "module"].includes(param.string)) { + dep = new ConstDependency(param.string, param.range); + } else if ( + (localModule = LocalModulesHelpers.getLocalModule( + parser.state, + param.string, + namedModule + )) + ) { + // eslint-disable-line no-cond-assign + dep = new LocalModuleDependency(localModule, param.range); + } else { + dep = this.newRequireItemDependency(param.string, param.range); + } + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + parser.state.current.addDependency(dep); + return true; + } + } + processContext(expr, param) { + const dep = ContextDependencyHelpers.create( + AMDRequireContextDependency, + param.range, + param, + expr, + this.options + ); + if (!dep) return; + dep.loc = expr.loc; + dep.optional = !!this.parser.scope.inTry; + this.parser.state.current.addDependency(dep); + return true; + } + + processCallDefine(expr) { + const parser = this.parser; + let array, fn, obj, namedModule; + switch (expr.arguments.length) { + case 1: + if (isCallable(expr.arguments[0])) { + // define(f() {...}) + fn = expr.arguments[0]; + } else if (expr.arguments[0].type === "ObjectExpression") { + // define({...}) + obj = expr.arguments[0]; + } else { + // define(expr) + // unclear if function or object + obj = fn = expr.arguments[0]; + } + break; + case 2: + if (expr.arguments[0].type === "Literal") { + namedModule = expr.arguments[0].value; + // define("...", ...) + if (isCallable(expr.arguments[1])) { + // define("...", f() {...}) + fn = expr.arguments[1]; + } else if (expr.arguments[1].type === "ObjectExpression") { + // define("...", {...}) + obj = expr.arguments[1]; + } else { + // define("...", expr) + // unclear if function or object + obj = fn = expr.arguments[1]; + } + } else { + array = expr.arguments[0]; + if (isCallable(expr.arguments[1])) { + // define([...], f() {}) + fn = expr.arguments[1]; + } else if (expr.arguments[1].type === "ObjectExpression") { + // define([...], {...}) + obj = expr.arguments[1]; + } else { + // define([...], expr) + // unclear if function or object + obj = fn = expr.arguments[1]; } } - let fnRenames = parser.scope.renames.createChild(); - let identifiers; - if (array) { - identifiers = {}; - const param = parser.evaluateExpression(array); - const result = processArray(expr, param, identifiers, namedModule); - if (!result) return; - if (fnParams) - fnParams = fnParams.slice(fnParamsOffset).filter((param, idx) => { - if (identifiers[idx]) { - fnRenames.set(param.name, identifiers[idx]); - return false; - } - return true; - }); + break; + case 3: + // define("...", [...], f() {...}) + namedModule = expr.arguments[0].value; + array = expr.arguments[1]; + if (isCallable(expr.arguments[2])) { + // define("...", [...], f() {}) + fn = expr.arguments[2]; + } else if (expr.arguments[2].type === "ObjectExpression") { + // define("...", [...], {...}) + obj = expr.arguments[2]; } else { - identifiers = ["require", "exports", "module"]; - if (fnParams) - fnParams = fnParams.slice(fnParamsOffset).filter((param, idx) => { - if (identifiers[idx]) { - fnRenames.set(param.name, identifiers[idx]); - return false; - } - return true; - }); + // define("...", [...], expr) + // unclear if function or object + obj = fn = expr.arguments[2]; } - let inTry; - if (fn && isUnboundFunctionExpression(fn)) { - inTry = parser.scope.inTry; - parser.inScope(fnParams, () => { - parser.scope.renames = fnRenames; - parser.scope.inTry = inTry; - if (fn.body.type === "BlockStatement") - parser.walkStatement(fn.body); - else parser.walkExpression(fn.body); - }); - } else if (fn && isBoundFunctionExpression(fn)) { - inTry = parser.scope.inTry; - parser.inScope( - fn.callee.object.params.filter( - i => !["require", "module", "exports"].includes(i.name) - ), - () => { - parser.scope.renames = fnRenames; - parser.scope.inTry = inTry; - if (fn.callee.object.body.type === "BlockStatement") - parser.walkStatement(fn.callee.object.body); - else parser.walkExpression(fn.callee.object.body); - } - ); - if (fn.arguments) parser.walkExpressions(fn.arguments); - } else if (fn || obj) { - parser.walkExpression(fn || obj); - } - - const dep = this.newDefineDependency( - expr.range, - array ? array.range : null, - fn ? fn.range : null, - obj ? obj.range : null, - namedModule ? namedModule : null - ); - dep.loc = expr.loc; - if (namedModule) { - dep.localModule = LocalModulesHelpers.addLocalModule( - parser.state, - namedModule - ); - } - parser.state.current.addDependency(dep); - return true; + break; + default: + return; + } + let fnParams = null; + let fnParamsOffset = 0; + if (fn) { + if (isUnboundFunctionExpression(fn)) fnParams = fn.params; + else if (isBoundFunctionExpression(fn)) { + fnParams = fn.callee.object.params; + fnParamsOffset = fn.arguments.length - 1; + if (fnParamsOffset < 0) fnParamsOffset = 0; + } + } + let fnRenames = parser.scope.renames.createChild(); + let identifiers; + if (array) { + identifiers = {}; + const param = parser.evaluateExpression(array); + const result = this.processArray(expr, param, identifiers, namedModule); + if (!result) return; + if (fnParams) + fnParams = fnParams.slice(fnParamsOffset).filter((param, idx) => { + if (identifiers[idx]) { + fnRenames.set(param.name, identifiers[idx]); + return false; + } + return true; + }); + } else { + identifiers = ["require", "exports", "module"]; + if (fnParams) + fnParams = fnParams.slice(fnParamsOffset).filter((param, idx) => { + if (identifiers[idx]) { + fnRenames.set(param.name, identifiers[idx]); + return false; + } + return true; + }); + } + let inTry; + if (fn && isUnboundFunctionExpression(fn)) { + inTry = parser.scope.inTry; + parser.inScope(fnParams, () => { + parser.scope.renames = fnRenames; + parser.scope.inTry = inTry; + if (fn.body.type === "BlockStatement") + parser.walkStatement(fn.body); + else parser.walkExpression(fn.body); }); + } else if (fn && isBoundFunctionExpression(fn)) { + inTry = parser.scope.inTry; + parser.inScope( + fn.callee.object.params.filter( + i => !["require", "module", "exports"].includes(i.name) + ), + () => { + parser.scope.renames = fnRenames; + parser.scope.inTry = inTry; + if (fn.callee.object.body.type === "BlockStatement") + parser.walkStatement(fn.callee.object.body); + else parser.walkExpression(fn.callee.object.body); + } + ); + if (fn.arguments) parser.walkExpressions(fn.arguments); + } else if (fn || obj) { + parser.walkExpression(fn || obj); + } + + const dep = this.newDefineDependency( + expr.range, + array ? array.range : null, + fn ? fn.range : null, + obj ? obj.range : null, + namedModule ? namedModule : null + ); + dep.loc = expr.loc; + if (namedModule) { + dep.localModule = LocalModulesHelpers.addLocalModule( + parser.state, + namedModule + ); + } + parser.state.current.addDependency(dep); + return true; + } + + newDefineDependency(...args) { + return new AMDDefineDependency(...args); + } + newRequireArrayDependency(...args) { + return new AMDRequireArrayDependency(...args); + } + newRequireItemDependency(...args) { + return new AMDRequireItemDependency(...args); } } module.exports = AMDDefineDependencyParserPlugin; diff --git a/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js b/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js index 673c86fac..f8afac505 100644 --- a/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js +++ b/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js @@ -46,8 +46,117 @@ class AMDRequireDependenciesBlockParserPlugin { } apply(parser) { - const options = this.options; + this.parser = parser; + parser.hooks.call.for("require").tap( + "AMDRequireDependenciesBlockParserPlugin", + this.processCallRequire.bind( + Object.create(this, { + parser: { value: parser } + }) + ) + ); + } + processArray(expr, param) { + const parser = this.parser; + if (param.isArray()) { + for (const p of param.items) { + const result = this.processItem(expr, p); + if (result === undefined) { + this.processContext(expr, p); + } + } + return true; + } else if (param.isConstArray()) { + const deps = []; + for (const request of param.array) { + let dep, localModule; + if (request === "require") { + dep = "__webpack_require__"; + } else if (["exports", "module"].includes(request)) { + dep = request; + } else if ( + (localModule = LocalModulesHelpers.getLocalModule( + parser.state, + request + )) + ) { + // eslint-disable-line no-cond-assign + dep = new LocalModuleDependency(localModule); + dep.loc = expr.loc; + parser.state.current.addDependency(dep); + } else { + dep = this.newRequireItemDependency(request); + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + parser.state.current.addDependency(dep); + } + deps.push(dep); + } + const dep = this.newRequireArrayDependency(deps, param.range); + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + parser.state.current.addDependency(dep); + return true; + } + } + processItem(expr, param) { + const parser = this.parser; + if (param.isConditional()) { + for (const p of param.options) { + const result = this.processItem(expr, p); + if (result === undefined) { + this.processContext(expr, p); + } + } + return true; + } else if (param.isString()) { + let dep, localModule; + if (param.string === "require") { + dep = new ConstDependency("__webpack_require__", param.string); + } else if (param.string === "module") { + dep = new ConstDependency( + parser.state.module.buildInfo.moduleArgument, + param.range + ); + } else if (param.string === "exports") { + dep = new ConstDependency( + parser.state.module.buildInfo.exportsArgument, + param.range + ); + } else if ( + (localModule = LocalModulesHelpers.getLocalModule( + parser.state, + param.string + )) + ) { + // eslint-disable-line no-cond-assign + dep = new LocalModuleDependency(localModule, param.range); + } else { + dep = this.newRequireItemDependency(param.string, param.range); + } + dep.loc = expr.loc; + dep.optional = !!parser.scope.inTry; + parser.state.current.addDependency(dep); + return true; + } + } + processContext(expr, param) { + const dep = ContextDependencyHelpers.create( + AMDRequireContextDependency, + param.range, + param, + expr, + this.options + ); + if (!dep) return; + dep.loc = expr.loc; + dep.optional = !!this.parser.scope.inTry; + this.parser.state.current.addDependency(dep); + return true; + } + + processCallRequire(expr) { const processArrayForRequestString = param => { if (param.isArray()) { const result = param.items.map(item => @@ -70,172 +179,82 @@ class AMDRequireDependenciesBlockParserPlugin { } }; - const processArray = (expr, param) => { - if (param.isArray()) { - for (const p of param.items) { - const result = processItem(expr, p); - if (result === undefined) { - processContext(expr, p); - } - } - return true; - } else if (param.isConstArray()) { - const deps = []; - for (const request of param.array) { - let dep, localModule; - if (request === "require") { - dep = "__webpack_require__"; - } else if (["exports", "module"].includes(request)) { - dep = request; - } else if ( - (localModule = LocalModulesHelpers.getLocalModule( - parser.state, - request - )) - ) { - // eslint-disable-line no-cond-assign - dep = new LocalModuleDependency(localModule); - dep.loc = expr.loc; - parser.state.current.addDependency(dep); - } else { - dep = new AMDRequireItemDependency(request); - dep.loc = expr.loc; - dep.optional = !!parser.scope.inTry; - parser.state.current.addDependency(dep); - } - deps.push(dep); - } - const dep = new AMDRequireArrayDependency(deps, param.range); - dep.loc = expr.loc; - dep.optional = !!parser.scope.inTry; - parser.state.current.addDependency(dep); - return true; - } - }; - const processItem = (expr, param) => { - if (param.isConditional()) { - for (const p of param.options) { - const result = processItem(expr, p); - if (result === undefined) { - processContext(expr, p); - } - } - return true; - } else if (param.isString()) { - let dep, localModule; - if (param.string === "require") { - dep = new ConstDependency("__webpack_require__", param.string); - } else if (param.string === "module") { - dep = new ConstDependency( - parser.state.module.buildInfo.moduleArgument, - param.range - ); - } else if (param.string === "exports") { - dep = new ConstDependency( - parser.state.module.buildInfo.exportsArgument, - param.range - ); - } else if ( - (localModule = LocalModulesHelpers.getLocalModule( - parser.state, - param.string - )) - ) { - // eslint-disable-line no-cond-assign - dep = new LocalModuleDependency(localModule, param.range); - } else { - dep = new AMDRequireItemDependency(param.string, param.range); - } - dep.loc = expr.loc; - dep.optional = !!parser.scope.inTry; - parser.state.current.addDependency(dep); - return true; - } - }; - const processContext = (expr, param) => { - const dep = ContextDependencyHelpers.create( - AMDRequireContextDependency, - param.range, - param, + let param; + let dep; + let result; + + const parser = this.parser; + const old = parser.state.current; + + if (expr.arguments.length >= 1) { + param = parser.evaluateExpression(expr.arguments[0]); + dep = this.newRequireDependenciesBlock( expr, - options + param.range, + expr.arguments.length > 1 ? expr.arguments[1].range : null, + expr.arguments.length > 2 ? expr.arguments[2].range : null, + parser.state.module, + expr.loc, + processArrayForRequestString(param) ); - if (!dep) return; - dep.loc = expr.loc; - dep.optional = !!parser.scope.inTry; - parser.state.current.addDependency(dep); - return true; - }; + parser.state.current = dep; + } - parser.hooks.call - .for("require") - .tap("AMDRequireDependenciesBlockParserPlugin", expr => { - let param; - let dep; - let result; - - const old = parser.state.current; - - if (expr.arguments.length >= 1) { - param = parser.evaluateExpression(expr.arguments[0]); - dep = new AMDRequireDependenciesBlock( - expr, - param.range, - expr.arguments.length > 1 ? expr.arguments[1].range : null, - expr.arguments.length > 2 ? expr.arguments[2].range : null, - parser.state.module, - expr.loc, - processArrayForRequestString(param) - ); - parser.state.current = dep; - } - - if (expr.arguments.length === 1) { - parser.inScope([], () => { - result = processArray(expr, param); - }); - parser.state.current = old; - if (!result) return; - parser.state.current.addBlock(dep); - return true; - } - - if (expr.arguments.length === 2 || expr.arguments.length === 3) { - try { - parser.inScope([], () => { - result = processArray(expr, param); - }); - if (!result) { - dep = new UnsupportedDependency("unsupported", expr.range); - old.addDependency(dep); - if (parser.state.module) - parser.state.module.errors.push( - new UnsupportedFeatureWarning( - parser.state.module, - "Cannot statically analyse 'require(..., ...)' in line " + - expr.loc.start.line - ) - ); - dep = null; - return true; - } - dep.functionBindThis = this.processFunctionArgument( - parser, - expr.arguments[1] - ); - if (expr.arguments.length === 3) { - dep.errorCallbackBindThis = this.processFunctionArgument( - parser, - expr.arguments[2] - ); - } - } finally { - parser.state.current = old; - if (dep) parser.state.current.addBlock(dep); - } - return true; - } + if (expr.arguments.length === 1) { + parser.inScope([], () => { + result = this.processArray(expr, param); }); + parser.state.current = old; + if (!result) return; + parser.state.current.addBlock(dep); + return true; + } + + if (expr.arguments.length === 2 || expr.arguments.length === 3) { + try { + parser.inScope([], () => { + result = this.processArray(expr, param); + }); + if (!result) { + dep = new UnsupportedDependency("unsupported", expr.range); + old.addDependency(dep); + if (parser.state.module) + parser.state.module.errors.push( + new UnsupportedFeatureWarning( + parser.state.module, + "Cannot statically analyse 'require(..., ...)' in line " + + expr.loc.start.line + ) + ); + dep = null; + return true; + } + dep.functionBindThis = this.processFunctionArgument( + parser, + expr.arguments[1] + ); + if (expr.arguments.length === 3) { + dep.errorCallbackBindThis = this.processFunctionArgument( + parser, + expr.arguments[2] + ); + } + } finally { + parser.state.current = old; + if (dep) parser.state.current.addBlock(dep); + } + return true; + } + } + + newRequireDependenciesBlock(...args) { + return new AMDRequireDependenciesBlock(...args); + } + newRequireItemDependency(...args) { + return new AMDRequireItemDependency(...args); + } + newRequireArrayDependency(...args) { + return new AMDRequireArrayDependency(...args); } } module.exports = AMDRequireDependenciesBlockParserPlugin;