tdz.js 2.6 KB

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