| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-30 23:08:51 +08:00
										 |  |  | "use strict"; | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-02 20:20:20 +08:00
										 |  |  | const { Parser } = require("acorn"); | 
					
						
							| 
									
										
										
										
											2018-06-26 14:27:44 +08:00
										 |  |  | const { SyncBailHook, HookMap } = require("tapable"); | 
					
						
							| 
									
										
										
										
											2017-10-14 05:31:15 +08:00
										 |  |  | const vm = require("vm"); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | const BasicEvaluatedExpression = require("./BasicEvaluatedExpression"); | 
					
						
							| 
									
										
										
										
											2017-08-11 18:30:33 +08:00
										 |  |  | const StackedSetMap = require("./util/StackedSetMap"); | 
					
						
							| 
									
										
										
										
											2017-12-20 15:37:49 +08:00
										 |  |  | const TrackingSet = require("./util/TrackingSet"); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-30 23:08:51 +08:00
										 |  |  | // Syntax: https://developer.mozilla.org/en/SpiderMonkey/Parser_API
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-02 20:20:20 +08:00
										 |  |  | const parser = Parser.extend(require("acorn-dynamic-import").default); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | const joinRanges = (startRange, endRange) => { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 	if (!endRange) return startRange; | 
					
						
							|  |  |  | 	if (!startRange) return endRange; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	return [startRange[0], endRange[1]]; | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 05:35:30 +08:00
										 |  |  | const defaultParserOptions = { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	ranges: true, | 
					
						
							|  |  |  | 	locations: true, | 
					
						
							| 
									
										
										
										
											2018-06-04 19:44:30 +08:00
										 |  |  | 	ecmaVersion: 2019, | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	sourceType: "module", | 
					
						
							| 
									
										
										
										
											2018-10-02 20:20:20 +08:00
										 |  |  | 	onComment: null | 
					
						
							| 
									
										
										
										
											2018-01-22 05:35:30 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-30 09:24:36 +08:00
										 |  |  | // regexp to match at lease one "magic comment"
 | 
					
						
							|  |  |  | const webpackCommentRegExp = new RegExp(/(^|\W)webpack[A-Z]{1,}[A-Za-z]{1,}:/); | 
					
						
							| 
									
										
										
										
											2018-05-28 15:29:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-04 19:44:30 +08:00
										 |  |  | const EMPTY_ARRAY = []; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-29 19:17:36 +08:00
										 |  |  | const EMPTY_COMMENT_OPTIONS = { | 
					
						
							|  |  |  | 	options: null, | 
					
						
							|  |  |  | 	errors: null | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | class JavascriptParser { | 
					
						
							| 
									
										
										
										
											2018-01-22 05:35:30 +08:00
										 |  |  | 	constructor(options, sourceType = "auto") { | 
					
						
							| 
									
										
										
										
											2018-07-30 20:25:40 +08:00
										 |  |  | 		this.hooks = Object.freeze({ | 
					
						
							| 
									
										
										
										
											2017-11-27 22:27:41 +08:00
										 |  |  | 			evaluateTypeof: new HookMap(() => new SyncBailHook(["expression"])), | 
					
						
							|  |  |  | 			evaluate: new HookMap(() => new SyncBailHook(["expression"])), | 
					
						
							|  |  |  | 			evaluateIdentifier: new HookMap(() => new SyncBailHook(["expression"])), | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			evaluateDefinedIdentifier: new HookMap( | 
					
						
							|  |  |  | 				() => new SyncBailHook(["expression"]) | 
					
						
							|  |  |  | 			), | 
					
						
							|  |  |  | 			evaluateCallExpressionMember: new HookMap( | 
					
						
							|  |  |  | 				() => new SyncBailHook(["expression", "param"]) | 
					
						
							|  |  |  | 			), | 
					
						
							| 
									
										
										
										
											2017-11-27 22:27:41 +08:00
										 |  |  | 			statement: new SyncBailHook(["statement"]), | 
					
						
							|  |  |  | 			statementIf: new SyncBailHook(["statement"]), | 
					
						
							|  |  |  | 			label: new HookMap(() => new SyncBailHook(["statement"])), | 
					
						
							|  |  |  | 			import: new SyncBailHook(["statement", "source"]), | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			importSpecifier: new SyncBailHook([ | 
					
						
							|  |  |  | 				"statement", | 
					
						
							|  |  |  | 				"source", | 
					
						
							|  |  |  | 				"exportName", | 
					
						
							|  |  |  | 				"identifierName" | 
					
						
							|  |  |  | 			]), | 
					
						
							| 
									
										
										
										
											2017-11-27 22:27:41 +08:00
										 |  |  | 			export: new SyncBailHook(["statement"]), | 
					
						
							|  |  |  | 			exportImport: new SyncBailHook(["statement", "source"]), | 
					
						
							|  |  |  | 			exportDeclaration: new SyncBailHook(["statement", "declaration"]), | 
					
						
							|  |  |  | 			exportExpression: new SyncBailHook(["statement", "declaration"]), | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			exportSpecifier: new SyncBailHook([ | 
					
						
							|  |  |  | 				"statement", | 
					
						
							|  |  |  | 				"identifierName", | 
					
						
							|  |  |  | 				"exportName", | 
					
						
							|  |  |  | 				"index" | 
					
						
							|  |  |  | 			]), | 
					
						
							|  |  |  | 			exportImportSpecifier: new SyncBailHook([ | 
					
						
							|  |  |  | 				"statement", | 
					
						
							|  |  |  | 				"source", | 
					
						
							|  |  |  | 				"identifierName", | 
					
						
							|  |  |  | 				"exportName", | 
					
						
							|  |  |  | 				"index" | 
					
						
							|  |  |  | 			]), | 
					
						
							| 
									
										
										
										
											2017-11-27 22:27:41 +08:00
										 |  |  | 			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"])), | 
					
						
							| 
									
										
										
										
											2017-12-05 15:58:51 +08:00
										 |  |  | 			new: new HookMap(() => new SyncBailHook(["expression"])), | 
					
						
							| 
									
										
										
										
											2017-11-27 22:27:41 +08:00
										 |  |  | 			expression: new HookMap(() => new SyncBailHook(["expression"])), | 
					
						
							|  |  |  | 			expressionAnyMember: new HookMap(() => new SyncBailHook(["expression"])), | 
					
						
							| 
									
										
										
										
											2017-12-19 21:35:30 +08:00
										 |  |  | 			expressionConditionalOperator: new SyncBailHook(["expression"]), | 
					
						
							| 
									
										
										
										
											2018-10-17 23:12:07 +08:00
										 |  |  | 			expressionLogicalOperator: new SyncBailHook(["expression"]), | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			program: new SyncBailHook(["ast", "comments"]) | 
					
						
							| 
									
										
										
										
											2018-07-30 20:25:40 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		this.options = options; | 
					
						
							| 
									
										
										
										
											2018-01-22 05:35:30 +08:00
										 |  |  | 		this.sourceType = sourceType; | 
					
						
							| 
									
										
										
										
											2017-04-10 19:53:16 +08:00
										 |  |  | 		this.scope = undefined; | 
					
						
							|  |  |  | 		this.state = undefined; | 
					
						
							|  |  |  | 		this.comments = undefined; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		this.initializeEvaluating(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	initializeEvaluating() { | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 		this.hooks.evaluate.for("Literal").tap("JavascriptParser", expr => { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			switch (typeof expr.value) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				case "number": | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					return new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 						.setNumber(expr.value) | 
					
						
							|  |  |  | 						.setRange(expr.range); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				case "string": | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					return new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 						.setString(expr.value) | 
					
						
							|  |  |  | 						.setRange(expr.range); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				case "boolean": | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					return new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 						.setBoolean(expr.value) | 
					
						
							|  |  |  | 						.setRange(expr.range); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 			if (expr.value === null) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				return new BasicEvaluatedExpression().setNull().setRange(expr.range); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			if (expr.value instanceof RegExp) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				return new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 					.setRegExp(expr.value) | 
					
						
							|  |  |  | 					.setRange(expr.range); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 		this.hooks.evaluate | 
					
						
							|  |  |  | 			.for("LogicalExpression") | 
					
						
							|  |  |  | 			.tap("JavascriptParser", 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("JavascriptParser", 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() | 
					
						
							|  |  |  | 						) { | 
					
						
							| 
									
										
										
										
											2018-11-06 02:54:56 +08:00
										 |  |  | 							// "left" + ("prefix" + inner + "postfix")
 | 
					
						
							|  |  |  | 							// => ("leftprefix" + inner + "postfix")
 | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 							res.setWrapped( | 
					
						
							|  |  |  | 								new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 									.setString(left.string + right.prefix.string) | 
					
						
							|  |  |  | 									.setRange(joinRanges(left.range, right.prefix.range)), | 
					
						
							| 
									
										
										
										
											2018-11-06 02:54:56 +08:00
										 |  |  | 								right.postfix, | 
					
						
							|  |  |  | 								right.wrappedInnerExpressions | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 							); | 
					
						
							|  |  |  | 						} else if (right.isWrapped()) { | 
					
						
							| 
									
										
										
										
											2018-11-06 02:54:56 +08:00
										 |  |  | 							// "left" + ([null] + inner + "postfix")
 | 
					
						
							|  |  |  | 							// => ("left" + inner + "postfix")
 | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 							res.setWrapped( | 
					
						
							| 
									
										
										
										
											2018-11-06 02:54:56 +08:00
										 |  |  | 								left, | 
					
						
							|  |  |  | 								right.postfix, | 
					
						
							|  |  |  | 								right.wrappedInnerExpressions | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 							); | 
					
						
							|  |  |  | 						} else { | 
					
						
							| 
									
										
										
										
											2018-11-06 02:54:56 +08:00
										 |  |  | 							// "left" + expr
 | 
					
						
							|  |  |  | 							// => ("left" + expr + "")
 | 
					
						
							|  |  |  | 							res.setWrapped(left, null, [right]); | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 						} | 
					
						
							|  |  |  | 					} else if (left.isNumber()) { | 
					
						
							|  |  |  | 						if (right.isString()) { | 
					
						
							|  |  |  | 							res.setString(left.number + right.string); | 
					
						
							|  |  |  | 						} else if (right.isNumber()) { | 
					
						
							|  |  |  | 							res.setNumber(left.number + right.number); | 
					
						
							| 
									
										
										
										
											2018-11-06 02:54:56 +08:00
										 |  |  | 						} else { | 
					
						
							|  |  |  | 							return; | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 						} | 
					
						
							|  |  |  | 					} else if (left.isWrapped()) { | 
					
						
							|  |  |  | 						if (left.postfix && left.postfix.isString() && right.isString()) { | 
					
						
							| 
									
										
										
										
											2018-11-06 02:54:56 +08:00
										 |  |  | 							// ("prefix" + inner + "postfix") + "right"
 | 
					
						
							|  |  |  | 							// => ("prefix" + inner + "postfixright")
 | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 							res.setWrapped( | 
					
						
							|  |  |  | 								left.prefix, | 
					
						
							|  |  |  | 								new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 									.setString(left.postfix.string + right.string) | 
					
						
							| 
									
										
										
										
											2018-11-06 02:54:56 +08:00
										 |  |  | 									.setRange(joinRanges(left.postfix.range, right.range)), | 
					
						
							| 
									
										
										
										
											2018-11-05 22:17:10 +08:00
										 |  |  | 								left.wrappedInnerExpressions | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 							); | 
					
						
							|  |  |  | 						} else if ( | 
					
						
							|  |  |  | 							left.postfix && | 
					
						
							|  |  |  | 							left.postfix.isString() && | 
					
						
							|  |  |  | 							right.isNumber() | 
					
						
							|  |  |  | 						) { | 
					
						
							| 
									
										
										
										
											2018-11-06 02:54:56 +08:00
										 |  |  | 							// ("prefix" + inner + "postfix") + 123
 | 
					
						
							|  |  |  | 							// => ("prefix" + inner + "postfix123")
 | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 							res.setWrapped( | 
					
						
							|  |  |  | 								left.prefix, | 
					
						
							|  |  |  | 								new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 									.setString(left.postfix.string + right.number) | 
					
						
							| 
									
										
										
										
											2018-11-06 02:54:56 +08:00
										 |  |  | 									.setRange(joinRanges(left.postfix.range, right.range)), | 
					
						
							|  |  |  | 								left.wrappedInnerExpressions | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 							); | 
					
						
							|  |  |  | 						} else if (right.isString()) { | 
					
						
							| 
									
										
										
										
											2018-11-06 02:54:56 +08:00
										 |  |  | 							// ("prefix" + inner + [null]) + "right"
 | 
					
						
							|  |  |  | 							// => ("prefix" + inner + "right")
 | 
					
						
							|  |  |  | 							res.setWrapped(left.prefix, right, left.wrappedInnerExpressions); | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 						} else if (right.isNumber()) { | 
					
						
							| 
									
										
										
										
											2018-11-06 02:54:56 +08:00
										 |  |  | 							// ("prefix" + inner + [null]) + 123
 | 
					
						
							|  |  |  | 							// => ("prefix" + inner + "123")
 | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 							res.setWrapped( | 
					
						
							|  |  |  | 								left.prefix, | 
					
						
							|  |  |  | 								new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 									.setString(right.number + "") | 
					
						
							| 
									
										
										
										
											2018-11-06 02:54:56 +08:00
										 |  |  | 									.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) | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 							); | 
					
						
							|  |  |  | 						} else { | 
					
						
							| 
									
										
										
										
											2018-11-06 02:54:56 +08:00
										 |  |  | 							// ("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] | 
					
						
							|  |  |  | 									) | 
					
						
							|  |  |  | 							); | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 					} else { | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 						if (right.isString()) { | 
					
						
							| 
									
										
										
										
											2018-11-06 02:54:56 +08:00
										 |  |  | 							// 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; | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 					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); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 				} 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); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 				} 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; | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 			}); | 
					
						
							|  |  |  | 		this.hooks.evaluate.for("UnaryExpression").tap("JavascriptParser", expr => { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (expr.operator === "typeof") { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				let res; | 
					
						
							|  |  |  | 				let name; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				if (expr.argument.type === "Identifier") { | 
					
						
							|  |  |  | 					name = | 
					
						
							|  |  |  | 						this.scope.renames.get(expr.argument.name) || expr.argument.name; | 
					
						
							|  |  |  | 					if (!this.scope.definitions.has(name)) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 						const hook = this.hooks.evaluateTypeof.get(name); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 						if (hook !== undefined) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 							res = hook.call(expr); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							if (res !== undefined) return res; | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2014-10-07 21:15:09 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2013-09-24 21:09:08 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				if (expr.argument.type === "MemberExpression") { | 
					
						
							| 
									
										
										
										
											2017-07-19 02:22:20 +08:00
										 |  |  | 					const exprName = this.getNameForExpression(expr.argument); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					if (exprName && exprName.free) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 						const hook = this.hooks.evaluateTypeof.get(exprName.name); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 						if (hook !== undefined) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 							res = hook.call(expr); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							if (res !== undefined) return res; | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				if (expr.argument.type === "FunctionExpression") { | 
					
						
							|  |  |  | 					return new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 						.setString("function") | 
					
						
							|  |  |  | 						.setRange(expr.range); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				const arg = this.evaluateExpression(expr.argument); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				if (arg.isString() || arg.isWrapped()) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					return new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 						.setString("string") | 
					
						
							|  |  |  | 						.setRange(expr.range); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				if (arg.isNumber()) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					return new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 						.setString("number") | 
					
						
							|  |  |  | 						.setRange(expr.range); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				if (arg.isBoolean()) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					return new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 						.setString("boolean") | 
					
						
							|  |  |  | 						.setRange(expr.range); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				if (arg.isArray() || arg.isConstArray() || arg.isRegExp()) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					return new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 						.setString("object") | 
					
						
							|  |  |  | 						.setRange(expr.range); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			} else if (expr.operator === "!") { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				const argument = this.evaluateExpression(expr.argument); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				if (!argument) return; | 
					
						
							|  |  |  | 				if (argument.isBoolean()) { | 
					
						
							|  |  |  | 					return new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 						.setBoolean(!argument.bool) | 
					
						
							|  |  |  | 						.setRange(expr.range); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				if (argument.isTruthy()) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					return new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 						.setBoolean(false) | 
					
						
							|  |  |  | 						.setRange(expr.range); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				if (argument.isFalsy()) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					return new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 						.setBoolean(true) | 
					
						
							|  |  |  | 						.setRange(expr.range); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				if (argument.isString()) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					return new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 						.setBoolean(!argument.string) | 
					
						
							|  |  |  | 						.setRange(expr.range); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				if (argument.isNumber()) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					return new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 						.setBoolean(!argument.number) | 
					
						
							|  |  |  | 						.setRange(expr.range); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			} else if (expr.operator === "~") { | 
					
						
							| 
									
										
										
										
											2017-12-06 00:11:53 +08:00
										 |  |  | 				const argument = this.evaluateExpression(expr.argument); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				if (!argument) return; | 
					
						
							|  |  |  | 				if (!argument.isNumber()) return; | 
					
						
							| 
									
										
										
										
											2017-12-06 00:11:53 +08:00
										 |  |  | 				const res = new BasicEvaluatedExpression(); | 
					
						
							|  |  |  | 				res.setNumber(~argument.number); | 
					
						
							|  |  |  | 				res.setRange(expr.range); | 
					
						
							|  |  |  | 				return res; | 
					
						
							| 
									
										
										
										
											2013-09-24 21:09:08 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 		this.hooks.evaluateTypeof.for("undefined").tap("JavascriptParser", expr => { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			return new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 				.setString("undefined") | 
					
						
							|  |  |  | 				.setRange(expr.range); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 		this.hooks.evaluate.for("Identifier").tap("JavascriptParser", expr => { | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 			const name = this.scope.renames.get(expr.name) || expr.name; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (!this.scope.definitions.has(expr.name)) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 				const hook = this.hooks.evaluateIdentifier.get(name); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				if (hook !== undefined) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 					const result = hook.call(expr); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					if (result) return result; | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				return new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 					.setIdentifier(name) | 
					
						
							|  |  |  | 					.setRange(expr.range); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 				const hook = this.hooks.evaluateDefinedIdentifier.get(name); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				if (hook !== undefined) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 					return hook.call(expr); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2013-09-24 21:09:08 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 		this.hooks.evaluate.for("ThisExpression").tap("JavascriptParser", expr => { | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 			const name = this.scope.renames.get("this"); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (name) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 				const hook = this.hooks.evaluateIdentifier.get(name); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				if (hook !== undefined) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 					const result = hook.call(expr); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					if (result) return result; | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				return new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 					.setIdentifier(name) | 
					
						
							|  |  |  | 					.setRange(expr.range); | 
					
						
							| 
									
										
										
										
											2017-07-12 00:12:15 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 		this.hooks.evaluate | 
					
						
							|  |  |  | 			.for("MemberExpression") | 
					
						
							|  |  |  | 			.tap("JavascriptParser", 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); | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2014-10-07 21:15:09 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 			}); | 
					
						
							|  |  |  | 		this.hooks.evaluate.for("CallExpression").tap("JavascriptParser", expr => { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (expr.callee.type !== "MemberExpression") return; | 
					
						
							|  |  |  | 			if ( | 
					
						
							|  |  |  | 				expr.callee.property.type !== | 
					
						
							|  |  |  | 				(expr.callee.computed ? "Literal" : "Identifier") | 
					
						
							|  |  |  | 			) | 
					
						
							|  |  |  | 				return; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			const param = this.evaluateExpression(expr.callee.object); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (!param) return; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			const property = expr.callee.property.name || expr.callee.property.value; | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 			const hook = this.hooks.evaluateCallExpressionMember.get(property); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (hook !== undefined) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 				return hook.call(expr, param); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		this.hooks.evaluateCallExpressionMember | 
					
						
							|  |  |  | 			.for("replace") | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 			.tap("JavascriptParser", (expr, param) => { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				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); | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		["substr", "substring"].forEach(fn => { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			this.hooks.evaluateCallExpressionMember | 
					
						
							|  |  |  | 				.for(fn) | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 				.tap("JavascriptParser", (expr, param) => { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					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: { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 							arg1 = this.evaluateExpression(expr.arguments[0]); | 
					
						
							|  |  |  | 							const arg2 = this.evaluateExpression(expr.arguments[1]); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							if (!arg1.isNumber()) return; | 
					
						
							|  |  |  | 							if (!arg2.isNumber()) return; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 							result = str[fn](arg1.number, arg2.number); | 
					
						
							|  |  |  | 							break; | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 						default: | 
					
						
							|  |  |  | 							return; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					return new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 						.setString(result) | 
					
						
							|  |  |  | 						.setRange(expr.range); | 
					
						
							|  |  |  | 				}); | 
					
						
							| 
									
										
										
										
											2017-09-15 01:02:34 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2016-11-17 20:42:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-15 01:02:34 +08:00
										 |  |  | 		/** | 
					
						
							|  |  |  | 		 * @param {string} kind "cooked" | "raw" | 
					
						
							| 
									
										
										
										
											2018-10-30 23:43:44 +08:00
										 |  |  | 		 * @param {TODO} templateLiteralExpr TemplateLiteral expr | 
					
						
							| 
									
										
										
										
											2018-10-30 23:50:09 +08:00
										 |  |  | 		 * @returns {{quasis: BasicEvaluatedExpression[], parts: BasicEvaluatedExpression[]}} Simplified template | 
					
						
							| 
									
										
										
										
											2017-09-15 01:02:34 +08:00
										 |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2018-10-30 19:39:43 +08:00
										 |  |  | 		const getSimplifiedTemplateResult = (kind, templateLiteralExpr) => { | 
					
						
							|  |  |  | 			const quasis = []; | 
					
						
							| 
									
										
										
										
											2017-09-15 01:02:34 +08:00
										 |  |  | 			const parts = []; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 19:39:43 +08:00
										 |  |  | 			for (let i = 0; i < templateLiteralExpr.quasis.length; i++) { | 
					
						
							|  |  |  | 				const quasiExpr = templateLiteralExpr.quasis[i]; | 
					
						
							| 
									
										
										
										
											2018-11-03 18:14:15 +08:00
										 |  |  | 				const quasi = quasiExpr.value[kind]; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				if (i > 0) { | 
					
						
							| 
									
										
										
										
											2018-11-03 18:14:15 +08:00
										 |  |  | 					const prevExpr = parts[parts.length - 1]; | 
					
						
							| 
									
										
										
										
											2018-10-30 19:39:43 +08:00
										 |  |  | 					const expr = this.evaluateExpression( | 
					
						
							|  |  |  | 						templateLiteralExpr.expressions[i - 1] | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					); | 
					
						
							| 
									
										
										
										
											2018-11-03 18:14:15 +08:00
										 |  |  | 					const exprAsString = expr.asString(); | 
					
						
							|  |  |  | 					if (typeof exprAsString === "string") { | 
					
						
							|  |  |  | 						// We can merge quasi + expr + quasi when expr
 | 
					
						
							|  |  |  | 						// is a const string
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-03 18:14:15 +08:00
										 |  |  | 						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); | 
					
						
							| 
									
										
										
										
											2016-11-17 01:05:39 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-11-03 18:14:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				const part = new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 					.setString(quasi) | 
					
						
							|  |  |  | 					.setRange(quasiExpr.range) | 
					
						
							|  |  |  | 					.setExpression(quasiExpr); | 
					
						
							|  |  |  | 				quasis.push(part); | 
					
						
							|  |  |  | 				parts.push(part); | 
					
						
							| 
									
										
										
										
											2016-11-15 21:03:53 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-10-30 19:39:43 +08:00
										 |  |  | 			return { | 
					
						
							|  |  |  | 				quasis, | 
					
						
							|  |  |  | 				parts | 
					
						
							|  |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2016-11-17 20:42:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 		this.hooks.evaluate.for("TemplateLiteral").tap("JavascriptParser", node => { | 
					
						
							| 
									
										
										
										
											2018-11-03 18:14:15 +08:00
										 |  |  | 			const { quasis, parts } = getSimplifiedTemplateResult("cooked", node); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (parts.length === 1) { | 
					
						
							| 
									
										
										
										
											2017-09-15 01:02:34 +08:00
										 |  |  | 				return parts[0].setRange(node.range); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			return new BasicEvaluatedExpression() | 
					
						
							| 
									
										
										
										
											2018-11-03 18:14:15 +08:00
										 |  |  | 				.setTemplateString(quasis, parts, "cooked") | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				.setRange(node.range); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 		this.hooks.evaluate | 
					
						
							|  |  |  | 			.for("TaggedTemplateExpression") | 
					
						
							|  |  |  | 			.tap("JavascriptParser", node => { | 
					
						
							|  |  |  | 				if (this.evaluateExpression(node.tag).identifier !== "String.raw") | 
					
						
							|  |  |  | 					return; | 
					
						
							| 
									
										
										
										
											2018-11-05 17:19:09 +08:00
										 |  |  | 				const { quasis, parts } = getSimplifiedTemplateResult( | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 					"raw", | 
					
						
							| 
									
										
										
										
											2018-11-05 17:19:09 +08:00
										 |  |  | 					node.quasi | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 				); | 
					
						
							| 
									
										
										
										
											2018-11-05 17:19:09 +08:00
										 |  |  | 				if (parts.length === 1) { | 
					
						
							|  |  |  | 					return parts[0].setRange(node.range); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 				return new BasicEvaluatedExpression() | 
					
						
							| 
									
										
										
										
											2018-11-05 17:19:09 +08:00
										 |  |  | 					.setTemplateString(quasis, parts, "raw") | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 					.setRange(node.range); | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2017-09-15 01:02:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		this.hooks.evaluateCallExpressionMember | 
					
						
							|  |  |  | 			.for("concat") | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 			.tap("JavascriptParser", (expr, param) => { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				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; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-09-15 02:35:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					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); | 
					
						
							| 
									
										
										
										
											2017-09-15 02:35:33 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				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") | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 			.tap("JavascriptParser", (expr, param) => { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				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); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				} else { | 
					
						
							|  |  |  | 					return; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				return new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 					.setArray(result) | 
					
						
							|  |  |  | 					.setRange(expr.range); | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 		this.hooks.evaluate | 
					
						
							|  |  |  | 			.for("ConditionalExpression") | 
					
						
							|  |  |  | 			.tap("JavascriptParser", 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]); | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 					res = this.evaluateExpression( | 
					
						
							|  |  |  | 						conditionValue ? expr.consequent : expr.alternate | 
					
						
							|  |  |  | 					); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | 				res.setRange(expr.range); | 
					
						
							|  |  |  | 				return res; | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		this.hooks.evaluate.for("ArrayExpression").tap("JavascriptParser", expr => { | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 			const items = expr.elements.map(element => { | 
					
						
							| 
									
										
										
										
											2017-11-09 03:49:41 +08:00
										 |  |  | 				return element !== null && this.evaluateExpression(element); | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (!items.every(Boolean)) return; | 
					
						
							|  |  |  | 			return new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 				.setItems(items) | 
					
						
							|  |  |  | 				.setRange(expr.range); | 
					
						
							| 
									
										
										
										
											2016-11-15 21:03:53 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	getRenameIdentifier(expr) { | 
					
						
							|  |  |  | 		const result = this.evaluateExpression(expr); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		if (result && result.isIdentifier()) { | 
					
						
							|  |  |  | 			return result.identifier; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkClass(classy) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (classy.superClass) this.walkExpression(classy.superClass); | 
					
						
							|  |  |  | 		if (classy.body && classy.body.type === "ClassBody") { | 
					
						
							| 
									
										
										
										
											2018-01-25 16:09:42 +08:00
										 |  |  | 			const wasTopLevel = this.scope.topLevelScope; | 
					
						
							|  |  |  | 			this.scope.topLevelScope = false; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			for (const methodDefinition of classy.body.body) { | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				if (methodDefinition.type === "MethodDefinition") { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 					this.walkMethodDefinition(methodDefinition); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-01-25 16:09:42 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			this.scope.topLevelScope = wasTopLevel; | 
					
						
							| 
									
										
										
										
											2013-09-13 17:17:57 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-10-22 00:14:47 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	walkMethodDefinition(methodDefinition) { | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		if (methodDefinition.computed && methodDefinition.key) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			this.walkExpression(methodDefinition.key); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if (methodDefinition.value) { | 
					
						
							|  |  |  | 			this.walkExpression(methodDefinition.value); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	// Prewalking iterates the scope for variable declarations
 | 
					
						
							|  |  |  | 	prewalkStatements(statements) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		for (let index = 0, len = statements.length; index < len; index++) { | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 			const statement = statements[index]; | 
					
						
							|  |  |  | 			this.prewalkStatement(statement); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	// Walking iterates the statements and expressions and processes them
 | 
					
						
							|  |  |  | 	walkStatements(statements) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		for (let index = 0, len = statements.length; index < len; index++) { | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 			const statement = statements[index]; | 
					
						
							|  |  |  | 			this.walkStatement(statement); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	prewalkStatement(statement) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		switch (statement.type) { | 
					
						
							| 
									
										
										
										
											2017-12-30 23:27:17 +08:00
										 |  |  | 			case "BlockStatement": | 
					
						
							|  |  |  | 				this.prewalkBlockStatement(statement); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			case "ClassDeclaration": | 
					
						
							|  |  |  | 				this.prewalkClassDeclaration(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; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkStatement(statement) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (this.hooks.statement.call(statement) !== undefined) return; | 
					
						
							|  |  |  | 		switch (statement.type) { | 
					
						
							| 
									
										
										
										
											2017-12-30 23:27:17 +08:00
										 |  |  | 			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; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Real Statements
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	prewalkBlockStatement(statement) { | 
					
						
							|  |  |  | 		this.prewalkStatements(statement.body); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkBlockStatement(statement) { | 
					
						
							|  |  |  | 		this.walkStatements(statement.body); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkExpressionStatement(statement) { | 
					
						
							|  |  |  | 		this.walkExpression(statement.expression); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	prewalkIfStatement(statement) { | 
					
						
							|  |  |  | 		this.prewalkStatement(statement.consequent); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		if (statement.alternate) { | 
					
						
							|  |  |  | 			this.prewalkStatement(statement.alternate); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkIfStatement(statement) { | 
					
						
							| 
									
										
										
										
											2017-11-27 22:27:41 +08:00
										 |  |  | 		const result = this.hooks.statementIf.call(statement); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (result === undefined) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			this.walkExpression(statement.test); | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 			this.walkStatement(statement.consequent); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 			if (statement.alternate) { | 
					
						
							|  |  |  | 				this.walkStatement(statement.alternate); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 			if (result) { | 
					
						
							|  |  |  | 				this.walkStatement(statement.consequent); | 
					
						
							|  |  |  | 			} else if (statement.alternate) { | 
					
						
							|  |  |  | 				this.walkStatement(statement.alternate); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	prewalkLabeledStatement(statement) { | 
					
						
							|  |  |  | 		this.prewalkStatement(statement.body); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkLabeledStatement(statement) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 		const hook = this.hooks.label.get(statement.label.name); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (hook !== undefined) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 			const result = hook.call(statement); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (result === true) return; | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		this.walkStatement(statement.body); | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	prewalkWithStatement(statement) { | 
					
						
							|  |  |  | 		this.prewalkStatement(statement.body); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkWithStatement(statement) { | 
					
						
							|  |  |  | 		this.walkExpression(statement.object); | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 		this.walkStatement(statement.body); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	prewalkSwitchStatement(statement) { | 
					
						
							|  |  |  | 		this.prewalkSwitchCases(statement.cases); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkSwitchStatement(statement) { | 
					
						
							|  |  |  | 		this.walkExpression(statement.discriminant); | 
					
						
							|  |  |  | 		this.walkSwitchCases(statement.cases); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-26 07:02:43 +08:00
										 |  |  | 	walkTerminatingStatement(statement) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (statement.argument) this.walkExpression(statement.argument); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-26 07:02:43 +08:00
										 |  |  | 	walkReturnStatement(statement) { | 
					
						
							|  |  |  | 		this.walkTerminatingStatement(statement); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkThrowStatement(statement) { | 
					
						
							| 
									
										
										
										
											2017-02-26 07:02:43 +08:00
										 |  |  | 		this.walkTerminatingStatement(statement); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	prewalkTryStatement(statement) { | 
					
						
							|  |  |  | 		this.prewalkStatement(statement.block); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkTryStatement(statement) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (this.scope.inTry) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			this.walkStatement(statement.block); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			this.scope.inTry = true; | 
					
						
							|  |  |  | 			this.walkStatement(statement.block); | 
					
						
							|  |  |  | 			this.scope.inTry = false; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (statement.handler) this.walkCatchClause(statement.handler); | 
					
						
							|  |  |  | 		if (statement.finalizer) this.walkStatement(statement.finalizer); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	prewalkWhileStatement(statement) { | 
					
						
							|  |  |  | 		this.prewalkStatement(statement.body); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkWhileStatement(statement) { | 
					
						
							| 
									
										
										
										
											2015-07-13 06:20:09 +08:00
										 |  |  | 		this.walkExpression(statement.test); | 
					
						
							|  |  |  | 		this.walkStatement(statement.body); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	prewalkDoWhileStatement(statement) { | 
					
						
							|  |  |  | 		this.prewalkStatement(statement.body); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkDoWhileStatement(statement) { | 
					
						
							|  |  |  | 		this.walkStatement(statement.body); | 
					
						
							| 
									
										
										
										
											2015-07-13 06:20:09 +08:00
										 |  |  | 		this.walkExpression(statement.test); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	prewalkForStatement(statement) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (statement.init) { | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 			if (statement.init.type === "VariableDeclaration") { | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 				this.prewalkStatement(statement.init); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		this.prewalkStatement(statement.body); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkForStatement(statement) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (statement.init) { | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 			if (statement.init.type === "VariableDeclaration") { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				this.walkStatement(statement.init); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				this.walkExpression(statement.init); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (statement.test) { | 
					
						
							|  |  |  | 			this.walkExpression(statement.test); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (statement.update) { | 
					
						
							|  |  |  | 			this.walkExpression(statement.update); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-07-13 06:20:09 +08:00
										 |  |  | 		this.walkStatement(statement.body); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	prewalkForInStatement(statement) { | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		if (statement.left.type === "VariableDeclaration") { | 
					
						
							| 
									
										
										
										
											2018-01-01 17:48:56 +08:00
										 |  |  | 			this.prewalkVariableDeclaration(statement.left); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 		this.prewalkStatement(statement.body); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkForInStatement(statement) { | 
					
						
							| 
									
										
										
										
											2018-05-25 23:34:19 +08:00
										 |  |  | 		if (statement.left.type === "VariableDeclaration") { | 
					
						
							| 
									
										
										
										
											2018-01-01 17:48:56 +08:00
										 |  |  | 			this.walkVariableDeclaration(statement.left); | 
					
						
							| 
									
										
										
										
											2018-05-25 23:34:19 +08:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			this.walkPattern(statement.left); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		this.walkExpression(statement.right); | 
					
						
							|  |  |  | 		this.walkStatement(statement.body); | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	prewalkForOfStatement(statement) { | 
					
						
							| 
									
										
										
										
											2018-05-25 23:34:19 +08:00
										 |  |  | 		if (statement.left.type === "VariableDeclaration") { | 
					
						
							| 
									
										
										
										
											2018-01-01 17:48:56 +08:00
										 |  |  | 			this.prewalkVariableDeclaration(statement.left); | 
					
						
							| 
									
										
										
										
											2018-05-25 23:34:19 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 		this.prewalkStatement(statement.body); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkForOfStatement(statement) { | 
					
						
							| 
									
										
										
										
											2018-05-25 23:34:19 +08:00
										 |  |  | 		if (statement.left.type === "VariableDeclaration") { | 
					
						
							| 
									
										
										
										
											2018-01-01 17:48:56 +08:00
										 |  |  | 			this.walkVariableDeclaration(statement.left); | 
					
						
							| 
									
										
										
										
											2018-05-25 23:34:19 +08:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			this.walkPattern(statement.left); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		this.walkExpression(statement.right); | 
					
						
							|  |  |  | 		this.walkStatement(statement.body); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Declarations
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	prewalkFunctionDeclaration(statement) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (statement.id) { | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 			this.scope.renames.set(statement.id.name, null); | 
					
						
							|  |  |  | 			this.scope.definitions.add(statement.id.name); | 
					
						
							| 
									
										
										
										
											2015-01-13 00:45:30 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkFunctionDeclaration(statement) { | 
					
						
							| 
									
										
										
										
											2018-04-05 23:34:27 +08:00
										 |  |  | 		const wasTopLevel = this.scope.topLevelScope; | 
					
						
							|  |  |  | 		this.scope.topLevelScope = false; | 
					
						
							| 
									
										
										
										
											2017-08-11 13:52:25 +08:00
										 |  |  | 		this.inScope(statement.params, () => { | 
					
						
							| 
									
										
										
										
											2018-05-25 23:34:19 +08:00
										 |  |  | 			for (const param of statement.params) { | 
					
						
							|  |  |  | 				this.walkPattern(param); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (statement.body.type === "BlockStatement") { | 
					
						
							| 
									
										
										
										
											2018-01-09 17:35:08 +08:00
										 |  |  | 				this.detectStrictMode(statement.body.body); | 
					
						
							| 
									
										
										
										
											2017-04-14 21:23:27 +08:00
										 |  |  | 				this.prewalkStatement(statement.body); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				this.walkStatement(statement.body); | 
					
						
							| 
									
										
										
										
											2017-04-14 21:23:27 +08:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				this.walkExpression(statement.body); | 
					
						
							| 
									
										
										
										
											2017-04-14 21:23:27 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-08-11 13:52:25 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2018-04-05 23:34:27 +08:00
										 |  |  | 		this.scope.topLevelScope = wasTopLevel; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-01-13 00:45:30 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	prewalkImportDeclaration(statement) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		const source = statement.source.value; | 
					
						
							| 
									
										
										
										
											2017-11-27 22:27:41 +08:00
										 |  |  | 		this.hooks.import.call(statement, source); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		for (const specifier of statement.specifiers) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			const name = specifier.local.name; | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 			this.scope.renames.set(name, null); | 
					
						
							|  |  |  | 			this.scope.definitions.add(name); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			switch (specifier.type) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				case "ImportDefaultSpecifier": | 
					
						
							| 
									
										
										
										
											2017-11-27 22:27:41 +08:00
										 |  |  | 					this.hooks.importSpecifier.call(statement, source, "default", name); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 					break; | 
					
						
							|  |  |  | 				case "ImportSpecifier": | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					this.hooks.importSpecifier.call( | 
					
						
							|  |  |  | 						statement, | 
					
						
							|  |  |  | 						source, | 
					
						
							|  |  |  | 						specifier.imported.name, | 
					
						
							|  |  |  | 						name | 
					
						
							|  |  |  | 					); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 					break; | 
					
						
							|  |  |  | 				case "ImportNamespaceSpecifier": | 
					
						
							| 
									
										
										
										
											2017-11-27 22:27:41 +08:00
										 |  |  | 					this.hooks.importSpecifier.call(statement, source, null, name); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 					break; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-01-04 05:43:40 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-01-13 00:45:30 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	prewalkExportNamedDeclaration(statement) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		let source; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (statement.source) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			source = statement.source.value; | 
					
						
							| 
									
										
										
										
											2017-11-27 22:27:41 +08:00
										 |  |  | 			this.hooks.exportImport.call(statement, source); | 
					
						
							| 
									
										
										
										
											2015-01-13 00:45:30 +08:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2017-11-27 22:27:41 +08:00
										 |  |  | 			this.hooks.export.call(statement); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (statement.declaration) { | 
					
						
							|  |  |  | 			if ( | 
					
						
							|  |  |  | 				!this.hooks.exportDeclaration.call(statement, statement.declaration) | 
					
						
							|  |  |  | 			) { | 
					
						
							| 
									
										
										
										
											2018-01-07 00:44:20 +08:00
										 |  |  | 				const originalDefinitions = this.scope.definitions; | 
					
						
							|  |  |  | 				const tracker = new TrackingSet(this.scope.definitions); | 
					
						
							|  |  |  | 				this.scope.definitions = tracker; | 
					
						
							|  |  |  | 				this.prewalkStatement(statement.declaration); | 
					
						
							|  |  |  | 				const newDefs = Array.from(tracker.getAddedItems()); | 
					
						
							|  |  |  | 				this.scope.definitions = originalDefinitions; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				for (let index = newDefs.length - 1; index >= 0; index--) { | 
					
						
							| 
									
										
										
										
											2018-01-07 00:44:20 +08:00
										 |  |  | 					const def = newDefs[index]; | 
					
						
							|  |  |  | 					this.hooks.exportSpecifier.call(statement, def, def, index); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (statement.specifiers) { | 
					
						
							|  |  |  | 			for ( | 
					
						
							|  |  |  | 				let specifierIndex = 0; | 
					
						
							|  |  |  | 				specifierIndex < statement.specifiers.length; | 
					
						
							|  |  |  | 				specifierIndex++ | 
					
						
							|  |  |  | 			) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				const specifier = statement.specifiers[specifierIndex]; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				switch (specifier.type) { | 
					
						
							|  |  |  | 					case "ExportSpecifier": { | 
					
						
							|  |  |  | 						const name = specifier.exported.name; | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 						if (source) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							this.hooks.exportImportSpecifier.call( | 
					
						
							|  |  |  | 								statement, | 
					
						
							|  |  |  | 								source, | 
					
						
							|  |  |  | 								specifier.local.name, | 
					
						
							|  |  |  | 								name, | 
					
						
							|  |  |  | 								specifierIndex | 
					
						
							|  |  |  | 							); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 						} else { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							this.hooks.exportSpecifier.call( | 
					
						
							|  |  |  | 								statement, | 
					
						
							|  |  |  | 								specifier.local.name, | 
					
						
							|  |  |  | 								name, | 
					
						
							|  |  |  | 								specifierIndex | 
					
						
							|  |  |  | 							); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 						break; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	walkExportNamedDeclaration(statement) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (statement.declaration) { | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 			this.walkStatement(statement.declaration); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	prewalkExportDefaultDeclaration(statement) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (statement.declaration.id) { | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 			const originalDefinitions = this.scope.definitions; | 
					
						
							|  |  |  | 			const tracker = new TrackingSet(this.scope.definitions); | 
					
						
							|  |  |  | 			this.scope.definitions = tracker; | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 			this.prewalkStatement(statement.declaration); | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 			const newDefs = Array.from(tracker.getAddedItems()); | 
					
						
							|  |  |  | 			this.scope.definitions = originalDefinitions; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			for (let index = 0, len = newDefs.length; index < len; index++) { | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 				const def = newDefs[index]; | 
					
						
							| 
									
										
										
										
											2017-11-27 22:27:41 +08:00
										 |  |  | 				this.hooks.exportSpecifier.call(statement, def, "default"); | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkExportDefaultDeclaration(statement) { | 
					
						
							| 
									
										
										
										
											2017-11-27 22:27:41 +08:00
										 |  |  | 		this.hooks.export.call(statement); | 
					
						
							| 
									
										
										
										
											2018-03-28 17:02:17 +08:00
										 |  |  | 		if ( | 
					
						
							|  |  |  | 			statement.declaration.id && | 
					
						
							| 
									
										
										
										
											2018-03-28 18:08:14 +08:00
										 |  |  | 			statement.declaration.type !== "FunctionExpression" && | 
					
						
							|  |  |  | 			statement.declaration.type !== "ClassExpression" | 
					
						
							| 
									
										
										
										
											2018-03-28 17:02:17 +08:00
										 |  |  | 		) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if ( | 
					
						
							|  |  |  | 				!this.hooks.exportDeclaration.call(statement, statement.declaration) | 
					
						
							|  |  |  | 			) { | 
					
						
							| 
									
										
										
										
											2015-01-13 00:45:30 +08:00
										 |  |  | 				this.walkStatement(statement.declaration); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2018-01-07 00:44:20 +08:00
										 |  |  | 			// Acorn parses `export default function() {}` as `FunctionDeclaration` and
 | 
					
						
							|  |  |  | 			// `export default class {}` as `ClassDeclaration`, both with `id = null`.
 | 
					
						
							|  |  |  | 			// These nodes must be treated as expressions.
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (statement.declaration.type === "FunctionDeclaration") { | 
					
						
							| 
									
										
										
										
											2018-01-07 00:44:20 +08:00
										 |  |  | 				this.walkFunctionDeclaration(statement.declaration); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			} else if (statement.declaration.type === "ClassDeclaration") { | 
					
						
							| 
									
										
										
										
											2018-01-07 00:44:20 +08:00
										 |  |  | 				this.walkClassDeclaration(statement.declaration); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				this.walkExpression(statement.declaration); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (!this.hooks.exportExpression.call(statement, statement.declaration)) { | 
					
						
							|  |  |  | 				this.hooks.exportSpecifier.call( | 
					
						
							|  |  |  | 					statement, | 
					
						
							|  |  |  | 					statement.declaration, | 
					
						
							|  |  |  | 					"default" | 
					
						
							|  |  |  | 				); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-01-13 00:45:30 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	prewalkExportAllDeclaration(statement) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		const source = statement.source.value; | 
					
						
							| 
									
										
										
										
											2017-11-27 22:27:41 +08:00
										 |  |  | 		this.hooks.exportImport.call(statement, source); | 
					
						
							|  |  |  | 		this.hooks.exportImportSpecifier.call(statement, source, null, null, 0); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	prewalkVariableDeclaration(statement) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		const hookMap = | 
					
						
							|  |  |  | 			statement.kind === "const" | 
					
						
							|  |  |  | 				? this.hooks.varDeclarationConst | 
					
						
							|  |  |  | 				: statement.kind === "let" | 
					
						
							|  |  |  | 					? this.hooks.varDeclarationLet | 
					
						
							|  |  |  | 					: this.hooks.varDeclarationVar; | 
					
						
							|  |  |  | 		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); | 
					
						
							| 
									
										
										
										
											2017-05-21 14:09:29 +08:00
										 |  |  | 							} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 						} | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-01-04 05:43:40 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-11 04:17:47 +08:00
										 |  |  | 	walkVariableDeclaration(statement) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		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); | 
					
						
							| 
									
										
										
										
											2017-05-21 14:09:29 +08:00
										 |  |  | 							} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							break; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					this.walkPattern(declarator.id); | 
					
						
							|  |  |  | 					if (declarator.init) this.walkExpression(declarator.init); | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-01-04 05:43:40 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-11 04:17:47 +08:00
										 |  |  | 	prewalkClassDeclaration(statement) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (statement.id) { | 
					
						
							| 
									
										
										
										
											2018-01-11 04:17:47 +08:00
										 |  |  | 			this.scope.renames.set(statement.id.name, null); | 
					
						
							|  |  |  | 			this.scope.definitions.add(statement.id.name); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkClassDeclaration(statement) { | 
					
						
							|  |  |  | 		this.walkClass(statement); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	prewalkSwitchCases(switchCases) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		for (let index = 0, len = switchCases.length; index < len; index++) { | 
					
						
							| 
									
										
										
										
											2018-01-11 04:17:47 +08:00
										 |  |  | 			const switchCase = switchCases[index]; | 
					
						
							|  |  |  | 			this.prewalkStatements(switchCase.consequent); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkSwitchCases(switchCases) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		for (let index = 0, len = switchCases.length; index < len; index++) { | 
					
						
							| 
									
										
										
										
											2018-01-11 04:17:47 +08:00
										 |  |  | 			const switchCase = switchCases[index]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (switchCase.test) { | 
					
						
							| 
									
										
										
										
											2018-01-11 04:17:47 +08:00
										 |  |  | 				this.walkExpression(switchCase.test); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			this.walkStatements(switchCase.consequent); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkCatchClause(catchClause) { | 
					
						
							| 
									
										
										
										
											2018-06-04 19:44:30 +08:00
										 |  |  | 		// Error binding is optional in catch clause since ECMAScript 2019
 | 
					
						
							|  |  |  | 		const errorBinding = | 
					
						
							|  |  |  | 			catchClause.param === null ? EMPTY_ARRAY : [catchClause.param]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		this.inScope(errorBinding, () => { | 
					
						
							| 
									
										
										
										
											2018-01-11 04:17:47 +08:00
										 |  |  | 			this.prewalkStatement(catchClause.body); | 
					
						
							|  |  |  | 			this.walkStatement(catchClause.body); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkPattern(pattern) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		switch (pattern.type) { | 
					
						
							| 
									
										
										
										
											2017-12-30 23:27:17 +08:00
										 |  |  | 			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; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-03-28 20:16:28 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-22 00:14:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-21 14:09:29 +08:00
										 |  |  | 	walkAssignmentPattern(pattern) { | 
					
						
							|  |  |  | 		this.walkExpression(pattern.right); | 
					
						
							|  |  |  | 		this.walkPattern(pattern.left); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkObjectPattern(pattern) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		for (let i = 0, len = pattern.properties.length; i < len; i++) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			const prop = pattern.properties[i]; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (prop) { | 
					
						
							|  |  |  | 				if (prop.computed) this.walkExpression(prop.key); | 
					
						
							|  |  |  | 				if (prop.value) this.walkPattern(prop.value); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-22 01:36:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkArrayPattern(pattern) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		for (let i = 0, len = pattern.elements.length; i < len; i++) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			const element = pattern.elements[i]; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (element) this.walkPattern(element); | 
					
						
							| 
									
										
										
										
											2017-01-22 01:36:14 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkRestElement(pattern) { | 
					
						
							|  |  |  | 		this.walkPattern(pattern.argument); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkExpressions(expressions) { | 
					
						
							| 
									
										
										
										
											2018-05-25 23:34:19 +08:00
										 |  |  | 		for (const expression of expressions) { | 
					
						
							|  |  |  | 			if (expression) { | 
					
						
							|  |  |  | 				this.walkExpression(expression); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkExpression(expression) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		switch (expression.type) { | 
					
						
							| 
									
										
										
										
											2017-12-30 23:27:17 +08:00
										 |  |  | 			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; | 
					
						
							| 
									
										
										
										
											2018-01-08 22:31:54 +08:00
										 |  |  | 			case "ThisExpression": | 
					
						
							|  |  |  | 				this.walkThisExpression(expression); | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2017-12-30 23:27:17 +08:00
										 |  |  | 			case "UnaryExpression": | 
					
						
							|  |  |  | 				this.walkUnaryExpression(expression); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			case "UpdateExpression": | 
					
						
							|  |  |  | 				this.walkUpdateExpression(expression); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			case "YieldExpression": | 
					
						
							|  |  |  | 				this.walkYieldExpression(expression); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkAwaitExpression(expression) { | 
					
						
							| 
									
										
										
										
											2017-12-30 23:27:17 +08:00
										 |  |  | 		this.walkExpression(expression.argument); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkArrayExpression(expression) { | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		if (expression.elements) { | 
					
						
							|  |  |  | 			this.walkExpressions(expression.elements); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkSpreadElement(expression) { | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		if (expression.argument) { | 
					
						
							|  |  |  | 			this.walkExpression(expression.argument); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkObjectExpression(expression) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		for ( | 
					
						
							|  |  |  | 			let propIndex = 0, len = expression.properties.length; | 
					
						
							|  |  |  | 			propIndex < len; | 
					
						
							|  |  |  | 			propIndex++ | 
					
						
							|  |  |  | 		) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			const prop = expression.properties[propIndex]; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (prop.type === "SpreadElement") { | 
					
						
							| 
									
										
										
										
											2018-02-07 17:39:06 +08:00
										 |  |  | 				this.walkExpression(prop.argument); | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 			if (prop.computed) { | 
					
						
							|  |  |  | 				this.walkExpression(prop.key); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (prop.shorthand) { | 
					
						
							|  |  |  | 				this.scope.inShorthand = true; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			this.walkExpression(prop.value); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 			if (prop.shorthand) { | 
					
						
							|  |  |  | 				this.scope.inShorthand = false; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-02-24 06:06:05 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkFunctionExpression(expression) { | 
					
						
							| 
									
										
										
										
											2018-04-05 23:34:27 +08:00
										 |  |  | 		const wasTopLevel = this.scope.topLevelScope; | 
					
						
							|  |  |  | 		this.scope.topLevelScope = false; | 
					
						
							| 
									
										
										
										
											2017-08-11 13:52:25 +08:00
										 |  |  | 		this.inScope(expression.params, () => { | 
					
						
							| 
									
										
										
										
											2018-05-25 23:34:19 +08:00
										 |  |  | 			for (const param of expression.params) { | 
					
						
							|  |  |  | 				this.walkPattern(param); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (expression.body.type === "BlockStatement") { | 
					
						
							| 
									
										
										
										
											2018-01-09 17:35:08 +08:00
										 |  |  | 				this.detectStrictMode(expression.body.body); | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 				this.prewalkStatement(expression.body); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				this.walkStatement(expression.body); | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				this.walkExpression(expression.body); | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-08-11 13:52:25 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2018-04-05 23:34:27 +08:00
										 |  |  | 		this.scope.topLevelScope = wasTopLevel; | 
					
						
							| 
									
										
										
										
											2017-02-24 06:06:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkArrowFunctionExpression(expression) { | 
					
						
							| 
									
										
										
										
											2017-08-11 13:52:25 +08:00
										 |  |  | 		this.inScope(expression.params, () => { | 
					
						
							| 
									
										
										
										
											2018-05-25 23:34:19 +08:00
										 |  |  | 			for (const param of expression.params) { | 
					
						
							|  |  |  | 				this.walkPattern(param); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (expression.body.type === "BlockStatement") { | 
					
						
							| 
									
										
										
										
											2018-01-09 17:35:08 +08:00
										 |  |  | 				this.detectStrictMode(expression.body.body); | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 				this.prewalkStatement(expression.body); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				this.walkStatement(expression.body); | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				this.walkExpression(expression.body); | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-08-11 13:52:25 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-24 06:06:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkSequenceExpression(expression) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (expression.expressions) this.walkExpressions(expression.expressions); | 
					
						
							| 
									
										
										
										
											2017-01-22 01:47:43 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkUpdateExpression(expression) { | 
					
						
							|  |  |  | 		this.walkExpression(expression.argument); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-12-31 19:23:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkUnaryExpression(expression) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (expression.operator === "typeof") { | 
					
						
							| 
									
										
										
										
											2017-07-19 02:22:20 +08:00
										 |  |  | 			const exprName = this.getNameForExpression(expression.argument); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (exprName && exprName.free) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 				const hook = this.hooks.typeof.get(exprName.name); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				if (hook !== undefined) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 					const result = hook.call(expression); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					if (result === true) return; | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		this.walkExpression(expression.argument); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-10-31 09:48:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkLeftRightExpression(expression) { | 
					
						
							|  |  |  | 		this.walkExpression(expression.left); | 
					
						
							|  |  |  | 		this.walkExpression(expression.right); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-12-31 19:23:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkBinaryExpression(expression) { | 
					
						
							|  |  |  | 		this.walkLeftRightExpression(expression); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkLogicalExpression(expression) { | 
					
						
							| 
									
										
										
										
											2018-10-17 23:12:07 +08:00
										 |  |  | 		const result = this.hooks.expressionLogicalOperator.call(expression); | 
					
						
							|  |  |  | 		if (result === undefined) { | 
					
						
							|  |  |  | 			this.walkLeftRightExpression(expression); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			if (result) { | 
					
						
							|  |  |  | 				this.walkExpression(expression.right); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkAssignmentExpression(expression) { | 
					
						
							|  |  |  | 		const renameIdentifier = this.getRenameIdentifier(expression.right); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (expression.left.type === "Identifier" && renameIdentifier) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 			const hook = this.hooks.canRename.get(renameIdentifier); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (hook !== undefined && hook.call(expression.right)) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 				// renaming "a = b;"
 | 
					
						
							|  |  |  | 				const hook = this.hooks.rename.get(renameIdentifier); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				if (hook === undefined || !hook.call(expression.right)) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 					this.scope.renames.set(expression.left.name, renameIdentifier); | 
					
						
							|  |  |  | 					this.scope.definitions.delete(expression.left.name); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (expression.left.type === "Identifier") { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 			const assignedHook = this.hooks.assigned.get(expression.left.name); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (assignedHook === undefined || !assignedHook.call(expression)) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				this.walkExpression(expression.right); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 			this.scope.renames.set(expression.left.name, null); | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 			const assignHook = this.hooks.assign.get(expression.left.name); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (assignHook === undefined || !assignHook.call(expression)) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				this.walkExpression(expression.left); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 			return; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 		this.walkExpression(expression.right); | 
					
						
							|  |  |  | 		this.walkPattern(expression.left); | 
					
						
							|  |  |  | 		this.enterPattern(expression.left, (name, decl) => { | 
					
						
							|  |  |  | 			this.scope.renames.set(name, null); | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkConditionalExpression(expression) { | 
					
						
							| 
									
										
										
										
											2017-11-27 22:27:41 +08:00
										 |  |  | 		const result = this.hooks.expressionConditionalOperator.call(expression); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (result === undefined) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			this.walkExpression(expression.test); | 
					
						
							|  |  |  | 			this.walkExpression(expression.consequent); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 			if (expression.alternate) { | 
					
						
							|  |  |  | 				this.walkExpression(expression.alternate); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 			if (result) { | 
					
						
							|  |  |  | 				this.walkExpression(expression.consequent); | 
					
						
							|  |  |  | 			} else if (expression.alternate) { | 
					
						
							|  |  |  | 				this.walkExpression(expression.alternate); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkNewExpression(expression) { | 
					
						
							| 
									
										
										
										
											2017-12-02 08:43:39 +08:00
										 |  |  | 		const callee = this.evaluateExpression(expression.callee); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (callee.isIdentifier()) { | 
					
						
							| 
									
										
										
										
											2018-01-11 03:52:33 +08:00
										 |  |  | 			const hook = this.hooks.new.get(callee.identifier); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (hook !== undefined) { | 
					
						
							| 
									
										
										
										
											2017-12-05 15:58:51 +08:00
										 |  |  | 				const result = hook.call(expression); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				if (result === true) { | 
					
						
							| 
									
										
										
										
											2017-12-05 15:58:51 +08:00
										 |  |  | 					return; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-12-02 08:43:39 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		this.walkExpression(expression.callee); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		if (expression.arguments) { | 
					
						
							|  |  |  | 			this.walkExpressions(expression.arguments); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkYieldExpression(expression) { | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		if (expression.argument) { | 
					
						
							|  |  |  | 			this.walkExpression(expression.argument); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkTemplateLiteral(expression) { | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		if (expression.expressions) { | 
					
						
							|  |  |  | 			this.walkExpressions(expression.expressions); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkTaggedTemplateExpression(expression) { | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		if (expression.tag) { | 
					
						
							|  |  |  | 			this.walkExpression(expression.tag); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (expression.quasi && expression.quasi.expressions) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			this.walkExpressions(expression.quasi.expressions); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkClassExpression(expression) { | 
					
						
							|  |  |  | 		this.walkClass(expression); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-09 01:31:01 +08:00
										 |  |  | 	_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); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 					if (hook === undefined || !hook.call(argOrThis)) { | 
					
						
							| 
									
										
										
										
											2018-05-09 01:31:01 +08:00
										 |  |  | 						return renameIdentifier; | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-06-16 21:31:45 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-05-09 01:31:01 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			this.walkExpression(argOrThis); | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2018-05-09 01:31:01 +08:00
										 |  |  | 		const params = functionExpression.params; | 
					
						
							|  |  |  | 		const renameThis = currentThis ? renameArgOrThis(currentThis) : null; | 
					
						
							|  |  |  | 		const args = options.map(renameArgOrThis); | 
					
						
							|  |  |  | 		const wasTopLevel = this.scope.topLevelScope; | 
					
						
							|  |  |  | 		this.scope.topLevelScope = false; | 
					
						
							|  |  |  | 		this.inScope(params.filter((identifier, idx) => !args[idx]), () => { | 
					
						
							|  |  |  | 			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.prewalkStatement(functionExpression.body); | 
					
						
							|  |  |  | 				this.walkStatement(functionExpression.body); | 
					
						
							| 
									
										
										
										
											2018-05-25 23:34:19 +08:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				this.walkExpression(functionExpression.body); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-05-09 01:31:01 +08:00
										 |  |  | 		}); | 
					
						
							|  |  |  | 		this.scope.topLevelScope = wasTopLevel; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkCallExpression(expression) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if ( | 
					
						
							|  |  |  | 			expression.callee.type === "MemberExpression" && | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			expression.callee.object.type === "FunctionExpression" && | 
					
						
							|  |  |  | 			!expression.callee.computed && | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			(expression.callee.property.name === "call" || | 
					
						
							|  |  |  | 				expression.callee.property.name === "bind") && | 
					
						
							| 
									
										
										
										
											2017-06-16 19:33:09 +08:00
										 |  |  | 			expression.arguments.length > 0 | 
					
						
							| 
									
										
										
										
											2016-06-04 18:06:10 +08:00
										 |  |  | 		) { | 
					
						
							| 
									
										
										
										
											2018-03-22 17:54:18 +08:00
										 |  |  | 			// (function(…) { }.call/bind(?, …))
 | 
					
						
							| 
									
										
										
										
											2018-05-09 01:31:01 +08:00
										 |  |  | 			this._walkIIFE( | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				expression.callee.object, | 
					
						
							|  |  |  | 				expression.arguments.slice(1), | 
					
						
							|  |  |  | 				expression.arguments[0] | 
					
						
							|  |  |  | 			); | 
					
						
							| 
									
										
										
										
											2018-05-09 01:31:01 +08:00
										 |  |  | 		} else if (expression.callee.type === "FunctionExpression") { | 
					
						
							| 
									
										
										
										
											2018-03-22 17:54:18 +08:00
										 |  |  | 			// (function(…) { }(…))
 | 
					
						
							| 
									
										
										
										
											2018-05-09 01:31:01 +08:00
										 |  |  | 			this._walkIIFE(expression.callee, expression.arguments, null); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		} else if (expression.callee.type === "Import") { | 
					
						
							| 
									
										
										
										
											2018-05-09 01:31:01 +08:00
										 |  |  | 			let result = this.hooks.importCall.call(expression); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (result === true) return; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (expression.arguments) this.walkExpressions(expression.arguments); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			const callee = this.evaluateExpression(expression.callee); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (callee.isIdentifier()) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 				const callHook = this.hooks.call.get(callee.identifier); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				if (callHook !== undefined) { | 
					
						
							| 
									
										
										
										
											2018-05-09 01:31:01 +08:00
										 |  |  | 					let result = callHook.call(expression); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					if (result === true) return; | 
					
						
							| 
									
										
										
										
											2017-05-21 15:13:33 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 				let identifier = callee.identifier.replace(/\.[^.]+$/, ""); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				if (identifier !== callee.identifier) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 					const callAnyHook = this.hooks.callAnyMember.get(identifier); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					if (callAnyHook !== undefined) { | 
					
						
							| 
									
										
										
										
											2018-05-09 01:31:01 +08:00
										 |  |  | 						let result = callAnyHook.call(expression); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 						if (result === true) return; | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (expression.callee) this.walkExpression(expression.callee); | 
					
						
							|  |  |  | 			if (expression.arguments) this.walkExpressions(expression.arguments); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkMemberExpression(expression) { | 
					
						
							| 
									
										
										
										
											2017-07-19 02:22:20 +08:00
										 |  |  | 		const exprName = this.getNameForExpression(expression); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (exprName && exprName.free) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 			const expressionHook = this.hooks.expression.get(exprName.name); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (expressionHook !== undefined) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 				const result = expressionHook.call(expression); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				if (result === true) return; | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			const expressionAnyMemberHook = this.hooks.expressionAnyMember.get( | 
					
						
							|  |  |  | 				exprName.nameGeneral | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 			if (expressionAnyMemberHook !== undefined) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 				const result = expressionAnyMemberHook.call(expression); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				if (result === true) return; | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		this.walkExpression(expression.object); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (expression.computed === true) this.walkExpression(expression.property); | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-08 22:31:54 +08:00
										 |  |  | 	walkThisExpression(expression) { | 
					
						
							|  |  |  | 		const expressionHook = this.hooks.expression.get("this"); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (expressionHook !== undefined) { | 
					
						
							| 
									
										
										
										
											2018-01-08 22:31:54 +08:00
										 |  |  | 			expressionHook.call(expression); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkIdentifier(expression) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (!this.scope.definitions.has(expression.name)) { | 
					
						
							|  |  |  | 			const hook = this.hooks.expression.get( | 
					
						
							|  |  |  | 				this.scope.renames.get(expression.name) || expression.name | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 			if (hook !== undefined) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 				const result = hook.call(expression); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				if (result === true) return; | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	inScope(params, fn) { | 
					
						
							|  |  |  | 		const oldScope = this.scope; | 
					
						
							|  |  |  | 		this.scope = { | 
					
						
							| 
									
										
										
										
											2018-01-08 22:31:54 +08:00
										 |  |  | 			topLevelScope: oldScope.topLevelScope, | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			inTry: false, | 
					
						
							|  |  |  | 			inShorthand: false, | 
					
						
							| 
									
										
										
										
											2018-01-09 17:35:08 +08:00
										 |  |  | 			isStrict: oldScope.isStrict, | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 			definitions: oldScope.definitions.createChild(), | 
					
						
							|  |  |  | 			renames: oldScope.renames.createChild() | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 		this.scope.renames.set("this", null); | 
					
						
							| 
									
										
										
										
											2017-06-16 21:31:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-25 23:34:19 +08:00
										 |  |  | 		for (const param of params) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (typeof param !== "string") { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				this.enterPattern(param, param => { | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 					this.scope.renames.set(param, null); | 
					
						
							|  |  |  | 					this.scope.definitions.add(param); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				}); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			} else if (param) { | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 				this.scope.renames.set(param, null); | 
					
						
							|  |  |  | 				this.scope.definitions.add(param); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		fn(); | 
					
						
							|  |  |  | 		this.scope = oldScope; | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-09 17:35:08 +08:00
										 |  |  | 	detectStrictMode(statements) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		const isStrict = | 
					
						
							|  |  |  | 			statements.length >= 1 && | 
					
						
							| 
									
										
										
										
											2018-01-09 17:35:08 +08:00
										 |  |  | 			statements[0].type === "ExpressionStatement" && | 
					
						
							|  |  |  | 			statements[0].expression.type === "Literal" && | 
					
						
							|  |  |  | 			statements[0].expression.value === "use strict"; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (isStrict) { | 
					
						
							| 
									
										
										
										
											2018-01-09 17:35:08 +08:00
										 |  |  | 			this.scope.isStrict = true; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	enterPattern(pattern, onIdent) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (!pattern) return; | 
					
						
							|  |  |  | 		switch (pattern.type) { | 
					
						
							| 
									
										
										
										
											2018-01-04 05:53:37 +08:00
										 |  |  | 			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; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	enterIdentifier(pattern, onIdent) { | 
					
						
							|  |  |  | 		onIdent(pattern.name, pattern); | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-12-03 18:36:10 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	enterObjectPattern(pattern, onIdent) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		for ( | 
					
						
							|  |  |  | 			let propIndex = 0, len = pattern.properties.length; | 
					
						
							|  |  |  | 			propIndex < len; | 
					
						
							|  |  |  | 			propIndex++ | 
					
						
							|  |  |  | 		) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			const prop = pattern.properties[propIndex]; | 
					
						
							|  |  |  | 			this.enterPattern(prop.value, onIdent); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	enterArrayPattern(pattern, onIdent) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		for ( | 
					
						
							|  |  |  | 			let elementIndex = 0, len = pattern.elements.length; | 
					
						
							|  |  |  | 			elementIndex < len; | 
					
						
							|  |  |  | 			elementIndex++ | 
					
						
							|  |  |  | 		) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			const element = pattern.elements[elementIndex]; | 
					
						
							|  |  |  | 			this.enterPattern(element, onIdent); | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	enterRestElement(pattern, onIdent) { | 
					
						
							|  |  |  | 		this.enterPattern(pattern.argument, onIdent); | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	enterAssignmentPattern(pattern, onIdent) { | 
					
						
							|  |  |  | 		this.enterPattern(pattern.left, onIdent); | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	evaluateExpression(expression) { | 
					
						
							|  |  |  | 		try { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 			const hook = this.hooks.evaluate.get(expression.type); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (hook !== undefined) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 				const result = hook.call(expression); | 
					
						
							| 
									
										
										
										
											2018-10-30 19:39:43 +08:00
										 |  |  | 				if (result !== undefined) { | 
					
						
							|  |  |  | 					if (result) { | 
					
						
							|  |  |  | 						result.setExpression(expression); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					return result; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-11-29 19:08:52 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		} catch (e) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			console.warn(e); | 
					
						
							|  |  |  | 			// ignore error
 | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-10-30 19:39:43 +08:00
										 |  |  | 		return new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 			.setRange(expression.range) | 
					
						
							|  |  |  | 			.setExpression(expression); | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	parseString(expression) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		switch (expression.type) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			case "BinaryExpression": | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				if (expression.operator === "+") { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					return ( | 
					
						
							|  |  |  | 						this.parseString(expression.left) + | 
					
						
							|  |  |  | 						this.parseString(expression.right) | 
					
						
							|  |  |  | 					); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			case "Literal": | 
					
						
							|  |  |  | 				return expression.value + ""; | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		throw new Error( | 
					
						
							|  |  |  | 			expression.type + " is not supported as parameter for require" | 
					
						
							|  |  |  | 		); | 
					
						
							| 
									
										
										
										
											2017-01-25 00:20:20 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	parseCalculatedString(expression) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		switch (expression.type) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			case "BinaryExpression": | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				if (expression.operator === "+") { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 					const left = this.parseCalculatedString(expression.left); | 
					
						
							|  |  |  | 					const right = this.parseCalculatedString(expression.right); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					if (left.code) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 						return { | 
					
						
							|  |  |  | 							range: left.range, | 
					
						
							|  |  |  | 							value: left.value, | 
					
						
							| 
									
										
										
										
											2018-04-11 03:18:12 +08:00
										 |  |  | 							code: true, | 
					
						
							|  |  |  | 							conditional: false | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 						}; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					} else if (right.code) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 						return { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 							range: [ | 
					
						
							|  |  |  | 								left.range[0], | 
					
						
							|  |  |  | 								right.range ? right.range[1] : left.range[1] | 
					
						
							|  |  |  | 							], | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 							value: left.value + right.value, | 
					
						
							| 
									
										
										
										
											2018-04-11 03:18:12 +08:00
										 |  |  | 							code: true, | 
					
						
							|  |  |  | 							conditional: false | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 						}; | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						return { | 
					
						
							|  |  |  | 							range: [left.range[0], right.range[1]], | 
					
						
							| 
									
										
										
										
											2018-04-11 03:18:12 +08:00
										 |  |  | 							value: left.value + right.value, | 
					
						
							|  |  |  | 							code: false, | 
					
						
							|  |  |  | 							conditional: false | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 						}; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			case "ConditionalExpression": { | 
					
						
							|  |  |  | 				const consequent = this.parseCalculatedString(expression.consequent); | 
					
						
							|  |  |  | 				const alternate = this.parseCalculatedString(expression.alternate); | 
					
						
							|  |  |  | 				const items = []; | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 				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; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				return { | 
					
						
							| 
									
										
										
										
											2018-04-11 03:18:12 +08:00
										 |  |  | 					range: undefined, | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					value: "", | 
					
						
							|  |  |  | 					code: true, | 
					
						
							|  |  |  | 					conditional: items | 
					
						
							|  |  |  | 				}; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			case "Literal": | 
					
						
							|  |  |  | 				return { | 
					
						
							|  |  |  | 					range: expression.range, | 
					
						
							| 
									
										
										
										
											2018-04-11 03:18:12 +08:00
										 |  |  | 					value: expression.value + "", | 
					
						
							|  |  |  | 					code: false, | 
					
						
							|  |  |  | 					conditional: false | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				}; | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		return { | 
					
						
							| 
									
										
										
										
											2018-04-11 03:18:12 +08:00
										 |  |  | 			range: undefined, | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			value: "", | 
					
						
							| 
									
										
										
										
											2018-04-11 03:18:12 +08:00
										 |  |  | 			code: true, | 
					
						
							|  |  |  | 			conditional: false | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		}; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	parse(source, initialState) { | 
					
						
							|  |  |  | 		let ast; | 
					
						
							| 
									
										
										
										
											2018-01-22 05:35:30 +08:00
										 |  |  | 		let comments; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (typeof source === "object" && source !== null) { | 
					
						
							| 
									
										
										
										
											2017-11-03 18:12:45 +08:00
										 |  |  | 			ast = source; | 
					
						
							|  |  |  | 			comments = source.comments; | 
					
						
							| 
									
										
										
										
											2018-01-22 05:35:30 +08:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			comments = []; | 
					
						
							| 
									
										
										
										
											2018-07-03 21:35:24 +08:00
										 |  |  | 			ast = JavascriptParser.parse(source, { | 
					
						
							| 
									
										
										
										
											2018-01-22 05:35:30 +08:00
										 |  |  | 				sourceType: this.sourceType, | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				onComment: comments | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-01-22 05:35:30 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		const oldScope = this.scope; | 
					
						
							|  |  |  | 		const oldState = this.state; | 
					
						
							| 
									
										
										
										
											2017-04-10 19:53:16 +08:00
										 |  |  | 		const oldComments = this.comments; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		this.scope = { | 
					
						
							| 
									
										
										
										
											2018-01-08 22:31:54 +08:00
										 |  |  | 			topLevelScope: true, | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			inTry: false, | 
					
						
							| 
									
										
										
										
											2018-01-09 17:35:08 +08:00
										 |  |  | 			inShorthand: false, | 
					
						
							|  |  |  | 			isStrict: false, | 
					
						
							| 
									
										
										
										
											2017-08-11 20:11:58 +08:00
										 |  |  | 			definitions: new StackedSetMap(), | 
					
						
							|  |  |  | 			renames: new StackedSetMap() | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		const state = (this.state = initialState || {}); | 
					
						
							| 
									
										
										
										
											2017-04-10 19:53:16 +08:00
										 |  |  | 		this.comments = comments; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (this.hooks.program.call(ast, comments) === undefined) { | 
					
						
							| 
									
										
										
										
											2018-01-09 17:35:08 +08:00
										 |  |  | 			this.detectStrictMode(ast.body); | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 			this.prewalkStatements(ast.body); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			this.walkStatements(ast.body); | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		this.scope = oldScope; | 
					
						
							|  |  |  | 		this.state = oldState; | 
					
						
							| 
									
										
										
										
											2017-04-10 19:53:16 +08:00
										 |  |  | 		this.comments = oldComments; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		return state; | 
					
						
							| 
									
										
										
										
											2016-02-13 17:53:31 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	evaluate(source) { | 
					
						
							| 
									
										
										
										
											2018-07-03 21:35:24 +08:00
										 |  |  | 		const ast = JavascriptParser.parse("(" + source + ")", { | 
					
						
							| 
									
										
										
										
											2018-01-22 05:35:30 +08:00
										 |  |  | 			sourceType: this.sourceType, | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			locations: false | 
					
						
							| 
									
										
										
										
											2016-02-13 17:53:31 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2018-10-02 20:20:20 +08:00
										 |  |  | 		// TODO(https://github.com/acornjs/acorn/issues/741)
 | 
					
						
							|  |  |  | 		// @ts-ignore
 | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		if (ast.body.length !== 1 || ast.body[0].type !== "ExpressionStatement") { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			throw new Error("evaluate: Source is not a expression"); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-10-02 20:20:20 +08:00
										 |  |  | 		// TODO(https://github.com/acornjs/acorn/issues/741)
 | 
					
						
							|  |  |  | 		// @ts-ignore
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		return this.evaluateExpression(ast.body[0].expression); | 
					
						
							| 
									
										
										
										
											2016-02-13 17:53:31 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-10 19:53:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	getComments(range) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		return this.comments.filter( | 
					
						
							|  |  |  | 			comment => comment.range[0] >= range[0] && comment.range[1] <= range[1] | 
					
						
							|  |  |  | 		); | 
					
						
							| 
									
										
										
										
											2017-04-10 19:53:16 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-29 17:09:34 +08:00
										 |  |  | 	parseCommentOptions(range) { | 
					
						
							| 
									
										
										
										
											2017-04-10 19:53:16 +08:00
										 |  |  | 		const comments = this.getComments(range); | 
					
						
							| 
									
										
										
										
											2018-05-29 19:17:36 +08:00
										 |  |  | 		if (comments.length === 0) { | 
					
						
							|  |  |  | 			return EMPTY_COMMENT_OPTIONS; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		let options = {}; | 
					
						
							|  |  |  | 		let errors = []; | 
					
						
							|  |  |  | 		for (const comment of comments) { | 
					
						
							| 
									
										
										
										
											2018-05-27 09:24:01 +08:00
										 |  |  | 			const { value } = comment; | 
					
						
							|  |  |  | 			if (value && webpackCommentRegExp.test(value)) { | 
					
						
							|  |  |  | 				// try compile only if webpack options comment is present
 | 
					
						
							|  |  |  | 				try { | 
					
						
							| 
									
										
										
										
											2018-05-29 15:29:23 +08:00
										 |  |  | 					const val = vm.runInNewContext(`(function(){return {${value}};})()`); | 
					
						
							| 
									
										
										
										
											2018-05-29 19:17:36 +08:00
										 |  |  | 					Object.assign(options, val); | 
					
						
							| 
									
										
										
										
											2018-05-27 09:24:01 +08:00
										 |  |  | 				} catch (e) { | 
					
						
							| 
									
										
										
										
											2018-05-29 19:17:36 +08:00
										 |  |  | 					e.comment = comment; | 
					
						
							|  |  |  | 					errors.push(e); | 
					
						
							| 
									
										
										
										
											2018-05-27 09:24:01 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-04-10 19:53:16 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-05-29 19:17:36 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return { options, errors }; | 
					
						
							| 
									
										
										
										
											2017-04-10 19:53:16 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-19 02:22:20 +08:00
										 |  |  | 	getNameForExpression(expression) { | 
					
						
							|  |  |  | 		let expr = expression; | 
					
						
							|  |  |  | 		const exprName = []; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		while ( | 
					
						
							|  |  |  | 			expr.type === "MemberExpression" && | 
					
						
							|  |  |  | 			expr.property.type === (expr.computed ? "Literal" : "Identifier") | 
					
						
							|  |  |  | 		) { | 
					
						
							| 
									
										
										
										
											2017-07-19 02:22:20 +08:00
										 |  |  | 			exprName.push(expr.computed ? expr.property.value : expr.property.name); | 
					
						
							|  |  |  | 			expr = expr.object; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		let free; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (expr.type === "Identifier") { | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 			free = !this.scope.definitions.has(expr.name); | 
					
						
							|  |  |  | 			exprName.push(this.scope.renames.get(expr.name) || expr.name); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		} else if ( | 
					
						
							|  |  |  | 			expr.type === "ThisExpression" && | 
					
						
							|  |  |  | 			this.scope.renames.get("this") | 
					
						
							|  |  |  | 		) { | 
					
						
							| 
									
										
										
										
											2017-07-19 02:22:20 +08:00
										 |  |  | 			free = true; | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 			exprName.push(this.scope.renames.get("this")); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		} else if (expr.type === "ThisExpression") { | 
					
						
							| 
									
										
										
										
											2018-02-27 08:32:09 +08:00
										 |  |  | 			free = this.scope.topLevelScope; | 
					
						
							| 
									
										
										
										
											2017-07-19 02:22:20 +08:00
										 |  |  | 			exprName.push("this"); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			return null; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		let prefix = ""; | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 		for (let i = exprName.length - 1; i >= 2; i--) { | 
					
						
							|  |  |  | 			prefix += exprName[i] + "."; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (exprName.length > 1) { | 
					
						
							|  |  |  | 			prefix += exprName[1]; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-11-27 22:27:41 +08:00
										 |  |  | 		const name = prefix ? prefix + "." + exprName[0] : exprName[0]; | 
					
						
							|  |  |  | 		const nameGeneral = prefix; | 
					
						
							| 
									
										
										
										
											2017-07-19 02:22:20 +08:00
										 |  |  | 		return { | 
					
						
							|  |  |  | 			name, | 
					
						
							|  |  |  | 			nameGeneral, | 
					
						
							|  |  |  | 			free | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 05:35:30 +08:00
										 |  |  | 	static parse(code, options) { | 
					
						
							| 
									
										
										
										
											2018-02-07 17:39:06 +08:00
										 |  |  | 		const type = options ? options.sourceType : "module"; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		const parserOptions = Object.assign( | 
					
						
							|  |  |  | 			Object.create(null), | 
					
						
							|  |  |  | 			defaultParserOptions, | 
					
						
							|  |  |  | 			options | 
					
						
							|  |  |  | 		); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (type === "auto") { | 
					
						
							| 
									
										
										
										
											2018-01-22 05:35:30 +08:00
										 |  |  | 			parserOptions.sourceType = "module"; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		let ast; | 
					
						
							|  |  |  | 		let error; | 
					
						
							|  |  |  | 		let threw = false; | 
					
						
							|  |  |  | 		try { | 
					
						
							| 
									
										
										
										
											2018-10-02 20:20:20 +08:00
										 |  |  | 			ast = parser.parse(code, parserOptions); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		} catch (e) { | 
					
						
							| 
									
										
										
										
											2018-01-22 05:35:30 +08:00
										 |  |  | 			error = e; | 
					
						
							|  |  |  | 			threw = true; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (threw && type === "auto") { | 
					
						
							| 
									
										
										
										
											2018-01-22 05:35:30 +08:00
										 |  |  | 			parserOptions.sourceType = "script"; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (Array.isArray(parserOptions.onComment)) { | 
					
						
							| 
									
										
										
										
											2018-01-22 05:35:30 +08:00
										 |  |  | 				parserOptions.onComment.length = 0; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			try { | 
					
						
							| 
									
										
										
										
											2018-10-02 20:20:20 +08:00
										 |  |  | 				ast = parser.parse(code, parserOptions); | 
					
						
							| 
									
										
										
										
											2018-01-22 05:35:30 +08:00
										 |  |  | 				threw = false; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:15:37 +08:00
										 |  |  | 			} catch (e) { | 
					
						
							|  |  |  | 				threw = true; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-01-22 05:35:30 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (threw) { | 
					
						
							| 
									
										
										
										
											2018-01-22 05:35:30 +08:00
										 |  |  | 			throw error; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return ast; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-05-21 12:56:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-03 16:15:48 +08:00
										 |  |  | module.exports = JavascriptParser; |