| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454 | /*	MIT License http://www.opensource.org/licenses/mit-license.php	Author Tobias Koppers @sokra*/"use strict";// Syntax: https://developer.mozilla.org/en/SpiderMonkey/Parser_APIconst acorn = require("acorn");const { Tapable, SyncBailHook, HookMap } = require("tapable");const util = require("util");const vm = require("vm");const BasicEvaluatedExpression = require("./BasicEvaluatedExpression");const StackedSetMap = require("./util/StackedSetMap");const acornParser = acorn.Parser;const joinRanges = (startRange, endRange) => {	if (!endRange) return startRange;	if (!startRange) return endRange;	return [startRange[0], endRange[1]];};const defaultParserOptions = {	ranges: true,	locations: true,	ecmaVersion: 11,	sourceType: "module",	onComment: null};// regexp to match at least one "magic comment"const webpackCommentRegExp = new RegExp(/(^|\W)webpack[A-Z]{1,}[A-Za-z]{1,}:/);const EMPTY_COMMENT_OPTIONS = {	options: null,	errors: null};class Parser extends Tapable {	constructor(options, sourceType = "auto") {		super();		this.hooks = {			evaluateTypeof: new HookMap(() => new SyncBailHook(["expression"])),			evaluate: new HookMap(() => new SyncBailHook(["expression"])),			evaluateIdentifier: new HookMap(() => new SyncBailHook(["expression"])),			evaluateDefinedIdentifier: new HookMap(				() => new SyncBailHook(["expression"])			),			evaluateCallExpressionMember: new HookMap(				() => new SyncBailHook(["expression", "param"])			),			statement: new SyncBailHook(["statement"]),			statementIf: new SyncBailHook(["statement"]),			label: new HookMap(() => new SyncBailHook(["statement"])),			import: new SyncBailHook(["statement", "source"]),			importSpecifier: new SyncBailHook([				"statement",				"source",				"exportName",				"identifierName"			]),			export: new SyncBailHook(["statement"]),			exportImport: new SyncBailHook(["statement", "source"]),			exportDeclaration: new SyncBailHook(["statement", "declaration"]),			exportExpression: new SyncBailHook(["statement", "declaration"]),			exportSpecifier: new SyncBailHook([				"statement",				"identifierName",				"exportName",				"index"			]),			exportImportSpecifier: new SyncBailHook([				"statement",				"source",				"identifierName",				"exportName",				"index"			]),			varDeclaration: new HookMap(() => new SyncBailHook(["declaration"])),			varDeclarationLet: new HookMap(() => new SyncBailHook(["declaration"])),			varDeclarationConst: new HookMap(() => new SyncBailHook(["declaration"])),			varDeclarationVar: new HookMap(() => new SyncBailHook(["declaration"])),			canRename: new HookMap(() => new SyncBailHook(["initExpression"])),			rename: new HookMap(() => new SyncBailHook(["initExpression"])),			assigned: new HookMap(() => new SyncBailHook(["expression"])),			assign: new HookMap(() => new SyncBailHook(["expression"])),			typeof: new HookMap(() => new SyncBailHook(["expression"])),			importCall: new SyncBailHook(["expression"]),			call: new HookMap(() => new SyncBailHook(["expression"])),			callAnyMember: new HookMap(() => new SyncBailHook(["expression"])),			new: new HookMap(() => new SyncBailHook(["expression"])),			expression: new HookMap(() => new SyncBailHook(["expression"])),			expressionAnyMember: new HookMap(() => new SyncBailHook(["expression"])),			expressionConditionalOperator: new SyncBailHook(["expression"]),			expressionLogicalOperator: new SyncBailHook(["expression"]),			program: new SyncBailHook(["ast", "comments"])		};		const HOOK_MAP_COMPAT_CONFIG = {			evaluateTypeof: /^evaluate typeof (.+)$/,			evaluateIdentifier: /^evaluate Identifier (.+)$/,			evaluateDefinedIdentifier: /^evaluate defined Identifier (.+)$/,			evaluateCallExpressionMember: /^evaluate CallExpression .(.+)$/,			evaluate: /^evaluate (.+)$/,			label: /^label (.+)$/,			varDeclarationLet: /^var-let (.+)$/,			varDeclarationConst: /^var-const (.+)$/,			varDeclarationVar: /^var-var (.+)$/,			varDeclaration: /^var (.+)$/,			canRename: /^can-rename (.+)$/,			rename: /^rename (.+)$/,			typeof: /^typeof (.+)$/,			assigned: /^assigned (.+)$/,			assign: /^assign (.+)$/,			callAnyMember: /^call (.+)\.\*$/,			call: /^call (.+)$/,			new: /^new (.+)$/,			expressionConditionalOperator: /^expression \?:$/,			expressionAnyMember: /^expression (.+)\.\*$/,			expression: /^expression (.+)$/		};		this._pluginCompat.tap("Parser", options => {			for (const name of Object.keys(HOOK_MAP_COMPAT_CONFIG)) {				const regexp = HOOK_MAP_COMPAT_CONFIG[name];				const match = regexp.exec(options.name);				if (match) {					if (match[1]) {						this.hooks[name].tap(							match[1],							options.fn.name || "unnamed compat plugin",							options.fn.bind(this)						);					} else {						this.hooks[name].tap(							options.fn.name || "unnamed compat plugin",							options.fn.bind(this)						);					}					return true;				}			}		});		this.options = options;		this.sourceType = sourceType;		this.scope = undefined;		this.state = undefined;		this.comments = undefined;		this.initializeEvaluating();	}	initializeEvaluating() {		this.hooks.evaluate.for("Literal").tap("Parser", expr => {			switch (typeof expr.value) {				case "number":					return new BasicEvaluatedExpression()						.setNumber(expr.value)						.setRange(expr.range);				case "string":					return new BasicEvaluatedExpression()						.setString(expr.value)						.setRange(expr.range);				case "boolean":					return new BasicEvaluatedExpression()						.setBoolean(expr.value)						.setRange(expr.range);			}			if (expr.value === null) {				return new BasicEvaluatedExpression().setNull().setRange(expr.range);			}			if (expr.value instanceof RegExp) {				return new BasicEvaluatedExpression()					.setRegExp(expr.value)					.setRange(expr.range);			}		});		this.hooks.evaluate.for("LogicalExpression").tap("Parser", expr => {			let left;			let leftAsBool;			let right;			if (expr.operator === "&&") {				left = this.evaluateExpression(expr.left);				leftAsBool = left && left.asBool();				if (leftAsBool === false) return left.setRange(expr.range);				if (leftAsBool !== true) return;				right = this.evaluateExpression(expr.right);				return right.setRange(expr.range);			} else if (expr.operator === "||") {				left = this.evaluateExpression(expr.left);				leftAsBool = left && left.asBool();				if (leftAsBool === true) return left.setRange(expr.range);				if (leftAsBool !== false) return;				right = this.evaluateExpression(expr.right);				return right.setRange(expr.range);			}		});		this.hooks.evaluate.for("BinaryExpression").tap("Parser", expr => {			let left;			let right;			let res;			if (expr.operator === "+") {				left = this.evaluateExpression(expr.left);				right = this.evaluateExpression(expr.right);				if (!left || !right) return;				res = new BasicEvaluatedExpression();				if (left.isString()) {					if (right.isString()) {						res.setString(left.string + right.string);					} else if (right.isNumber()) {						res.setString(left.string + right.number);					} else if (						right.isWrapped() &&						right.prefix &&						right.prefix.isString()					) {						// "left" + ("prefix" + inner + "postfix")						// => ("leftprefix" + inner + "postfix")						res.setWrapped(							new BasicEvaluatedExpression()								.setString(left.string + right.prefix.string)								.setRange(joinRanges(left.range, right.prefix.range)),							right.postfix,							right.wrappedInnerExpressions						);					} else if (right.isWrapped()) {						// "left" + ([null] + inner + "postfix")						// => ("left" + inner + "postfix")						res.setWrapped(left, right.postfix, right.wrappedInnerExpressions);					} else {						// "left" + expr						// => ("left" + expr + "")						res.setWrapped(left, null, [right]);					}				} else if (left.isNumber()) {					if (right.isString()) {						res.setString(left.number + right.string);					} else if (right.isNumber()) {						res.setNumber(left.number + right.number);					} else {						return;					}				} else if (left.isWrapped()) {					if (left.postfix && left.postfix.isString() && right.isString()) {						// ("prefix" + inner + "postfix") + "right"						// => ("prefix" + inner + "postfixright")						res.setWrapped(							left.prefix,							new BasicEvaluatedExpression()								.setString(left.postfix.string + right.string)								.setRange(joinRanges(left.postfix.range, right.range)),							left.wrappedInnerExpressions						);					} else if (						left.postfix &&						left.postfix.isString() &&						right.isNumber()					) {						// ("prefix" + inner + "postfix") + 123						// => ("prefix" + inner + "postfix123")						res.setWrapped(							left.prefix,							new BasicEvaluatedExpression()								.setString(left.postfix.string + right.number)								.setRange(joinRanges(left.postfix.range, right.range)),							left.wrappedInnerExpressions						);					} else if (right.isString()) {						// ("prefix" + inner + [null]) + "right"						// => ("prefix" + inner + "right")						res.setWrapped(left.prefix, right, left.wrappedInnerExpressions);					} else if (right.isNumber()) {						// ("prefix" + inner + [null]) + 123						// => ("prefix" + inner + "123")						res.setWrapped(							left.prefix,							new BasicEvaluatedExpression()								.setString(right.number + "")								.setRange(right.range),							left.wrappedInnerExpressions						);					} else if (right.isWrapped()) {						// ("prefix1" + inner1 + "postfix1") + ("prefix2" + inner2 + "postfix2")						// ("prefix1" + inner1 + "postfix1" + "prefix2" + inner2 + "postfix2")						res.setWrapped(							left.prefix,							right.postfix,							left.wrappedInnerExpressions &&								right.wrappedInnerExpressions &&								left.wrappedInnerExpressions									.concat(left.postfix ? [left.postfix] : [])									.concat(right.prefix ? [right.prefix] : [])									.concat(right.wrappedInnerExpressions)						);					} else {						// ("prefix" + inner + postfix) + expr						// => ("prefix" + inner + postfix + expr + [null])						res.setWrapped(							left.prefix,							null,							left.wrappedInnerExpressions &&								left.wrappedInnerExpressions.concat(									left.postfix ? [left.postfix, right] : [right]								)						);					}				} else {					if (right.isString()) {						// left + "right"						// => ([null] + left + "right")						res.setWrapped(null, right, [left]);					} else if (right.isWrapped()) {						// left + (prefix + inner + "postfix")						// => ([null] + left + prefix + inner + "postfix")						res.setWrapped(							null,							right.postfix,							right.wrappedInnerExpressions &&								(right.prefix ? [left, right.prefix] : [left]).concat(									right.wrappedInnerExpressions								)						);					} else {						return;					}				}				res.setRange(expr.range);				return res;			} else if (expr.operator === "-") {				left = this.evaluateExpression(expr.left);				right = this.evaluateExpression(expr.right);				if (!left || !right) return;				if (!left.isNumber() || !right.isNumber()) return;				res = new BasicEvaluatedExpression();				res.setNumber(left.number - right.number);				res.setRange(expr.range);				return res;			} else if (expr.operator === "*") {				left = this.evaluateExpression(expr.left);				right = this.evaluateExpression(expr.right);				if (!left || !right) return;				if (!left.isNumber() || !right.isNumber()) return;				res = new BasicEvaluatedExpression();				res.setNumber(left.number * right.number);				res.setRange(expr.range);				return res;			} else if (expr.operator === "/") {				left = this.evaluateExpression(expr.left);				right = this.evaluateExpression(expr.right);				if (!left || !right) return;				if (!left.isNumber() || !right.isNumber()) return;				res = new BasicEvaluatedExpression();				res.setNumber(left.number / right.number);				res.setRange(expr.range);				return res;			} else if (expr.operator === "**") {				left = this.evaluateExpression(expr.left);				right = this.evaluateExpression(expr.right);				if (!left || !right) return;				if (!left.isNumber() || !right.isNumber()) return;				res = new BasicEvaluatedExpression();				res.setNumber(Math.pow(left.number, right.number));				res.setRange(expr.range);				return res;			} else if (expr.operator === "==" || expr.operator === "===") {				left = this.evaluateExpression(expr.left);				right = this.evaluateExpression(expr.right);				if (!left || !right) return;				res = new BasicEvaluatedExpression();				res.setRange(expr.range);				if (left.isString() && right.isString()) {					return res.setBoolean(left.string === right.string);				} else if (left.isNumber() && right.isNumber()) {					return res.setBoolean(left.number === right.number);				} else if (left.isBoolean() && right.isBoolean()) {					return res.setBoolean(left.bool === right.bool);				}			} else if (expr.operator === "!=" || expr.operator === "!==") {				left = this.evaluateExpression(expr.left);				right = this.evaluateExpression(expr.right);				if (!left || !right) return;				res = new BasicEvaluatedExpression();				res.setRange(expr.range);				if (left.isString() && right.isString()) {					return res.setBoolean(left.string !== right.string);				} else if (left.isNumber() && right.isNumber()) {					return res.setBoolean(left.number !== right.number);				} else if (left.isBoolean() && right.isBoolean()) {					return res.setBoolean(left.bool !== right.bool);				}			} else if (expr.operator === "&") {				left = this.evaluateExpression(expr.left);				right = this.evaluateExpression(expr.right);				if (!left || !right) return;				if (!left.isNumber() || !right.isNumber()) return;				res = new BasicEvaluatedExpression();				res.setNumber(left.number & right.number);				res.setRange(expr.range);				return res;			} else if (expr.operator === "|") {				left = this.evaluateExpression(expr.left);				right = this.evaluateExpression(expr.right);				if (!left || !right) return;				if (!left.isNumber() || !right.isNumber()) return;				res = new BasicEvaluatedExpression();				res.setNumber(left.number | right.number);				res.setRange(expr.range);				return res;			} else if (expr.operator === "^") {				left = this.evaluateExpression(expr.left);				right = this.evaluateExpression(expr.right);				if (!left || !right) return;				if (!left.isNumber() || !right.isNumber()) return;				res = new BasicEvaluatedExpression();				res.setNumber(left.number ^ right.number);				res.setRange(expr.range);				return res;			} else if (expr.operator === ">>>") {				left = this.evaluateExpression(expr.left);				right = this.evaluateExpression(expr.right);				if (!left || !right) return;				if (!left.isNumber() || !right.isNumber()) return;				res = new BasicEvaluatedExpression();				res.setNumber(left.number >>> right.number);				res.setRange(expr.range);				return res;			} else if (expr.operator === ">>") {				left = this.evaluateExpression(expr.left);				right = this.evaluateExpression(expr.right);				if (!left || !right) return;				if (!left.isNumber() || !right.isNumber()) return;				res = new BasicEvaluatedExpression();				res.setNumber(left.number >> right.number);				res.setRange(expr.range);				return res;			} else if (expr.operator === "<<") {				left = this.evaluateExpression(expr.left);				right = this.evaluateExpression(expr.right);				if (!left || !right) return;				if (!left.isNumber() || !right.isNumber()) return;				res = new BasicEvaluatedExpression();				res.setNumber(left.number << right.number);				res.setRange(expr.range);				return res;			}		});		this.hooks.evaluate.for("UnaryExpression").tap("Parser", expr => {			if (expr.operator === "typeof") {				let res;				let name;				if (expr.argument.type === "Identifier") {					name =						this.scope.renames.get(expr.argument.name) || expr.argument.name;					if (!this.scope.definitions.has(name)) {						const hook = this.hooks.evaluateTypeof.get(name);						if (hook !== undefined) {							res = hook.call(expr);							if (res !== undefined) return res;						}					}				}				if (expr.argument.type === "MemberExpression") {					const exprName = this.getNameForExpression(expr.argument);					if (exprName && exprName.free) {						const hook = this.hooks.evaluateTypeof.get(exprName.name);						if (hook !== undefined) {							res = hook.call(expr);							if (res !== undefined) return res;						}					}				}				if (expr.argument.type === "FunctionExpression") {					return new BasicEvaluatedExpression()						.setString("function")						.setRange(expr.range);				}				const arg = this.evaluateExpression(expr.argument);				if (arg.isString() || arg.isWrapped()) {					return new BasicEvaluatedExpression()						.setString("string")						.setRange(expr.range);				}				if (arg.isNumber()) {					return new BasicEvaluatedExpression()						.setString("number")						.setRange(expr.range);				}				if (arg.isBoolean()) {					return new BasicEvaluatedExpression()						.setString("boolean")						.setRange(expr.range);				}				if (arg.isArray() || arg.isConstArray() || arg.isRegExp()) {					return new BasicEvaluatedExpression()						.setString("object")						.setRange(expr.range);				}			} else if (expr.operator === "!") {				const argument = this.evaluateExpression(expr.argument);				if (!argument) return;				if (argument.isBoolean()) {					return new BasicEvaluatedExpression()						.setBoolean(!argument.bool)						.setRange(expr.range);				}				if (argument.isTruthy()) {					return new BasicEvaluatedExpression()						.setBoolean(false)						.setRange(expr.range);				}				if (argument.isFalsy()) {					return new BasicEvaluatedExpression()						.setBoolean(true)						.setRange(expr.range);				}				if (argument.isString()) {					return new BasicEvaluatedExpression()						.setBoolean(!argument.string)						.setRange(expr.range);				}				if (argument.isNumber()) {					return new BasicEvaluatedExpression()						.setBoolean(!argument.number)						.setRange(expr.range);				}			} else if (expr.operator === "~") {				const argument = this.evaluateExpression(expr.argument);				if (!argument) return;				if (!argument.isNumber()) return;				const res = new BasicEvaluatedExpression();				res.setNumber(~argument.number);				res.setRange(expr.range);				return res;			}		});		this.hooks.evaluateTypeof.for("undefined").tap("Parser", expr => {			return new BasicEvaluatedExpression()				.setString("undefined")				.setRange(expr.range);		});		this.hooks.evaluate.for("Identifier").tap("Parser", expr => {			const name = this.scope.renames.get(expr.name) || expr.name;			if (!this.scope.definitions.has(expr.name)) {				const hook = this.hooks.evaluateIdentifier.get(name);				if (hook !== undefined) {					const result = hook.call(expr);					if (result) return result;				}				return new BasicEvaluatedExpression()					.setIdentifier(name)					.setRange(expr.range);			} else {				const hook = this.hooks.evaluateDefinedIdentifier.get(name);				if (hook !== undefined) {					return hook.call(expr);				}			}		});		this.hooks.evaluate.for("ThisExpression").tap("Parser", expr => {			const name = this.scope.renames.get("this");			if (name) {				const hook = this.hooks.evaluateIdentifier.get(name);				if (hook !== undefined) {					const result = hook.call(expr);					if (result) return result;				}				return new BasicEvaluatedExpression()					.setIdentifier(name)					.setRange(expr.range);			}		});		this.hooks.evaluate.for("MemberExpression").tap("Parser", expression => {			let exprName = this.getNameForExpression(expression);			if (exprName) {				if (exprName.free) {					const hook = this.hooks.evaluateIdentifier.get(exprName.name);					if (hook !== undefined) {						const result = hook.call(expression);						if (result) return result;					}					return new BasicEvaluatedExpression()						.setIdentifier(exprName.name)						.setRange(expression.range);				} else {					const hook = this.hooks.evaluateDefinedIdentifier.get(exprName.name);					if (hook !== undefined) {						return hook.call(expression);					}				}			}		});		this.hooks.evaluate.for("CallExpression").tap("Parser", expr => {			if (expr.callee.type !== "MemberExpression") return;			if (				expr.callee.property.type !==				(expr.callee.computed ? "Literal" : "Identifier")			)				return;			const param = this.evaluateExpression(expr.callee.object);			if (!param) return;			const property = expr.callee.property.name || expr.callee.property.value;			const hook = this.hooks.evaluateCallExpressionMember.get(property);			if (hook !== undefined) {				return hook.call(expr, param);			}		});		this.hooks.evaluateCallExpressionMember			.for("replace")			.tap("Parser", (expr, param) => {				if (!param.isString()) return;				if (expr.arguments.length !== 2) return;				let arg1 = this.evaluateExpression(expr.arguments[0]);				let arg2 = this.evaluateExpression(expr.arguments[1]);				if (!arg1.isString() && !arg1.isRegExp()) return;				arg1 = arg1.regExp || arg1.string;				if (!arg2.isString()) return;				arg2 = arg2.string;				return new BasicEvaluatedExpression()					.setString(param.string.replace(arg1, arg2))					.setRange(expr.range);			});		["substr", "substring"].forEach(fn => {			this.hooks.evaluateCallExpressionMember				.for(fn)				.tap("Parser", (expr, param) => {					if (!param.isString()) return;					let arg1;					let result,						str = param.string;					switch (expr.arguments.length) {						case 1:							arg1 = this.evaluateExpression(expr.arguments[0]);							if (!arg1.isNumber()) return;							result = str[fn](arg1.number);							break;						case 2: {							arg1 = this.evaluateExpression(expr.arguments[0]);							const arg2 = this.evaluateExpression(expr.arguments[1]);							if (!arg1.isNumber()) return;							if (!arg2.isNumber()) return;							result = str[fn](arg1.number, arg2.number);							break;						}						default:							return;					}					return new BasicEvaluatedExpression()						.setString(result)						.setRange(expr.range);				});		});		/**		 * @param {string} kind "cooked" | "raw"		 * @param {TODO} templateLiteralExpr TemplateLiteral expr		 * @returns {{quasis: BasicEvaluatedExpression[], parts: BasicEvaluatedExpression[]}} Simplified template		 */		const getSimplifiedTemplateResult = (kind, templateLiteralExpr) => {			const quasis = [];			const parts = [];			for (let i = 0; i < templateLiteralExpr.quasis.length; i++) {				const quasiExpr = templateLiteralExpr.quasis[i];				const quasi = quasiExpr.value[kind];				if (i > 0) {					const prevExpr = parts[parts.length - 1];					const expr = this.evaluateExpression(						templateLiteralExpr.expressions[i - 1]					);					const exprAsString = expr.asString();					if (typeof exprAsString === "string") {						// We can merge quasi + expr + quasi when expr						// is a const string						prevExpr.setString(prevExpr.string + exprAsString + quasi);						prevExpr.setRange([prevExpr.range[0], quasiExpr.range[1]]);						// We unset the expression as it doesn't match to a single expression						prevExpr.setExpression(undefined);						continue;					}					parts.push(expr);				}				const part = new BasicEvaluatedExpression()					.setString(quasi)					.setRange(quasiExpr.range)					.setExpression(quasiExpr);				quasis.push(part);				parts.push(part);			}			return {				quasis,				parts			};		};		this.hooks.evaluate.for("TemplateLiteral").tap("Parser", node => {			const { quasis, parts } = getSimplifiedTemplateResult("cooked", node);			if (parts.length === 1) {				return parts[0].setRange(node.range);			}			return new BasicEvaluatedExpression()				.setTemplateString(quasis, parts, "cooked")				.setRange(node.range);		});		this.hooks.evaluate.for("TaggedTemplateExpression").tap("Parser", node => {			if (this.evaluateExpression(node.tag).identifier !== "String.raw") return;			const { quasis, parts } = getSimplifiedTemplateResult("raw", node.quasi);			if (parts.length === 1) {				return parts[0].setRange(node.range);			}			return new BasicEvaluatedExpression()				.setTemplateString(quasis, parts, "raw")				.setRange(node.range);		});		this.hooks.evaluateCallExpressionMember			.for("concat")			.tap("Parser", (expr, param) => {				if (!param.isString() && !param.isWrapped()) return;				let stringSuffix = null;				let hasUnknownParams = false;				for (let i = expr.arguments.length - 1; i >= 0; i--) {					const argExpr = this.evaluateExpression(expr.arguments[i]);					if (!argExpr.isString() && !argExpr.isNumber()) {						hasUnknownParams = true;						break;					}					const value = argExpr.isString()						? argExpr.string						: "" + argExpr.number;					const newString = value + (stringSuffix ? stringSuffix.string : "");					const newRange = [						argExpr.range[0],						(stringSuffix || argExpr).range[1]					];					stringSuffix = new BasicEvaluatedExpression()						.setString(newString)						.setRange(newRange);				}				if (hasUnknownParams) {					const prefix = param.isString() ? param : param.prefix;					return new BasicEvaluatedExpression()						.setWrapped(prefix, stringSuffix)						.setRange(expr.range);				} else if (param.isWrapped()) {					const postfix = stringSuffix || param.postfix;					return new BasicEvaluatedExpression()						.setWrapped(param.prefix, postfix)						.setRange(expr.range);				} else {					const newString =						param.string + (stringSuffix ? stringSuffix.string : "");					return new BasicEvaluatedExpression()						.setString(newString)						.setRange(expr.range);				}			});		this.hooks.evaluateCallExpressionMember			.for("split")			.tap("Parser", (expr, param) => {				if (!param.isString()) return;				if (expr.arguments.length !== 1) return;				let result;				const arg = this.evaluateExpression(expr.arguments[0]);				if (arg.isString()) {					result = param.string.split(arg.string);				} else if (arg.isRegExp()) {					result = param.string.split(arg.regExp);				} else {					return;				}				return new BasicEvaluatedExpression()					.setArray(result)					.setRange(expr.range);			});		this.hooks.evaluate.for("ConditionalExpression").tap("Parser", expr => {			const condition = this.evaluateExpression(expr.test);			const conditionValue = condition.asBool();			let res;			if (conditionValue === undefined) {				const consequent = this.evaluateExpression(expr.consequent);				const alternate = this.evaluateExpression(expr.alternate);				if (!consequent || !alternate) return;				res = new BasicEvaluatedExpression();				if (consequent.isConditional()) {					res.setOptions(consequent.options);				} else {					res.setOptions([consequent]);				}				if (alternate.isConditional()) {					res.addOptions(alternate.options);				} else {					res.addOptions([alternate]);				}			} else {				res = this.evaluateExpression(					conditionValue ? expr.consequent : expr.alternate				);			}			res.setRange(expr.range);			return res;		});		this.hooks.evaluate.for("ArrayExpression").tap("Parser", expr => {			const items = expr.elements.map(element => {				return element !== null && this.evaluateExpression(element);			});			if (!items.every(Boolean)) return;			return new BasicEvaluatedExpression()				.setItems(items)				.setRange(expr.range);		});	}	getRenameIdentifier(expr) {		const result = this.evaluateExpression(expr);		if (result && result.isIdentifier()) {			return result.identifier;		}	}	walkClass(classy) {		if (classy.superClass) this.walkExpression(classy.superClass);		if (classy.body && classy.body.type === "ClassBody") {			const wasTopLevel = this.scope.topLevelScope;			this.scope.topLevelScope = false;			for (const methodDefinition of classy.body.body) {				if (methodDefinition.type === "MethodDefinition") {					this.walkMethodDefinition(methodDefinition);				}			}			this.scope.topLevelScope = wasTopLevel;		}	}	walkMethodDefinition(methodDefinition) {		if (methodDefinition.computed && methodDefinition.key) {			this.walkExpression(methodDefinition.key);		}		if (methodDefinition.value) {			this.walkExpression(methodDefinition.value);		}	}	// Prewalking iterates the scope for variable declarations	prewalkStatements(statements) {		for (let index = 0, len = statements.length; index < len; index++) {			const statement = statements[index];			this.prewalkStatement(statement);		}	}	// Block-Prewalking iterates the scope for block variable declarations	blockPrewalkStatements(statements) {		for (let index = 0, len = statements.length; index < len; index++) {			const statement = statements[index];			this.blockPrewalkStatement(statement);		}	}	// Walking iterates the statements and expressions and processes them	walkStatements(statements) {		for (let index = 0, len = statements.length; index < len; index++) {			const statement = statements[index];			this.walkStatement(statement);		}	}	prewalkStatement(statement) {		switch (statement.type) {			case "BlockStatement":				this.prewalkBlockStatement(statement);				break;			case "DoWhileStatement":				this.prewalkDoWhileStatement(statement);				break;			case "ExportAllDeclaration":				this.prewalkExportAllDeclaration(statement);				break;			case "ExportDefaultDeclaration":				this.prewalkExportDefaultDeclaration(statement);				break;			case "ExportNamedDeclaration":				this.prewalkExportNamedDeclaration(statement);				break;			case "ForInStatement":				this.prewalkForInStatement(statement);				break;			case "ForOfStatement":				this.prewalkForOfStatement(statement);				break;			case "ForStatement":				this.prewalkForStatement(statement);				break;			case "FunctionDeclaration":				this.prewalkFunctionDeclaration(statement);				break;			case "IfStatement":				this.prewalkIfStatement(statement);				break;			case "ImportDeclaration":				this.prewalkImportDeclaration(statement);				break;			case "LabeledStatement":				this.prewalkLabeledStatement(statement);				break;			case "SwitchStatement":				this.prewalkSwitchStatement(statement);				break;			case "TryStatement":				this.prewalkTryStatement(statement);				break;			case "VariableDeclaration":				this.prewalkVariableDeclaration(statement);				break;			case "WhileStatement":				this.prewalkWhileStatement(statement);				break;			case "WithStatement":				this.prewalkWithStatement(statement);				break;		}	}	blockPrewalkStatement(statement) {		switch (statement.type) {			case "VariableDeclaration":				this.blockPrewalkVariableDeclaration(statement);				break;			case "ExportDefaultDeclaration":				this.blockPrewalkExportDefaultDeclaration(statement);				break;			case "ExportNamedDeclaration":				this.blockPrewalkExportNamedDeclaration(statement);				break;			case "ClassDeclaration":				this.blockPrewalkClassDeclaration(statement);				break;		}	}	walkStatement(statement) {		if (this.hooks.statement.call(statement) !== undefined) return;		switch (statement.type) {			case "BlockStatement":				this.walkBlockStatement(statement);				break;			case "ClassDeclaration":				this.walkClassDeclaration(statement);				break;			case "DoWhileStatement":				this.walkDoWhileStatement(statement);				break;			case "ExportDefaultDeclaration":				this.walkExportDefaultDeclaration(statement);				break;			case "ExportNamedDeclaration":				this.walkExportNamedDeclaration(statement);				break;			case "ExpressionStatement":				this.walkExpressionStatement(statement);				break;			case "ForInStatement":				this.walkForInStatement(statement);				break;			case "ForOfStatement":				this.walkForOfStatement(statement);				break;			case "ForStatement":				this.walkForStatement(statement);				break;			case "FunctionDeclaration":				this.walkFunctionDeclaration(statement);				break;			case "IfStatement":				this.walkIfStatement(statement);				break;			case "LabeledStatement":				this.walkLabeledStatement(statement);				break;			case "ReturnStatement":				this.walkReturnStatement(statement);				break;			case "SwitchStatement":				this.walkSwitchStatement(statement);				break;			case "ThrowStatement":				this.walkThrowStatement(statement);				break;			case "TryStatement":				this.walkTryStatement(statement);				break;			case "VariableDeclaration":				this.walkVariableDeclaration(statement);				break;			case "WhileStatement":				this.walkWhileStatement(statement);				break;			case "WithStatement":				this.walkWithStatement(statement);				break;		}	}	// Real Statements	prewalkBlockStatement(statement) {		this.prewalkStatements(statement.body);	}	walkBlockStatement(statement) {		this.inBlockScope(() => {			const body = statement.body;			this.blockPrewalkStatements(body);			this.walkStatements(body);		});	}	walkExpressionStatement(statement) {		this.walkExpression(statement.expression);	}	prewalkIfStatement(statement) {		this.prewalkStatement(statement.consequent);		if (statement.alternate) {			this.prewalkStatement(statement.alternate);		}	}	walkIfStatement(statement) {		const result = this.hooks.statementIf.call(statement);		if (result === undefined) {			this.walkExpression(statement.test);			this.walkStatement(statement.consequent);			if (statement.alternate) {				this.walkStatement(statement.alternate);			}		} else {			if (result) {				this.walkStatement(statement.consequent);			} else if (statement.alternate) {				this.walkStatement(statement.alternate);			}		}	}	prewalkLabeledStatement(statement) {		this.prewalkStatement(statement.body);	}	walkLabeledStatement(statement) {		const hook = this.hooks.label.get(statement.label.name);		if (hook !== undefined) {			const result = hook.call(statement);			if (result === true) return;		}		this.walkStatement(statement.body);	}	prewalkWithStatement(statement) {		this.prewalkStatement(statement.body);	}	walkWithStatement(statement) {		this.walkExpression(statement.object);		this.walkStatement(statement.body);	}	prewalkSwitchStatement(statement) {		this.prewalkSwitchCases(statement.cases);	}	walkSwitchStatement(statement) {		this.walkExpression(statement.discriminant);		this.walkSwitchCases(statement.cases);	}	walkTerminatingStatement(statement) {		if (statement.argument) this.walkExpression(statement.argument);	}	walkReturnStatement(statement) {		this.walkTerminatingStatement(statement);	}	walkThrowStatement(statement) {		this.walkTerminatingStatement(statement);	}	prewalkTryStatement(statement) {		this.prewalkStatement(statement.block);	}	walkTryStatement(statement) {		if (this.scope.inTry) {			this.walkStatement(statement.block);		} else {			this.scope.inTry = true;			this.walkStatement(statement.block);			this.scope.inTry = false;		}		if (statement.handler) this.walkCatchClause(statement.handler);		if (statement.finalizer) this.walkStatement(statement.finalizer);	}	prewalkWhileStatement(statement) {		this.prewalkStatement(statement.body);	}	walkWhileStatement(statement) {		this.walkExpression(statement.test);		this.walkStatement(statement.body);	}	prewalkDoWhileStatement(statement) {		this.prewalkStatement(statement.body);	}	walkDoWhileStatement(statement) {		this.walkStatement(statement.body);		this.walkExpression(statement.test);	}	prewalkForStatement(statement) {		if (statement.init) {			if (statement.init.type === "VariableDeclaration") {				this.prewalkStatement(statement.init);			}		}		this.prewalkStatement(statement.body);	}	walkForStatement(statement) {		this.inBlockScope(() => {			if (statement.init) {				if (statement.init.type === "VariableDeclaration") {					this.blockPrewalkVariableDeclaration(statement.init);					this.walkStatement(statement.init);				} else {					this.walkExpression(statement.init);				}			}			if (statement.test) {				this.walkExpression(statement.test);			}			if (statement.update) {				this.walkExpression(statement.update);			}			const body = statement.body;			if (body.type === "BlockStatement") {				// no need to add additional scope				this.blockPrewalkStatements(body.body);				this.walkStatements(body.body);			} else {				this.walkStatement(body);			}		});	}	prewalkForInStatement(statement) {		if (statement.left.type === "VariableDeclaration") {			this.prewalkVariableDeclaration(statement.left);		}		this.prewalkStatement(statement.body);	}	walkForInStatement(statement) {		this.inBlockScope(() => {			if (statement.left.type === "VariableDeclaration") {				this.blockPrewalkVariableDeclaration(statement.left);				this.walkVariableDeclaration(statement.left);			} else {				this.walkPattern(statement.left);			}			this.walkExpression(statement.right);			const body = statement.body;			if (body.type === "BlockStatement") {				// no need to add additional scope				this.blockPrewalkStatements(body.body);				this.walkStatements(body.body);			} else {				this.walkStatement(body);			}		});	}	prewalkForOfStatement(statement) {		if (statement.left.type === "VariableDeclaration") {			this.prewalkVariableDeclaration(statement.left);		}		this.prewalkStatement(statement.body);	}	walkForOfStatement(statement) {		this.inBlockScope(() => {			if (statement.left.type === "VariableDeclaration") {				this.blockPrewalkVariableDeclaration(statement.left);				this.walkVariableDeclaration(statement.left);			} else {				this.walkPattern(statement.left);			}			this.walkExpression(statement.right);			const body = statement.body;			if (body.type === "BlockStatement") {				// no need to add additional scope				this.blockPrewalkStatements(body.body);				this.walkStatements(body.body);			} else {				this.walkStatement(body);			}		});	}	// Declarations	prewalkFunctionDeclaration(statement) {		if (statement.id) {			this.scope.renames.set(statement.id.name, null);			this.scope.definitions.add(statement.id.name);		}	}	walkFunctionDeclaration(statement) {		const wasTopLevel = this.scope.topLevelScope;		this.scope.topLevelScope = false;		this.inFunctionScope(true, statement.params, () => {			for (const param of statement.params) {				this.walkPattern(param);			}			if (statement.body.type === "BlockStatement") {				this.detectMode(statement.body.body);				this.prewalkStatement(statement.body);				this.walkStatement(statement.body);			} else {				this.walkExpression(statement.body);			}		});		this.scope.topLevelScope = wasTopLevel;	}	prewalkImportDeclaration(statement) {		const source = statement.source.value;		this.hooks.import.call(statement, source);		for (const specifier of statement.specifiers) {			const name = specifier.local.name;			this.scope.renames.set(name, null);			this.scope.definitions.add(name);			switch (specifier.type) {				case "ImportDefaultSpecifier":					this.hooks.importSpecifier.call(statement, source, "default", name);					break;				case "ImportSpecifier":					this.hooks.importSpecifier.call(						statement,						source,						specifier.imported.name,						name					);					break;				case "ImportNamespaceSpecifier":					this.hooks.importSpecifier.call(statement, source, null, name);					break;			}		}	}	enterDeclaration(declaration, onIdent) {		switch (declaration.type) {			case "VariableDeclaration":				for (const declarator of declaration.declarations) {					switch (declarator.type) {						case "VariableDeclarator": {							this.enterPattern(declarator.id, onIdent);							break;						}					}				}				break;			case "FunctionDeclaration":				this.enterPattern(declaration.id, onIdent);				break;			case "ClassDeclaration":				this.enterPattern(declaration.id, onIdent);				break;		}	}	blockPrewalkExportNamedDeclaration(statement) {		if (statement.declaration) {			this.blockPrewalkStatement(statement.declaration);		}	}	prewalkExportNamedDeclaration(statement) {		let source;		if (statement.source) {			source = statement.source.value;			this.hooks.exportImport.call(statement, source);		} else {			this.hooks.export.call(statement);		}		if (statement.declaration) {			if (				!this.hooks.exportDeclaration.call(statement, statement.declaration)			) {				this.prewalkStatement(statement.declaration);				let index = 0;				this.enterDeclaration(statement.declaration, def => {					this.hooks.exportSpecifier.call(statement, def, def, index++);				});			}		}		if (statement.specifiers) {			for (				let specifierIndex = 0;				specifierIndex < statement.specifiers.length;				specifierIndex++			) {				const specifier = statement.specifiers[specifierIndex];				switch (specifier.type) {					case "ExportSpecifier": {						const name = specifier.exported.name;						if (source) {							this.hooks.exportImportSpecifier.call(								statement,								source,								specifier.local.name,								name,								specifierIndex							);						} else {							this.hooks.exportSpecifier.call(								statement,								specifier.local.name,								name,								specifierIndex							);						}						break;					}				}			}		}	}	walkExportNamedDeclaration(statement) {		if (statement.declaration) {			this.walkStatement(statement.declaration);		}	}	blockPrewalkExportDefaultDeclaration(statement) {		if (statement.declaration.type === "ClassDeclaration") {			this.blockPrewalkClassDeclaration(statement.declaration);		}	}	prewalkExportDefaultDeclaration(statement) {		this.prewalkStatement(statement.declaration);		if (			statement.declaration.id &&			statement.declaration.type !== "FunctionExpression" &&			statement.declaration.type !== "ClassExpression"		) {			this.hooks.exportSpecifier.call(				statement,				statement.declaration.id.name,				"default"			);		}	}	walkExportDefaultDeclaration(statement) {		this.hooks.export.call(statement);		if (			statement.declaration.id &&			statement.declaration.type !== "FunctionExpression" &&			statement.declaration.type !== "ClassExpression"		) {			if (				!this.hooks.exportDeclaration.call(statement, statement.declaration)			) {				this.walkStatement(statement.declaration);			}		} else {			// Acorn parses `export default function() {}` as `FunctionDeclaration` and			// `export default class {}` as `ClassDeclaration`, both with `id = null`.			// These nodes must be treated as expressions.			if (statement.declaration.type === "FunctionDeclaration") {				this.walkFunctionDeclaration(statement.declaration);			} else if (statement.declaration.type === "ClassDeclaration") {				this.walkClassDeclaration(statement.declaration);			} else {				this.walkExpression(statement.declaration);			}			if (!this.hooks.exportExpression.call(statement, statement.declaration)) {				this.hooks.exportSpecifier.call(					statement,					statement.declaration,					"default"				);			}		}	}	prewalkExportAllDeclaration(statement) {		const source = statement.source.value;		this.hooks.exportImport.call(statement, source);		this.hooks.exportImportSpecifier.call(statement, source, null, null, 0);	}	prewalkVariableDeclaration(statement) {		if (statement.kind !== "var") return;		this._prewalkVariableDeclaration(statement, this.hooks.varDeclarationVar);	}	blockPrewalkVariableDeclaration(statement) {		if (statement.kind === "var") return;		const hookMap =			statement.kind === "const"				? this.hooks.varDeclarationConst				: this.hooks.varDeclarationLet;		this._prewalkVariableDeclaration(statement, hookMap);	}	_prewalkVariableDeclaration(statement, hookMap) {		for (const declarator of statement.declarations) {			switch (declarator.type) {				case "VariableDeclarator": {					this.enterPattern(declarator.id, (name, decl) => {						let hook = hookMap.get(name);						if (hook === undefined || !hook.call(decl)) {							hook = this.hooks.varDeclaration.get(name);							if (hook === undefined || !hook.call(decl)) {								this.scope.renames.set(name, null);								this.scope.definitions.add(name);							}						}					});					break;				}			}		}	}	walkVariableDeclaration(statement) {		for (const declarator of statement.declarations) {			switch (declarator.type) {				case "VariableDeclarator": {					const renameIdentifier =						declarator.init && this.getRenameIdentifier(declarator.init);					if (renameIdentifier && declarator.id.type === "Identifier") {						const hook = this.hooks.canRename.get(renameIdentifier);						if (hook !== undefined && hook.call(declarator.init)) {							// renaming with "var a = b;"							const hook = this.hooks.rename.get(renameIdentifier);							if (hook === undefined || !hook.call(declarator.init)) {								this.scope.renames.set(									declarator.id.name,									this.scope.renames.get(renameIdentifier) || renameIdentifier								);								this.scope.definitions.delete(declarator.id.name);							}							break;						}					}					this.walkPattern(declarator.id);					if (declarator.init) this.walkExpression(declarator.init);					break;				}			}		}	}	blockPrewalkClassDeclaration(statement) {		if (statement.id) {			this.scope.renames.set(statement.id.name, null);			this.scope.definitions.add(statement.id.name);		}	}	walkClassDeclaration(statement) {		this.walkClass(statement);	}	prewalkSwitchCases(switchCases) {		for (let index = 0, len = switchCases.length; index < len; index++) {			const switchCase = switchCases[index];			this.prewalkStatements(switchCase.consequent);		}	}	walkSwitchCases(switchCases) {		for (let index = 0, len = switchCases.length; index < len; index++) {			const switchCase = switchCases[index];			if (switchCase.test) {				this.walkExpression(switchCase.test);			}			this.walkStatements(switchCase.consequent);		}	}	walkCatchClause(catchClause) {		this.inBlockScope(() => {			// Error binding is optional in catch clause since ECMAScript 2019			if (catchClause.param !== null) {				this.enterPattern(catchClause.param, ident => {					this.scope.renames.set(ident, null);					this.scope.definitions.add(ident);				});				this.walkPattern(catchClause.param);			}			this.prewalkStatement(catchClause.body);			this.walkStatement(catchClause.body);		});	}	walkPattern(pattern) {		switch (pattern.type) {			case "ArrayPattern":				this.walkArrayPattern(pattern);				break;			case "AssignmentPattern":				this.walkAssignmentPattern(pattern);				break;			case "MemberExpression":				this.walkMemberExpression(pattern);				break;			case "ObjectPattern":				this.walkObjectPattern(pattern);				break;			case "RestElement":				this.walkRestElement(pattern);				break;		}	}	walkAssignmentPattern(pattern) {		this.walkExpression(pattern.right);		this.walkPattern(pattern.left);	}	walkObjectPattern(pattern) {		for (let i = 0, len = pattern.properties.length; i < len; i++) {			const prop = pattern.properties[i];			if (prop) {				if (prop.computed) this.walkExpression(prop.key);				if (prop.value) this.walkPattern(prop.value);			}		}	}	walkArrayPattern(pattern) {		for (let i = 0, len = pattern.elements.length; i < len; i++) {			const element = pattern.elements[i];			if (element) this.walkPattern(element);		}	}	walkRestElement(pattern) {		this.walkPattern(pattern.argument);	}	walkExpressions(expressions) {		for (const expression of expressions) {			if (expression) {				this.walkExpression(expression);			}		}	}	walkExpression(expression) {		switch (expression.type) {			case "ArrayExpression":				this.walkArrayExpression(expression);				break;			case "ArrowFunctionExpression":				this.walkArrowFunctionExpression(expression);				break;			case "AssignmentExpression":				this.walkAssignmentExpression(expression);				break;			case "AwaitExpression":				this.walkAwaitExpression(expression);				break;			case "BinaryExpression":				this.walkBinaryExpression(expression);				break;			case "CallExpression":				this.walkCallExpression(expression);				break;			case "ClassExpression":				this.walkClassExpression(expression);				break;			case "ConditionalExpression":				this.walkConditionalExpression(expression);				break;			case "FunctionExpression":				this.walkFunctionExpression(expression);				break;			case "Identifier":				this.walkIdentifier(expression);				break;			case "LogicalExpression":				this.walkLogicalExpression(expression);				break;			case "MemberExpression":				this.walkMemberExpression(expression);				break;			case "NewExpression":				this.walkNewExpression(expression);				break;			case "ObjectExpression":				this.walkObjectExpression(expression);				break;			case "SequenceExpression":				this.walkSequenceExpression(expression);				break;			case "SpreadElement":				this.walkSpreadElement(expression);				break;			case "TaggedTemplateExpression":				this.walkTaggedTemplateExpression(expression);				break;			case "TemplateLiteral":				this.walkTemplateLiteral(expression);				break;			case "ThisExpression":				this.walkThisExpression(expression);				break;			case "UnaryExpression":				this.walkUnaryExpression(expression);				break;			case "UpdateExpression":				this.walkUpdateExpression(expression);				break;			case "YieldExpression":				this.walkYieldExpression(expression);				break;		}	}	walkAwaitExpression(expression) {		this.walkExpression(expression.argument);	}	walkArrayExpression(expression) {		if (expression.elements) {			this.walkExpressions(expression.elements);		}	}	walkSpreadElement(expression) {		if (expression.argument) {			this.walkExpression(expression.argument);		}	}	walkObjectExpression(expression) {		for (			let propIndex = 0, len = expression.properties.length;			propIndex < len;			propIndex++		) {			const prop = expression.properties[propIndex];			if (prop.type === "SpreadElement") {				this.walkExpression(prop.argument);				continue;			}			if (prop.computed) {				this.walkExpression(prop.key);			}			if (prop.shorthand) {				this.scope.inShorthand = true;			}			this.walkExpression(prop.value);			if (prop.shorthand) {				this.scope.inShorthand = false;			}		}	}	walkFunctionExpression(expression) {		const wasTopLevel = this.scope.topLevelScope;		this.scope.topLevelScope = false;		const scopeParams = expression.params;		// Add function name in scope for recursive calls		if (expression.id) {			scopeParams.push(expression.id.name);		}		this.inFunctionScope(true, scopeParams, () => {			for (const param of expression.params) {				this.walkPattern(param);			}			if (expression.body.type === "BlockStatement") {				this.detectMode(expression.body.body);				this.prewalkStatement(expression.body);				this.walkStatement(expression.body);			} else {				this.walkExpression(expression.body);			}		});		this.scope.topLevelScope = wasTopLevel;	}	walkArrowFunctionExpression(expression) {		this.inFunctionScope(false, expression.params, () => {			for (const param of expression.params) {				this.walkPattern(param);			}			if (expression.body.type === "BlockStatement") {				this.detectMode(expression.body.body);				this.prewalkStatement(expression.body);				this.walkStatement(expression.body);			} else {				this.walkExpression(expression.body);			}		});	}	walkSequenceExpression(expression) {		if (expression.expressions) this.walkExpressions(expression.expressions);	}	walkUpdateExpression(expression) {		this.walkExpression(expression.argument);	}	walkUnaryExpression(expression) {		if (expression.operator === "typeof") {			const exprName = this.getNameForExpression(expression.argument);			if (exprName && exprName.free) {				const hook = this.hooks.typeof.get(exprName.name);				if (hook !== undefined) {					const result = hook.call(expression);					if (result === true) return;				}			}		}		this.walkExpression(expression.argument);	}	walkLeftRightExpression(expression) {		this.walkExpression(expression.left);		this.walkExpression(expression.right);	}	walkBinaryExpression(expression) {		this.walkLeftRightExpression(expression);	}	walkLogicalExpression(expression) {		const result = this.hooks.expressionLogicalOperator.call(expression);		if (result === undefined) {			this.walkLeftRightExpression(expression);		} else {			if (result) {				this.walkExpression(expression.right);			}		}	}	walkAssignmentExpression(expression) {		const renameIdentifier = this.getRenameIdentifier(expression.right);		if (expression.left.type === "Identifier" && renameIdentifier) {			const hook = this.hooks.canRename.get(renameIdentifier);			if (hook !== undefined && hook.call(expression.right)) {				// renaming "a = b;"				const hook = this.hooks.rename.get(renameIdentifier);				if (hook === undefined || !hook.call(expression.right)) {					this.scope.renames.set(expression.left.name, renameIdentifier);					this.scope.definitions.delete(expression.left.name);				}				return;			}		}		if (expression.left.type === "Identifier") {			const assignedHook = this.hooks.assigned.get(expression.left.name);			if (assignedHook === undefined || !assignedHook.call(expression)) {				this.walkExpression(expression.right);			}			this.scope.renames.set(expression.left.name, null);			const assignHook = this.hooks.assign.get(expression.left.name);			if (assignHook === undefined || !assignHook.call(expression)) {				this.walkExpression(expression.left);			}			return;		}		this.walkExpression(expression.right);		this.walkPattern(expression.left);		this.enterPattern(expression.left, (name, decl) => {			this.scope.renames.set(name, null);		});	}	walkConditionalExpression(expression) {		const result = this.hooks.expressionConditionalOperator.call(expression);		if (result === undefined) {			this.walkExpression(expression.test);			this.walkExpression(expression.consequent);			if (expression.alternate) {				this.walkExpression(expression.alternate);			}		} else {			if (result) {				this.walkExpression(expression.consequent);			} else if (expression.alternate) {				this.walkExpression(expression.alternate);			}		}	}	walkNewExpression(expression) {		const callee = this.evaluateExpression(expression.callee);		if (callee.isIdentifier()) {			const hook = this.hooks.new.get(callee.identifier);			if (hook !== undefined) {				const result = hook.call(expression);				if (result === true) {					return;				}			}		}		this.walkExpression(expression.callee);		if (expression.arguments) {			this.walkExpressions(expression.arguments);		}	}	walkYieldExpression(expression) {		if (expression.argument) {			this.walkExpression(expression.argument);		}	}	walkTemplateLiteral(expression) {		if (expression.expressions) {			this.walkExpressions(expression.expressions);		}	}	walkTaggedTemplateExpression(expression) {		if (expression.tag) {			this.walkExpression(expression.tag);		}		if (expression.quasi && expression.quasi.expressions) {			this.walkExpressions(expression.quasi.expressions);		}	}	walkClassExpression(expression) {		this.walkClass(expression);	}	_walkIIFE(functionExpression, options, currentThis) {		const renameArgOrThis = argOrThis => {			const renameIdentifier = this.getRenameIdentifier(argOrThis);			if (renameIdentifier) {				const hook = this.hooks.canRename.get(renameIdentifier);				if (hook !== undefined && hook.call(argOrThis)) {					const hook = this.hooks.rename.get(renameIdentifier);					if (hook === undefined || !hook.call(argOrThis)) {						return renameIdentifier;					}				}			}			this.walkExpression(argOrThis);		};		const params = functionExpression.params;		const renameThis = currentThis ? renameArgOrThis(currentThis) : null;		const args = options.map(renameArgOrThis);		const wasTopLevel = this.scope.topLevelScope;		this.scope.topLevelScope = false;		const scopeParams = params.filter((identifier, idx) => !args[idx]);		// Add function name in scope for recursive calls		if (functionExpression.id) {			scopeParams.push(functionExpression.id.name);		}		this.inFunctionScope(true, scopeParams, () => {			if (renameThis) {				this.scope.renames.set("this", renameThis);			}			for (let i = 0; i < args.length; i++) {				const param = args[i];				if (!param) continue;				if (!params[i] || params[i].type !== "Identifier") continue;				this.scope.renames.set(params[i].name, param);			}			if (functionExpression.body.type === "BlockStatement") {				this.detectMode(functionExpression.body.body);				this.prewalkStatement(functionExpression.body);				this.walkStatement(functionExpression.body);			} else {				this.walkExpression(functionExpression.body);			}		});		this.scope.topLevelScope = wasTopLevel;	}	walkCallExpression(expression) {		if (			expression.callee.type === "MemberExpression" &&			expression.callee.object.type === "FunctionExpression" &&			!expression.callee.computed &&			(expression.callee.property.name === "call" ||				expression.callee.property.name === "bind") &&			expression.arguments.length > 0		) {			// (function(…) { }.call/bind(?, …))			this._walkIIFE(				expression.callee.object,				expression.arguments.slice(1),				expression.arguments[0]			);		} else if (expression.callee.type === "FunctionExpression") {			// (function(…) { }(…))			this._walkIIFE(expression.callee, expression.arguments, null);		} else if (expression.callee.type === "Import") {			let result = this.hooks.importCall.call(expression);			if (result === true) return;			if (expression.arguments) this.walkExpressions(expression.arguments);		} else {			const callee = this.evaluateExpression(expression.callee);			if (callee.isIdentifier()) {				const callHook = this.hooks.call.get(callee.identifier);				if (callHook !== undefined) {					let result = callHook.call(expression);					if (result === true) return;				}				let identifier = callee.identifier.replace(/\.[^.]+$/, "");				if (identifier !== callee.identifier) {					const callAnyHook = this.hooks.callAnyMember.get(identifier);					if (callAnyHook !== undefined) {						let result = callAnyHook.call(expression);						if (result === true) return;					}				}			}			if (expression.callee) this.walkExpression(expression.callee);			if (expression.arguments) this.walkExpressions(expression.arguments);		}	}	walkMemberExpression(expression) {		const exprName = this.getNameForExpression(expression);		if (exprName && exprName.free) {			const expressionHook = this.hooks.expression.get(exprName.name);			if (expressionHook !== undefined) {				const result = expressionHook.call(expression);				if (result === true) return;			}			const expressionAnyMemberHook = this.hooks.expressionAnyMember.get(				exprName.nameGeneral			);			if (expressionAnyMemberHook !== undefined) {				const result = expressionAnyMemberHook.call(expression);				if (result === true) return;			}		}		this.walkExpression(expression.object);		if (expression.computed === true) this.walkExpression(expression.property);	}	walkThisExpression(expression) {		const expressionHook = this.hooks.expression.get("this");		if (expressionHook !== undefined) {			expressionHook.call(expression);		}	}	walkIdentifier(expression) {		if (!this.scope.definitions.has(expression.name)) {			const hook = this.hooks.expression.get(				this.scope.renames.get(expression.name) || expression.name			);			if (hook !== undefined) {				const result = hook.call(expression);				if (result === true) return;			}		}	}	/**	 * @deprecated	 * @param {any} params scope params	 * @param {function(): void} fn inner function	 * @returns {void}	 */	inScope(params, fn) {		const oldScope = this.scope;		this.scope = {			topLevelScope: oldScope.topLevelScope,			inTry: false,			inShorthand: false,			isStrict: oldScope.isStrict,			isAsmJs: oldScope.isAsmJs,			definitions: oldScope.definitions.createChild(),			renames: oldScope.renames.createChild()		};		this.scope.renames.set("this", null);		this.enterPatterns(params, ident => {			this.scope.renames.set(ident, null);			this.scope.definitions.add(ident);		});		fn();		this.scope = oldScope;	}	inFunctionScope(hasThis, params, fn) {		const oldScope = this.scope;		this.scope = {			topLevelScope: oldScope.topLevelScope,			inTry: false,			inShorthand: false,			isStrict: oldScope.isStrict,			isAsmJs: oldScope.isAsmJs,			definitions: oldScope.definitions.createChild(),			renames: oldScope.renames.createChild()		};		if (hasThis) {			this.scope.renames.set("this", null);		}		this.enterPatterns(params, ident => {			this.scope.renames.set(ident, null);			this.scope.definitions.add(ident);		});		fn();		this.scope = oldScope;	}	inBlockScope(fn) {		const oldScope = this.scope;		this.scope = {			topLevelScope: oldScope.topLevelScope,			inTry: oldScope.inTry,			inShorthand: false,			isStrict: oldScope.isStrict,			isAsmJs: oldScope.isAsmJs,			definitions: oldScope.definitions.createChild(),			renames: oldScope.renames.createChild()		};		fn();		this.scope = oldScope;	}	// TODO webpack 5: remove this methods	// only for backward-compat	detectStrictMode(statements) {		this.detectMode(statements);	}	detectMode(statements) {		const isLiteral =			statements.length >= 1 &&			statements[0].type === "ExpressionStatement" &&			statements[0].expression.type === "Literal";		if (isLiteral && statements[0].expression.value === "use strict") {			this.scope.isStrict = true;		}		if (isLiteral && statements[0].expression.value === "use asm") {			this.scope.isAsmJs = true;		}	}	enterPatterns(patterns, onIdent) {		for (const pattern of patterns) {			if (typeof pattern !== "string") {				this.enterPattern(pattern, onIdent);			} else if (pattern) {				onIdent(pattern);			}		}	}	enterPattern(pattern, onIdent) {		if (!pattern) return;		switch (pattern.type) {			case "ArrayPattern":				this.enterArrayPattern(pattern, onIdent);				break;			case "AssignmentPattern":				this.enterAssignmentPattern(pattern, onIdent);				break;			case "Identifier":				this.enterIdentifier(pattern, onIdent);				break;			case "ObjectPattern":				this.enterObjectPattern(pattern, onIdent);				break;			case "RestElement":				this.enterRestElement(pattern, onIdent);				break;			case "Property":				this.enterPattern(pattern.value, onIdent);				break;		}	}	enterIdentifier(pattern, onIdent) {		onIdent(pattern.name, pattern);	}	enterObjectPattern(pattern, onIdent) {		for (			let propIndex = 0, len = pattern.properties.length;			propIndex < len;			propIndex++		) {			const prop = pattern.properties[propIndex];			this.enterPattern(prop, onIdent);		}	}	enterArrayPattern(pattern, onIdent) {		for (			let elementIndex = 0, len = pattern.elements.length;			elementIndex < len;			elementIndex++		) {			const element = pattern.elements[elementIndex];			this.enterPattern(element, onIdent);		}	}	enterRestElement(pattern, onIdent) {		this.enterPattern(pattern.argument, onIdent);	}	enterAssignmentPattern(pattern, onIdent) {		this.enterPattern(pattern.left, onIdent);	}	evaluateExpression(expression) {		try {			const hook = this.hooks.evaluate.get(expression.type);			if (hook !== undefined) {				const result = hook.call(expression);				if (result !== undefined) {					if (result) {						result.setExpression(expression);					}					return result;				}			}		} catch (e) {			console.warn(e);			// ignore error		}		return new BasicEvaluatedExpression()			.setRange(expression.range)			.setExpression(expression);	}	parseString(expression) {		switch (expression.type) {			case "BinaryExpression":				if (expression.operator === "+") {					return (						this.parseString(expression.left) +						this.parseString(expression.right)					);				}				break;			case "Literal":				return expression.value + "";		}		throw new Error(			expression.type + " is not supported as parameter for require"		);	}	parseCalculatedString(expression) {		switch (expression.type) {			case "BinaryExpression":				if (expression.operator === "+") {					const left = this.parseCalculatedString(expression.left);					const right = this.parseCalculatedString(expression.right);					if (left.code) {						return {							range: left.range,							value: left.value,							code: true,							conditional: false						};					} else if (right.code) {						return {							range: [								left.range[0],								right.range ? right.range[1] : left.range[1]							],							value: left.value + right.value,							code: true,							conditional: false						};					} else {						return {							range: [left.range[0], right.range[1]],							value: left.value + right.value,							code: false,							conditional: false						};					}				}				break;			case "ConditionalExpression": {				const consequent = this.parseCalculatedString(expression.consequent);				const alternate = this.parseCalculatedString(expression.alternate);				const items = [];				if (consequent.conditional) {					items.push(...consequent.conditional);				} else if (!consequent.code) {					items.push(consequent);				} else {					break;				}				if (alternate.conditional) {					items.push(...alternate.conditional);				} else if (!alternate.code) {					items.push(alternate);				} else {					break;				}				return {					range: undefined,					value: "",					code: true,					conditional: items				};			}			case "Literal":				return {					range: expression.range,					value: expression.value + "",					code: false,					conditional: false				};		}		return {			range: undefined,			value: "",			code: true,			conditional: false		};	}	parse(source, initialState) {		let ast;		let comments;		if (typeof source === "object" && source !== null) {			ast = source;			comments = source.comments;		} else {			comments = [];			ast = Parser.parse(source, {				sourceType: this.sourceType,				onComment: comments			});		}		const oldScope = this.scope;		const oldState = this.state;		const oldComments = this.comments;		this.scope = {			topLevelScope: true,			inTry: false,			inShorthand: false,			isStrict: false,			isAsmJs: false,			definitions: new StackedSetMap(),			renames: new StackedSetMap()		};		const state = (this.state = initialState || {});		this.comments = comments;		if (this.hooks.program.call(ast, comments) === undefined) {			this.detectMode(ast.body);			this.prewalkStatements(ast.body);			this.blockPrewalkStatements(ast.body);			this.walkStatements(ast.body);		}		this.scope = oldScope;		this.state = oldState;		this.comments = oldComments;		return state;	}	evaluate(source) {		const ast = Parser.parse("(" + source + ")", {			sourceType: this.sourceType,			locations: false		});		// TODO(https://github.com/acornjs/acorn/issues/741)		// @ts-ignore		if (ast.body.length !== 1 || ast.body[0].type !== "ExpressionStatement") {			throw new Error("evaluate: Source is not a expression");		}		// TODO(https://github.com/acornjs/acorn/issues/741)		// @ts-ignore		return this.evaluateExpression(ast.body[0].expression);	}	getComments(range) {		return this.comments.filter(			comment => comment.range[0] >= range[0] && comment.range[1] <= range[1]		);	}	parseCommentOptions(range) {		const comments = this.getComments(range);		if (comments.length === 0) {			return EMPTY_COMMENT_OPTIONS;		}		let options = {};		let errors = [];		for (const comment of comments) {			const { value } = comment;			if (value && webpackCommentRegExp.test(value)) {				// try compile only if webpack options comment is present				try {					const val = vm.runInNewContext(`(function(){return {${value}};})()`);					Object.assign(options, val);				} catch (e) {					e.comment = comment;					errors.push(e);				}			}		}		return { options, errors };	}	getNameForExpression(expression) {		let expr = expression;		const exprName = [];		while (			expr.type === "MemberExpression" &&			expr.property.type === (expr.computed ? "Literal" : "Identifier")		) {			exprName.push(expr.computed ? expr.property.value : expr.property.name);			expr = expr.object;		}		let free;		if (expr.type === "Identifier") {			free = !this.scope.definitions.has(expr.name);			exprName.push(this.scope.renames.get(expr.name) || expr.name);		} else if (			expr.type === "ThisExpression" &&			this.scope.renames.get("this")		) {			free = true;			exprName.push(this.scope.renames.get("this"));		} else if (expr.type === "ThisExpression") {			free = this.scope.topLevelScope;			exprName.push("this");		} else {			return null;		}		let prefix = "";		for (let i = exprName.length - 1; i >= 2; i--) {			prefix += exprName[i] + ".";		}		if (exprName.length > 1) {			prefix += exprName[1];		}		const name = prefix ? prefix + "." + exprName[0] : exprName[0];		const nameGeneral = prefix;		return {			name,			nameGeneral,			free		};	}	static parse(code, options) {		const type = options ? options.sourceType : "module";		const parserOptions = Object.assign(			Object.create(null),			defaultParserOptions,			options		);		if (type === "auto") {			parserOptions.sourceType = "module";		} else if (parserOptions.sourceType === "script") {			parserOptions.allowReturnOutsideFunction = true;		}		let ast;		let error;		let threw = false;		try {			ast = acornParser.parse(code, parserOptions);		} catch (e) {			error = e;			threw = true;		}		if (threw && type === "auto") {			parserOptions.sourceType = "script";			parserOptions.allowReturnOutsideFunction = true;			if (Array.isArray(parserOptions.onComment)) {				parserOptions.onComment.length = 0;			}			try {				ast = acornParser.parse(code, parserOptions);				threw = false;			} catch (e) {				threw = true;			}		}		if (threw) {			throw error;		}		return ast;	}}// TODO remove in webpack 5Object.defineProperty(Parser.prototype, "getCommentOptions", {	configurable: false,	value: util.deprecate(		/**		 * @deprecated		 * @param {TODO} range Range		 * @returns {void}		 * @this {Parser}		 */		function(range) {			return this.parseCommentOptions(range).options;		},		"Parser.getCommentOptions: Use Parser.parseCommentOptions(range) instead"	)});module.exports = Parser;
 |