Code coverage report for lib\dependencies\AMDDefineDependencyParserPlugin.js

Statements: 82.25% (139 / 169)      Branches: 76.85% (83 / 108)      Functions: 86.67% (13 / 15)      Lines: 85.99% (135 / 157)      Ignored: none     

All files » lib\dependencies\ » AMDDefineDependencyParserPlugin.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220        1 1 1 1 1 1 1 1   1 252 90 90 90 90 90 90     1 484     1 1 484 484 313 313   72   70 2   2           72   180 70   70   30 40           40       110 110   180     61 61 61 61     313 313 313 311 100 40 40 40     313 313 171 171 171 171 171 182 40 40   142     142 142 180 180 180         313 211 211 211 211 211 211       102 40 40 120   40 40 40 40       40 40 62 62   313 313 313 131   313 313   484 171 161 132 10 132 132       161 10 10 10 50 50 10 10 40 20 20 20         20 20 20 20   50   10 10 10 10 10     484 132               132 132 132 10 122   122 20   102   132 132 132 132     484                    
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
var AMDRequireItemDependency = require("./AMDRequireItemDependency");
var AMDRequireContextDependency = require("./AMDRequireContextDependency");
var ConstDependency = require("./ConstDependency");
var AMDDefineDependency = require("./AMDDefineDependency");
var AMDRequireArrayDependency = require("./AMDRequireArrayDependency");
var LocalModuleDependency = require("./LocalModuleDependency");
var ContextDependencyHelpers = require("./ContextDependencyHelpers");
var LocalModulesHelpers = require("./LocalModulesHelpers");
 
function isBoundFunctionExpression(expr) {
	if(expr.type !== "CallExpression") return false;
	Iif(expr.callee.type !== "MemberExpression") return false;
	Iif(expr.callee.computed) return false;
	Iif(expr.callee.object.type !== "FunctionExpression") return false;
	Iif(expr.callee.property.type !== "Identifier") return false;
	Iif(expr.callee.property.name !== "bind") return false;
	return true;
}
 
function AMDDefineDependencyParserPlugin(options) {
	this.options = options;
}
 
