await-async-utils.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.RULE_NAME = void 0;
  4. const utils_1 = require("@typescript-eslint/utils");
  5. const create_testing_library_rule_1 = require("../create-testing-library-rule");
  6. const node_utils_1 = require("../node-utils");
  7. exports.RULE_NAME = 'await-async-utils';
  8. exports.default = (0, create_testing_library_rule_1.createTestingLibraryRule)({
  9. name: exports.RULE_NAME,
  10. meta: {
  11. type: 'problem',
  12. docs: {
  13. description: 'Enforce promises from async utils to be awaited properly',
  14. recommendedConfig: {
  15. dom: 'error',
  16. angular: 'error',
  17. react: 'error',
  18. vue: 'error',
  19. marko: 'error',
  20. },
  21. },
  22. messages: {
  23. awaitAsyncUtil: 'Promise returned from `{{ name }}` must be handled',
  24. asyncUtilWrapper: 'Promise returned from {{ name }} wrapper over async util must be handled',
  25. },
  26. schema: [],
  27. },
  28. defaultOptions: [],
  29. create(context, _, helpers) {
  30. const functionWrappersNames = [];
  31. function detectAsyncUtilWrapper(node) {
  32. const innerFunction = (0, node_utils_1.getInnermostReturningFunction)(context, node);
  33. if (!innerFunction) {
  34. return;
  35. }
  36. const functionName = (0, node_utils_1.getFunctionName)(innerFunction);
  37. if (functionName.length === 0) {
  38. return;
  39. }
  40. functionWrappersNames.push(functionName);
  41. }
  42. function detectDestructuredAsyncUtilWrapperAliases(node) {
  43. for (const property of node.properties) {
  44. if (!(0, node_utils_1.isProperty)(property)) {
  45. continue;
  46. }
  47. if (!utils_1.ASTUtils.isIdentifier(property.key) ||
  48. !utils_1.ASTUtils.isIdentifier(property.value)) {
  49. continue;
  50. }
  51. if (functionWrappersNames.includes(property.key.name)) {
  52. const isDestructuredAsyncWrapperPropertyRenamed = property.key.name !== property.value.name;
  53. if (isDestructuredAsyncWrapperPropertyRenamed) {
  54. functionWrappersNames.push(property.value.name);
  55. }
  56. }
  57. }
  58. }
  59. const getMessageId = (node) => {
  60. if (helpers.isAsyncUtil(node)) {
  61. return 'awaitAsyncUtil';
  62. }
  63. return 'asyncUtilWrapper';
  64. };
  65. return {
  66. VariableDeclarator(node) {
  67. var _a, _b;
  68. if ((0, node_utils_1.isObjectPattern)(node.id)) {
  69. detectDestructuredAsyncUtilWrapperAliases(node.id);
  70. return;
  71. }
  72. const isAssigningKnownAsyncFunctionWrapper = utils_1.ASTUtils.isIdentifier(node.id) &&
  73. node.init !== null &&
  74. functionWrappersNames.includes((_b = (_a = (0, node_utils_1.getDeepestIdentifierNode)(node.init)) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : '');
  75. if (isAssigningKnownAsyncFunctionWrapper) {
  76. functionWrappersNames.push(node.id.name);
  77. }
  78. },
  79. 'CallExpression Identifier'(node) {
  80. const isAsyncUtilOrKnownAliasAroundIt = helpers.isAsyncUtil(node) ||
  81. functionWrappersNames.includes(node.name);
  82. if (!isAsyncUtilOrKnownAliasAroundIt) {
  83. return;
  84. }
  85. if (helpers.isAsyncUtil(node)) {
  86. detectAsyncUtilWrapper(node);
  87. }
  88. const closestCallExpression = (0, node_utils_1.findClosestCallExpressionNode)(node, true);
  89. if (!(closestCallExpression === null || closestCallExpression === void 0 ? void 0 : closestCallExpression.parent)) {
  90. return;
  91. }
  92. const references = (0, node_utils_1.getVariableReferences)(context, closestCallExpression.parent);
  93. if (references.length === 0) {
  94. if (!(0, node_utils_1.isPromiseHandled)(node)) {
  95. context.report({
  96. node,
  97. messageId: getMessageId(node),
  98. data: {
  99. name: node.name,
  100. },
  101. });
  102. }
  103. }
  104. else {
  105. for (const reference of references) {
  106. const referenceNode = reference.identifier;
  107. if (!(0, node_utils_1.isPromiseHandled)(referenceNode)) {
  108. context.report({
  109. node,
  110. messageId: getMessageId(node),
  111. data: {
  112. name: node.name,
  113. },
  114. });
  115. return;
  116. }
  117. }
  118. }
  119. },
  120. };
  121. },
  122. });