tdz.js 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.visitor = void 0;
  6. var _core = require("@babel/core");
  7. function getTDZStatus(refPath, bindingPath) {
  8. const executionStatus = bindingPath._guessExecutionStatusRelativeTo(refPath);
  9. if (executionStatus === "before") {
  10. return "outside";
  11. } else if (executionStatus === "after") {
  12. return "inside";
  13. } else {
  14. return "maybe";
  15. }
  16. }
  17. function buildTDZAssert(node, state) {
  18. return _core.types.callExpression(state.addHelper("temporalRef"), [node, _core.types.stringLiteral(node.name)]);
  19. }
  20. function isReference(node, scope, state) {
  21. const declared = state.letReferences.get(node.name);
  22. if (!declared) return false;
  23. return scope.getBindingIdentifier(node.name) === declared;
  24. }
  25. const visitedMaybeTDZNodes = new WeakSet();
  26. const visitor = {
  27. ReferencedIdentifier(path, state) {
  28. if (!state.tdzEnabled) return;
  29. const {
  30. node,
  31. parent,
  32. scope
  33. } = path;
  34. if (path.parentPath.isFor({
  35. left: node
  36. })) return;
  37. if (!isReference(node, scope, state)) return;
  38. const bindingPath = scope.getBinding(node.name).path;
  39. if (bindingPath.isFunctionDeclaration()) return;
  40. const status = getTDZStatus(path, bindingPath);
  41. if (status === "outside") return;
  42. if (status === "maybe") {
  43. if (visitedMaybeTDZNodes.has(node)) {
  44. return;
  45. }
  46. visitedMaybeTDZNodes.add(node);
  47. const assert = buildTDZAssert(node, state);
  48. bindingPath.parent._tdzThis = true;
  49. if (path.parentPath.isUpdateExpression()) {
  50. if (parent._ignoreBlockScopingTDZ) return;
  51. path.parentPath.replaceWith(_core.types.sequenceExpression([assert, parent]));
  52. } else {
  53. path.replaceWith(assert);
  54. }
  55. } else if (status === "inside") {
  56. path.replaceWith(_core.template.ast`${state.addHelper("tdz")}("${node.name}")`);
  57. }
  58. },
  59. AssignmentExpression: {
  60. exit(path, state) {
  61. if (!state.tdzEnabled) return;
  62. const {
  63. node
  64. } = path;
  65. if (node._ignoreBlockScopingTDZ) return;
  66. const nodes = [];
  67. const ids = path.getBindingIdentifiers();
  68. for (const name of Object.keys(ids)) {
  69. const id = ids[name];
  70. if (isReference(id, path.scope, state)) {
  71. nodes.push(id);
  72. }
  73. }
  74. if (nodes.length) {
  75. node._ignoreBlockScopingTDZ = true;
  76. nodes.push(node);
  77. path.replaceWithMultiple(nodes.map(n => _core.types.expressionStatement(n)));
  78. }
  79. }
  80. }
  81. };
  82. exports.visitor = visitor;