| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 | 
							- /*
 
- 	MIT License http://www.opensource.org/licenses/mit-license.php
 
- 	Author Tobias Koppers @sokra
 
- */
 
- "use strict";
 
- const RuntimeGlobals = require("../RuntimeGlobals");
 
- const formatLocation = require("../formatLocation");
 
- const { evaluateToString } = require("../javascript/JavascriptParserHelpers");
 
- const propertyAccess = require("../util/propertyAccess");
 
- const CommonJsExportRequireDependency = require("./CommonJsExportRequireDependency");
 
- const CommonJsExportsDependency = require("./CommonJsExportsDependency");
 
- const CommonJsSelfReferenceDependency = require("./CommonJsSelfReferenceDependency");
 
- const DynamicExports = require("./DynamicExports");
 
- const HarmonyExports = require("./HarmonyExports");
 
- const ModuleDecoratorDependency = require("./ModuleDecoratorDependency");
 
- /** @typedef {import("estree").Expression} ExpressionNode */
 
- /** @typedef {import("../NormalModule")} NormalModule */
 
- /** @typedef {import("../javascript/BasicEvaluatedExpression")} BasicEvaluatedExpression */
 
- /** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
 
- const getValueOfPropertyDescription = expr => {
 
- 	if (expr.type !== "ObjectExpression") return;
 
- 	for (const property of expr.properties) {
 
- 		if (property.computed) continue;
 
- 		const key = property.key;
 
- 		if (key.type !== "Identifier" || key.name !== "value") continue;
 
- 		return property.value;
 
- 	}
 
- };
 
- const isTruthyLiteral = expr => {
 
- 	switch (expr.type) {
 
- 		case "Literal":
 
- 			return !!expr.value;
 
- 		case "UnaryExpression":
 
- 			if (expr.operator === "!") return isFalsyLiteral(expr.argument);
 
- 	}
 
- 	return false;
 
- };
 
- const isFalsyLiteral = expr => {
 
- 	switch (expr.type) {
 
- 		case "Literal":
 
- 			return !expr.value;
 
- 		case "UnaryExpression":
 
- 			if (expr.operator === "!") return isTruthyLiteral(expr.argument);
 
- 	}
 
- 	return false;
 
- };
 
- /**
 
-  * @param {JavascriptParser} parser the parser
 
-  * @param {ExpressionNode} expr expression
 
-  * @returns {{ argument: BasicEvaluatedExpression, ids: string[] } | undefined} parsed call
 
-  */
 
- const parseRequireCall = (parser, expr) => {
 
- 	const ids = [];
 
- 	while (expr.type === "MemberExpression") {
 
- 		if (expr.object.type === "Super") return;
 
- 		if (!expr.property) return;
 
- 		const prop = expr.property;
 
- 		if (expr.computed) {
 
- 			if (prop.type !== "Literal") return;
 
- 			ids.push(`${prop.value}`);
 
- 		} else {
 
- 			if (prop.type !== "Identifier") return;
 
- 			ids.push(prop.name);
 
- 		}
 
- 		expr = expr.object;
 
- 	}
 
- 	if (expr.type !== "CallExpression" || expr.arguments.length !== 1) return;
 
- 	const callee = expr.callee;
 
- 	if (
 
- 		callee.type !== "Identifier" ||
 
- 		parser.getVariableInfo(callee.name) !== "require"
 
- 	) {
 
- 		return;
 
- 	}
 
- 	const arg = expr.arguments[0];
 
- 	if (arg.type === "SpreadElement") return;
 
- 	const argValue = parser.evaluateExpression(arg);
 
- 	return { argument: argValue, ids: ids.reverse() };
 
- };
 