module.exports = AMDDefineDependencyParserPlugin;
AMDDefineDependencyParserPlugin.prototype.apply = function(parser) {
	var options = this.options;
	parser.plugin("call define", function(expr) {
		var array, fn, obj, namedModule;
		switch(expr.arguments.length) {
		case 1:
			if(expr.arguments[0].type === "FunctionExpression" || isBoundFunctionExpression(expr.arguments[0])) {
				// define(f() {...})
				fn = expr.arguments[0];
			} else Eif(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(expr.arguments[1].type === "FunctionExpression" || isBoundFunctionExpression(expr.arguments[0])) {
					// define("...", f() {...})
					fn = expr.arguments[1];
				} else Iif(expr.arguments[1].type === "ObjectExpression") {
					// define("...", {...})
					obj = expr.arguments[1];
				} else {
					// define("...", expr)
					// unclear if function or object
					obj = fn = expr.arguments[1];
				}
			} else {
				// define([...], f() {})
				array = expr.arguments[0];
				fn = expr.arguments[1];
			}
			break;
		case 3:
			// define("...", [...], f() {...})
			namedModule = expr.arguments[0].value;
			array = expr.arguments[1];
			fn = expr.arguments[2];
			break;
		default: return;
		}
		var fnParams = null;
		var fnParamsOffset = 0;
		if(fn) {
			if(fn.type === "FunctionExpression") fnParams = fn.params;
			else if(isBoundFunctionExpression(fn)) {
				fnParams = fn.callee.object.params;
				fnParamsOffset = fn.arguments.length - 1;
				Iif(fnParamsOffset < 0) fnParamsOffset = 0;
			}
		}
		var fnRenames = Object.create(this.scope.renames);
		if(array) {
			var identifiers = {};
			var param = this.evaluateExpression(array);
			var result = this.applyPluginsBailResult("call define:amd:array", expr, param, identifiers);
			Iif(!result) return;
			if(fnParams) fnParams = fnParams.slice(fnParamsOffset).filter(function(param, idx) {
				if(identifiers[idx]) {
					fnRenames["$"+param.name] = identifiers[idx];
					return false;
				}
				return true;
			});
		} else {
			var identifiers = ["require", "exports", "module"];
			if(fnParams) fnParams = fnParams.slice(fnParamsOffset).filter(function(param, idx) {
				Eif(identifiers[idx]) {
					fnRenames["$"+param.name] = identifiers[idx];
					return false;
				}
				return true;
			});
		}
		if(fn && fn.type === "FunctionExpression") {
			var inTry = this.scope.inTry;
			this.inScope(fnParams, function() {
				this.scope.renames = fnRenames;
				this.scope.inTry = inTry;
				Eif(fn.body.type === "BlockStatement")
					this.walkStatement(fn.body);
				else
					this.walkExpression(fn.body);
			}.bind(this));
		} else if(fn && isBoundFunctionExpression(fn)) {
			var inTry = this.scope.inTry;
			this.inScope(fn.callee.object.params.filter(function(i) {
				return ["require", "module", "exports"].indexOf(i.name) < 0;
			}), function() {
				this.scope.renames = fnRenames;
				this.scope.inTry = inTry;
				Eif(fn.callee.object.body.type === "BlockStatement")
					this.walkStatement(fn.callee.object.body);
				else
					this.walkExpression(fn.callee.object.body);
			}.bind(this));
			Eif(fn.arguments)
				this.walkExpressions(fn.arguments);
		} else Eif(fn || obj) {
			this.walkExpression(fn || obj);
		}
		var dep = new AMDDefineDependency(expr.range, array ? array.range : null, fn ? fn.range : null, obj ? obj.range : null);
		dep.loc = expr.loc;
		if(namedModule) {
			dep.localModule = LocalModulesHelpers.addLocalModule(this.state, namedModule);
		}
		this.state.current.addDependency(dep);
		return true;
	});
	parser.plugin("call define:amd:array", function(expr, param, identifiers) {
		if(param.isArray()) {
			param.items.forEach(function(param, idx) {
				if(param.isString() && ["require", "module", "exports"].indexOf(param.string) >= 0)
					identifiers[idx] = param.string;
				var result = this.applyPluginsBailResult("call define:amd:item", expr, param);
				Iif(result === undefined) {
					this.applyPluginsBailResult("call define:amd:context", expr, param);
				}
			}, this);
			return true;
		} else Eif(param.isConstArray()) {
			var deps = [];
			param.array.forEach(function(request, idx) {
				var dep, localModule;
				if(request === "require") {
					identifiers[idx] = request;
					dep = "__webpack_require__";
				} else if(["exports", "module"].indexOf(request) >= 0) {
					identifiers[idx] = request;
					dep = request;
				} else Iif(localModule = LocalModulesHelpers.getLocalModule(this.state, request)) {
					dep = new LocalModuleDependency(localModule);
					dep.loc = expr.loc;
					this.state.current.addDependency(dep);
				} else {
					dep = new AMDRequireItemDependency(request);
					dep.loc = expr.loc;
					dep.optional = !!this.scope.inTry;
					this.state.current.addDependency(dep);
				}
				deps.push(dep);
			}, this);
			var dep = new AMDRequireArrayDependency(deps, param.range);
			dep.loc = expr.loc;
			dep.optional = !!this.scope.inTry;
			this.state.current.addDependency(dep);
			return true;
		}
	});
	parser.plugin("call define:amd:item", function(expr, param) {
		Iif(param.isConditional()) {
			param.options.forEach(function(param) {
				var result = this.applyPluginsBailResult("call define:amd:item", expr, param);
				if(result === undefined) {
					this.applyPluginsBailResult("call define:amd:context", expr, param);
				}
			}, this);
			return true;
		} else Eif(param.isString()) {
			var dep, localModule;
			if(param.string === "require") {
				dep = new ConstDependency("__webpack_require__", param.range);
			} else Iif(["require", "exports", "module"].indexOf(param.string) >= 0) {
				dep = new ConstDependency(param.string, param.range);
			} else if(localModule = LocalModulesHelpers.getLocalModule(this.state, param.string)) {
				dep = new LocalModuleDependency(localModule, param.range);
			} else {
				dep = new AMDRequireItemDependency(param.string, param.range);
			}
			dep.loc = expr.loc;
			dep.optional = !!this.scope.inTry;
			this.state.current.addDependency(dep);
			return true;
		}
	});
	parser.plugin("call define:amd:context", function(expr, param) {
		var dep = ContextDependencyHelpers.create(AMDRequireContextDependency, param.range, param, expr, options);
		if(!dep) return;
		dep.loc = expr.loc;
		dep.optional = !!this.scope.inTry;
		this.state.current.addDependency(dep);
		return true;
	});
};