You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			781 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			JavaScript
		
	
		
		
			
		
	
	
			781 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			JavaScript
		
	
| 
											9 months ago
										 | /* | ||
|  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | ||
|  | 	Author Tobias Koppers @sokra | ||
|  | */ | ||
|  | 
 | ||
|  | "use strict"; | ||
|  | 
 | ||
|  | const { fileURLToPath } = require("url"); | ||
|  | const CommentCompilationWarning = require("../CommentCompilationWarning"); | ||
|  | const RuntimeGlobals = require("../RuntimeGlobals"); | ||
|  | const UnsupportedFeatureWarning = require("../UnsupportedFeatureWarning"); | ||
|  | const WebpackError = require("../WebpackError"); | ||
|  | const BasicEvaluatedExpression = require("../javascript/BasicEvaluatedExpression"); | ||
|  | const { | ||
|  | 	evaluateToIdentifier, | ||
|  | 	evaluateToString, | ||
|  | 	expressionIsUnsupported, | ||
|  | 	toConstantDependency | ||
|  | } = require("../javascript/JavascriptParserHelpers"); | ||
|  | const CommonJsFullRequireDependency = require("./CommonJsFullRequireDependency"); | ||
|  | const CommonJsRequireContextDependency = require("./CommonJsRequireContextDependency"); | ||
|  | const CommonJsRequireDependency = require("./CommonJsRequireDependency"); | ||
|  | const ConstDependency = require("./ConstDependency"); | ||
|  | const ContextDependencyHelpers = require("./ContextDependencyHelpers"); | ||
|  | const LocalModuleDependency = require("./LocalModuleDependency"); | ||
|  | const { getLocalModule } = require("./LocalModulesHelpers"); | ||
|  | const RequireHeaderDependency = require("./RequireHeaderDependency"); | ||
|  | const RequireResolveContextDependency = require("./RequireResolveContextDependency"); | ||
|  | const RequireResolveDependency = require("./RequireResolveDependency"); | ||
|  | const RequireResolveHeaderDependency = require("./RequireResolveHeaderDependency"); | ||
|  | 
 | ||
|  | /** @typedef {import("estree").CallExpression} CallExpression */ | ||
|  | /** @typedef {import("estree").Expression} Expression */ | ||
|  | /** @typedef {import("estree").NewExpression} NewExpression */ | ||
|  | /** @typedef {import("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */ | ||
|  | /** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */ | ||
|  | /** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */ | ||
|  | /** @typedef {import("../javascript/JavascriptParser").ImportSource} ImportSource */ | ||
|  | /** @typedef {import("../javascript/JavascriptParser").Range} Range */ | ||
|  | 
 | ||
|  | const createRequireSpecifierTag = Symbol("createRequire"); | ||
|  | const createdRequireIdentifierTag = Symbol("createRequire()"); | ||
|  | 
 | ||