- class CommonJsExportsParserPlugin {
 
- 	constructor(moduleGraph) {
 
- 		this.moduleGraph = moduleGraph;
 
- 	}
 
- 	/**
 
- 	 * @param {JavascriptParser} parser the parser
 
- 	 */
 
- 	apply(parser) {
 
- 		const enableStructuredExports = () => {
 
- 			DynamicExports.enable(parser.state);
 
- 		};
 
- 		const checkNamespace = (topLevel, members, valueExpr) => {
 
- 			if (!DynamicExports.isEnabled(parser.state)) return;
 
- 			if (members.length > 0 && members[0] === "__esModule") {
 
- 				if (valueExpr && isTruthyLiteral(valueExpr) && topLevel) {
 
- 					DynamicExports.setFlagged(parser.state);
 
- 				} else {
 
- 					DynamicExports.setDynamic(parser.state);
 
- 				}
 
- 			}
 
- 		};
 
- 		const bailout = reason => {
 
- 			DynamicExports.bailout(parser.state);
 
- 			if (reason) bailoutHint(reason);
 
- 		};
 
- 		const bailoutHint = reason => {
 
- 			this.moduleGraph
 
- 				.getOptimizationBailout(parser.state.module)
 
- 				.push(`CommonJS bailout: ${reason}`);
 
- 		};
 
- 		// metadata //
 
- 		parser.hooks.evaluateTypeof
 
- 			.for("module")
 
- 			.tap("CommonJsExportsParserPlugin", evaluateToString("object"));
 
- 		parser.hooks.evaluateTypeof
 
- 			.for("exports")
 
- 			.tap("CommonJsPlugin", evaluateToString("object"));
 
- 		// exporting //
 
- 		const handleAssignExport = (expr, base, members) => {
 
- 			if (HarmonyExports.isEnabled(parser.state)) return;
 
- 			// Handle reexporting
 
- 			const requireCall = parseRequireCall(parser, expr.right);
 
- 			if (
 
- 				requireCall &&
 
- 				requireCall.argument.isString() &&
 
- 				(members.length === 0 || members[0] !== "__esModule")
 
- 			) {
 
- 				enableStructuredExports();
 
- 				// It's possible to reexport __esModule, so we must convert to a dynamic module
 
- 				if (members.length === 0) DynamicExports.setDynamic(parser.state);
 
- 				const dep = new CommonJsExportRequireDependency(
 
- 					expr.range,
 
- 					null,
 
- 					base,
 
- 					members,
 
- 					requireCall.argument.string,
 
- 					requireCall.ids,
 
- 					!parser.isStatementLevelExpression(expr)
 
- 				);
 
- 				dep.loc = expr.loc;
 
- 				dep.optional = !!parser.scope.inTry;
 
- 				parser.state.module.addDependency(dep);
 
- 				return true;
 
- 			}
 
- 			if (members.length === 0) return;
 
- 			enableStructuredExports();
 
- 			const remainingMembers = members;
 
- 			checkNamespace(
 
- 				parser.statementPath.length === 1 &&
 
- 					parser.isStatementLevelExpression(expr),
 
- 				remainingMembers,
 
- 				expr.right
 
- 			);
 
- 			const dep = new CommonJsExportsDependency(
 
- 				expr.left.range,
 
- 				null,
 
- 				base,
 
- 				remainingMembers
 
- 			);
 
- 			dep.loc = expr.loc;
 
- 			parser.state.module.addDependency(dep);
 
- 			parser.walkExpression(expr.right);
 
- 			return true;
 
- 		};
 
- 		parser.hooks.assignMemberChain
 
- 			.for("exports")
 
- 			.tap("CommonJsExportsParserPlugin", (expr, members) => {
 
- 				return handleAssignExport(expr, "exports", members);
 
- 			});
 
- 		parser.hooks.assignMemberChain
 
- 			.for("this")
 
- 			.tap("CommonJsExportsParserPlugin", (expr, members) => {
 
- 				if (!parser.scope.topLevelScope) return;
 
- 				return handleAssignExport(expr, "this", members);
 
- 			});
 
- 		parser.hooks.assignMemberChain
 
- 			.for("module")
 
- 			.tap("CommonJsExportsParserPlugin", (expr, members) => {
 
- 				if (members[0] !== "exports") return;
 
- 				return handleAssignExport(expr, "module.exports", members.slice(1));
 
- 			});
 
- 		parser.hooks.call
 
- 			.for("Object.defineProperty")
 
- 			.tap("CommonJsExportsParserPlugin", expression => {
 
- 				const expr = /** @type {import("estree").CallExpression} */ (
 
- 					expression
 
- 				);
 
- 				if (!parser.isStatementLevelExpression(expr)) return;
 
- 				if (expr.arguments.length !== 3) return;
 
- 				if (expr.arguments[0].type === "SpreadElement") return;
 
- 				if (expr.arguments[1].type === "SpreadElement") return;
 
- 				if (expr.arguments[2].type === "SpreadElement") return;
 
- 				const exportsArg = parser.evaluateExpression(expr.arguments[0]);
 
- 				if (!exportsArg.isIdentifier()) return;
 
- 				if (
 
- 					exportsArg.identifier !== "exports" &&
 
- 					exportsArg.identifier !== "module.exports" &&
 
- 					(exportsArg.identifier !== "this" || !parser.scope.topLevelScope)
 
- 				) {
 
- 					return;
 
- 				}
 
- 				const propertyArg = parser.evaluateExpression(expr.arguments[1]);
 
- 				const property = propertyArg.asString();
 
- 				if (typeof property !== "string") return;
 
- 				enableStructuredExports();
 
- 				const descArg = expr.arguments[2];
 
- 				checkNamespace(
 
- 					parser.statementPath.length === 1,
 
- 					[property],
 
- 					getValueOfPropertyDescription(descArg)
 
- 				);
 
- 				const dep = new CommonJsExportsDependency(
 
- 					expr.range,
 
- 					expr.arguments[2].range,
 
- 					`Object.defineProperty(${exportsArg.identifier})`,
 
- 					[property]
 
- 				);
 
- 				dep.loc = expr.loc;
 
- 				parser.state.module.addDependency(dep);
 
- 				parser.walkExpression(expr.arguments[2]);
 
- 				return true;
 
- 			});
 
- 		// Self reference //
 
- 		const handleAccessExport = (expr, base, members, call = undefined) => {
 
- 			if (HarmonyExports.isEnabled(parser.state)) return;
 
- 			if (members.length === 0) {
 
- 				bailout(`${base} is used directly at ${formatLocation(expr.loc)}`);
 
- 			}
 
- 			if (call && members.length === 1) {
 
- 				bailoutHint(
 
- 					`${base}${propertyAccess(
 
- 						members
 
- 					)}(...) prevents optimization as ${base} is passed as call context at ${formatLocation(
 
- 						expr.loc
 
- 					)}`
 
- 				);
 
- 			}
 
- 			const dep = new CommonJsSelfReferenceDependency(
 
- 				expr.range,
 
- 				base,
 
- 				members,
 
- 				!!call
 
- 			);
 
- 			dep.loc = expr.loc;
 
- 			parser.state.module.addDependency(dep);
 
- 			if (call) {
 
- 				parser.walkExpressions(call.arguments);
 
- 			}
 
- 			return true;
 
- 		};
 
- 		parser.hooks.callMemberChain
 
- 			.for("exports")
 
- 			.tap("CommonJsExportsParserPlugin", (expr, members) => {
 
- 				return handleAccessExport(expr.callee, "exports", members, expr);
 
- 			});
 
- 		parser.hooks.expressionMemberChain
 
- 			.for("exports")
 
- 			.tap("CommonJsExportsParserPlugin", (expr, members) => {
 
- 				return handleAccessExport(expr, "exports", members);
 
- 			});
 
- 		parser.hooks.expression
 
- 			.for("exports")
 
- 			.tap("CommonJsExportsParserPlugin", expr => {
 
- 				return handleAccessExport(expr, "exports", []);
 
- 			});
 
- 		parser.hooks.callMemberChain
 
- 			.for("module")
 
- 			.tap("CommonJsExportsParserPlugin", (expr, members) => {
 
- 				if (members[0] !== "exports") return;
 
- 				return handleAccessExport(
 
- 					expr.callee,
 
- 					"module.exports",
 
- 					members.slice(1),
 
- 					expr
 
- 				);
 
- 			});
 
- 		parser.hooks.expressionMemberChain
 
- 			.for("module")
 
- 			.tap("CommonJsExportsParserPlugin", (expr, members) => {
 
- 				if (members[0] !== "exports") return;
 
- 				return handleAccessExport(expr, "module.exports", members.slice(1));
 
- 			});
 
- 		parser.hooks.expression
 
- 			.for("module.exports")
 
- 			.tap("CommonJsExportsParserPlugin", expr => {
 
- 				return handleAccessExport(expr, "module.exports", []);
 
- 			});
 
- 		parser.hooks.callMemberChain
 
- 			.for("this")
 
- 			.tap("CommonJsExportsParserPlugin", (expr, members) => {
 
- 				if (!parser.scope.topLevelScope) return;
 
- 				return handleAccessExport(expr.callee, "this", members, expr);
 
- 			});
 
- 		parser.hooks.expressionMemberChain
 
- 			.for("this")
 
- 			.tap("CommonJsExportsParserPlugin", (expr, members) => {
 
- 				if (!parser.scope.topLevelScope) return;
 
- 				return handleAccessExport(expr, "this", members);
 
- 			});
 
- 		parser.hooks.expression
 
- 			.for("this")
 
- 			.tap("CommonJsExportsParserPlugin", expr => {
 
- 				if (!parser.scope.topLevelScope) return;
 
- 				return handleAccessExport(expr, "this", []);
 
- 			});
 
- 		// Bailouts //
 
- 		parser.hooks.expression.for("module").tap("CommonJsPlugin", expr => {
 
- 			bailout();
 
- 			const isHarmony = HarmonyExports.isEnabled(parser.state);
 
- 			const dep = new ModuleDecoratorDependency(
 
- 				isHarmony
 
- 					? RuntimeGlobals.harmonyModuleDecorator
 
- 					: RuntimeGlobals.nodeModuleDecorator,
 
- 				!isHarmony
 
- 			);
 
- 			dep.loc = expr.loc;
 
- 			parser.state.module.addDependency(dep);
 
- 			return true;
 
- 		});
 
- 	}
 
- }
 
- module.exports = CommonJsExportsParserPlugin;
 
 
  |