text: /*
  	MIT License http://www.opensource.org/licenses/mit-license.php
  	Author Tobias Koppers @sokra
  */
  
  "use strict";
  
  const CommentCompilationWarning = require("../CommentCompilationWarning");
  const RuntimeGlobals = require("../RuntimeGlobals");
  const UnsupportedFeatureWarning = require("../UnsupportedFeatureWarning");
  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("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */
  
  class CommonJsImportsParserPlugin {
  	/**
  	 * @param {JavascriptParserOptions} options parser options
  	 */
  	constructor(options) {
  		this.options = options;
  	}
  
  	apply(parser) {
  		const options = this.options;
  
  		// metadata //
  		const tapRequireExpression = (expression, getMembers) => {
  			parser.hooks.typeof
  				.for(expression)
  				.tap(
  					"CommonJsPlugin",
  					toConstantDependency(parser, JSON.stringify("function"))
  				);
  			parser.hooks.evaluateTypeof
  				.for(expression)
  				.tap("CommonJsPlugin", evaluateToString("function"));
  			parser.hooks.evaluateIdentifier
  				.for(expression)
  				.tap(
  					"CommonJsPlugin",
  					evaluateToIdentifier(expression, "require", getMembers, true)
  				);
  		};
  		tapRequireExpression("require", () => []);
  		tapRequireExpression("require.resolve", () => ["resolve"]);
  		tapRequireExpression("require.resolveWeak", () => ["resolveWeak"]);
  
  		// Weird stuff //
  		parser.hooks.assign.for("require").tap("CommonJsPlugin", expr => {
  			// to not leak to global "require", we need to define a local require here.
  			const dep = new ConstDependency("var require;", 0);
  			dep.loc = expr.loc;
  			parser.state.module.addPresentationalDependency(dep);
  			return true;
  		});
  
  		// Unsupported //
  		parser.hooks.expression
  			.for("require.main.require")
  			.tap(
  				"CommonJsPlugin",
  				expressionIsUnsupported(
  					parser,
  					"require.main.require is not supported by webpack."
  				)
  			);
  		parser.hooks.call
  			.for("require.main.require")
  			.tap(
  				"CommonJsPlugin",
  				expressionIsUnsupported(
  					parser,
  					"require.main.require is not supported by webpack."
  				)
  			);
  		parser.hooks.expression
  			.for("module.parent.require")
  			.tap(
  				"CommonJsPlugin",
  				expressionIsUnsupported(
  					parser,
  					"module.parent.require is not supported by webpack."
  				)
  			);
  		parser.hooks.call
  			.for("module.parent.require")
  			.tap(
  				"CommonJsPlugin",
  				expressionIsUnsupported(
  					parser,
  					"module.parent.require is not supported by webpack."
  				)
  			);
  
  		// renaming //
  		parser.hooks.canRename.for("require").tap("CommonJsPlugin", () => true);
  		parser.hooks.rename.for("require").tap("CommonJsPlugin", expr => {
  			// To avoid "not defined" error, replace the value with undefined
  			const dep = new ConstDependency("undefined", expr.range);
  			dep.loc = expr.loc;
  			parser.state.module.addPresentationalDependency(dep);
  			return false;
  		});
  
  		// inspection //
  		parser.hooks.expression
  			.for("require.cache")
  			.tap(
  				"CommonJsImportsParserPlugin",
  				toConstantDependency(parser, RuntimeGlobals.moduleCache, [
  					RuntimeGlobals.moduleCache,
  					RuntimeGlobals.moduleId,
  					RuntimeGlobals.moduleLoaded
  				])
  			);
  
  		// require as expression //
  		parser.hooks.expression
  			.for("require")
  			.tap("CommonJsImportsParserPlugin", expr => {
  				const dep = new CommonJsRequireContextDependency(
  					{
  						request: options.unknownContextRequest,
  						recursive: options.unknownContextRecursive,
  						regExp: options.unknownContextRegExp,
  						mode: "sync"
  					},
  					expr.range
  				);
  				dep.critical =
  					options.unknownContextCritical &&
  					"require function is used in a way in which dependencies cannot be statically extracted";
  				dep.loc = expr.loc;
  				dep.optional = !!parser.scope.inTry;
  				parser.state.current.addDependency(dep);
  				return true;
  			});
  
  		// require //
  		const processRequireItem = (expr, param) => {
  			if (param.isString()) {
  				const dep = new CommonJsRequireDependency(param.string, param.range);
  				dep.loc = expr.loc;
  				dep.optional = !!parser.scope.inTry;
  				parser.state.current.addDependency(dep);
  				return true;
  			}
  		};
  		const processRequireContext = (expr, param) => {
  			const dep = ContextDependencyHelpers.create(
  				CommonJsRequireContextDependency,
  				expr.range,
  				param,
  				expr,
  				options,
  				{
  					category: "commonjs"
  				},
  				parser
  			);
  			if (!dep) return;
  			dep.loc = expr.loc;
  			dep.optional = !!parser.scope.inTry;
  			parser.state.current.addDependency(dep);
  			return true;
  		};
  		const createRequireHandler = callNew => expr => {
  			if (options.commonjsMagicComments) {
  				const { options: requireOptions, errors: commentErrors } =
  					parser.parseCommentOptions(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}.`,
  									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 param.options) {
  					const result = processRequireItem(expr, p);
  					if (result === undefined) {
  						isExpression = true;
  					}
  				}
  				if (!isExpression) {
  					const dep = new RequireHeaderDependency(expr.callee.range);
  					dep.loc = expr.loc;
  					parser.state.module.addPresentationalDependency(dep);
  					return true;
  				}
  			}
  			if (
  				param.isString() &&
  				(localModule = getLocalModule(parser.state, param.string))
  			) {
  				localModule.flagUsed();
  				const dep = new LocalModuleDependency(localModule, expr.range, callNew);
  				dep.loc = 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(expr.callee.range);
  					dep.loc = 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));
  
  		// require with property access //
  		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, param.string)) {
  				const dep = new CommonJsFullRequireDependency(
  					param.string,
  					expr.range,
  					members
  				);
  				dep.asiSafe = !parser.isAsiPosition(expr.range[0]);
  				dep.optional = !!parser.scope.inTry;
  				dep.loc = expr.loc;
  				parser.state.module.addDependency(dep);
  				return true;
  			}
  		};
  		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, param.string)) {
  				const dep = new CommonJsFullRequireDependency(
  					param.string,
  					expr.callee.range,
  					members
  				);
  				dep.call = true;
  				dep.asiSafe = !parser.isAsiPosition(expr.range[0]);
  				dep.optional = !!parser.scope.inTry;
  				dep.loc = expr.callee.loc;
  				parser.state.module.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);
  
  		// require.resolve //
  		const processResolve = (expr, weak) => {
  			if (expr.arguments.length !== 1) return;
  			const param = parser.evaluateExpression(expr.arguments[0]);
  			if (param.isConditional()) {
  				for (const option of param.options) {
  					const result = processResolveItem(expr, option, weak);
  					if (result === undefined) {
  						processResolveContext(expr, option, weak);
  					}
  				}
  				const dep = new RequireResolveHeaderDependency(expr.callee.range);
  				dep.loc = 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(expr.callee.range);
  				dep.loc = expr.loc;
  				parser.state.module.addPresentationalDependency(dep);
  				return true;
  			}
  		};
  		const processResolveItem = (expr, param, weak) => {
  			if (param.isString()) {
  				const dep = new RequireResolveDependency(param.string, param.range);
  				dep.loc = expr.loc;
  				dep.optional = !!parser.scope.inTry;
  				dep.weak = weak;
  				parser.state.current.addDependency(dep);
  				return true;
  			}
  		};
  		const processResolveContext = (expr, param, weak) => {
  			const dep = ContextDependencyHelpers.create(
  				RequireResolveContextDependency,
  				param.range,
  				param,
  				expr,
  				options,
  				{
  					category: "commonjs",
  					mode: weak ? "weak" : "sync"
  				},
  				parser
  			);
  			if (!dep) return;
  			dep.loc = expr.loc;
  			dep.optional = !!parser.scope.inTry;
  			parser.state.current.addDependency(dep);
  			return true;
  		};
  
  		parser.hooks.call
  			.for("require.resolve")
  			.tap("RequireResolveDependencyParserPlugin", expr => {
  				return processResolve(expr, false);
  			});
  		parser.hooks.call
  			.for("require.resolveWeak")
  			.tap("RequireResolveDependencyParserPlugin", expr => {
  				return processResolve(expr, true);
  			});
  	}
  }
  module.exports = CommonJsImportsParserPlugin;
  