UNPKG

7.78 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const RuntimeGlobals = require("../RuntimeGlobals");
9const UnsupportedFeatureWarning = require("../UnsupportedFeatureWarning");
10const AMDRequireArrayDependency = require("./AMDRequireArrayDependency");
11const AMDRequireContextDependency = require("./AMDRequireContextDependency");
12const AMDRequireDependenciesBlock = require("./AMDRequireDependenciesBlock");
13const AMDRequireDependency = require("./AMDRequireDependency");
14const AMDRequireItemDependency = require("./AMDRequireItemDependency");
15const ConstDependency = require("./ConstDependency");
16const ContextDependencyHelpers = require("./ContextDependencyHelpers");
17const LocalModuleDependency = require("./LocalModuleDependency");
18const { getLocalModule } = require("./LocalModulesHelpers");
19const UnsupportedDependency = require("./UnsupportedDependency");
20const getFunctionExpression = require("./getFunctionExpression");
21
22class AMDRequireDependenciesBlockParserPlugin {
23 constructor(options) {
24 this.options = options;
25 }
26
27 processFunctionArgument(parser, expression) {
28 let bindThis = true;
29 const fnData = getFunctionExpression(expression);
30 if (fnData) {
31 parser.inScope(
32 fnData.fn.params.filter(i => {
33 return !["require", "module", "exports"].includes(i.name);
34 }),
35 () => {
36 if (fnData.fn.body.type === "BlockStatement") {
37 parser.walkStatement(fnData.fn.body);
38 } else {
39 parser.walkExpression(fnData.fn.body);
40 }
41 }
42 );
43 parser.walkExpressions(fnData.expressions);
44 if (fnData.needThis === false) {
45 bindThis = false;
46 }
47 } else {
48 parser.walkExpression(expression);
49 }
50 return bindThis;
51 }
52
53 apply(parser) {
54 parser.hooks.call
55 .for("require")
56 .tap(
57 "AMDRequireDependenciesBlockParserPlugin",
58 this.processCallRequire.bind(this, parser)
59 );
60 }
61
62 processArray(parser, expr, param) {
63 if (param.isArray()) {
64 for (const p of param.items) {
65 const result = this.processItem(parser, expr, p);
66 if (result === undefined) {
67 this.processContext(parser, expr, p);
68 }
69 }
70 return true;
71 } else if (param.isConstArray()) {
72 const deps = [];
73 for (const request of param.array) {
74 let dep, localModule;
75 if (request === "require") {
76 dep = "__webpack_require__";
77 } else if (["exports", "module"].includes(request)) {
78 dep = request;
79 } else if ((localModule = getLocalModule(parser.state, request))) {
80 localModule.flagUsed();
81 dep = new LocalModuleDependency(localModule, undefined, false);
82 dep.loc = expr.loc;
83 parser.state.module.addPresentationalDependency(dep);
84 } else {
85 dep = this.newRequireItemDependency(request);
86 dep.loc = expr.loc;
87 dep.optional = !!parser.scope.inTry;
88 parser.state.current.addDependency(dep);
89 }
90 deps.push(dep);
91 }
92 const dep = this.newRequireArrayDependency(deps, param.range);
93 dep.loc = expr.loc;
94 dep.optional = !!parser.scope.inTry;
95 parser.state.module.addPresentationalDependency(dep);
96 return true;
97 }
98 }
99 processItem(parser, expr, param) {
100 if (param.isConditional()) {
101 for (const p of param.options) {
102 const result = this.processItem(parser, expr, p);
103 if (result === undefined) {
104 this.processContext(parser, expr, p);
105 }
106 }
107 return true;
108 } else if (param.isString()) {
109 let dep, localModule;
110 if (param.string === "require") {
111 dep = new ConstDependency("__webpack_require__", param.string, [
112 RuntimeGlobals.require
113 ]);
114 } else if (param.string === "module") {
115 dep = new ConstDependency(
116 parser.state.module.buildInfo.moduleArgument,
117 param.range,
118 [RuntimeGlobals.module]
119 );
120 } else if (param.string === "exports") {
121 dep = new ConstDependency(
122 parser.state.module.buildInfo.exportsArgument,
123 param.range,
124 [RuntimeGlobals.exports]
125 );
126 } else if ((localModule = getLocalModule(parser.state, param.string))) {
127 localModule.flagUsed();
128 dep = new LocalModuleDependency(localModule, param.range, false);
129 } else {
130 dep = this.newRequireItemDependency(param.string, param.range);
131 dep.loc = expr.loc;
132 dep.optional = !!parser.scope.inTry;
133 parser.state.current.addDependency(dep);
134 return true;
135 }
136 dep.loc = expr.loc;
137 parser.state.module.addPresentationalDependency(dep);
138 return true;
139 }
140 }
141 processContext(parser, expr, param) {
142 const dep = ContextDependencyHelpers.create(
143 AMDRequireContextDependency,
144 param.range,
145 param,
146 expr,
147 this.options,
148 {
149 category: "amd"
150 },
151 parser
152 );
153 if (!dep) return;
154 dep.loc = expr.loc;
155 dep.optional = !!parser.scope.inTry;
156 parser.state.current.addDependency(dep);
157 return true;
158 }
159
160 processArrayForRequestString(param) {
161 if (param.isArray()) {
162 const result = param.items.map(item =>
163 this.processItemForRequestString(item)
164 );
165 if (result.every(Boolean)) return result.join(" ");
166 } else if (param.isConstArray()) {
167 return param.array.join(" ");
168 }
169 }
170
171 processItemForRequestString(param) {
172 if (param.isConditional()) {
173 const result = param.options.map(item =>
174 this.processItemForRequestString(item)
175 );
176 if (result.every(Boolean)) return result.join("|");
177 } else if (param.isString()) {
178 return param.string;
179 }
180 }
181
182 processCallRequire(parser, expr) {
183 let param;
184 let depBlock;
185 let dep;
186 let result;
187
188 const old = parser.state.current;
189
190 if (expr.arguments.length >= 1) {
191 param = parser.evaluateExpression(expr.arguments[0]);
192 depBlock = this.newRequireDependenciesBlock(
193 expr.loc,
194 this.processArrayForRequestString(param)
195 );
196 dep = this.newRequireDependency(
197 expr.range,
198 param.range,
199 expr.arguments.length > 1 ? expr.arguments[1].range : null,
200 expr.arguments.length > 2 ? expr.arguments[2].range : null
201 );
202 dep.loc = expr.loc;
203 depBlock.addDependency(dep);
204
205 parser.state.current = depBlock;
206 }
207
208 if (expr.arguments.length === 1) {
209 parser.inScope([], () => {
210 result = this.processArray(parser, expr, param);
211 });
212 parser.state.current = old;
213 if (!result) return;
214 parser.state.current.addBlock(depBlock);
215 return true;
216 }
217
218 if (expr.arguments.length === 2 || expr.arguments.length === 3) {
219 try {
220 parser.inScope([], () => {
221 result = this.processArray(parser, expr, param);
222 });
223 if (!result) {
224 const dep = new UnsupportedDependency("unsupported", expr.range);
225 old.addPresentationalDependency(dep);
226 if (parser.state.module) {
227 parser.state.module.addError(
228 new UnsupportedFeatureWarning(
229 "Cannot statically analyse 'require(…, …)' in line " +
230 expr.loc.start.line,
231 expr.loc
232 )
233 );
234 }
235 depBlock = null;
236 return true;
237 }
238 dep.functionBindThis = this.processFunctionArgument(
239 parser,
240 expr.arguments[1]
241 );
242 if (expr.arguments.length === 3) {
243 dep.errorCallbackBindThis = this.processFunctionArgument(
244 parser,
245 expr.arguments[2]
246 );
247 }
248 } finally {
249 parser.state.current = old;
250 if (depBlock) parser.state.current.addBlock(depBlock);
251 }
252 return true;
253 }
254 }
255
256 newRequireDependenciesBlock(loc, request) {
257 return new AMDRequireDependenciesBlock(loc, request);
258 }
259 newRequireDependency(
260 outerRange,
261 arrayRange,
262 functionRange,
263 errorCallbackRange
264 ) {
265 return new AMDRequireDependency(
266 outerRange,
267 arrayRange,
268 functionRange,
269 errorCallbackRange
270 );
271 }
272 newRequireItemDependency(request, range) {
273 return new AMDRequireItemDependency(request, range);
274 }
275 newRequireArrayDependency(depsArray, range) {
276 return new AMDRequireArrayDependency(depsArray, range);
277 }
278}
279module.exports = AMDRequireDependenciesBlockParserPlugin;