| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | "use strict"; | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Syntax: https://developer.mozilla.org/en/SpiderMonkey/Parser_API
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | const acorn = require("acorn-dynamic-import").default; | 
					
						
							|  |  |  | const Tapable = 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-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | const joinRanges = (startRange, endRange) => { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	if(!endRange) return startRange; | 
					
						
							|  |  |  | 	if(!startRange) return endRange; | 
					
						
							|  |  |  | 	return [startRange[0], endRange[1]]; | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-21 12:56:24 +08:00
										 |  |  | const ECMA_VERSION = 2017; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | const POSSIBLE_AST_OPTIONS = [{ | 
					
						
							|  |  |  | 	ranges: true, | 
					
						
							|  |  |  | 	locations: true, | 
					
						
							| 
									
										
										
										
											2017-05-21 12:56:24 +08:00
										 |  |  | 	ecmaVersion: ECMA_VERSION, | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	sourceType: "module", | 
					
						
							|  |  |  | 	plugins: { | 
					
						
							|  |  |  | 		dynamicImport: true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | }, { | 
					
						
							|  |  |  | 	ranges: true, | 
					
						
							|  |  |  | 	locations: true, | 
					
						
							| 
									
										
										
										
											2017-05-21 12:56:24 +08:00
										 |  |  | 	ecmaVersion: ECMA_VERSION, | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	sourceType: "script", | 
					
						
							|  |  |  | 	plugins: { | 
					
						
							|  |  |  | 		dynamicImport: true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | }]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | class TrackingSet { | 
					
						
							|  |  |  | 	constructor(set) { | 
					
						
							|  |  |  | 		this.set = set; | 
					
						
							|  |  |  | 		this.set2 = new Set(); | 
					
						
							|  |  |  | 		this.stack = set.stack; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	add(item) { | 
					
						
							|  |  |  | 		this.set2.add(item); | 
					
						
							|  |  |  | 		return this.set.add(item); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	delete(item) { | 
					
						
							|  |  |  | 		this.set2.delete(item); | 
					
						
							|  |  |  | 		return this.set.delete(item); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	has(item) { | 
					
						
							|  |  |  | 		return this.set.has(item); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	createChild() { | 
					
						
							|  |  |  | 		return this.set.createChild(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	getAddedItems() { | 
					
						
							|  |  |  | 		return this.set2; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | class Parser extends Tapable { | 
					
						
							|  |  |  | 	constructor(options) { | 
					
						
							|  |  |  | 		super(); | 
					
						
							|  |  |  | 		this.options = options; | 
					
						
							| 
									
										
										
										
											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() { | 
					
						
							|  |  |  | 		this.plugin("evaluate Literal", expr => { | 
					
						
							|  |  |  | 			switch(typeof expr.value) { | 
					
						
							|  |  |  | 				case "number": | 
					
						
							|  |  |  | 					return new BasicEvaluatedExpression().setNumber(expr.value).setRange(expr.range); | 
					
						
							|  |  |  | 				case "string": | 
					
						
							|  |  |  | 					return new BasicEvaluatedExpression().setString(expr.value).setRange(expr.range); | 
					
						
							|  |  |  | 				case "boolean": | 
					
						
							|  |  |  | 					return new BasicEvaluatedExpression().setBoolean(expr.value).setRange(expr.range); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if(expr.value === null) | 
					
						
							|  |  |  | 				return new BasicEvaluatedExpression().setNull().setRange(expr.range); | 
					
						
							|  |  |  | 			if(expr.value instanceof RegExp) | 
					
						
							|  |  |  | 				return new BasicEvaluatedExpression().setRegExp(expr.value).setRange(expr.range); | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		this.plugin("evaluate LogicalExpression", expr => { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			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); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		this.plugin("evaluate BinaryExpression", expr => { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			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()) { | 
					
						
							|  |  |  | 						res.setWrapped( | 
					
						
							|  |  |  | 							new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 							.setString(left.string + right.prefix.string) | 
					
						
							|  |  |  | 							.setRange(joinRanges(left.range, right.prefix.range)), | 
					
						
							|  |  |  | 							right.postfix); | 
					
						
							| 
									
										
										
										
											2017-04-13 20:52:49 +08:00
										 |  |  | 					} else if(right.isWrapped()) { | 
					
						
							|  |  |  | 						res.setWrapped( | 
					
						
							|  |  |  | 							new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 							.setString(left.string) | 
					
						
							|  |  |  | 							.setRange(left.range), | 
					
						
							|  |  |  | 							right.postfix); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 					} else { | 
					
						
							|  |  |  | 						res.setWrapped(left, null); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} else if(left.isNumber()) { | 
					
						
							|  |  |  | 					if(right.isString()) { | 
					
						
							|  |  |  | 						res.setString(left.number + right.string); | 
					
						
							|  |  |  | 					} else if(right.isNumber()) { | 
					
						
							|  |  |  | 						res.setNumber(left.number + right.number); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} else if(left.isWrapped()) { | 
					
						
							|  |  |  | 					if(left.postfix && left.postfix.isString() && right.isString()) { | 
					
						
							|  |  |  | 						res.setWrapped(left.prefix, | 
					
						
							|  |  |  | 							new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 							.setString(left.postfix.string + right.string) | 
					
						
							|  |  |  | 							.setRange(joinRanges(left.postfix.range, right.range)) | 
					
						
							|  |  |  | 						); | 
					
						
							|  |  |  | 					} else if(left.postfix && left.postfix.isString() && right.isNumber()) { | 
					
						
							|  |  |  | 						res.setWrapped(left.prefix, | 
					
						
							|  |  |  | 							new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 							.setString(left.postfix.string + right.number) | 
					
						
							|  |  |  | 							.setRange(joinRanges(left.postfix.range, right.range)) | 
					
						
							|  |  |  | 						); | 
					
						
							|  |  |  | 					} else if(right.isString()) { | 
					
						
							|  |  |  | 						res.setWrapped(left.prefix, right); | 
					
						
							|  |  |  | 					} else if(right.isNumber()) { | 
					
						
							|  |  |  | 						res.setWrapped(left.prefix, | 
					
						
							|  |  |  | 							new BasicEvaluatedExpression() | 
					
						
							|  |  |  | 							.setString(right.number + "") | 
					
						
							|  |  |  | 							.setRange(right.range)); | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						res.setWrapped(left.prefix, new BasicEvaluatedExpression()); | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2014-07-07 19:20:38 +08:00
										 |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 					if(right.isString()) { | 
					
						
							|  |  |  | 						res.setWrapped(null, right); | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +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 === "==" || 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); | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +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); | 
					
						
							| 
									
										
										
										
											2014-10-07 21:15:09 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2013-09-24 20:49:39 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		this.plugin("evaluate UnaryExpression", expr => { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			if(expr.operator === "typeof") { | 
					
						
							|  |  |  | 				let res; | 
					
						
							|  |  |  | 				let name; | 
					
						
							|  |  |  | 				if(expr.argument.type === "Identifier") { | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 					name = this.scope.renames.get(expr.argument.name) || expr.argument.name; | 
					
						
							|  |  |  | 					if(!this.scope.definitions.has(name)) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 						res = this.applyPluginsBailResult1("evaluate typeof " + name, expr); | 
					
						
							| 
									
										
										
										
											2014-10-07 21:15:09 +08:00
										 |  |  | 						if(res !== undefined) return res; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2013-09-24 21:09:08 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				if(expr.argument.type === "MemberExpression") { | 
					
						
							| 
									
										
										
										
											2017-07-19 02:22:20 +08:00
										 |  |  | 					const exprName = this.getNameForExpression(expr.argument); | 
					
						
							|  |  |  | 					if(exprName && exprName.free) { | 
					
						
							|  |  |  | 						res = this.applyPluginsBailResult1("evaluate typeof " + exprName.name, expr); | 
					
						
							|  |  |  | 						if(res !== undefined) return res; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if(expr.argument.type === "FunctionExpression") { | 
					
						
							|  |  |  | 					return new BasicEvaluatedExpression().setString("function").setRange(expr.range); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				const arg = this.evaluateExpression(expr.argument); | 
					
						
							|  |  |  | 				if(arg.isString() || arg.isWrapped()) return new BasicEvaluatedExpression().setString("string").setRange(expr.range); | 
					
						
							|  |  |  | 				else if(arg.isNumber()) return new BasicEvaluatedExpression().setString("number").setRange(expr.range); | 
					
						
							|  |  |  | 				else if(arg.isBoolean()) return new BasicEvaluatedExpression().setString("boolean").setRange(expr.range); | 
					
						
							|  |  |  | 				else if(arg.isArray() || arg.isConstArray() || arg.isRegExp()) return new BasicEvaluatedExpression().setString("object").setRange(expr.range); | 
					
						
							|  |  |  | 			} else if(expr.operator === "!") { | 
					
						
							|  |  |  | 				const argument = this.evaluateExpression(expr.argument); | 
					
						
							|  |  |  | 				if(!argument) return; | 
					
						
							|  |  |  | 				if(argument.isBoolean()) { | 
					
						
							|  |  |  | 					return new BasicEvaluatedExpression().setBoolean(!argument.bool).setRange(expr.range); | 
					
						
							| 
									
										
										
										
											2017-06-20 21:58:24 +08:00
										 |  |  | 				} else if(argument.isTruthy()) { | 
					
						
							|  |  |  | 					return new BasicEvaluatedExpression().setBoolean(false).setRange(expr.range); | 
					
						
							|  |  |  | 				} else if(argument.isFalsy()) { | 
					
						
							|  |  |  | 					return new BasicEvaluatedExpression().setBoolean(true).setRange(expr.range); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				} else if(argument.isString()) { | 
					
						
							|  |  |  | 					return new BasicEvaluatedExpression().setBoolean(!argument.string).setRange(expr.range); | 
					
						
							|  |  |  | 				} else if(argument.isNumber()) { | 
					
						
							|  |  |  | 					return new BasicEvaluatedExpression().setBoolean(!argument.number).setRange(expr.range); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2013-09-24 21:09:08 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		this.plugin("evaluate typeof undefined", expr => { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			return new BasicEvaluatedExpression().setString("undefined").setRange(expr.range); | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		this.plugin("evaluate Identifier", expr => { | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 			const name = this.scope.renames.get(expr.name) || expr.name; | 
					
						
							|  |  |  | 			if(!this.scope.definitions.has(expr.name)) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				const result = this.applyPluginsBailResult1("evaluate Identifier " + name, expr); | 
					
						
							|  |  |  | 				if(result) return result; | 
					
						
							|  |  |  | 				return new BasicEvaluatedExpression().setIdentifier(name).setRange(expr.range); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				return this.applyPluginsBailResult1("evaluate defined Identifier " + name, expr); | 
					
						
							| 
									
										
										
										
											2013-09-24 21:09:08 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		this.plugin("evaluate ThisExpression", expr => { | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 			const name = this.scope.renames.get("this"); | 
					
						
							| 
									
										
										
										
											2017-07-12 00:12:15 +08:00
										 |  |  | 			if(name) { | 
					
						
							|  |  |  | 				const result = this.applyPluginsBailResult1("evaluate Identifier " + name, expr); | 
					
						
							|  |  |  | 				if(result) return result; | 
					
						
							|  |  |  | 				return new BasicEvaluatedExpression().setIdentifier(name).setRange(expr.range); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		this.plugin("evaluate MemberExpression", expression => { | 
					
						
							| 
									
										
										
										
											2017-07-19 02:22:20 +08:00
										 |  |  | 			let exprName = this.getNameForExpression(expression); | 
					
						
							|  |  |  | 			if(exprName) { | 
					
						
							|  |  |  | 				if(exprName.free) { | 
					
						
							|  |  |  | 					const result = this.applyPluginsBailResult1("evaluate Identifier " + exprName.name, expression); | 
					
						
							|  |  |  | 					if(result) return result; | 
					
						
							|  |  |  | 					return new BasicEvaluatedExpression().setIdentifier(exprName.name).setRange(expression.range); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					return this.applyPluginsBailResult1("evaluate defined Identifier " + exprName.name, expression); | 
					
						
							| 
									
										
										
										
											2014-10-07 21:15:09 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2013-11-08 16:00:39 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		this.plugin("evaluate CallExpression", expr => { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			if(expr.callee.type !== "MemberExpression") return; | 
					
						
							|  |  |  | 			if(expr.callee.property.type !== (expr.callee.computed ? "Literal" : "Identifier")) return; | 
					
						
							|  |  |  | 			const param = this.evaluateExpression(expr.callee.object); | 
					
						
							|  |  |  | 			if(!param) return; | 
					
						
							|  |  |  | 			const property = expr.callee.property.name || expr.callee.property.value; | 
					
						
							| 
									
										
										
										
											2017-07-20 14:02:20 +08:00
										 |  |  | 			return this.applyPluginsBailResult2("evaluate CallExpression ." + property, expr, param); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		this.plugin("evaluate CallExpression .replace", (expr, param) => { | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 			if(!param.isString()) return; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			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); | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		["substr", "substring"].forEach(fn => { | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 			this.plugin("evaluate CallExpression ." + fn, (expr, param) => { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +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: | 
					
						
							|  |  |  | 						{ | 
					
						
							|  |  |  | 							arg1 = this.evaluateExpression(expr.arguments[0]); | 
					
						
							|  |  |  | 							const arg2 = this.evaluateExpression(expr.arguments[1]); | 
					
						
							|  |  |  | 							if(!arg1.isNumber()) return; | 
					
						
							|  |  |  | 							if(!arg2.isNumber()) return; | 
					
						
							|  |  |  | 							result = str[fn](arg1.number, arg2.number); | 
					
						
							|  |  |  | 							break; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					default: | 
					
						
							|  |  |  | 						return; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return new BasicEvaluatedExpression().setString(result).setRange(expr.range); | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											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" | 
					
						
							|  |  |  | 		 * @param {any[]} quasis quasis | 
					
						
							|  |  |  | 		 * @param {any[]} expressions expressions | 
					
						
							|  |  |  | 		 * @return {BasicEvaluatedExpression[]} Simplified template | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		const getSimplifiedTemplateResult = (kind, quasis, expressions) => { | 
					
						
							| 
									
										
										
										
											2017-09-15 01:02:34 +08:00
										 |  |  | 			const parts = []; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-15 01:02:34 +08:00
										 |  |  | 			for(let i = 0; i < quasis.length; i++) { | 
					
						
							|  |  |  | 				parts.push(new BasicEvaluatedExpression().setString(quasis[i].value[kind]).setRange(quasis[i].range)); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-15 01:02:34 +08:00
										 |  |  | 				if(i > 0) { | 
					
						
							|  |  |  | 					const prevExpr = parts[parts.length - 2], | 
					
						
							|  |  |  | 						lastExpr = parts[parts.length - 1]; | 
					
						
							|  |  |  | 					const expr = this.evaluateExpression(expressions[i - 1]); | 
					
						
							|  |  |  | 					if(!(expr.isString() || expr.isNumber())) continue; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-15 01:02:34 +08:00
										 |  |  | 					prevExpr.setString(prevExpr.string + (expr.isString() ? expr.string : expr.number) + lastExpr.string); | 
					
						
							|  |  |  | 					prevExpr.setRange([prevExpr.range[0], lastExpr.range[1]]); | 
					
						
							|  |  |  | 					parts.pop(); | 
					
						
							| 
									
										
										
										
											2016-11-17 01:05:39 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-11-15 21:03:53 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-09-15 01:02:34 +08:00
										 |  |  | 			return parts; | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2016-11-17 20:42:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		this.plugin("evaluate TemplateLiteral", node => { | 
					
						
							| 
									
										
										
										
											2017-09-15 01:02:34 +08:00
										 |  |  | 			const parts = getSimplifiedTemplateResult.call(this, "cooked", node.quasis, node.expressions); | 
					
						
							|  |  |  | 			if(parts.length === 1) { | 
					
						
							|  |  |  | 				return parts[0].setRange(node.range); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return new BasicEvaluatedExpression().setTemplateString(parts).setRange(node.range); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		this.plugin("evaluate TaggedTemplateExpression", node => { | 
					
						
							| 
									
										
										
										
											2017-09-15 01:02:34 +08:00
										 |  |  | 			if(this.evaluateExpression(node.tag).identifier !== "String.raw") return; | 
					
						
							|  |  |  | 			const parts = getSimplifiedTemplateResult.call(this, "raw", node.quasi.quasis, node.quasi.expressions); | 
					
						
							|  |  |  | 			return new BasicEvaluatedExpression().setTemplateString(parts).setRange(node.range); | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		this.plugin("evaluate CallExpression .concat", (expr, param) => { | 
					
						
							| 
									
										
										
										
											2017-09-15 02:35:33 +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; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				const value = argExpr.isString() ? argExpr.string : "" + argExpr.number; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				const newString = value + (stringSuffix ? stringSuffix.string : ""); | 
					
						
							|  |  |  | 				const newRange = [argExpr.range[0], (stringSuffix || argExpr).range[1]]; | 
					
						
							|  |  |  | 				stringSuffix = new BasicEvaluatedExpression().setString(newString).setRange(newRange); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(hasUnknownParams) { | 
					
						
							|  |  |  | 				const prefix = param.isString() ? param : param.prefix; | 
					
						
							|  |  |  | 				return new BasicEvaluatedExpression().setWrapped(prefix, stringSuffix).setRange(expr.range); | 
					
						
							|  |  |  | 			} else if(param.isWrapped()) { | 
					
						
							|  |  |  | 				const postfix = stringSuffix || param.postfix; | 
					
						
							|  |  |  | 				return new BasicEvaluatedExpression().setWrapped(param.prefix, postfix).setRange(expr.range); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				const newString = param.string + (stringSuffix ? stringSuffix.string : ""); | 
					
						
							|  |  |  | 				return new BasicEvaluatedExpression().setString(newString).setRange(expr.range); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		this.plugin("evaluate CallExpression .split", (expr, param) => { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +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); | 
					
						
							|  |  |  | 			} else return; | 
					
						
							|  |  |  | 			return new BasicEvaluatedExpression().setArray(result).setRange(expr.range); | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		this.plugin("evaluate ConditionalExpression", expr => { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			const condition = this.evaluateExpression(expr.test); | 
					
						
							|  |  |  | 			const conditionValue = condition.asBool(); | 
					
						
							|  |  |  | 			let res; | 
					
						
							|  |  |  | 			if(conditionValue === undefined) { | 
					
						
							|  |  |  | 				const consequent = this.evaluateExpression(expr.consequent); | 
					
						
							|  |  |  | 				const alternate = this.evaluateExpression(expr.alternate); | 
					
						
							|  |  |  | 				if(!consequent || !alternate) return; | 
					
						
							|  |  |  | 				res = new BasicEvaluatedExpression(); | 
					
						
							|  |  |  | 				if(consequent.isConditional()) | 
					
						
							|  |  |  | 					res.setOptions(consequent.options); | 
					
						
							|  |  |  | 				else | 
					
						
							|  |  |  | 					res.setOptions([consequent]); | 
					
						
							|  |  |  | 				if(alternate.isConditional()) | 
					
						
							|  |  |  | 					res.addOptions(alternate.options); | 
					
						
							|  |  |  | 				else | 
					
						
							|  |  |  | 					res.addOptions([alternate]); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				res = this.evaluateExpression(conditionValue ? expr.consequent : expr.alternate); | 
					
						
							| 
									
										
										
										
											2016-11-17 00:33:16 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			res.setRange(expr.range); | 
					
						
							|  |  |  | 			return res; | 
					
						
							| 
									
										
										
										
											2016-11-15 21:03:53 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		this.plugin("evaluate ArrayExpression", expr => { | 
					
						
							|  |  |  | 			const items = expr.elements.map(element => { | 
					
						
							| 
									
										
										
										
											2017-11-09 03:49:41 +08:00
										 |  |  | 				return element !== null && this.evaluateExpression(element); | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +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); | 
					
						
							|  |  |  | 		if(!result) return; | 
					
						
							|  |  |  | 		if(result.isIdentifier()) return result.identifier; | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkClass(classy) { | 
					
						
							|  |  |  | 		if(classy.superClass) | 
					
						
							|  |  |  | 			this.walkExpression(classy.superClass); | 
					
						
							|  |  |  | 		if(classy.body && classy.body.type === "ClassBody") { | 
					
						
							|  |  |  | 			classy.body.body.forEach(methodDefinition => { | 
					
						
							|  |  |  | 				if(methodDefinition.type === "MethodDefinition") | 
					
						
							|  |  |  | 					this.walkMethodDefinition(methodDefinition); | 
					
						
							|  |  |  | 			}); | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							|  |  |  | 		if(methodDefinition.computed && methodDefinition.key) | 
					
						
							|  |  |  | 			this.walkExpression(methodDefinition.key); | 
					
						
							|  |  |  | 		if(methodDefinition.value) | 
					
						
							|  |  |  | 			this.walkExpression(methodDefinition.value); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	// Prewalking iterates the scope for variable declarations
 | 
					
						
							|  |  |  | 	prewalkStatements(statements) { | 
					
						
							|  |  |  | 		for(let index = 0, len = statements.length; index < len; index++) { | 
					
						
							|  |  |  | 			const statement = statements[index]; | 
					
						
							|  |  |  | 			this.prewalkStatement(statement); | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							|  |  |  | 		for(let index = 0, len = statements.length; index < len; index++) { | 
					
						
							|  |  |  | 			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) { | 
					
						
							|  |  |  | 		const handler = this["prewalk" + statement.type]; | 
					
						
							|  |  |  | 		if(handler) | 
					
						
							|  |  |  | 			handler.call(this, statement); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkStatement(statement) { | 
					
						
							|  |  |  | 		if(this.applyPluginsBailResult1("statement", statement) !== undefined) return; | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 		const handler = this["walk" + statement.type]; | 
					
						
							|  |  |  | 		if(handler) | 
					
						
							|  |  |  | 			handler.call(this, statement); | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							|  |  |  | 		if(statement.alternate) | 
					
						
							|  |  |  | 			this.prewalkStatement(statement.alternate); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkIfStatement(statement) { | 
					
						
							|  |  |  | 		const result = this.applyPluginsBailResult1("statement if", statement); | 
					
						
							|  |  |  | 		if(result === undefined) { | 
					
						
							|  |  |  | 			this.walkExpression(statement.test); | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 			this.walkStatement(statement.consequent); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			if(statement.alternate) | 
					
						
							|  |  |  | 				this.walkStatement(statement.alternate); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			if(result) | 
					
						
							|  |  |  | 				this.walkStatement(statement.consequent); | 
					
						
							|  |  |  | 			else if(statement.alternate) | 
					
						
							|  |  |  | 				this.walkStatement(statement.alternate); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							|  |  |  | 		const result = this.applyPluginsBailResult1("label " + statement.label.name, statement); | 
					
						
							|  |  |  | 		if(result !== true) | 
					
						
							|  |  |  | 			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) { | 
					
						
							| 
									
										
										
										
											2015-07-16 06:19:23 +08:00
										 |  |  | 		if(statement.argument) | 
					
						
							| 
									
										
										
										
											2015-07-13 06:20:09 +08:00
										 |  |  | 			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) { | 
					
						
							|  |  |  | 		if(this.scope.inTry) { | 
					
						
							|  |  |  | 			this.walkStatement(statement.block); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			this.scope.inTry = true; | 
					
						
							|  |  |  | 			this.walkStatement(statement.block); | 
					
						
							|  |  |  | 			this.scope.inTry = false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if(statement.handler) | 
					
						
							|  |  |  | 			this.walkCatchClause(statement.handler); | 
					
						
							|  |  |  | 		if(statement.finalizer) | 
					
						
							|  |  |  | 			this.walkStatement(statement.finalizer); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							|  |  |  | 		if(statement.init) { | 
					
						
							|  |  |  | 			if(statement.init.type === "VariableDeclaration") | 
					
						
							|  |  |  | 				this.prewalkStatement(statement.init); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		this.prewalkStatement(statement.body); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkForStatement(statement) { | 
					
						
							|  |  |  | 		if(statement.init) { | 
					
						
							|  |  |  | 			if(statement.init.type === "VariableDeclaration") | 
					
						
							|  |  |  | 				this.walkStatement(statement.init); | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 				this.walkExpression(statement.init); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if(statement.test) | 
					
						
							|  |  |  | 			this.walkExpression(statement.test); | 
					
						
							|  |  |  | 		if(statement.update) | 
					
						
							|  |  |  | 			this.walkExpression(statement.update); | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							|  |  |  | 		if(statement.left.type === "VariableDeclaration") | 
					
						
							|  |  |  | 			this.prewalkStatement(statement.left); | 
					
						
							|  |  |  | 		this.prewalkStatement(statement.body); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkForInStatement(statement) { | 
					
						
							|  |  |  | 		if(statement.left.type === "VariableDeclaration") | 
					
						
							|  |  |  | 			this.walkStatement(statement.left); | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 		else | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			this.walkExpression(statement.left); | 
					
						
							|  |  |  | 		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) { | 
					
						
							|  |  |  | 		if(statement.left.type === "VariableDeclaration") | 
					
						
							|  |  |  | 			this.prewalkStatement(statement.left); | 
					
						
							|  |  |  | 		this.prewalkStatement(statement.body); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkForOfStatement(statement) { | 
					
						
							|  |  |  | 		if(statement.left.type === "VariableDeclaration") | 
					
						
							|  |  |  | 			this.walkStatement(statement.left); | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 		else | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			this.walkExpression(statement.left); | 
					
						
							|  |  |  | 		this.walkExpression(statement.right); | 
					
						
							|  |  |  | 		this.walkStatement(statement.body); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Declarations
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	prewalkFunctionDeclaration(statement) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +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) { | 
					
						
							| 
									
										
										
										
											2017-05-21 14:09:29 +08:00
										 |  |  | 		statement.params.forEach(param => { | 
					
						
							|  |  |  | 			this.walkPattern(param); | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-08-11 13:52:25 +08:00
										 |  |  | 		this.inScope(statement.params, () => { | 
					
						
							| 
									
										
										
										
											2017-04-14 21:23:27 +08:00
										 |  |  | 			if(statement.body.type === "BlockStatement") { | 
					
						
							|  |  |  | 				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
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											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-07-20 14:02:20 +08:00
										 |  |  | 		this.applyPluginsBailResult2("import", statement, source); | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		statement.specifiers.forEach(specifier => { | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			switch(specifier.type) { | 
					
						
							|  |  |  | 				case "ImportDefaultSpecifier": | 
					
						
							| 
									
										
										
										
											2017-07-20 14:02:20 +08:00
										 |  |  | 					this.applyPluginsBailResult4("import specifier", statement, source, "default", name); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 					break; | 
					
						
							|  |  |  | 				case "ImportSpecifier": | 
					
						
							| 
									
										
										
										
											2017-07-20 14:02:20 +08:00
										 |  |  | 					this.applyPluginsBailResult4("import specifier", statement, source, specifier.imported.name, name); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 					break; | 
					
						
							|  |  |  | 				case "ImportNamespaceSpecifier": | 
					
						
							| 
									
										
										
										
											2017-07-20 14:02:20 +08:00
										 |  |  | 					this.applyPluginsBailResult4("import specifier", statement, source, null, name); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 					break; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-11-09 03:49:41 +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; | 
					
						
							|  |  |  | 		if(statement.source) { | 
					
						
							|  |  |  | 			source = statement.source.value; | 
					
						
							| 
									
										
										
										
											2017-07-20 14:02:20 +08:00
										 |  |  | 			this.applyPluginsBailResult2("export import", statement, source); | 
					
						
							| 
									
										
										
										
											2015-01-13 00:45:30 +08:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			this.applyPluginsBailResult1("export", statement); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if(statement.declaration) { | 
					
						
							|  |  |  | 			if(/Expression$/.test(statement.declaration.type)) { | 
					
						
							|  |  |  | 				throw new Error("Doesn't occur?"); | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2017-07-20 14:02:20 +08:00
										 |  |  | 				if(!this.applyPluginsBailResult2("export declaration", statement, statement.declaration)) { | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 					for(let index = newDefs.length - 1; index >= 0; index--) { | 
					
						
							|  |  |  | 						const def = newDefs[index]; | 
					
						
							| 
									
										
										
										
											2017-07-20 14:02:20 +08:00
										 |  |  | 						this.applyPluginsBailResult4("export specifier", statement, def, def, index); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if(statement.specifiers) { | 
					
						
							|  |  |  | 			for(let specifierIndex = 0; specifierIndex < statement.specifiers.length; specifierIndex++) { | 
					
						
							|  |  |  | 				const specifier = statement.specifiers[specifierIndex]; | 
					
						
							|  |  |  | 				switch(specifier.type) { | 
					
						
							|  |  |  | 					case "ExportSpecifier": | 
					
						
							|  |  |  | 						{ | 
					
						
							|  |  |  | 							const name = specifier.exported.name; | 
					
						
							|  |  |  | 							if(source) | 
					
						
							| 
									
										
										
										
											2017-07-20 14:02:20 +08:00
										 |  |  | 								this.applyPluginsBailResult5("export import specifier", statement, source, specifier.local.name, name, specifierIndex); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 							else | 
					
						
							| 
									
										
										
										
											2017-07-20 14:02:20 +08:00
										 |  |  | 								this.applyPluginsBailResult4("export specifier", statement, specifier.local.name, name, specifierIndex); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 							break; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	walkExportNamedDeclaration(statement) { | 
					
						
							|  |  |  | 		if(statement.declaration) { | 
					
						
							|  |  |  | 			this.walkStatement(statement.declaration); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	prewalkExportDefaultDeclaration(statement) { | 
					
						
							|  |  |  | 		if(/Declaration$/.test(statement.declaration.type)) { | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 			for(let index = 0, len = newDefs.length; index < len; index++) { | 
					
						
							|  |  |  | 				const def = newDefs[index]; | 
					
						
							| 
									
										
										
										
											2017-07-20 14:02:20 +08:00
										 |  |  | 				this.applyPluginsBailResult3("export specifier", statement, def, "default"); | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkExportDefaultDeclaration(statement) { | 
					
						
							|  |  |  | 		this.applyPluginsBailResult1("export", statement); | 
					
						
							|  |  |  | 		if(/Declaration$/.test(statement.declaration.type)) { | 
					
						
							| 
									
										
										
										
											2017-07-20 14:02:20 +08:00
										 |  |  | 			if(!this.applyPluginsBailResult2("export declaration", statement, statement.declaration)) { | 
					
						
							| 
									
										
										
										
											2015-01-13 00:45:30 +08:00
										 |  |  | 				this.walkStatement(statement.declaration); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			this.walkExpression(statement.declaration); | 
					
						
							| 
									
										
										
										
											2017-07-20 14:02:20 +08:00
										 |  |  | 			if(!this.applyPluginsBailResult2("export expression", statement, statement.declaration)) { | 
					
						
							|  |  |  | 				this.applyPluginsBailResult3("export specifier", 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-07-20 14:02:20 +08:00
										 |  |  | 		this.applyPluginsBailResult2("export import", statement, source); | 
					
						
							|  |  |  | 		this.applyPluginsBailResult5("export import specifier", statement, source, null, null, 0); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	prewalkVariableDeclaration(statement) { | 
					
						
							|  |  |  | 		if(statement.declarations) | 
					
						
							|  |  |  | 			this.prewalkVariableDeclarators(statement.declarations); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkVariableDeclaration(statement) { | 
					
						
							|  |  |  | 		if(statement.declarations) | 
					
						
							|  |  |  | 			this.walkVariableDeclarators(statement.declarations); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	prewalkClassDeclaration(statement) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +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); | 
					
						
							| 
									
										
										
										
											2017-01-22 02:12:54 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkClassDeclaration(statement) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		this.walkClass(statement); | 
					
						
							| 
									
										
										
										
											2015-01-13 00:45:30 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	prewalkSwitchCases(switchCases) { | 
					
						
							|  |  |  | 		for(let index = 0, len = switchCases.length; index < len; index++) { | 
					
						
							|  |  |  | 			const switchCase = switchCases[index]; | 
					
						
							|  |  |  | 			this.prewalkStatements(switchCase.consequent); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkSwitchCases(switchCases) { | 
					
						
							|  |  |  | 		for(let index = 0, len = switchCases.length; index < len; index++) { | 
					
						
							|  |  |  | 			const switchCase = switchCases[index]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(switchCase.test) { | 
					
						
							|  |  |  | 				this.walkExpression(switchCase.test); | 
					
						
							| 
									
										
										
										
											2017-01-22 01:36:14 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			this.walkStatements(switchCase.consequent); | 
					
						
							| 
									
										
										
										
											2015-10-22 00:14:47 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-04-15 04:44:21 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkCatchClause(catchClause) { | 
					
						
							| 
									
										
										
										
											2017-08-11 13:52:25 +08:00
										 |  |  | 		this.inScope([catchClause.param], () => { | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 			this.prewalkStatement(catchClause.body); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			this.walkStatement(catchClause.body); | 
					
						
							| 
									
										
										
										
											2017-08-11 13:52:25 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-15 04:44:21 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 	prewalkVariableDeclarators(declarators) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		declarators.forEach(declarator => { | 
					
						
							|  |  |  | 			switch(declarator.type) { | 
					
						
							|  |  |  | 				case "VariableDeclarator": | 
					
						
							|  |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2017-05-21 14:09:29 +08:00
										 |  |  | 						this.enterPattern(declarator.id, (name, decl) => { | 
					
						
							|  |  |  | 							if(!this.applyPluginsBailResult1("var-" + declarator.kind + " " + name, decl)) { | 
					
						
							|  |  |  | 								if(!this.applyPluginsBailResult1("var " + name, decl)) { | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 									this.scope.renames.set(name, null); | 
					
						
							|  |  |  | 									this.scope.definitions.add(name); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 								} | 
					
						
							| 
									
										
										
										
											2017-05-21 14:09:29 +08:00
										 |  |  | 							} | 
					
						
							|  |  |  | 						}); | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 						break; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkVariableDeclarators(declarators) { | 
					
						
							|  |  |  | 		declarators.forEach(declarator => { | 
					
						
							|  |  |  | 			switch(declarator.type) { | 
					
						
							|  |  |  | 				case "VariableDeclarator": | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						const renameIdentifier = declarator.init && this.getRenameIdentifier(declarator.init); | 
					
						
							| 
									
										
										
										
											2017-05-21 14:09:29 +08:00
										 |  |  | 						if(renameIdentifier && declarator.id.type === "Identifier" && this.applyPluginsBailResult1("can-rename " + renameIdentifier, declarator.init)) { | 
					
						
							|  |  |  | 							// renaming with "var a = b;"
 | 
					
						
							|  |  |  | 							if(!this.applyPluginsBailResult1("rename " + renameIdentifier, declarator.init)) { | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 								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
										 |  |  | 							} | 
					
						
							|  |  |  | 						} else { | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 							this.walkPattern(declarator.id); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 							if(declarator.init) | 
					
						
							|  |  |  | 								this.walkExpression(declarator.init); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						break; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkPattern(pattern) { | 
					
						
							|  |  |  | 		if(pattern.type === "Identifier") | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		if(this["walk" + pattern.type]) | 
					
						
							|  |  |  | 			this["walk" + pattern.type](pattern); | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							|  |  |  | 		for(let i = 0, len = pattern.properties.length; i < len; i++) { | 
					
						
							|  |  |  | 			const prop = pattern.properties[i]; | 
					
						
							|  |  |  | 			if(prop) { | 
					
						
							|  |  |  | 				if(prop.computed) | 
					
						
							|  |  |  | 					this.walkExpression(prop.key); | 
					
						
							|  |  |  | 				if(prop.value) | 
					
						
							|  |  |  | 					this.walkPattern(prop.value); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-22 01:36:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkArrayPattern(pattern) { | 
					
						
							|  |  |  | 		for(let i = 0, len = pattern.elements.length; i < len; i++) { | 
					
						
							|  |  |  | 			const element = pattern.elements[i]; | 
					
						
							|  |  |  | 			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) { | 
					
						
							|  |  |  | 		for(let expressionsIndex = 0, len = expressions.length; expressionsIndex < len; expressionsIndex++) { | 
					
						
							|  |  |  | 			const expression = expressions[expressionsIndex]; | 
					
						
							|  |  |  | 			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) { | 
					
						
							|  |  |  | 		if(this["walk" + expression.type]) | 
					
						
							|  |  |  | 			return this["walk" + expression.type](expression); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkAwaitExpression(expression) { | 
					
						
							|  |  |  | 		const argument = expression.argument; | 
					
						
							|  |  |  | 		if(this["walk" + argument.type]) | 
					
						
							|  |  |  | 			return this["walk" + argument.type](argument); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkArrayExpression(expression) { | 
					
						
							|  |  |  | 		if(expression.elements) | 
					
						
							|  |  |  | 			this.walkExpressions(expression.elements); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkSpreadElement(expression) { | 
					
						
							|  |  |  | 		if(expression.argument) | 
					
						
							|  |  |  | 			this.walkExpression(expression.argument); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkObjectExpression(expression) { | 
					
						
							|  |  |  | 		for(let propIndex = 0, len = expression.properties.length; propIndex < len; propIndex++) { | 
					
						
							|  |  |  | 			const prop = expression.properties[propIndex]; | 
					
						
							| 
									
										
										
										
											2017-02-24 06:06:05 +08:00
										 |  |  | 			if(prop.computed) | 
					
						
							|  |  |  | 				this.walkExpression(prop.key); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			if(prop.shorthand) | 
					
						
							|  |  |  | 				this.scope.inShorthand = true; | 
					
						
							|  |  |  | 			this.walkExpression(prop.value); | 
					
						
							|  |  |  | 			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) { | 
					
						
							| 
									
										
										
										
											2017-05-21 14:09:29 +08:00
										 |  |  | 		expression.params.forEach(param => { | 
					
						
							|  |  |  | 			this.walkPattern(param); | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-08-11 13:52:25 +08:00
										 |  |  | 		this.inScope(expression.params, () => { | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 			if(expression.body.type === "BlockStatement") { | 
					
						
							|  |  |  | 				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-02-24 06:06:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkArrowFunctionExpression(expression) { | 
					
						
							| 
									
										
										
										
											2017-05-21 14:09:29 +08:00
										 |  |  | 		expression.params.forEach(param => { | 
					
						
							|  |  |  | 			this.walkPattern(param); | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-08-11 13:52:25 +08:00
										 |  |  | 		this.inScope(expression.params, () => { | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 			if(expression.body.type === "BlockStatement") { | 
					
						
							|  |  |  | 				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) { | 
					
						
							|  |  |  | 		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) { | 
					
						
							|  |  |  | 		if(expression.operator === "typeof") { | 
					
						
							| 
									
										
										
										
											2017-07-19 02:22:20 +08:00
										 |  |  | 			const exprName = this.getNameForExpression(expression.argument); | 
					
						
							|  |  |  | 			if(exprName && exprName.free) { | 
					
						
							|  |  |  | 				const result = this.applyPluginsBailResult1("typeof " + exprName.name, expression); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				if(result === true) | 
					
						
							|  |  |  | 					return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		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) { | 
					
						
							|  |  |  | 		this.walkLeftRightExpression(expression); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkAssignmentExpression(expression) { | 
					
						
							|  |  |  | 		const renameIdentifier = this.getRenameIdentifier(expression.right); | 
					
						
							|  |  |  | 		if(expression.left.type === "Identifier" && renameIdentifier && this.applyPluginsBailResult1("can-rename " + renameIdentifier, expression.right)) { | 
					
						
							|  |  |  | 			// renaming "a = b;"
 | 
					
						
							|  |  |  | 			if(!this.applyPluginsBailResult1("rename " + renameIdentifier, expression.right)) { | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 				this.scope.renames.set(expression.left.name, renameIdentifier); | 
					
						
							|  |  |  | 				this.scope.definitions.delete(expression.left.name); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} else if(expression.left.type === "Identifier") { | 
					
						
							|  |  |  | 			if(!this.applyPluginsBailResult1("assigned " + expression.left.name, expression)) { | 
					
						
							|  |  |  | 				this.walkExpression(expression.right); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 			this.scope.renames.set(expression.left.name, null); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			if(!this.applyPluginsBailResult1("assign " + expression.left.name, expression)) { | 
					
						
							|  |  |  | 				this.walkExpression(expression.left); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			this.walkExpression(expression.right); | 
					
						
							| 
									
										
										
										
											2017-05-21 14:16:32 +08:00
										 |  |  | 			this.walkPattern(expression.left); | 
					
						
							| 
									
										
										
										
											2017-05-16 16:55:15 +08:00
										 |  |  | 			this.enterPattern(expression.left, (name, decl) => { | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 				this.scope.renames.set(name, null); | 
					
						
							| 
									
										
										
										
											2017-05-16 16:55:15 +08:00
										 |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkConditionalExpression(expression) { | 
					
						
							|  |  |  | 		const result = this.applyPluginsBailResult1("expression ?:", expression); | 
					
						
							|  |  |  | 		if(result === undefined) { | 
					
						
							|  |  |  | 			this.walkExpression(expression.test); | 
					
						
							|  |  |  | 			this.walkExpression(expression.consequent); | 
					
						
							|  |  |  | 			if(expression.alternate) | 
					
						
							|  |  |  | 				this.walkExpression(expression.alternate); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			if(result) | 
					
						
							|  |  |  | 				this.walkExpression(expression.consequent); | 
					
						
							|  |  |  | 			else if(expression.alternate) | 
					
						
							|  |  |  | 				this.walkExpression(expression.alternate); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkNewExpression(expression) { | 
					
						
							|  |  |  | 		this.walkExpression(expression.callee); | 
					
						
							|  |  |  | 		if(expression.arguments) | 
					
						
							|  |  |  | 			this.walkExpressions(expression.arguments); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkYieldExpression(expression) { | 
					
						
							|  |  |  | 		if(expression.argument) | 
					
						
							|  |  |  | 			this.walkExpression(expression.argument); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkTemplateLiteral(expression) { | 
					
						
							|  |  |  | 		if(expression.expressions) | 
					
						
							|  |  |  | 			this.walkExpressions(expression.expressions); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkTaggedTemplateExpression(expression) { | 
					
						
							|  |  |  | 		if(expression.tag) | 
					
						
							|  |  |  | 			this.walkExpression(expression.tag); | 
					
						
							|  |  |  | 		if(expression.quasi && expression.quasi.expressions) | 
					
						
							|  |  |  | 			this.walkExpressions(expression.quasi.expressions); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkClassExpression(expression) { | 
					
						
							|  |  |  | 		this.walkClass(expression); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkCallExpression(expression) { | 
					
						
							|  |  |  | 		let result; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		const walkIIFE = (functionExpression, options, currentThis) => { | 
					
						
							|  |  |  | 			const renameArgOrThis = argOrThis => { | 
					
						
							| 
									
										
										
										
											2017-06-16 19:33:09 +08:00
										 |  |  | 				const renameIdentifier = this.getRenameIdentifier(argOrThis); | 
					
						
							|  |  |  | 				if(renameIdentifier && this.applyPluginsBailResult1("can-rename " + renameIdentifier, argOrThis)) { | 
					
						
							|  |  |  | 					if(!this.applyPluginsBailResult1("rename " + renameIdentifier, argOrThis)) | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 						return renameIdentifier; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-06-16 19:33:09 +08:00
										 |  |  | 				this.walkExpression(argOrThis); | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2017-06-16 19:33:09 +08:00
										 |  |  | 			const params = functionExpression.params; | 
					
						
							|  |  |  | 			const renameThis = currentThis ? renameArgOrThis.call(this, currentThis) : null; | 
					
						
							| 
									
										
										
										
											2017-11-09 03:49:41 +08:00
										 |  |  | 			const args = options.map(renameArgOrThis); | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 			this.inScope(params.filter((identifier, idx) => !args[idx]), () => { | 
					
						
							| 
									
										
										
										
											2017-06-16 21:31:45 +08:00
										 |  |  | 				if(renameThis) { | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 					this.scope.renames.set("this", renameThis); | 
					
						
							| 
									
										
										
										
											2017-06-16 21:31:45 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				for(let i = 0; i < args.length; i++) { | 
					
						
							|  |  |  | 					const param = args[i]; | 
					
						
							|  |  |  | 					if(!param) continue; | 
					
						
							|  |  |  | 					if(!params[i] || params[i].type !== "Identifier") continue; | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 					this.scope.renames.set(params[i].name, param); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 				if(functionExpression.body.type === "BlockStatement") { | 
					
						
							|  |  |  | 					this.prewalkStatement(functionExpression.body); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 					this.walkStatement(functionExpression.body); | 
					
						
							| 
									
										
										
										
											2017-04-13 13:52:05 +08:00
										 |  |  | 				} else | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 					this.walkExpression(functionExpression.body); | 
					
						
							| 
									
										
										
										
											2017-08-11 13:52:25 +08:00
										 |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		if(expression.callee.type === "MemberExpression" && | 
					
						
							|  |  |  | 			expression.callee.object.type === "FunctionExpression" && | 
					
						
							|  |  |  | 			!expression.callee.computed && | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 			(expression.callee.property.name === "call" || expression.callee.property.name === "bind") && | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			expression.arguments && | 
					
						
							| 
									
										
										
										
											2017-06-16 19:33:09 +08:00
										 |  |  | 			expression.arguments.length > 0 | 
					
						
							| 
									
										
										
										
											2016-06-04 18:06:10 +08:00
										 |  |  | 		) { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			// (function(...) { }.call/bind(?, ...))
 | 
					
						
							| 
									
										
										
										
											2017-06-16 19:33:09 +08:00
										 |  |  | 			walkIIFE.call(this, expression.callee.object, expression.arguments.slice(1), expression.arguments[0]); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		} else if(expression.callee.type === "FunctionExpression" && expression.arguments) { | 
					
						
							|  |  |  | 			// (function(...) { }(...))
 | 
					
						
							|  |  |  | 			walkIIFE.call(this, expression.callee, expression.arguments); | 
					
						
							|  |  |  | 		} else if(expression.callee.type === "Import") { | 
					
						
							|  |  |  | 			result = this.applyPluginsBailResult1("import-call", expression); | 
					
						
							|  |  |  | 			if(result === true) | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(expression.arguments) | 
					
						
							|  |  |  | 				this.walkExpressions(expression.arguments); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			const callee = this.evaluateExpression(expression.callee); | 
					
						
							|  |  |  | 			if(callee.isIdentifier()) { | 
					
						
							|  |  |  | 				result = this.applyPluginsBailResult1("call " + callee.identifier, expression); | 
					
						
							|  |  |  | 				if(result === true) | 
					
						
							|  |  |  | 					return; | 
					
						
							| 
									
										
										
										
											2017-07-24 17:54:06 +08:00
										 |  |  | 				let identifier = callee.identifier.replace(/\.[^.]+$/, ".*"); | 
					
						
							| 
									
										
										
										
											2017-05-21 15:13:33 +08:00
										 |  |  | 				if(identifier !== callee.identifier) { | 
					
						
							|  |  |  | 					result = this.applyPluginsBailResult1("call " + identifier, expression); | 
					
						
							|  |  |  | 					if(result === true) | 
					
						
							|  |  |  | 						return; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(expression.callee) | 
					
						
							|  |  |  | 				this.walkExpression(expression.callee); | 
					
						
							|  |  |  | 			if(expression.arguments) | 
					
						
							|  |  |  | 				this.walkExpressions(expression.arguments); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	walkMemberExpression(expression) { | 
					
						
							| 
									
										
										
										
											2017-07-19 02:22:20 +08:00
										 |  |  | 		const exprName = this.getNameForExpression(expression); | 
					
						
							|  |  |  | 		if(exprName && exprName.free) { | 
					
						
							|  |  |  | 			let result = this.applyPluginsBailResult1("expression " + exprName.name, expression); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			if(result === true) | 
					
						
							|  |  |  | 				return; | 
					
						
							| 
									
										
										
										
											2017-07-19 02:22:20 +08:00
										 |  |  | 			result = this.applyPluginsBailResult1("expression " + exprName.nameGeneral, expression); | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 			if(result === true) | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 				return; | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		this.walkExpression(expression.object); | 
					
						
							|  |  |  | 		if(expression.computed === true) | 
					
						
							|  |  |  | 			this.walkExpression(expression.property); | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	walkIdentifier(expression) { | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | 		if(!this.scope.definitions.has(expression.name)) { | 
					
						
							|  |  |  | 			const result = this.applyPluginsBailResult1("expression " + (this.scope.renames.get(expression.name) || expression.name), expression); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			if(result === true) | 
					
						
							|  |  |  | 				return; | 
					
						
							| 
									
										
										
										
											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 = { | 
					
						
							|  |  |  | 			inTry: false, | 
					
						
							|  |  |  | 			inShorthand: false, | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		for(let paramIndex = 0, len = params.length; paramIndex < len; paramIndex++) { | 
					
						
							|  |  |  | 			const param = params[paramIndex]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(typeof param !== "string") { | 
					
						
							|  |  |  | 				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
										 |  |  | 				}); | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	enterPattern(pattern, onIdent) { | 
					
						
							|  |  |  | 		if(pattern && this["enter" + pattern.type]) | 
					
						
							|  |  |  | 			this["enter" + pattern.type](pattern, onIdent); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							|  |  |  | 		for(let propIndex = 0, len = pattern.properties.length; propIndex < len; propIndex++) { | 
					
						
							|  |  |  | 			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) { | 
					
						
							|  |  |  | 		for(let elementIndex = 0, len = pattern.elements.length; elementIndex < len; elementIndex++) { | 
					
						
							|  |  |  | 			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 { | 
					
						
							|  |  |  | 			const result = this.applyPluginsBailResult1("evaluate " + expression.type, expression); | 
					
						
							|  |  |  | 			if(result !== undefined) | 
					
						
							|  |  |  | 				return result; | 
					
						
							|  |  |  | 		} catch(e) { | 
					
						
							|  |  |  | 			console.warn(e); | 
					
						
							|  |  |  | 			// ignore error
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return new BasicEvaluatedExpression().setRange(expression.range); | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	parseString(expression) { | 
					
						
							|  |  |  | 		switch(expression.type) { | 
					
						
							|  |  |  | 			case "BinaryExpression": | 
					
						
							|  |  |  | 				if(expression.operator === "+") | 
					
						
							|  |  |  | 					return this.parseString(expression.left) + this.parseString(expression.right); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			case "Literal": | 
					
						
							|  |  |  | 				return expression.value + ""; | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +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) { | 
					
						
							|  |  |  | 		switch(expression.type) { | 
					
						
							|  |  |  | 			case "BinaryExpression": | 
					
						
							|  |  |  | 				if(expression.operator === "+") { | 
					
						
							|  |  |  | 					const left = this.parseCalculatedString(expression.left); | 
					
						
							|  |  |  | 					const right = this.parseCalculatedString(expression.right); | 
					
						
							|  |  |  | 					if(left.code) { | 
					
						
							|  |  |  | 						return { | 
					
						
							|  |  |  | 							range: left.range, | 
					
						
							|  |  |  | 							value: left.value, | 
					
						
							|  |  |  | 							code: true | 
					
						
							|  |  |  | 						}; | 
					
						
							|  |  |  | 					} else if(right.code) { | 
					
						
							|  |  |  | 						return { | 
					
						
							|  |  |  | 							range: [left.range[0], right.range ? right.range[1] : left.range[1]], | 
					
						
							|  |  |  | 							value: left.value + right.value, | 
					
						
							|  |  |  | 							code: true | 
					
						
							|  |  |  | 						}; | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						return { | 
					
						
							|  |  |  | 							range: [left.range[0], right.range[1]], | 
					
						
							|  |  |  | 							value: left.value + right.value | 
					
						
							|  |  |  | 						}; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			case "ConditionalExpression": | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					const consequent = this.parseCalculatedString(expression.consequent); | 
					
						
							|  |  |  | 					const alternate = this.parseCalculatedString(expression.alternate); | 
					
						
							|  |  |  | 					const items = []; | 
					
						
							|  |  |  | 					if(consequent.conditional) | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 						items.push(...consequent.conditional); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 					else if(!consequent.code) | 
					
						
							|  |  |  | 						items.push(consequent); | 
					
						
							|  |  |  | 					else break; | 
					
						
							|  |  |  | 					if(alternate.conditional) | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 						items.push(...alternate.conditional); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 					else if(!alternate.code) | 
					
						
							|  |  |  | 						items.push(alternate); | 
					
						
							|  |  |  | 					else break; | 
					
						
							| 
									
										
										
										
											2015-07-13 06:20:09 +08:00
										 |  |  | 					return { | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 						value: "", | 
					
						
							|  |  |  | 						code: true, | 
					
						
							|  |  |  | 						conditional: items | 
					
						
							| 
									
										
										
										
											2015-07-13 06:20:09 +08:00
										 |  |  | 					}; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			case "Literal": | 
					
						
							|  |  |  | 				return { | 
					
						
							|  |  |  | 					range: expression.range, | 
					
						
							|  |  |  | 					value: expression.value + "" | 
					
						
							|  |  |  | 				}; | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		return { | 
					
						
							|  |  |  | 			value: "", | 
					
						
							|  |  |  | 			code: true | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-26 07:02:43 +08:00
										 |  |  | 	parseStringArray(expression) { | 
					
						
							|  |  |  | 		if(expression.type !== "ArrayExpression") { | 
					
						
							|  |  |  | 			return [this.parseString(expression)]; | 
					
						
							| 
									
										
										
										
											2014-06-25 00:53:32 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-01-31 01:49:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-10 18:24:00 +08:00
										 |  |  | 		const arr = []; | 
					
						
							| 
									
										
										
										
											2017-02-26 07:02:43 +08:00
										 |  |  | 		if(expression.elements) | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 			expression.elements.forEach(expr => { | 
					
						
							| 
									
										
										
										
											2017-02-26 07:02:43 +08:00
										 |  |  | 				arr.push(this.parseString(expr)); | 
					
						
							| 
									
										
										
										
											2017-11-09 03:49:41 +08:00
										 |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2017-02-26 07:02:43 +08:00
										 |  |  | 		return arr; | 
					
						
							| 
									
										
										
										
											2016-12-05 06:47:19 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	parseCalculatedStringArray(expression) { | 
					
						
							| 
									
										
										
										
											2017-02-26 07:02:43 +08:00
										 |  |  | 		if(expression.type !== "ArrayExpression") { | 
					
						
							|  |  |  | 			return [this.parseCalculatedString(expression)]; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-10 18:24:00 +08:00
										 |  |  | 		const arr = []; | 
					
						
							| 
									
										
										
										
											2017-02-26 07:02:43 +08:00
										 |  |  | 		if(expression.elements) | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | 			expression.elements.forEach(expr => { | 
					
						
							| 
									
										
										
										
											2017-02-26 07:02:43 +08:00
										 |  |  | 				arr.push(this.parseCalculatedString(expr)); | 
					
						
							| 
									
										
										
										
											2017-11-09 03:49:41 +08:00
										 |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2017-02-26 07:02:43 +08:00
										 |  |  | 		return arr; | 
					
						
							| 
									
										
										
										
											2016-12-05 06:47:19 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-13 17:53:31 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 	parse(source, initialState) { | 
					
						
							|  |  |  | 		let ast; | 
					
						
							| 
									
										
										
										
											2017-11-03 18:12:45 +08:00
										 |  |  | 		let comments = []; | 
					
						
							|  |  |  | 		if(typeof source === "object" && source !== null) { | 
					
						
							|  |  |  | 			ast = source; | 
					
						
							|  |  |  | 			comments = source.comments; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		for(let i = 0, len = POSSIBLE_AST_OPTIONS.length; i < len; i++) { | 
					
						
							|  |  |  | 			if(!ast) { | 
					
						
							|  |  |  | 				try { | 
					
						
							|  |  |  | 					comments.length = 0; | 
					
						
							|  |  |  | 					POSSIBLE_AST_OPTIONS[i].onComment = comments; | 
					
						
							|  |  |  | 					ast = acorn.parse(source, POSSIBLE_AST_OPTIONS[i]); | 
					
						
							|  |  |  | 				} catch(e) { | 
					
						
							|  |  |  | 					// ignore the error
 | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-02-13 17:53:31 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		if(!ast) { | 
					
						
							|  |  |  | 			// for the error
 | 
					
						
							|  |  |  | 			ast = acorn.parse(source, { | 
					
						
							|  |  |  | 				ranges: true, | 
					
						
							|  |  |  | 				locations: true, | 
					
						
							| 
									
										
										
										
											2017-05-21 12:56:24 +08:00
										 |  |  | 				ecmaVersion: ECMA_VERSION, | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 				sourceType: "module", | 
					
						
							|  |  |  | 				plugins: { | 
					
						
							|  |  |  | 					dynamicImport: true | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				onComment: comments | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if(!ast || typeof ast !== "object") | 
					
						
							|  |  |  | 			throw new Error("Source couldn't be parsed"); | 
					
						
							|  |  |  | 		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 = { | 
					
						
							|  |  |  | 			inTry: false, | 
					
						
							| 
									
										
										
										
											2017-08-11 20:11:58 +08:00
										 |  |  | 			definitions: new StackedSetMap(), | 
					
						
							|  |  |  | 			renames: new StackedSetMap() | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		}; | 
					
						
							|  |  |  | 		const state = this.state = initialState || {}; | 
					
						
							| 
									
										
										
										
											2017-04-10 19:53:16 +08:00
										 |  |  | 		this.comments = comments; | 
					
						
							| 
									
										
										
										
											2017-07-20 14:02:20 +08:00
										 |  |  | 		if(this.applyPluginsBailResult2("program", ast, comments) === undefined) { | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							|  |  |  | 		const ast = acorn.parse("(" + source + ")", { | 
					
						
							| 
									
										
										
										
											2016-02-13 17:53:31 +08:00
										 |  |  | 			ranges: true, | 
					
						
							|  |  |  | 			locations: true, | 
					
						
							| 
									
										
										
										
											2017-05-21 12:56:24 +08:00
										 |  |  | 			ecmaVersion: ECMA_VERSION, | 
					
						
							| 
									
										
										
										
											2016-09-09 02:52:53 +08:00
										 |  |  | 			sourceType: "module", | 
					
						
							| 
									
										
										
										
											2016-12-05 06:47:19 +08:00
										 |  |  | 			plugins: { | 
					
						
							|  |  |  | 				dynamicImport: true | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-02-13 17:53:31 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | 		if(!ast || typeof ast !== "object" || ast.type !== "Program") | 
					
						
							|  |  |  | 			throw new Error("evaluate: Source couldn't be parsed"); | 
					
						
							|  |  |  | 		if(ast.body.length !== 1 || ast.body[0].type !== "ExpressionStatement") | 
					
						
							|  |  |  | 			throw new Error("evaluate: Source is not a expression"); | 
					
						
							|  |  |  | 		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) { | 
					
						
							|  |  |  | 		return this.comments.filter(comment => comment.range[0] >= range[0] && comment.range[1] <= range[1]); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	getCommentOptions(range) { | 
					
						
							|  |  |  | 		const comments = this.getComments(range); | 
					
						
							|  |  |  | 		if(comments.length === 0) return null; | 
					
						
							|  |  |  | 		const options = comments.map(comment => { | 
					
						
							|  |  |  | 			try { | 
					
						
							| 
									
										
										
										
											2017-10-14 05:31:15 +08:00
										 |  |  | 				let val = vm.runInNewContext(`(function(){return {${comment.value}};})()`); | 
					
						
							|  |  |  | 				return val; | 
					
						
							| 
									
										
										
										
											2017-04-10 19:53:16 +08:00
										 |  |  | 			} catch(e) { | 
					
						
							|  |  |  | 				return {}; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 		return options.reduce((o, i) => Object.assign(o, i), {}); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-19 02:22:20 +08:00
										 |  |  | 	getNameForExpression(expression) { | 
					
						
							|  |  |  | 		let expr = expression; | 
					
						
							|  |  |  | 		const exprName = []; | 
					
						
							|  |  |  | 		while(expr.type === "MemberExpression" && expr.property.type === (expr.computed ? "Literal" : "Identifier")) { | 
					
						
							|  |  |  | 			exprName.push(expr.computed ? expr.property.value : expr.property.name); | 
					
						
							|  |  |  | 			expr = expr.object; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		let free; | 
					
						
							|  |  |  | 		if(expr.type === "Identifier") { | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							| 
									
										
										
										
											2017-07-20 14:34:04 +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")); | 
					
						
							| 
									
										
										
										
											2017-07-19 02:22:20 +08:00
										 |  |  | 		} else if(expr.type === "ThisExpression") { | 
					
						
							|  |  |  | 			free = false; | 
					
						
							|  |  |  | 			exprName.push("this"); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			return null; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		let prefix = ""; | 
					
						
							|  |  |  | 		for(let i = exprName.length - 1; i >= 1; i--) | 
					
						
							|  |  |  | 			prefix += exprName[i] + "."; | 
					
						
							|  |  |  | 		const name = prefix + exprName[0]; | 
					
						
							|  |  |  | 		const nameGeneral = prefix + "*"; | 
					
						
							|  |  |  | 		return { | 
					
						
							|  |  |  | 			name, | 
					
						
							|  |  |  | 			nameGeneral, | 
					
						
							|  |  |  | 			free | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-21 12:56:24 +08:00
										 |  |  | Parser.ECMA_VERSION = ECMA_VERSION; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-04 22:04:28 +08:00
										 |  |  | module.exports = Parser; | 
					
						
							| 
									
										
										
										
											2017-07-19 21:41:27 +08:00
										 |  |  | Parser.StackedSetMap = StackedSetMap; |