You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							430 lines
						
					
					
						
							12 KiB
						
					
					
				
			
		
		
	
	
							430 lines
						
					
					
						
							12 KiB
						
					
					
				| "use strict";
 | |
| 
 | |
| Object.defineProperty(exports, "__esModule", {
 | |
|   value: true
 | |
| });
 | |
| exports._guessExecutionStatusRelativeTo = _guessExecutionStatusRelativeTo;
 | |
| exports._resolve = _resolve;
 | |
| exports.canHaveVariableDeclarationOrExpression = canHaveVariableDeclarationOrExpression;
 | |
| exports.canSwapBetweenExpressionAndStatement = canSwapBetweenExpressionAndStatement;
 | |
| exports.equals = equals;
 | |
| exports.getSource = getSource;
 | |
| exports.has = has;
 | |
| exports.is = void 0;
 | |
| exports.isCompletionRecord = isCompletionRecord;
 | |
| exports.isConstantExpression = isConstantExpression;
 | |
| exports.isInStrictMode = isInStrictMode;
 | |
| exports.isNodeType = isNodeType;
 | |
| exports.isStatementOrBlock = isStatementOrBlock;
 | |
| exports.isStatic = isStatic;
 | |
| exports.isnt = isnt;
 | |
| exports.matchesPattern = matchesPattern;
 | |
| exports.referencesImport = referencesImport;
 | |
| exports.resolve = resolve;
 | |
| exports.willIMaybeExecuteBefore = willIMaybeExecuteBefore;
 | |
| var _t = require("@babel/types");
 | |
| const {
 | |
|   STATEMENT_OR_BLOCK_KEYS,
 | |
|   VISITOR_KEYS,
 | |
|   isBlockStatement,
 | |
|   isExpression,
 | |
|   isIdentifier,
 | |
|   isLiteral,
 | |
|   isStringLiteral,
 | |
|   isType,
 | |
|   matchesPattern: _matchesPattern
 | |
| } = _t;
 | |
| 
 | |
| function matchesPattern(pattern, allowPartial) {
 | |
|   return _matchesPattern(this.node, pattern, allowPartial);
 | |
| }
 | |
| 
 | |
| function has(key) {
 | |
|   const val = this.node && this.node[key];
 | |
|   if (val && Array.isArray(val)) {
 | |
|     return !!val.length;
 | |
|   } else {
 | |
|     return !!val;
 | |
|   }
 | |
| }
 | |
| 
 | |
| function isStatic() {
 | |
|   return this.scope.isStatic(this.node);
 | |
| }
 | |
| 
 | |
| const is = has;
 | |
| 
 | |
| exports.is = is;
 | |
| 
 | |
| function isnt(key) {
 | |
|   return !this.has(key);
 | |
| }
 | |
| 
 | |
| function equals(key, value) {
 | |
|   return this.node[key] === value;
 | |
| }
 | |
| 
 | |
| function isNodeType(type) {
 | |
|   return isType(this.type, type);
 | |
| }
 | |
| 
 | |
| function canHaveVariableDeclarationOrExpression() {
 | |
|   return (this.key === "init" || this.key === "left") && this.parentPath.isFor();
 | |
| }
 | |
| 
 | |
