inferer-reference.js 5.0 KB

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