source: trip-planner-front/node_modules/webpack/lib/dependencies/CommonJsExportsParserPlugin.js@ 1ad8e64

Last change on this file since 1ad8e64 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 10.2 KB
Line 
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 formatLocation = require("../formatLocation");
10const { evaluateToString } = require("../javascript/JavascriptParserHelpers");
11const propertyAccess = require("../util/propertyAccess");
12const CommonJsExportRequireDependency = require("./CommonJsExportRequireDependency");
13const CommonJsExportsDependency = require("./CommonJsExportsDependency");
14const CommonJsSelfReferenceDependency = require("./CommonJsSelfReferenceDependency");
15const DynamicExports = require("./DynamicExports");
16const HarmonyExports = require("./HarmonyExports");
17const ModuleDecoratorDependency = require("./ModuleDecoratorDependency");
18
19/** @typedef {import("estree").Expression} ExpressionNode */
20/** @typedef {import("../NormalModule")} NormalModule */
21/** @typedef {import("../javascript/BasicEvaluatedExpression")} BasicEvaluatedExpression */
22/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
23
24const getValueOfPropertyDescription = expr => {
25 if (expr.type !== "ObjectExpression") return;
26 for (const property of expr.properties) {
27 if (property.computed) continue;
28 const key = property.key;
29 if (key.type !== "Identifier" || key.name !== "value") continue;
30 return property.value;
31 }
32};
33
34const isTruthyLiteral = expr => {
35 switch (expr.type) {
36 case "Literal":
37 return !!expr.value;
38 case "UnaryExpression":
39 if (expr.operator === "!") return isFalsyLiteral(expr.argument);
40 }
41 return false;
42};
43
44const isFalsyLiteral = expr => {
45 switch (expr.type) {
46 case "Literal":
47 return !expr.value;
48 case "UnaryExpression":
49 if (expr.operator === "!") return isTruthyLiteral(expr.argument);
50 }
51 return false;
52};
53
54/**
55 * @param {JavascriptParser} parser the parser
56 * @param {ExpressionNode} expr expression
57 * @returns {{ argument: BasicEvaluatedExpression, ids: string[] } | undefined} parsed call
58 */
59const parseRequireCall = (parser, expr) => {
60 const ids = [];
61 while (expr.type === "MemberExpression") {
62 if (expr.object.type === "Super") return;
63 if (!expr.property) return;
64 const prop = expr.property;
65 if (expr.computed) {
66 if (prop.type !== "Literal") return;
67 ids.push(`${prop.value}`);
68 } else {
69 if (prop.type !== "Identifier") return;
70 ids.push(prop.name);
71 }
72 expr = expr.object;
73 }
74 if (expr.type !== "CallExpression" || expr.arguments.length !== 1) return;
75 const callee = expr.callee;
76 if (
77 callee.type !== "Identifier" ||
78 parser.getVariableInfo(callee.name) !== "require"
79 ) {
80 return;
81 }
82 const arg = expr.arguments[0];
83 if (arg.type === "SpreadElement") return;
84 const argValue = parser.evaluateExpression(arg);
85 return { argument: argValue, ids: ids.reverse() };
86};
87
88class CommonJsExportsParserPlugin {
89 constructor(moduleGraph) {
90 this.moduleGraph = moduleGraph;
91 }
92
93 /**
94 * @param {JavascriptParser} parser the parser
95 */
96 apply(parser) {
97 const enableStructuredExports = () => {
98 DynamicExports.enable(parser.state);
99 };
100 const checkNamespace = (topLevel, members, valueExpr) => {
101 if (!DynamicExports.isEnabled(parser.state)) return;
102 if (members.length > 0 && members[0] === "__esModule") {
103 if (valueExpr && isTruthyLiteral(valueExpr) && topLevel) {
104 DynamicExports.setFlagged(parser.state);
105 } else {
106 DynamicExports.setDynamic(parser.state);
107 }
108 }
109 };
110 const bailout = reason => {
111 DynamicExports.bailout(parser.state);
112 if (reason) bailoutHint(reason);
113 };
114 const bailoutHint = reason => {
115 this.moduleGraph
116 .getOptimizationBailout(parser.state.module)
117 .push(`CommonJS bailout: ${reason}`);
118 };
119
120 // metadata //
121 parser.hooks.evaluateTypeof
122 .for("module")
123 .tap("CommonJsExportsParserPlugin", evaluateToString("object"));
124 parser.hooks.evaluateTypeof
125 .for("exports")
126 .tap("CommonJsPlugin", evaluateToString("object"));
127
128 // exporting //
129 const handleAssignExport = (expr, base, members) => {
130 if (HarmonyExports.isEnabled(parser.state)) return;
131 // Handle reexporting
132 const requireCall = parseRequireCall(parser, expr.right);
133 if (
134 requireCall &&
135 requireCall.argument.isString() &&
136 (members.length === 0 || members[0] !== "__esModule")
137 ) {
138 enableStructuredExports();
139 // It's possible to reexport __esModule, so we must convert to a dynamic module
140 if (members.length === 0) DynamicExports.setDynamic(parser.state);
141 const dep = new CommonJsExportRequireDependency(
142 expr.range,
143 null,
144 base,
145 members,
146 requireCall.argument.string,
147 requireCall.ids,
148 !parser.isStatementLevelExpression(expr)
149 );
150 dep.loc = expr.loc;
151 dep.optional = !!parser.scope.inTry;
152 parser.state.module.addDependency(dep);
153 return true;
154 }
155 if (members.length === 0) return;
156 enableStructuredExports();
157 const remainingMembers = members;
158 checkNamespace(
159 parser.statementPath.length === 1 &&
160 parser.isStatementLevelExpression(expr),
161 remainingMembers,
162 expr.right
163 );
164 const dep = new CommonJsExportsDependency(
165 expr.left.range,
166 null,
167 base,
168 remainingMembers
169 );
170 dep.loc = expr.loc;
171 parser.state.module.addDependency(dep);
172 parser.walkExpression(expr.right);
173 return true;
174 };
175 parser.hooks.assignMemberChain
176 .for("exports")
177 .tap("CommonJsExportsParserPlugin", (expr, members) => {
178 return handleAssignExport(expr, "exports", members);
179 });
180 parser.hooks.assignMemberChain
181 .for("this")
182 .tap("CommonJsExportsParserPlugin", (expr, members) => {
183 if (!parser.scope.topLevelScope) return;
184 return handleAssignExport(expr, "this", members);
185 });
186 parser.hooks.assignMemberChain
187 .for("module")
188 .tap("CommonJsExportsParserPlugin", (expr, members) => {
189 if (members[0] !== "exports") return;
190 return handleAssignExport(expr, "module.exports", members.slice(1));
191 });
192 parser.hooks.call
193 .for("Object.defineProperty")
194 .tap("CommonJsExportsParserPlugin", expression => {
195 const expr = /** @type {import("estree").CallExpression} */ (
196 expression
197 );
198 if (!parser.isStatementLevelExpression(expr)) return;
199 if (expr.arguments.length !== 3) return;
200 if (expr.arguments[0].type === "SpreadElement") return;
201 if (expr.arguments[1].type === "SpreadElement") return;
202 if (expr.arguments[2].type === "SpreadElement") return;
203 const exportsArg = parser.evaluateExpression(expr.arguments[0]);
204 if (!exportsArg || !exportsArg.isIdentifier()) return;
205 if (
206 exportsArg.identifier !== "exports" &&
207 exportsArg.identifier !== "module.exports" &&
208 (exportsArg.identifier !== "this" || !parser.scope.topLevelScope)
209 ) {
210 return;
211 }
212 const propertyArg = parser.evaluateExpression(expr.arguments[1]);
213 if (!propertyArg) return;
214 const property = propertyArg.asString();
215 if (typeof property !== "string") return;
216 enableStructuredExports();
217 const descArg = expr.arguments[2];
218 checkNamespace(
219 parser.statementPath.length === 1,
220 [property],
221 getValueOfPropertyDescription(descArg)
222 );
223 const dep = new CommonJsExportsDependency(
224 expr.range,
225 expr.arguments[2].range,
226 `Object.defineProperty(${exportsArg.identifier})`,
227 [property]
228 );
229 dep.loc = expr.loc;
230 parser.state.module.addDependency(dep);
231
232 parser.walkExpression(expr.arguments[2]);
233 return true;
234 });
235
236 // Self reference //
237 const handleAccessExport = (expr, base, members, call = undefined) => {
238 if (HarmonyExports.isEnabled(parser.state)) return;
239 if (members.length === 0) {
240 bailout(`${base} is used directly at ${formatLocation(expr.loc)}`);
241 }
242 if (call && members.length === 1) {
243 bailoutHint(
244 `${base}${propertyAccess(
245 members
246 )}(...) prevents optimization as ${base} is passed as call context at ${formatLocation(
247 expr.loc
248 )}`
249 );
250 }
251 const dep = new CommonJsSelfReferenceDependency(
252 expr.range,
253 base,
254 members,
255 !!call
256 );
257 dep.loc = expr.loc;
258 parser.state.module.addDependency(dep);
259 if (call) {
260 parser.walkExpressions(call.arguments);
261 }
262 return true;
263 };
264 parser.hooks.callMemberChain
265 .for("exports")
266 .tap("CommonJsExportsParserPlugin", (expr, members) => {
267 return handleAccessExport(expr.callee, "exports", members, expr);
268 });
269 parser.hooks.expressionMemberChain
270 .for("exports")
271 .tap("CommonJsExportsParserPlugin", (expr, members) => {
272 return handleAccessExport(expr, "exports", members);
273 });
274 parser.hooks.expression
275 .for("exports")
276 .tap("CommonJsExportsParserPlugin", expr => {
277 return handleAccessExport(expr, "exports", []);
278 });
279 parser.hooks.callMemberChain
280 .for("module")
281 .tap("CommonJsExportsParserPlugin", (expr, members) => {
282 if (members[0] !== "exports") return;
283 return handleAccessExport(
284 expr.callee,
285 "module.exports",
286 members.slice(1),
287 expr
288 );
289 });
290 parser.hooks.expressionMemberChain
291 .for("module")
292 .tap("CommonJsExportsParserPlugin", (expr, members) => {
293 if (members[0] !== "exports") return;
294 return handleAccessExport(expr, "module.exports", members.slice(1));
295 });
296 parser.hooks.expression
297 .for("module.exports")
298 .tap("CommonJsExportsParserPlugin", expr => {
299 return handleAccessExport(expr, "module.exports", []);
300 });
301 parser.hooks.callMemberChain
302 .for("this")
303 .tap("CommonJsExportsParserPlugin", (expr, members) => {
304 if (!parser.scope.topLevelScope) return;
305 return handleAccessExport(expr.callee, "this", members, expr);
306 });
307 parser.hooks.expressionMemberChain
308 .for("this")
309 .tap("CommonJsExportsParserPlugin", (expr, members) => {
310 if (!parser.scope.topLevelScope) return;
311 return handleAccessExport(expr, "this", members);
312 });
313 parser.hooks.expression
314 .for("this")
315 .tap("CommonJsExportsParserPlugin", expr => {
316 if (!parser.scope.topLevelScope) return;
317 return handleAccessExport(expr, "this", []);
318 });
319
320 // Bailouts //
321 parser.hooks.expression.for("module").tap("CommonJsPlugin", expr => {
322 bailout();
323 const isHarmony = HarmonyExports.isEnabled(parser.state);
324 const dep = new ModuleDecoratorDependency(
325 isHarmony
326 ? RuntimeGlobals.harmonyModuleDecorator
327 : RuntimeGlobals.nodeModuleDecorator,
328 !isHarmony
329 );
330 dep.loc = expr.loc;
331 parser.state.module.addDependency(dep);
332 return true;
333 });
334 }
335}
336module.exports = CommonJsExportsParserPlugin;
Note: See TracBrowser for help on using the repository browser.