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.

91 lines
2.4 KiB

4 years ago
  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[node.name];
  22. if (!declared) return false;
  23. return scope.getBindingIdentifier(node.name) === declared;
  24. }
  25. const visitor = {
  26. ReferencedIdentifier(path, state) {
  27. if (!state.tdzEnabled) return;
  28. const {
  29. node,
  30. parent,
  31. scope
  32. } = path;
  33. if (path.parentPath.isFor({
  34. left: node
  35. })) return;
  36. if (!isReference(node, scope, state)) return;
  37. const bindingPath = scope.getBinding(node.name).path;
  38. if (bindingPath.isFunctionDeclaration()) return;
  39. const status = getTDZStatus(path, bindingPath);
  40. if (status === "outside") return;
  41. if (status === "maybe") {
  42. const assert = buildTDZAssert(node, state);
  43. bindingPath.parent._tdzThis = true;
  44. path.skip();
  45. if (path.parentPath.isUpdateExpression()) {
  46. if (parent._ignoreBlockScopingTDZ) return;
  47. path.parentPath.replaceWith(_core.types.sequenceExpression([assert, parent]));
  48. } else {
  49. path.replaceWith(assert);
  50. }
  51. } else if (status === "inside") {
  52. path.replaceWith(_core.template.ast`${state.addHelper("tdz")}("${node.name}")`);
  53. }
  54. },
  55. AssignmentExpression: {
  56. exit(path, state) {
  57. if (!state.tdzEnabled) return;
  58. const {
  59. node
  60. } = path;
  61. if (node._ignoreBlockScopingTDZ) return;
  62. const nodes = [];
  63. const ids = path.getBindingIdentifiers();
  64. for (const name of Object.keys(ids)) {
  65. const id = ids[name];
  66. if (isReference(id, path.scope, state)) {
  67. nodes.push(id);
  68. }
  69. }
  70. if (nodes.length) {
  71. node._ignoreBlockScopingTDZ = true;
  72. nodes.push(node);
  73. path.replaceWithMultiple(nodes.map(n => _core.types.expressionStatement(n)));
  74. }
  75. }
  76. }
  77. };
  78. exports.visitor = visitor;