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.
		
		
		
		
		
			
		
			
				
					
					
						
							194 lines
						
					
					
						
							6.2 KiB
						
					
					
				
			
		
		
	
	
							194 lines
						
					
					
						
							6.2 KiB
						
					
					
				| "use strict";
 | |
| 
 | |
| Object.defineProperty(exports, "__esModule", {
 | |
|   value: true
 | |
| });
 | |
| exports.default = void 0;
 | |
| var _helperPluginUtils = require("@babel/helper-plugin-utils");
 | |
| var _core = require("@babel/core");
 | |
| var _loop = require("./loop");
 | |
| var _validation = require("./validation");
 | |
| var _annexB_3_ = require("./annex-B_3_3");
 | |
| var _default = (0, _helperPluginUtils.declare)((api, opts) => {
 | |
|   api.assertVersion(7);
 | |
|   const {
 | |
|     throwIfClosureRequired = false,
 | |
|     tdz: tdzEnabled = false
 | |
|   } = opts;
 | |
|   if (typeof throwIfClosureRequired !== "boolean") {
 | |
|     throw new Error(`.throwIfClosureRequired must be a boolean, or undefined`);
 | |
|   }
 | |
|   if (typeof tdzEnabled !== "boolean") {
 | |
|     throw new Error(`.tdz must be a boolean, or undefined`);
 | |
|   }
 | |
|   return {
 | |
|     name: "transform-block-scoping",
 | |
|     visitor: _core.traverse.visitors.merge([
 | |
|     _annexB_3_.annexB33FunctionsVisitor, {
 | |
|       Loop(path, state) {
 | |
|         const isForStatement = path.isForStatement();
 | |
|         const headPath = isForStatement ? path.get("init") : path.isForXStatement() ? path.get("left") : null;
 | |
|         let needsBodyWrap = false;
 | |
|         const markNeedsBodyWrap = () => {
 | |
|           if (throwIfClosureRequired) {
 | |
|             throw path.buildCodeFrameError("Compiling let/const in this block would add a closure " + "(throwIfClosureRequired).");
 | |
|           }
 | |
|           needsBodyWrap = true;
 | |
|         };
 | |
|         const body = path.get("body");
 | |
|         let bodyScope;
 | |
|         if (body.isBlockStatement()) {
 | |
|           bodyScope = body.scope;
 | |
|           const bindings = (0, _loop.getLoopBodyBindings)(path);
 | |
|           for (const binding of bindings) {
 | |
|             const {
 | |
|               capturedInClosure
 | |
|             } = (0, _loop.getUsageInBody)(binding, path);
 | |
|             if (capturedInClosure) markNeedsBodyWrap();
 | |
|           }
 | |
|         }
 | |
|         const captured = [];
 | |
|         const updatedBindingsUsages = new Map();
 | |
|         if (headPath && isBlockScoped(headPath.node)) {
 | |
|           const names = Object.keys(headPath.getBindingIdentifiers());
 | |
|           const headScope = headPath.scope;
 | |
|           for (let name of names) {
 | |
|             var _bodyScope;
 | |
|             if ((_bodyScope = bodyScope) != null && _bodyScope.hasOwnBinding(name)) continue;
 | |
| 
 | |
|             let binding = headScope.getOwnBinding(name);
 | |
|             if (!binding) {
 | |
|               headScope.crawl();
 | |
|               binding = headScope.getOwnBinding(name);
 | |
|             }
 | |
|             const {
 | |
|               usages,
 | |
|               capturedInClosure,
 | |
|               hasConstantViolations
 | |
|             } = (0, _loop.getUsageInBody)(binding, path);
 | |
|             if (capturedInClosure) {
 | |
|               markNeedsBodyWrap();
 | |
|               captured.push(name);
 | |
|             } else if (headScope.parent.hasBinding(name)) {
 | |
|               const newName = headScope.generateUid(name);
 | |
|               headPath.scope.rename(name, newName);
 | |
|               name = newName;
 | |
|             }
 | |
|             if (isForStatement && hasConstantViolations) {
 | |
|               updatedBindingsUsages.set(name, usages);
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|         if (needsBodyWrap) {
 | |
|           const varPath = (0, _loop.wrapLoopBody)(path, captured, updatedBindingsUsages);
 | |
|           if (headPath != null && headPath.isVariableDeclaration()) {
 | |
|             transformBlockScopedVariable(headPath, state, tdzEnabled);
 | |
|           }
 | |
|           varPath.get("declarations.0.init").unwrapFunctionEnvironment();
 | |
|         }
 | |
|       },
 | |
|       VariableDeclaration(path, state) {
 | |
|         transformBlockScopedVariable(path, state, tdzEnabled);
 | |
|       },
 | |
|       ClassDeclaration(path) {
 | |
|         const {
 | |
|           id
 | |
|         } = path.node;
 | |
|         if (!id) return;
 | |
|         const {
 | |
|           scope
 | |
|         } = path.parentPath;
 | |
|         if (!(0, _annexB_3_.isVarScope)(scope) && scope.parent.hasBinding(id.name, {
 | |
|           noUids: true
 | |
|         })) {
 | |
|           path.scope.rename(id.name);
 | |
|         }
 | |
|       }
 | |
|     }])
 | |
|   };
 | |
| });
 | |
| exports.default = _default;
 | |
| const conflictingFunctionsVisitor = {
 | |
|   Scope(path, {
 | |
|     names
 | |
|   }) {
 | |
|     for (const name of names) {
 | |
|       const binding = path.scope.getOwnBinding(name);
 | |
|       if (binding && binding.kind === "hoisted") {
 | |
|         path.scope.rename(name);
 | |
|       }
 | |
|     }
 | |
|   },
 | |
|   "Expression|Declaration"(path) {
 | |
|     path.skip();
 | |
|   }
 | |
| };
 | |
| function transformBlockScopedVariable(path, state, tdzEnabled) {
 | |
|   if (!isBlockScoped(path.node)) return;
 | |
|   const dynamicTDZNames = (0, _validation.validateUsage)(path, state, tdzEnabled);
 | |
|   path.node.kind = "var";
 | |
|   const bindingNames = Object.keys(path.getBindingIdentifiers());
 | |
|   for (const name of bindingNames) {
 | |
|     const binding = path.scope.getOwnBinding(name);
 | |
|     if (!binding) continue;
 | |
|     binding.kind = "var";
 | |
|   }
 | |
|   if (isInLoop(path) && !(0, _loop.isVarInLoopHead)(path) || dynamicTDZNames.length > 0) {
 | |
|     for (const decl of path.node.declarations) {
 | |
|       var _decl$init;
 | |
|       (_decl$init = decl.init) != null ? _decl$init : decl.init = path.scope.buildUndefinedNode();
 | |
|     }
 | |
|   }
 | |
|   const blockScope = path.scope;
 | |
|   let varScope = blockScope.getFunctionParent();
 | |
|   let isProgramScope = false;
 | |
|   if (!varScope) {
 | |
|     varScope = blockScope.getProgramParent();
 | |
|     isProgramScope = true;
 | |
|   }
 | |
|   if (varScope !== blockScope) {
 | |
|     for (const name of bindingNames) {
 | |
|       let newName = name;
 | |
|       if (
 | |
|       blockScope.parent.hasBinding(name, {
 | |
|         noUids: true
 | |
|       }) || blockScope.parent.hasGlobal(name) || isProgramScope && varScope.hasGlobal(name)) {
 | |
|         newName = blockScope.generateUid(name);
 | |
|         blockScope.rename(name, newName);
 | |
|       }
 | |
|       blockScope.moveBindingTo(newName, varScope);
 | |
|     }
 | |
|   }
 | |
|   blockScope.path.traverse(conflictingFunctionsVisitor, {
 | |
|     names: bindingNames
 | |
|   });
 | |
|   for (const name of dynamicTDZNames) {
 | |
|     path.scope.push({
 | |
|       id: _core.types.identifier(name),
 | |
|       init: state.addHelper("temporalUndefined")
 | |
|     });
 | |
|   }
 | |
| }
 | |
| function isLetOrConst(kind) {
 | |
|   return kind === "let" || kind === "const";
 | |
| }
 | |
| function isInLoop(path) {
 | |
|   if (!path.parentPath) return false;
 | |
|   if (path.parentPath.isLoop()) return true;
 | |
|   if (path.parentPath.isFunctionParent()) return false;
 | |
|   return isInLoop(path.parentPath);
 | |
| }
 | |
| function isBlockScoped(node) {
 | |
|   if (!_core.types.isVariableDeclaration(node)) return false;
 | |
|   if (
 | |
|   node[_core.types.BLOCK_SCOPED_SYMBOL]) {
 | |
|     return true;
 | |
|   }
 | |
|   if (!isLetOrConst(node.kind) && node.kind !== "using") {
 | |
|     return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| //# sourceMappingURL=index.js.map
 |