|  | class CommonJsImportsParserPlugin { | ||
|  | 	/** | ||
|  | 	 * @param {JavascriptParserOptions} options parser options | ||
|  | 	 */ | ||
|  | 	constructor(options) { | ||
|  | 		this.options = options; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param {JavascriptParser} parser the parser | ||
|  | 	 * @returns {void} | ||
|  | 	 */ | ||
|  | 	apply(parser) { | ||
|  | 		const options = this.options; | ||
|  | 
 | ||
|  | 		const getContext = () => { | ||
|  | 			if (parser.currentTagData) { | ||
|  | 				const { context } = parser.currentTagData; | ||
|  | 				return context; | ||
|  | 			} | ||
|  | 		}; | ||
|  | 
 | ||
|  | 		//#region metadata
 | ||
|  | 		/** | ||
|  | 		 * @param {TODO} expression expression | ||
|  | 		 * @param {() => string[]} getMembers get members | ||
|  | 		 */ | ||
|  | 		const tapRequireExpression = (expression, getMembers) => { | ||
|  | 			parser.hooks.typeof | ||
|  | 				.for(expression) | ||
|  | 				.tap( | ||
|  | 					"CommonJsImportsParserPlugin", | ||
|  | 					toConstantDependency(parser, JSON.stringify("function")) | ||
|  | 				); | ||
|  | 			parser.hooks.evaluateTypeof | ||
|  | 				.for(expression) | ||
|  | 				.tap("CommonJsImportsParserPlugin", evaluateToString("function")); | ||
|  | 			parser.hooks.evaluateIdentifier | ||
|  | 				.for(expression) | ||
|  | 				.tap( | ||
|  | 					"CommonJsImportsParserPlugin", | ||
|  | 					evaluateToIdentifier(expression, "require", getMembers, true) | ||
|  | 				); | ||
|  | 		}; | ||
|  | 		/** | ||
|  | 		 * @param {string | symbol} tag tag | ||
|  | 		 */ | ||
|  | 		const tapRequireExpressionTag = tag => { | ||
|  | 			parser.hooks.typeof | ||
|  | 				.for(tag) | ||
|  | 				.tap( | ||
|  | 					"CommonJsImportsParserPlugin", | ||
|  | 					toConstantDependency(parser, JSON.stringify("function")) | ||
|  | 				); | ||
|  | 			parser.hooks.evaluateTypeof | ||
|  | 				.for(tag) | ||
|  | 				.tap("CommonJsImportsParserPlugin", evaluateToString("function")); | ||
|  | 		}; | ||
|  | 		tapRequireExpression("require", () => []); | ||
|  | 		tapRequireExpression("require.resolve", () => ["resolve"]); | ||
|  | 		tapRequireExpression("require.resolveWeak", () => ["resolveWeak"]); | ||
|  | 		//#endregion
 | ||
|  | 
 | ||
|  | 		// Weird stuff //
 | ||
|  | 		parser.hooks.assign | ||
|  | 			.for("require") | ||
|  | 			.tap("CommonJsImportsParserPlugin", expr => { | ||
|  | 				// to not leak to global "require", we need to define a local require here.
 | ||
|  | 				const dep = new ConstDependency("var require;", 0); | ||
|  | 				dep.loc = /** @type {DependencyLocation} */ (expr.loc); | ||
|  | 				parser.state.module.addPresentationalDependency(dep); | ||
|  | 				return true; | ||
|  | 			}); | ||
|  | 
 | ||
|  | 		//#region Unsupported
 | ||
|  | 		parser.hooks.expression | ||
|  | 			.for("require.main") | ||
|  | 			.tap( | ||
|  | 				"CommonJsImportsParserPlugin", | ||
|  | 				expressionIsUnsupported( | ||
|  | 					parser, | ||
|  | 					"require.main is not supported by webpack." | ||
|  | 				) | ||
|  | 			); | ||
|  | 		parser.hooks.call | ||
|  | 			.for("require.main.require") | ||
|  | 			.tap( | ||
|  | 				"CommonJsImportsParserPlugin", | ||
|  | 				expressionIsUnsupported( | ||
|  | 					parser, | ||
|  | 					"require.main.require is not supported by webpack." | ||
|  | 				) | ||
|  | 			); | ||
|  | 		parser.hooks.expression | ||
|  | 			.for("module.parent.require") | ||
|  | 			.tap( | ||
|  | 				"CommonJsImportsParserPlugin", | ||
|  | 				expressionIsUnsupported( | ||
|  | 					parser, | ||
|  | 					"module.parent.require is not supported by webpack." | ||
|  | 				) | ||
|  | 			); | ||
|  | 		parser.hooks.call | ||
|  | 			.for("module.parent.require") | ||
|  | 			.tap( | ||
|  | 				"CommonJsImportsParserPlugin", | ||
|  | 				expressionIsUnsupported( | ||
|  | 					parser, | ||
|  | 					"module.parent.require is not supported by webpack." | ||
|  | 				) | ||
|  | 			); | ||
|  | 		//#endregion
 | ||
|  | 
 | ||
|  | 		//#region Renaming
 | ||
|  | 		/** | ||
|  | 		 * @param {Expression} expr expression | ||
|  | 		 * @returns {boolean} true when set undefined | ||
|  | 		 */ | ||
|  | 		const defineUndefined = expr => { | ||
|  | 			// To avoid "not defined" error, replace the value with undefined
 | ||
|  | 			const dep = new ConstDependency( | ||
|  | 				"undefined", | ||
|  | 				/** @type {Range} */ (expr.range) | ||
|  | 			); | ||
|  | 			dep.loc = /** @type {DependencyLocation} */ (expr.loc); | ||
|  | 			parser.state.module.addPresentationalDependency(dep); | ||
|  | 			return false; | ||
|  | 		}; | ||
|  | 		parser.hooks.canRename | ||
|  | 			.for("require") | ||
|  | 			.tap("CommonJsImportsParserPlugin", () => true); | ||
|  | 		parser.hooks.rename | ||
|  | 			.for("require") | ||
|  | 			.tap("CommonJsImportsParserPlugin", defineUndefined); | ||
|  | 		//#endregion
 | ||
|  | 
 | ||
|  | 		//#region Inspection
 | ||
|  | 		const requireCache = toConstantDependency( | ||
|  | 			parser, | ||
|  | 			RuntimeGlobals.moduleCache, | ||
|  | 			[ | ||
|  | 				RuntimeGlobals.moduleCache, | ||
|  | 				RuntimeGlobals.moduleId, | ||
|  | 				RuntimeGlobals.moduleLoaded | ||
|  | 			] | ||
|  | 		); | ||
|  | 
 | ||
|  | 		parser.hooks.expression | ||
|  | 			.for("require.cache") | ||
|  | 			.tap("CommonJsImportsParserPlugin", requireCache); | ||
|  | 		//#endregion
 | ||
|  | 
 | ||
|  | 		//#region Require as expression
 | ||
|  | 		/** | ||
|  | 		 * @param {Expression} expr expression | ||
|  | 		 * @returns {boolean} true when handled | ||
|  | 		 */ | ||
|  | 		const requireAsExpressionHandler = expr => { | ||
|  | 			const dep = new CommonJsRequireContextDependency( | ||
|  | 				{ | ||
|  | 					request: options.unknownContextRequest, | ||
|  | 					recursive: options.unknownContextRecursive, | ||
|  | 					regExp: options.unknownContextRegExp, | ||
|  | 					mode: "sync" | ||
|  | 				}, | ||
|  | 				/** @type {Range} */ (expr.range), | ||
|  | 				undefined, | ||
|  | 				parser.scope.inShorthand, | ||
|  | 				getContext() | ||
|  | 			); | ||
|  | 			dep.critical = | ||
|  | 				options.unknownContextCritical && | ||
|  | 				"require function is used in a way in which dependencies cannot be statically extracted"; | ||
|  | 			dep.loc = /** @type {DependencyLocation} */ (expr.loc); | ||
|  | 			dep.optional = !!parser.scope.inTry; | ||
|  | 			parser.state.current.addDependency(dep); | ||
|  | 			return true; | ||
|  | 		}; | ||
|  | 		parser.hooks.expression | ||
|  | 			.for("require") | ||
|  | 			.tap("CommonJsImportsParserPlugin", requireAsExpressionHandler); | ||
|  | 		//#endregion
 | ||
|  | 
 | ||
|  | 		//#region Require
 | ||
|  | 		/** | ||
|  | 		 * @param {CallExpression | NewExpression} expr expression | ||
|  | 		 * @param {BasicEvaluatedExpression} param param | ||
|  | 		 * @returns {boolean | void} true when handled | ||
|  | 		 */ | ||
|  | 		const processRequireItem = (expr, param) => { | ||
|  | 			if (param.isString()) { | ||
|  | 				const dep = new CommonJsRequireDependency( | ||
|  | 					/** @type {string} */ (param.string), | ||
|  | 					/** @type {Range} */ (param.range), | ||
|  | 					getContext() | ||
|  | 				); | ||
|  | 				dep.loc = /** @type {DependencyLocation} */ (expr.loc); | ||
|  | 				dep.optional = !!parser.scope.inTry; | ||
|  | 				parser.state.current.addDependency(dep); | ||
|  | 				return true; | ||
|  | 			} | ||
|  | 		}; | ||
|  | 		/** | ||
|  | 		 * @param {CallExpression | NewExpression} expr expression | ||
|  | 		 * @param {BasicEvaluatedExpression} param param | ||
|  | 		 * @returns {boolean | void} true when handled | ||
|  | 		 */ | ||
|  | 		const processRequireContext = (expr, param) => { | ||
|  | 			const dep = ContextDependencyHelpers.create( | ||
|  | 				CommonJsRequireContextDependency, | ||
|  | 				/** @type {Range} */ (expr.range), | ||
|  | 				param, | ||
|  | 				expr, | ||
|  | 				options, | ||
|  | 				{ | ||
|  | 					category: "commonjs" | ||
|  | 				}, | ||
|  | 				parser, | ||
|  | 				undefined, | ||
|  | 				getContext() | ||
|  | 			); | ||
|  | 			if (!dep) return; | ||
|  | 			dep.loc = /** @type {DependencyLocation} */ (expr.loc); | ||
|  | 			dep.optional = !!parser.scope.inTry; | ||
|  | 			parser.state.current.addDependency(dep); | ||
|  | 			return true; | ||
|  | 		}; | ||
|  | 		/** | ||
|  | 		 * @param {boolean} callNew true, when require is called with new | ||
|  | 		 * @returns {(expr: CallExpression | NewExpression) => (boolean | void)} handler | ||
|  | 		 */ | ||
|  | 		const createRequireHandler = callNew => expr => { | ||
|  | 			if (options.commonjsMagicComments) { | ||
|  | 				const { options: requireOptions, errors: commentErrors } = | ||
|  | 					parser.parseCommentOptions(/** @type {Range} */ (expr.range)); | ||
|  | 
 | ||
|  | 				if (commentErrors) { | ||
|  | 					for (const e of commentErrors) { | ||
|  | 						const { comment } = e; | ||
|  | 						parser.state.module.addWarning( | ||
|  | 							new CommentCompilationWarning( | ||
|  | 								`Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`, | ||
|  | 								comment.loc | ||
|  | 							) | ||
|  | 						); | ||
|  | 					} | ||
|  | 				} | ||
|  | 				if (requireOptions) { | ||
|  | 					if (requireOptions.webpackIgnore !== undefined) { | ||
|  | 						if (typeof requireOptions.webpackIgnore !== "boolean") { | ||
|  | 							parser.state.module.addWarning( | ||
|  | 								new UnsupportedFeatureWarning( | ||
|  | 									`\`webpackIgnore\` expected a boolean, but received: ${requireOptions.webpackIgnore}.`, | ||
|  | 									/** @type {DependencyLocation} */ (expr.loc) | ||
|  | 								) | ||
|  | 							); | ||
|  | 						} else { | ||
|  | 							// Do not instrument `require()` if `webpackIgnore` is `true`
 | ||
|  | 							if (requireOptions.webpackIgnore) { | ||
|  | 								return true; | ||
|  | 							} | ||
|  | 						} | ||
|  | 					} | ||
|  | 				} | ||
|  | 			} | ||
|  | 
 | ||
|  | 			if (expr.arguments.length !== 1) return; | ||
|  | 			let localModule; | ||
|  | 			const param = parser.evaluateExpression(expr.arguments[0]); | ||
|  | 			if (param.isConditional()) { | ||
|  | 				let isExpression = false; | ||
|  | 				for (const p of /** @type {BasicEvaluatedExpression[]} */ ( | ||
|  | 					param.options | ||
|  | 				)) { | ||
|  | 					const result = processRequireItem(expr, p); | ||
|  | 					if (result === undefined) { | ||
|  | 						isExpression = true; | ||
|  | 					} | ||
|  | 				} | ||
|  | 				if (!isExpression) { | ||
|  | 					const dep = new RequireHeaderDependency( | ||
|  | 						/** @type {Range} */ (expr.callee.range) | ||
|  | 					); | ||
|  | 					dep.loc = /** @type {DependencyLocation} */ (expr.loc); | ||
|  | 					parser.state.module.addPresentationalDependency(dep); | ||
|  | 					return true; | ||
|  | 				} | ||
|  | 			} | ||
|  | 			if ( | ||
|  | 				param.isString() && | ||
|  | 				(localModule = getLocalModule( | ||
|  | 					parser.state, | ||
|  | 					/** @type {string} */ (param.string) | ||
|  | 				)) | ||
|  | 			) { | ||
|  | 				localModule.flagUsed(); | ||
|  | 				const dep = new LocalModuleDependency( | ||
|  | 					localModule, | ||
|  | 					/** @type {Range} */ (expr.range), | ||
|  | 					callNew | ||
|  | 				); | ||
|  | 				dep.loc = /** @type {DependencyLocation} */ (expr.loc); | ||
|  | 				parser.state.module.addPresentationalDependency(dep); | ||
|  | 				return true; | ||
|  | 			} else { | ||
|  | 				const result = processRequireItem(expr, param); | ||
|  | 				if (result === undefined) { | ||
|  | 					processRequireContext(expr, param); | ||
|  | 				} else { | ||
|  | 					const dep = new RequireHeaderDependency( | ||
|  | 						/** @type {Range} */ (expr.callee.range) | ||
|  | 					); | ||
|  | 					dep.loc = /** @type {DependencyLocation} */ (expr.loc); | ||
|  | 					parser.state.module.addPresentationalDependency(dep); | ||
|  | 				} | ||
|  | 				return true; | ||
|  | 			} | ||
|  | 		}; | ||
|  | 		parser.hooks.call | ||
|  | 			.for("require") | ||
|  | 			.tap("CommonJsImportsParserPlugin", createRequireHandler(false)); | ||
|  | 		parser.hooks.new | ||
|  | 			.for("require") | ||
|  | 			.tap("CommonJsImportsParserPlugin", createRequireHandler(true)); | ||
|  | 		parser.hooks.call | ||
|  | 			.for("module.require") | ||
|  | 			.tap("CommonJsImportsParserPlugin", createRequireHandler(false)); | ||
|  | 		parser.hooks.new | ||
|  | 			.for("module.require") | ||
|  | 			.tap("CommonJsImportsParserPlugin", createRequireHandler(true)); | ||
|  | 		//#endregion
 | ||
|  | 
 | ||
|  | 		//#region Require with property access
 | ||
|  | 		/** | ||
|  | 		 * @param {Expression} expr expression | ||
|  | 		 * @param {string[]} calleeMembers callee members | ||
|  | 		 * @param {CallExpression} callExpr call expression | ||
|  | 		 * @param {string[]} members members | ||
|  | 		 * @returns {boolean | void} true when handled | ||
|  | 		 */ | ||
|  | 		const chainHandler = (expr, calleeMembers, callExpr, members) => { | ||
|  | 			if (callExpr.arguments.length !== 1) return; | ||
|  | 			const param = parser.evaluateExpression(callExpr.arguments[0]); | ||
|  | 			if ( | ||
|  | 				param.isString() && | ||
|  | 				!getLocalModule(parser.state, /** @type {string} */ (param.string)) | ||
|  | 			) { | ||
|  | 				const dep = new CommonJsFullRequireDependency( | ||
|  | 					/** @type {string} */ (param.string), | ||
|  | 					/** @type {Range} */ (expr.range), | ||
|  | 					members | ||
|  | 				); | ||
|  | 				dep.asiSafe = !parser.isAsiPosition( | ||
|  | 					/** @type {Range} */ (expr.range)[0] | ||
|  | 				); | ||
|  | 				dep.optional = !!parser.scope.inTry; | ||
|  | 				dep.loc = /** @type {DependencyLocation} */ (expr.loc); | ||
|  | 				parser.state.current.addDependency(dep); | ||
|  | 				return true; | ||
|  | 			} | ||
|  | 		}; | ||
|  | 		/** | ||
|  | 		 * @param {CallExpression} expr expression | ||
|  | 		 * @param {string[]} calleeMembers callee members | ||
|  | 		 * @param {CallExpression} callExpr call expression | ||
|  | 		 * @param {string[]} members members | ||
|  | 		 * @returns {boolean | void} true when handled | ||
|  | 		 */ | ||
|  | 		const callChainHandler = (expr, calleeMembers, callExpr, members) => { | ||
|  | 			if (callExpr.arguments.length !== 1) return; | ||
|  | 			const param = parser.evaluateExpression(callExpr.arguments[0]); | ||
|  | 			if ( | ||
|  | 				param.isString() && | ||
|  | 				!getLocalModule(parser.state, /** @type {string} */ (param.string)) | ||
|  | 			) { | ||
|  | 				const dep = new CommonJsFullRequireDependency( | ||
|  | 					/** @type {string} */ (param.string), | ||
|  | 					/** @type {Range} */ (expr.callee.range), | ||
|  | 					members | ||
|  | 				); | ||
|  | 				dep.call = true; | ||
|  | 				dep.asiSafe = !parser.isAsiPosition( | ||
|  | 					/** @type {Range} */ (expr.range)[0] | ||
|  | 				); | ||
|  | 				dep.optional = !!parser.scope.inTry; | ||
|  | 				dep.loc = /** @type {DependencyLocation} */ (expr.callee.loc); | ||
|  | 				parser.state.current.addDependency(dep); | ||
|  | 				parser.walkExpressions(expr.arguments); | ||
|  | 				return true; | ||
|  | 			} | ||
|  | 		}; | ||
|  | 		parser.hooks.memberChainOfCallMemberChain | ||
|  | 			.for("require") | ||
|  | 			.tap("CommonJsImportsParserPlugin", chainHandler); | ||
|  | 		parser.hooks.memberChainOfCallMemberChain | ||
|  | 			.for("module.require") | ||
|  | 			.tap("CommonJsImportsParserPlugin", chainHandler); | ||
|  | 		parser.hooks.callMemberChainOfCallMemberChain | ||
|  | 			.for("require") | ||
|  | 			.tap("CommonJsImportsParserPlugin", callChainHandler); | ||
|  | 		parser.hooks.callMemberChainOfCallMemberChain | ||
|  | 			.for("module.require") | ||
|  | 			.tap("CommonJsImportsParserPlugin", callChainHandler); | ||
|  | 		//#endregion
 | ||
|  | 
 | ||
|  | 		//#region Require.resolve
 | ||
|  | 		/** | ||
|  | 		 * @param {CallExpression} expr call expression | ||
|  | 		 * @param {boolean} weak weak | ||
|  | 		 * @returns {boolean | void} true when handled | ||
|  | 		 */ | ||
|  | 		const processResolve = (expr, weak) => { | ||
|  | 			if (expr.arguments.length !== 1) return; | ||
|  | 			const param = parser.evaluateExpression(expr.arguments[0]); | ||
|  | 			if (param.isConditional()) { | ||
|  | 				for (const option of /** @type {BasicEvaluatedExpression[]} */ ( | ||
|  | 					param.options | ||
|  | 				)) { | ||
|  | 					const result = processResolveItem(expr, option, weak); | ||
|  | 					if (result === undefined) { | ||
|  | 						processResolveContext(expr, option, weak); | ||
|  | 					} | ||
|  | 				} | ||
|  | 				const dep = new RequireResolveHeaderDependency( | ||
|  | 					/** @type {Range} */ (expr.callee.range) | ||
|  | 				); | ||
|  | 				dep.loc = /** @type {DependencyLocation} */ (expr.loc); | ||
|  | 				parser.state.module.addPresentationalDependency(dep); | ||
|  | 				return true; | ||
|  | 			} else { | ||
|  | 				const result = processResolveItem(expr, param, weak); | ||
|  | 				if (result === undefined) { | ||
|  | 					processResolveContext(expr, param, weak); | ||
|  | 				} | ||
|  | 				const dep = new RequireResolveHeaderDependency( | ||
|  | 					/** @type {Range} */ (expr.callee.range) | ||
|  | 				); | ||
|  | 				dep.loc = /** @type {DependencyLocation} */ (expr.loc); | ||
|  | 				parser.state.module.addPresentationalDependency(dep); | ||
|  | 				return true; | ||
|  | 			} | ||
|  | 		}; | ||
|  | 		/** | ||
|  | 		 * @param {CallExpression} expr call expression | ||
|  | 		 * @param {BasicEvaluatedExpression} param param | ||
|  | 		 * @param {boolean} weak weak | ||
|  | 		 * @returns {boolean | void} true when handled | ||
|  | 		 */ | ||
|  | 		const processResolveItem = (expr, param, weak) => { | ||
|  | 			if (param.isString()) { | ||
|  | 				const dep = new RequireResolveDependency( | ||
|  | 					/** @type {string} */ (param.string), | ||
|  | 					/** @type {Range} */ (param.range), | ||
|  | 					getContext() | ||
|  | 				); | ||
|  | 				dep.loc = /** @type {DependencyLocation} */ (expr.loc); | ||
|  | 				dep.optional = !!parser.scope.inTry; | ||
|  | 				dep.weak = weak; | ||
|  | 				parser.state.current.addDependency(dep); | ||
|  | 				return true; | ||
|  | 			} | ||
|  | 		}; | ||
|  | 		/** | ||
|  | 		 * @param {CallExpression} expr call expression | ||
|  | 		 * @param {BasicEvaluatedExpression} param param | ||
|  | 		 * @param {boolean} weak weak | ||
|  | 		 * @returns {boolean | void} true when handled | ||
|  | 		 */ | ||
|  | 		const processResolveContext = (expr, param, weak) => { | ||
|  | 			const dep = ContextDependencyHelpers.create( | ||
|  | 				RequireResolveContextDependency, | ||
|  | 				/** @type {Range} */ (param.range), | ||
|  | 				param, | ||
|  | 				expr, | ||
|  | 				options, | ||
|  | 				{ | ||
|  | 					category: "commonjs", | ||
|  | 					mode: weak ? "weak" : "sync" | ||
|  | 				}, | ||
|  | 				parser, | ||
|  | 				getContext() | ||
|  | 			); | ||
|  | 			if (!dep) return; | ||
|  | 			dep.loc = /** @type {DependencyLocation} */ (expr.loc); | ||
|  | 			dep.optional = !!parser.scope.inTry; | ||
|  | 			parser.state.current.addDependency(dep); | ||
|  | 			return true; | ||
|  | 		}; | ||
|  | 
 | ||
|  | 		parser.hooks.call | ||
|  | 			.for("require.resolve") | ||
|  | 			.tap("CommonJsImportsParserPlugin", expr => { | ||
|  | 				return processResolve(expr, false); | ||
|  | 			}); | ||
|  | 		parser.hooks.call | ||
|  | 			.for("require.resolveWeak") | ||
|  | 			.tap("CommonJsImportsParserPlugin", expr => { | ||
|  | 				return processResolve(expr, true); | ||
|  | 			}); | ||
|  | 		//#endregion
 | ||
|  | 
 | ||
|  | 		//#region Create require
 | ||
|  | 
 | ||
|  | 		if (!options.createRequire) return; | ||
|  | 
 | ||
|  | 		/** @type {ImportSource[]} */ | ||
|  | 		let moduleName = []; | ||
|  | 		/** @type {string | undefined} */ | ||
|  | 		let specifierName; | ||
|  | 
 | ||
|  | 		if (options.createRequire === true) { | ||
|  | 			moduleName = ["module", "node:module"]; | ||
|  | 			specifierName = "createRequire"; | ||
|  | 		} else { | ||
|  | 			let moduleName; | ||
|  | 			const match = /^(.*) from (.*)$/.exec(options.createRequire); | ||
|  | 			if (match) { | ||
|  | 				[, specifierName, moduleName] = match; | ||
|  | 			} | ||
|  | 			if (!specifierName || !moduleName) { | ||
|  | 				const err = new WebpackError( | ||
|  | 					`Parsing javascript parser option "createRequire" failed, got ${JSON.stringify( | ||
|  | 						options.createRequire | ||
|  | 					)}`
 | ||
|  | 				); | ||
|  | 				err.details = | ||
|  | 					'Expected string in format "createRequire from module", where "createRequire" is specifier name and "module" name of the module'; | ||
|  | 				throw err; | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		tapRequireExpressionTag(createdRequireIdentifierTag); | ||
|  | 		tapRequireExpressionTag(createRequireSpecifierTag); | ||
|  | 		parser.hooks.evaluateCallExpression | ||
|  | 			.for(createRequireSpecifierTag) | ||
|  | 			.tap("CommonJsImportsParserPlugin", expr => { | ||
|  | 				const context = parseCreateRequireArguments(expr); | ||
|  | 				if (context === undefined) return; | ||
|  | 				const ident = parser.evaluatedVariable({ | ||
|  | 					tag: createdRequireIdentifierTag, | ||
|  | 					data: { context }, | ||
|  | 					next: undefined | ||
|  | 				}); | ||
|  | 				return new BasicEvaluatedExpression() | ||
|  | 					.setIdentifier( | ||
|  | 						/** @type {TODO} */ (ident), | ||
|  | 						/** @type {TODO} */ (ident), | ||
|  | 						() => [] | ||
|  | 					) | ||
|  | 					.setSideEffects(false) | ||
|  | 					.setRange(/** @type {Range} */ (expr.range)); | ||
|  | 			}); | ||
|  | 		parser.hooks.unhandledExpressionMemberChain | ||
|  | 			.for(createdRequireIdentifierTag) | ||
|  | 			.tap("CommonJsImportsParserPlugin", (expr, members) => { | ||
|  | 				return expressionIsUnsupported( | ||
|  | 					parser, | ||
|  | 					`createRequire().${members.join(".")} is not supported by webpack.` | ||
|  | 				)(expr); | ||
|  | 			}); | ||
|  | 		parser.hooks.canRename | ||
|  | 			.for(createdRequireIdentifierTag) | ||
|  | 			.tap("CommonJsImportsParserPlugin", () => true); | ||
|  | 		parser.hooks.canRename | ||
|  | 			.for(createRequireSpecifierTag) | ||
|  | 			.tap("CommonJsImportsParserPlugin", () => true); | ||
|  | 		parser.hooks.rename | ||
|  | 			.for(createRequireSpecifierTag) | ||
|  | 			.tap("CommonJsImportsParserPlugin", defineUndefined); | ||
|  | 		parser.hooks.expression | ||
|  | 			.for(createdRequireIdentifierTag) | ||
|  | 			.tap("CommonJsImportsParserPlugin", requireAsExpressionHandler); | ||
|  | 		parser.hooks.call | ||
|  | 			.for(createdRequireIdentifierTag) | ||
|  | 			.tap("CommonJsImportsParserPlugin", createRequireHandler(false)); | ||
|  | 		/** | ||
|  | 		 * @param {CallExpression} expr call expression | ||
|  | 		 * @returns {string | void} context | ||
|  | 		 */ | ||
|  | 		const parseCreateRequireArguments = expr => { | ||
|  | 			const args = expr.arguments; | ||
|  | 			if (args.length !== 1) { | ||
|  | 				const err = new WebpackError( | ||
|  | 					"module.createRequire supports only one argument." | ||
|  | 				); | ||
|  | 				err.loc = /** @type {DependencyLocation} */ (expr.loc); | ||
|  | 				parser.state.module.addWarning(err); | ||
|  | 				return; | ||
|  | 			} | ||
|  | 			const arg = args[0]; | ||
|  | 			const evaluated = parser.evaluateExpression(arg); | ||
|  | 			if (!evaluated.isString()) { | ||
|  | 				const err = new WebpackError( | ||
|  | 					"module.createRequire failed parsing argument." | ||
|  | 				); | ||
|  | 				err.loc = /** @type {DependencyLocation} */ (arg.loc); | ||
|  | 				parser.state.module.addWarning(err); | ||
|  | 				return; | ||
|  | 			} | ||
|  | 			const ctx = /** @type {string} */ (evaluated.string).startsWith("file://") | ||
|  | 				? fileURLToPath(/** @type {string} */ (evaluated.string)) | ||
|  | 				: /** @type {string} */ (evaluated.string); | ||
|  | 			// argument always should be a filename
 | ||
|  | 			return ctx.slice(0, ctx.lastIndexOf(ctx.startsWith("/") ? "/" : "\\")); | ||
|  | 		}; | ||
|  | 
 | ||
|  | 		parser.hooks.import.tap( | ||
|  | 			{ | ||
|  | 				name: "CommonJsImportsParserPlugin", | ||
|  | 				stage: -10 | ||
|  | 			}, | ||
|  | 			(statement, source) => { | ||
|  | 				if ( | ||
|  | 					!moduleName.includes(source) || | ||
|  | 					statement.specifiers.length !== 1 || | ||
|  | 					statement.specifiers[0].type !== "ImportSpecifier" || | ||
|  | 					statement.specifiers[0].imported.type !== "Identifier" || | ||
|  | 					statement.specifiers[0].imported.name !== specifierName | ||
|  | 				) | ||
|  | 					return; | ||
|  | 				// clear for 'import { createRequire as x } from "module"'
 | ||
|  | 				// if any other specifier was used import module
 | ||
|  | 				const clearDep = new ConstDependency( | ||
|  | 					parser.isAsiPosition(/** @type {Range} */ (statement.range)[0]) | ||
|  | 						? ";" | ||
|  | 						: "", | ||
|  | 					/** @type {Range} */ (statement.range) | ||
|  | 				); | ||
|  | 				clearDep.loc = /** @type {DependencyLocation} */ (statement.loc); | ||
|  | 				parser.state.module.addPresentationalDependency(clearDep); | ||
|  | 				parser.unsetAsiPosition(/** @type {Range} */ (statement.range)[1]); | ||
|  | 				return true; | ||
|  | 			} | ||
|  | 		); | ||
|  | 		parser.hooks.importSpecifier.tap( | ||
|  | 			{ | ||
|  | 				name: "CommonJsImportsParserPlugin", | ||
|  | 				stage: -10 | ||
|  | 			}, | ||
|  | 			(statement, source, id, name) => { | ||
|  | 				if (!moduleName.includes(source) || id !== specifierName) return; | ||
|  | 				parser.tagVariable(name, createRequireSpecifierTag); | ||
|  | 				return true; | ||
|  | 			} | ||
|  | 		); | ||
|  | 		parser.hooks.preDeclarator.tap( | ||
|  | 			"CommonJsImportsParserPlugin", | ||
|  | 			declarator => { | ||
|  | 				if ( | ||
|  | 					declarator.id.type !== "Identifier" || | ||
|  | 					!declarator.init || | ||
|  | 					declarator.init.type !== "CallExpression" || | ||
|  | 					declarator.init.callee.type !== "Identifier" | ||
|  | 				) | ||
|  | 					return; | ||
|  | 				const variableInfo = | ||
|  | 					/** @type {TODO} */ | ||
|  | 					(parser.getVariableInfo(declarator.init.callee.name)); | ||
|  | 				if ( | ||
|  | 					variableInfo && | ||
|  | 					variableInfo.tagInfo && | ||
|  | 					variableInfo.tagInfo.tag === createRequireSpecifierTag | ||
|  | 				) { | ||
|  | 					const context = parseCreateRequireArguments(declarator.init); | ||
|  | 					if (context === undefined) return; | ||
|  | 					parser.tagVariable(declarator.id.name, createdRequireIdentifierTag, { | ||
|  | 						name: declarator.id.name, | ||
|  | 						context | ||
|  | 					}); | ||
|  | 					return true; | ||
|  | 				} | ||
|  | 			} | ||
|  | 		); | ||
|  | 
 | ||
|  | 		parser.hooks.memberChainOfCallMemberChain | ||
|  | 			.for(createRequireSpecifierTag) | ||
|  | 			.tap( | ||
|  | 				"CommonJsImportsParserPlugin", | ||
|  | 				(expr, calleeMembers, callExpr, members) => { | ||
|  | 					if ( | ||
|  | 						calleeMembers.length !== 0 || | ||
|  | 						members.length !== 1 || | ||
|  | 						members[0] !== "cache" | ||
|  | 					) | ||
|  | 						return; | ||
|  | 					// createRequire().cache
 | ||
|  | 					const context = parseCreateRequireArguments(callExpr); | ||
|  | 					if (context === undefined) return; | ||
|  | 					return requireCache(expr); | ||
|  | 				} | ||
|  | 			); | ||
|  | 		parser.hooks.callMemberChainOfCallMemberChain | ||
|  | 			.for(createRequireSpecifierTag) | ||
|  | 			.tap( | ||
|  | 				"CommonJsImportsParserPlugin", | ||
|  | 				(expr, calleeMembers, innerCallExpression, members) => { | ||
|  | 					if ( | ||
|  | 						calleeMembers.length !== 0 || | ||
|  | 						members.length !== 1 || | ||
|  | 						members[0] !== "resolve" | ||
|  | 					) | ||
|  | 						return; | ||
|  | 					// createRequire().resolve()
 | ||
|  | 					return processResolve(expr, false); | ||
|  | 				} | ||
|  | 			); | ||
|  | 		parser.hooks.expressionMemberChain | ||
|  | 			.for(createdRequireIdentifierTag) | ||
|  | 			.tap("CommonJsImportsParserPlugin", (expr, members) => { | ||
|  | 				// require.cache
 | ||
|  | 				if (members.length === 1 && members[0] === "cache") { | ||
|  | 					return requireCache(expr); | ||
|  | 				} | ||
|  | 			}); | ||
|  | 		parser.hooks.callMemberChain | ||
|  | 			.for(createdRequireIdentifierTag) | ||
|  | 			.tap("CommonJsImportsParserPlugin", (expr, members) => { | ||
|  | 				// require.resolve()
 | ||
|  | 				if (members.length === 1 && members[0] === "resolve") { | ||
|  | 					return processResolve(expr, false); | ||
|  | 				} | ||
|  | 			}); | ||
|  | 		parser.hooks.call | ||
|  | 			.for(createRequireSpecifierTag) | ||
|  | 			.tap("CommonJsImportsParserPlugin", expr => { | ||
|  | 				const clearDep = new ConstDependency( | ||
|  | 					"/* createRequire() */ undefined", | ||
|  | 					/** @type {Range} */ (expr.range) | ||
|  | 				); | ||
|  | 				clearDep.loc = /** @type {DependencyLocation} */ (expr.loc); | ||
|  | 				parser.state.module.addPresentationalDependency(clearDep); | ||
|  | 				return true; | ||
|  | 			}); | ||
|  | 		//#endregion
 | ||
|  | 	} | ||
|  | } | ||
|  | module.exports = CommonJsImportsParserPlugin; |