validation.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.validateUsage = validateUsage;
  6. var _core = require("@babel/core");
  7. function validateUsage(path, state, tdzEnabled) {
  8. const dynamicTDZNames = [];
  9. for (const name of Object.keys(path.getBindingIdentifiers())) {
  10. const binding = path.scope.getBinding(name);
  11. if (!binding) continue;
  12. if (tdzEnabled) {
  13. if (injectTDZChecks(binding, state)) dynamicTDZNames.push(name);
  14. }
  15. if (path.node.kind === "const") {
  16. disallowConstantViolations(name, binding, state);
  17. }
  18. }
  19. return dynamicTDZNames;
  20. }
  21. function disallowConstantViolations(name, binding, state) {
  22. for (const violation of binding.constantViolations) {
  23. const readOnlyError = state.addHelper("readOnlyError");
  24. const throwNode = _core.types.callExpression(readOnlyError, [_core.types.stringLiteral(name)]);
  25. if (violation.isAssignmentExpression()) {
  26. const {
  27. operator,
  28. left,
  29. right
  30. } = violation.node;
  31. if (operator === "=") {
  32. const exprs = [right];
  33. exprs.push(throwNode);
  34. violation.replaceWith(_core.types.sequenceExpression(exprs));
  35. } else if (["&&=", "||=", "??="].includes(operator)) {
  36. violation.replaceWith(_core.types.logicalExpression(operator.slice(0, -1), left, _core.types.sequenceExpression([right, throwNode])));
  37. } else {
  38. violation.replaceWith(_core.types.sequenceExpression([_core.types.binaryExpression(operator.slice(0, -1), left, right), throwNode]));
  39. }
  40. } else if (violation.isUpdateExpression()) {
  41. violation.replaceWith(_core.types.sequenceExpression([_core.types.unaryExpression("+", violation.get("argument").node), throwNode]));
  42. } else if (violation.isForXStatement()) {
  43. violation.ensureBlock();
  44. violation.get("left").replaceWith(_core.types.variableDeclaration("var", [_core.types.variableDeclarator(violation.scope.generateUidIdentifier(name))]));
  45. violation.node.body.body.unshift(_core.types.expressionStatement(throwNode));
  46. }
  47. }
  48. }
  49. function getTDZStatus(refPath, bindingPath) {
  50. const executionStatus = bindingPath._guessExecutionStatusRelativeTo(refPath);
  51. if (executionStatus === "before") {
  52. return "outside";
  53. } else if (executionStatus === "after") {
  54. return "inside";
  55. } else {
  56. return "maybe";
  57. }
  58. }
  59. const skipTDZChecks = new WeakSet();
  60. function buildTDZAssert(status, node, state) {
  61. if (status === "maybe") {
  62. const clone = _core.types.cloneNode(node);
  63. skipTDZChecks.add(clone);
  64. return _core.types.callExpression(state.addHelper("temporalRef"), [clone, _core.types.stringLiteral(node.name)]);
  65. } else {
  66. return _core.types.callExpression(state.addHelper("tdz"), [_core.types.stringLiteral(node.name)]);
  67. }
  68. }
  69. function getTDZReplacement(path, state, id = path.node) {
  70. var _path$scope$getBindin;
  71. if (skipTDZChecks.has(id)) return;
  72. skipTDZChecks.add(id);
  73. const bindingPath = (_path$scope$getBindin = path.scope.getBinding(id.name)) == null ? void 0 : _path$scope$getBindin.path;
  74. if (!bindingPath || bindingPath.isFunctionDeclaration()) return;
  75. const status = getTDZStatus(path, bindingPath);
  76. if (status === "outside") return;
  77. if (status === "maybe") {
  78. bindingPath.parent._tdzThis = true;
  79. }
  80. return {
  81. status,
  82. node: buildTDZAssert(status, id, state)
  83. };
  84. }
  85. function injectTDZChecks(binding, state) {
  86. const allUsages = new Set(binding.referencePaths);
  87. binding.constantViolations.forEach(allUsages.add, allUsages);
  88. let dynamicTdz = false;
  89. for (const path of binding.constantViolations) {
  90. const {
  91. node
  92. } = path;
  93. if (skipTDZChecks.has(node)) continue;
  94. skipTDZChecks.add(node);
  95. if (path.isUpdateExpression()) {
  96. const arg = path.get("argument");
  97. const replacement = getTDZReplacement(path, state, arg.node);
  98. if (!replacement) continue;
  99. if (replacement.status === "maybe") {
  100. dynamicTdz = true;
  101. path.insertBefore(replacement.node);
  102. } else {
  103. path.replaceWith(replacement.node);
  104. }
  105. } else if (path.isAssignmentExpression()) {
  106. const nodes = [];
  107. const ids = path.getBindingIdentifiers();
  108. for (const name of Object.keys(ids)) {
  109. const replacement = getTDZReplacement(path, state, ids[name]);
  110. if (replacement) {
  111. nodes.push(_core.types.expressionStatement(replacement.node));
  112. if (replacement.status === "inside") break;
  113. if (replacement.status === "maybe") dynamicTdz = true;
  114. }
  115. }
  116. if (nodes.length > 0) path.insertBefore(nodes);
  117. }
  118. }
  119. for (const path of binding.referencePaths) {
  120. if (path.parentPath.isUpdateExpression()) continue;
  121. if (path.parentPath.isFor({
  122. left: path.node
  123. })) continue;
  124. const replacement = getTDZReplacement(path, state);
  125. if (!replacement) continue;
  126. if (replacement.status === "maybe") dynamicTdz = true;
  127. path.replaceWith(replacement.node);
  128. }
  129. return dynamicTdz;
  130. }
  131. //# sourceMappingURL=validation.js.map