| function canSwapBetweenExpressionAndStatement(replacement) {
 | |
|   if (this.key !== "body" || !this.parentPath.isArrowFunctionExpression()) {
 | |
|     return false;
 | |
|   }
 | |
|   if (this.isExpression()) {
 | |
|     return isBlockStatement(replacement);
 | |
|   } else if (this.isBlockStatement()) {
 | |
|     return isExpression(replacement);
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| function isCompletionRecord(allowInsideFunction) {
 | |
|   let path = this;
 | |
|   let first = true;
 | |
|   do {
 | |
|     const {
 | |
|       type,
 | |
|       container
 | |
|     } = path;
 | |
| 
 | |
|     if (!first && (path.isFunction() || type === "StaticBlock")) {
 | |
|       return !!allowInsideFunction;
 | |
|     }
 | |
|     first = false;
 | |
| 
 | |
|     if (Array.isArray(container) && path.key !== container.length - 1) {
 | |
|       return false;
 | |
|     }
 | |
|   } while ((path = path.parentPath) && !path.isProgram() && !path.isDoExpression());
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| function isStatementOrBlock() {
 | |
|   if (this.parentPath.isLabeledStatement() || isBlockStatement(this.container)) {
 | |
|     return false;
 | |
|   } else {
 | |
|     return STATEMENT_OR_BLOCK_KEYS.includes(this.key);
 | |
|   }
 | |
| }
 | |
| 
 | |
| function referencesImport(moduleSource, importName) {
 | |
|   if (!this.isReferencedIdentifier()) {
 | |
|     if (this.isJSXMemberExpression() && this.node.property.name === importName || (this.isMemberExpression() || this.isOptionalMemberExpression()) && (this.node.computed ? isStringLiteral(this.node.property, {
 | |
|       value: importName
 | |
|     }) : this.node.property.name === importName)) {
 | |
|       const object = this.get("object");
 | |
|       return object.isReferencedIdentifier() && object.referencesImport(moduleSource, "*");
 | |
|     }
 | |
|     return false;
 | |
|   }
 | |
|   const binding = this.scope.getBinding(this.node.name);
 | |
|   if (!binding || binding.kind !== "module") return false;
 | |
|   const path = binding.path;
 | |
|   const parent = path.parentPath;
 | |
|   if (!parent.isImportDeclaration()) return false;
 | |
| 
 | |
|   if (parent.node.source.value === moduleSource) {
 | |
|     if (!importName) return true;
 | |
|   } else {
 | |
|     return false;
 | |
|   }
 | |
|   if (path.isImportDefaultSpecifier() && importName === "default") {
 | |
|     return true;
 | |
|   }
 | |
|   if (path.isImportNamespaceSpecifier() && importName === "*") {
 | |
|     return true;
 | |
|   }
 | |
|   if (path.isImportSpecifier() && isIdentifier(path.node.imported, {
 | |
|     name: importName
 | |
|   })) {
 | |
|     return true;
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| function getSource() {
 | |
|   const node = this.node;
 | |
|   if (node.end) {
 | |
|     const code = this.hub.getCode();
 | |
|     if (code) return code.slice(node.start, node.end);
 | |
|   }
 | |
|   return "";
 | |
| }
 | |
| function willIMaybeExecuteBefore(target) {
 | |
|   return this._guessExecutionStatusRelativeTo(target) !== "after";
 | |
| }
 | |
| function getOuterFunction(path) {
 | |
|   return path.isProgram() ? path : (path.parentPath.scope.getFunctionParent() || path.parentPath.scope.getProgramParent()).path;
 | |
| }
 | |
| function isExecutionUncertain(type, key) {
 | |
|   switch (type) {
 | |
|     case "LogicalExpression":
 | |
|       return key === "right";
 | |
| 
 | |
|     case "ConditionalExpression":
 | |
|     case "IfStatement":
 | |
|       return key === "consequent" || key === "alternate";
 | |
| 
 | |
|     case "WhileStatement":
 | |
|     case "DoWhileStatement":
 | |
|     case "ForInStatement":
 | |
|     case "ForOfStatement":
 | |
|       return key === "body";
 | |
| 
 | |
|     case "ForStatement":
 | |
|       return key === "body" || key === "update";
 | |
| 
 | |
|     case "SwitchStatement":
 | |
|       return key === "cases";
 | |
| 
 | |
|     case "TryStatement":
 | |
|       return key === "handler";
 | |
| 
 | |
|     case "AssignmentPattern":
 | |
|       return key === "right";
 | |
| 
 | |
|     case "OptionalMemberExpression":
 | |
|       return key === "property";
 | |
| 
 | |
|     case "OptionalCallExpression":
 | |
|       return key === "arguments";
 | |
|     default:
 | |
|       return false;
 | |
|   }
 | |
| }
 | |
| function isExecutionUncertainInList(paths, maxIndex) {
 | |
|   for (let i = 0; i < maxIndex; i++) {
 | |
|     const path = paths[i];
 | |
|     if (isExecutionUncertain(path.parent.type, path.parentKey)) {
 | |
|       return true;
 | |
|     }
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| const SYMBOL_CHECKING = Symbol();
 | |
| 
 | |
| function _guessExecutionStatusRelativeTo(target) {
 | |
|   return _guessExecutionStatusRelativeToCached(this, target, new Map());
 | |
| }
 | |
| function _guessExecutionStatusRelativeToCached(base, target, cache) {
 | |
|   const funcParent = {
 | |
|     this: getOuterFunction(base),
 | |
|     target: getOuterFunction(target)
 | |
|   };
 | |
| 
 | |
|   if (funcParent.target.node !== funcParent.this.node) {
 | |
|     return _guessExecutionStatusRelativeToDifferentFunctionsCached(base, funcParent.target, cache);
 | |
|   }
 | |
|   const paths = {
 | |
|     target: target.getAncestry(),
 | |
|     this: base.getAncestry()
 | |
|   };
 | |
| 
 | |
|   if (paths.target.indexOf(base) >= 0) return "after";
 | |
|   if (paths.this.indexOf(target) >= 0) return "before";
 | |
| 
 | |
|   let commonPath;
 | |
|   const commonIndex = {
 | |
|     target: 0,
 | |
|     this: 0
 | |
|   };
 | |
|   while (!commonPath && commonIndex.this < paths.this.length) {
 | |
|     const path = paths.this[commonIndex.this];
 | |
|     commonIndex.target = paths.target.indexOf(path);
 | |
|     if (commonIndex.target >= 0) {
 | |
|       commonPath = path;
 | |
|     } else {
 | |
|       commonIndex.this++;
 | |
|     }
 | |
|   }
 | |
|   if (!commonPath) {
 | |
|     throw new Error("Internal Babel error - The two compared nodes" + " don't appear to belong to the same program.");
 | |
|   }
 | |
|   if (isExecutionUncertainInList(paths.this, commonIndex.this - 1) || isExecutionUncertainInList(paths.target, commonIndex.target - 1)) {
 | |
|     return "unknown";
 | |
|   }
 | |
|   const divergence = {
 | |
|     this: paths.this[commonIndex.this - 1],
 | |
|     target: paths.target[commonIndex.target - 1]
 | |
|   };
 | |
| 
 | |
|   if (divergence.target.listKey && divergence.this.listKey && divergence.target.container === divergence.this.container) {
 | |
|     return divergence.target.key > divergence.this.key ? "before" : "after";
 | |
|   }
 | |
| 
 | |
|   const keys = VISITOR_KEYS[commonPath.type];
 | |
|   const keyPosition = {
 | |
|     this: keys.indexOf(divergence.this.parentKey),
 | |
|     target: keys.indexOf(divergence.target.parentKey)
 | |
|   };
 | |
|   return keyPosition.target > keyPosition.this ? "before" : "after";
 | |
| }
 | |
| function _guessExecutionStatusRelativeToDifferentFunctionsInternal(base, target, cache) {
 | |
|   if (!target.isFunctionDeclaration()) {
 | |
|     if (_guessExecutionStatusRelativeToCached(base, target, cache) === "before") {
 | |
|       return "before";
 | |
|     }
 | |
|     return "unknown";
 | |
|   } else if (target.parentPath.isExportDeclaration()) {
 | |
|     return "unknown";
 | |
|   }
 | |
| 
 | |
|   const binding = target.scope.getBinding(target.node.id.name);
 | |
| 
 | |
|   if (!binding.references) return "before";
 | |
|   const referencePaths = binding.referencePaths;
 | |
|   let allStatus;
 | |
| 
 | |
|   for (const path of referencePaths) {
 | |
|     const childOfFunction = !!path.find(path => path.node === target.node);
 | |
|     if (childOfFunction) continue;
 | |
|     if (path.key !== "callee" || !path.parentPath.isCallExpression()) {
 | |
|       return "unknown";
 | |
|     }
 | |
|     const status = _guessExecutionStatusRelativeToCached(base, path, cache);
 | |
|     if (allStatus && allStatus !== status) {
 | |
|       return "unknown";
 | |
|     } else {
 | |
|       allStatus = status;
 | |
|     }
 | |
|   }
 | |
|   return allStatus;
 | |
| }
 | |
| function _guessExecutionStatusRelativeToDifferentFunctionsCached(base, target, cache) {
 | |
|   let nodeMap = cache.get(base.node);
 | |
|   let cached;
 | |
|   if (!nodeMap) {
 | |
|     cache.set(base.node, nodeMap = new Map());
 | |
|   } else if (cached = nodeMap.get(target.node)) {
 | |
|     if (cached === SYMBOL_CHECKING) {
 | |
|       return "unknown";
 | |
|     }
 | |
|     return cached;
 | |
|   }
 | |
|   nodeMap.set(target.node, SYMBOL_CHECKING);
 | |
|   const result = _guessExecutionStatusRelativeToDifferentFunctionsInternal(base, target, cache);
 | |
|   nodeMap.set(target.node, result);
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| function resolve(dangerous, resolved) {
 | |
|   return this._resolve(dangerous, resolved) || this;
 | |
| }
 | |
| function _resolve(dangerous, resolved) {
 | |
|   if (resolved && resolved.indexOf(this) >= 0) return;
 | |
| 
 | |
|   resolved = resolved || [];
 | |
|   resolved.push(this);
 | |
|   if (this.isVariableDeclarator()) {
 | |
|     if (this.get("id").isIdentifier()) {
 | |
|       return this.get("init").resolve(dangerous, resolved);
 | |
|     } else {
 | |
|     }
 | |
|   } else if (this.isReferencedIdentifier()) {
 | |
|     const binding = this.scope.getBinding(this.node.name);
 | |
|     if (!binding) return;
 | |
| 
 | |
|     if (!binding.constant) return;
 | |
| 
 | |
|     if (binding.kind === "module") return;
 | |
|     if (binding.path !== this) {
 | |
|       const ret = binding.path.resolve(dangerous, resolved);
 | |
|       if (this.find(parent => parent.node === ret.node)) return;
 | |
|       return ret;
 | |
|     }
 | |
|   } else if (this.isTypeCastExpression()) {
 | |
|     return this.get("expression").resolve(dangerous, resolved);
 | |
|   } else if (dangerous && this.isMemberExpression()) {
 | |
| 
 | |
|     const targetKey = this.toComputedKey();
 | |
|     if (!isLiteral(targetKey)) return;
 | |
| 
 | |
|     const targetName = targetKey.value;
 | |
|     const target = this.get("object").resolve(dangerous, resolved);
 | |
|     if (target.isObjectExpression()) {
 | |
|       const props = target.get("properties");
 | |
|       for (const prop of props) {
 | |
|         if (!prop.isProperty()) continue;
 | |
|         const key = prop.get("key");
 | |
| 
 | |
|         let match = prop.isnt("computed") && key.isIdentifier({
 | |
|           name: targetName
 | |
|         });
 | |
| 
 | |
|         match = match || key.isLiteral({
 | |
|           value: targetName
 | |
|         });
 | |
|         if (match) return prop.get("value").resolve(dangerous, resolved);
 | |
|       }
 | |
|     } else if (target.isArrayExpression() && !isNaN(+targetName)) {
 | |
|       const elems = target.get("elements");
 | |
|       const elem = elems[targetName];
 | |
|       if (elem) return elem.resolve(dangerous, resolved);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| function isConstantExpression() {
 | |
|   if (this.isIdentifier()) {
 | |
|     const binding = this.scope.getBinding(this.node.name);
 | |
|     if (!binding) return false;
 | |
|     return binding.constant;
 | |
|   }
 | |
|   if (this.isLiteral()) {
 | |
|     if (this.isRegExpLiteral()) {
 | |
|       return false;
 | |
|     }
 | |
|     if (this.isTemplateLiteral()) {
 | |
|       return this.get("expressions").every(expression => expression.isConstantExpression());
 | |
|     }
 | |
|     return true;
 | |
|   }
 | |
|   if (this.isUnaryExpression()) {
 | |
|     if (this.node.operator !== "void") {
 | |
|       return false;
 | |
|     }
 | |
|     return this.get("argument").isConstantExpression();
 | |
|   }
 | |
|   if (this.isBinaryExpression()) {
 | |
|     const {
 | |
|       operator
 | |
|     } = this.node;
 | |
|     return operator !== "in" && operator !== "instanceof" && this.get("left").isConstantExpression() && this.get("right").isConstantExpression();
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| function isInStrictMode() {
 | |
|   const start = this.isProgram() ? this : this.parentPath;
 | |
|   const strictParent = start.find(path => {
 | |
|     if (path.isProgram({
 | |
|       sourceType: "module"
 | |
|     })) return true;
 | |
|     if (path.isClass()) return true;
 | |
|     if (path.isArrowFunctionExpression() && !path.get("body").isBlockStatement()) {
 | |
|       return false;
 | |
|     }
 | |
|     let body;
 | |
|     if (path.isFunction()) {
 | |
|       body = path.node.body;
 | |
|     } else if (path.isProgram()) {
 | |
|       body = path.node;
 | |
|     } else {
 | |
|       return false;
 | |
|     }
 | |
|     for (const directive of body.directives) {
 | |
|       if (directive.value.value === "use strict") {
 | |
|         return true;
 | |
|       }
 | |
|     }
 | |
|   });
 | |
|   return !!strictParent;
 | |
| }
 | |
| 
 | |
| //# sourceMappingURL=introspection.js.map
 |