inferer-reference.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = _default;
  6. function t() {
  7. const data = _interopRequireWildcard(require("@babel/types"));
  8. t = function () {
  9. return data;
  10. };
  11. return data;
  12. }
  13. function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
  14. function _default(node) {
  15. if (!this.isReferenced()) return;
  16. const binding = this.scope.getBinding(node.name);
  17. if (binding) {
  18. if (binding.identifier.typeAnnotation) {
  19. return binding.identifier.typeAnnotation;
  20. } else {
  21. return getTypeAnnotationBindingConstantViolations(binding, this, node.name);
  22. }
  23. }
  24. if (node.name === "undefined") {
  25. return t().voidTypeAnnotation();
  26. } else if (node.name === "NaN" || node.name === "Infinity") {
  27. return t().numberTypeAnnotation();
  28. } else if (node.name === "arguments") {}
  29. }
  30. function getTypeAnnotationBindingConstantViolations(binding, path, name) {
  31. const types = [];
  32. const functionConstantViolations = [];
  33. let constantViolations = getConstantViolationsBefore(binding, path, functionConstantViolations);
  34. const testType = getConditionalAnnotation(binding, path, name);
  35. if (testType) {
  36. const testConstantViolations = getConstantViolationsBefore(binding, testType.ifStatement);
  37. constantViolations = constantViolations.filter(path => testConstantViolations.indexOf(path) < 0);
  38. types.push(testType.typeAnnotation);
  39. }
  40. if (constantViolations.length) {
  41. constantViolations = constantViolations.concat(functionConstantViolations);
  42. for (const violation of constantViolations) {
  43. types.push(violation.getTypeAnnotation());
  44. }
  45. }
  46. if (types.length) {
  47. return t().createUnionTypeAnnotation(types);
  48. }
  49. }
  50. function getConstantViolationsBefore(binding, path, functions) {
  51. const violations = binding.constantViolations.slice();
  52. violations.unshift(binding.path);
  53. return violations.filter(violation => {
  54. violation = violation.resolve();
  55. const status = violation._guessExecutionStatusRelativeTo(path);
  56. if (functions && status === "function") functions.push(violation);
  57. return status === "before";
  58. });
  59. }
  60. function inferAnnotationFromBinaryExpression(name, path) {
  61. const operator = path.node.operator;
  62. const right = path.get("right").resolve();
  63. const left = path.get("left").resolve();
  64. let target;
  65. if (left.isIdentifier({
  66. name
  67. })) {
  68. target = right;
  69. } else if (right.isIdentifier({
  70. name
  71. })) {
  72. target = left;
  73. }
  74. if (target) {
  75. if (operator === "===") {
  76. return target.getTypeAnnotation();
  77. }
  78. if (t().BOOLEAN_NUMBER_BINARY_OPERATORS.indexOf(operator) >= 0) {
  79. return t().numberTypeAnnotation();
  80. }
  81. return;
  82. }
  83. if (operator !== "===" && operator !== "==") return;
  84. let typeofPath;
  85. let typePath;
  86. if (left.isUnaryExpression({
  87. operator: "typeof"
  88. })) {
  89. typeofPath = left;
  90. typePath = right;
  91. } else if (right.isUnaryExpression({
  92. operator: "typeof"
  93. })) {
  94. typeofPath = right;
  95. typePath = left;
  96. }
  97. if (!typeofPath) return;
  98. if (!typeofPath.get("argument").isIdentifier({
  99. name
  100. })) return;
  101. typePath = typePath.resolve();
  102. if (!typePath.isLiteral()) return;
  103. const typeValue = typePath.node.value;
  104. if (typeof typeValue !== "string") return;
  105. return t().createTypeAnnotationBasedOnTypeof(typeValue);
  106. }
  107. function getParentConditionalPath(binding, path, name) {
  108. let parentPath;
  109. while (parentPath = path.parentPath) {
  110. if (parentPath.isIfStatement() || parentPath.isConditionalExpression()) {
  111. if (path.key === "test") {
  112. return;
  113. }
  114. return parentPath;
  115. }
  116. if (parentPath.isFunction()) {
  117. if (parentPath.parentPath.scope.getBinding(name) !== binding) return;
  118. }
  119. path = parentPath;
  120. }
  121. }
  122. function getConditionalAnnotation(binding, path, name) {
  123. const ifStatement = getParentConditionalPath(binding, path, name);
  124. if (!ifStatement) return;
  125. const test = ifStatement.get("test");
  126. const paths = [test];
  127. const types = [];
  128. for (let i = 0; i < paths.length; i++) {
  129. const path = paths[i];
  130. if (path.isLogicalExpression()) {
  131. if (path.node.operator === "&&") {
  132. paths.push(path.get("left"));
  133. paths.push(path.get("right"));
  134. }
  135. } else if (path.isBinaryExpression()) {
  136. const type = inferAnnotationFromBinaryExpression(name, path);
  137. if (type) types.push(type);
  138. }
  139. }
  140. if (types.length) {
  141. return {
  142. typeAnnotation: t().createUnionTypeAnnotation(types),
  143. ifStatement
  144. };
  145. }
  146. return getConditionalAnnotation(ifStatement, name);
  147. }