index.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _helperPluginUtils = require("@babel/helper-plugin-utils");
  7. var _core = require("@babel/core");
  8. var _loop = require("./loop.js");
  9. var _validation = require("./validation.js");
  10. var _annexB_3_ = require("./annex-B_3_3.js");
  11. var _default = (0, _helperPluginUtils.declare)((api, opts) => {
  12. api.assertVersion(7);
  13. const {
  14. throwIfClosureRequired = false,
  15. tdz: tdzEnabled = false
  16. } = opts;
  17. if (typeof throwIfClosureRequired !== "boolean") {
  18. throw new Error(`.throwIfClosureRequired must be a boolean, or undefined`);
  19. }
  20. if (typeof tdzEnabled !== "boolean") {
  21. throw new Error(`.tdz must be a boolean, or undefined`);
  22. }
  23. return {
  24. name: "transform-block-scoping",
  25. visitor: _core.traverse.visitors.merge([_annexB_3_.annexB33FunctionsVisitor, {
  26. Loop(path, state) {
  27. const isForStatement = path.isForStatement();
  28. const headPath = isForStatement ? path.get("init") : path.isForXStatement() ? path.get("left") : null;
  29. let needsBodyWrap = false;
  30. const markNeedsBodyWrap = () => {
  31. if (throwIfClosureRequired) {
  32. throw path.buildCodeFrameError("Compiling let/const in this block would add a closure " + "(throwIfClosureRequired).");
  33. }
  34. needsBodyWrap = true;
  35. };
  36. const body = path.get("body");
  37. let bodyScope;
  38. if (body.isBlockStatement()) {
  39. bodyScope = body.scope;
  40. const bindings = (0, _loop.getLoopBodyBindings)(path);
  41. for (const binding of bindings) {
  42. const {
  43. capturedInClosure
  44. } = (0, _loop.getUsageInBody)(binding, path);
  45. if (capturedInClosure) markNeedsBodyWrap();
  46. }
  47. }
  48. const captured = [];
  49. const updatedBindingsUsages = new Map();
  50. if (headPath && isBlockScoped(headPath.node)) {
  51. const names = Object.keys(headPath.getBindingIdentifiers());
  52. const headScope = headPath.scope;
  53. for (let name of names) {
  54. var _bodyScope;
  55. if ((_bodyScope = bodyScope) != null && _bodyScope.hasOwnBinding(name)) continue;
  56. let binding = headScope.getOwnBinding(name);
  57. if (!binding) {
  58. headScope.crawl();
  59. binding = headScope.getOwnBinding(name);
  60. }
  61. const {
  62. usages,
  63. capturedInClosure,
  64. hasConstantViolations
  65. } = (0, _loop.getUsageInBody)(binding, path);
  66. if (headScope.parent.hasBinding(name) || headScope.parent.hasGlobal(name)) {
  67. const newName = headScope.generateUid(name);
  68. headScope.rename(name, newName);
  69. name = newName;
  70. }
  71. if (capturedInClosure) {
  72. markNeedsBodyWrap();
  73. captured.push(name);
  74. }
  75. if (isForStatement && hasConstantViolations) {
  76. updatedBindingsUsages.set(name, usages);
  77. }
  78. }
  79. }
  80. if (needsBodyWrap) {
  81. const varPath = (0, _loop.wrapLoopBody)(path, captured, updatedBindingsUsages);
  82. if (headPath != null && headPath.isVariableDeclaration()) {
  83. transformBlockScopedVariable(headPath, state, tdzEnabled);
  84. }
  85. varPath.get("declarations.0.init").unwrapFunctionEnvironment();
  86. }
  87. },
  88. VariableDeclaration(path, state) {
  89. transformBlockScopedVariable(path, state, tdzEnabled);
  90. },
  91. ClassDeclaration(path) {
  92. const {
  93. id
  94. } = path.node;
  95. if (!id) return;
  96. const {
  97. scope
  98. } = path.parentPath;
  99. if (!(0, _annexB_3_.isVarScope)(scope) && scope.parent.hasBinding(id.name, {
  100. noUids: true
  101. })) {
  102. path.scope.rename(id.name);
  103. }
  104. }
  105. }])
  106. };
  107. });
  108. exports.default = _default;
  109. const conflictingFunctionsVisitor = {
  110. Scope(path, {
  111. names
  112. }) {
  113. for (const name of names) {
  114. const binding = path.scope.getOwnBinding(name);
  115. if (binding && binding.kind === "hoisted") {
  116. path.scope.rename(name);
  117. }
  118. }
  119. },
  120. "Expression|Declaration"(path) {
  121. path.skip();
  122. }
  123. };
  124. function transformBlockScopedVariable(path, state, tdzEnabled) {
  125. if (!isBlockScoped(path.node)) return;
  126. const dynamicTDZNames = (0, _validation.validateUsage)(path, state, tdzEnabled);
  127. path.node.kind = "var";
  128. const bindingNames = Object.keys(path.getBindingIdentifiers());
  129. for (const name of bindingNames) {
  130. const binding = path.scope.getOwnBinding(name);
  131. if (!binding) continue;
  132. binding.kind = "var";
  133. }
  134. if (isInLoop(path) && !(0, _loop.isVarInLoopHead)(path) || dynamicTDZNames.length > 0) {
  135. for (const decl of path.node.declarations) {
  136. var _decl$init;
  137. (_decl$init = decl.init) != null ? _decl$init : decl.init = path.scope.buildUndefinedNode();
  138. }
  139. }
  140. const blockScope = path.scope;
  141. const varScope = blockScope.getFunctionParent() || blockScope.getProgramParent();
  142. if (varScope !== blockScope) {
  143. for (const name of bindingNames) {
  144. let newName = name;
  145. if (blockScope.parent.hasBinding(name, {
  146. noUids: true
  147. }) || blockScope.parent.hasGlobal(name)) {
  148. newName = blockScope.generateUid(name);
  149. blockScope.rename(name, newName);
  150. }
  151. blockScope.moveBindingTo(newName, varScope);
  152. }
  153. }
  154. blockScope.path.traverse(conflictingFunctionsVisitor, {
  155. names: bindingNames
  156. });
  157. for (const name of dynamicTDZNames) {
  158. path.scope.push({
  159. id: _core.types.identifier(name),
  160. init: state.addHelper("temporalUndefined")
  161. });
  162. }
  163. }
  164. function isLetOrConst(kind) {
  165. return kind === "let" || kind === "const";
  166. }
  167. function isInLoop(path) {
  168. if (!path.parentPath) return false;
  169. if (path.parentPath.isLoop()) return true;
  170. if (path.parentPath.isFunctionParent()) return false;
  171. return isInLoop(path.parentPath);
  172. }
  173. function isBlockScoped(node) {
  174. if (!_core.types.isVariableDeclaration(node)) return false;
  175. if (node[_core.types.BLOCK_SCOPED_SYMBOL]) {
  176. return true;
  177. }
  178. if (!isLetOrConst(node.kind) && node.kind !== "using") {
  179. return false;
  180. }
  181. return true;
  182. }
  183. //# sourceMappingURL=index.js.map