require-await.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. /**
  2. * @fileoverview Rule to disallow async functions which have no `await` expression.
  3. * @author Toru Nagashima
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Requirements
  8. //------------------------------------------------------------------------------
  9. const astUtils = require("./utils/ast-utils");
  10. //------------------------------------------------------------------------------
  11. // Helpers
  12. //------------------------------------------------------------------------------
  13. /**
  14. * Capitalize the 1st letter of the given text.
  15. * @param {string} text The text to capitalize.
  16. * @returns {string} The text that the 1st letter was capitalized.
  17. */
  18. function capitalizeFirstLetter(text) {
  19. return text[0].toUpperCase() + text.slice(1);
  20. }
  21. //------------------------------------------------------------------------------
  22. // Rule Definition
  23. //------------------------------------------------------------------------------
  24. module.exports = {
  25. meta: {
  26. type: "suggestion",
  27. docs: {
  28. description: "disallow async functions which have no `await` expression",
  29. category: "Best Practices",
  30. recommended: false,
  31. url: "https://eslint.org/docs/rules/require-await"
  32. },
  33. schema: []
  34. },
  35. create(context) {
  36. const sourceCode = context.getSourceCode();
  37. let scopeInfo = null;
  38. /**
  39. * Push the scope info object to the stack.
  40. * @returns {void}
  41. */
  42. function enterFunction() {
  43. scopeInfo = {
  44. upper: scopeInfo,
  45. hasAwait: false
  46. };
  47. }
  48. /**
  49. * Pop the top scope info object from the stack.
  50. * Also, it reports the function if needed.
  51. * @param {ASTNode} node The node to report.
  52. * @returns {void}
  53. */
  54. function exitFunction(node) {
  55. if (node.async && !scopeInfo.hasAwait && !astUtils.isEmptyFunction(node)) {
  56. context.report({
  57. node,
  58. loc: astUtils.getFunctionHeadLoc(node, sourceCode),
  59. message: "{{name}} has no 'await' expression.",
  60. data: {
  61. name: capitalizeFirstLetter(
  62. astUtils.getFunctionNameWithKind(node)
  63. )
  64. }
  65. });
  66. }
  67. scopeInfo = scopeInfo.upper;
  68. }
  69. return {
  70. FunctionDeclaration: enterFunction,
  71. FunctionExpression: enterFunction,
  72. ArrowFunctionExpression: enterFunction,
  73. "FunctionDeclaration:exit": exitFunction,
  74. "FunctionExpression:exit": exitFunction,
  75. "ArrowFunctionExpression:exit": exitFunction,
  76. AwaitExpression() {
  77. if (!scopeInfo) {
  78. return;
  79. }
  80. scopeInfo.hasAwait = true;
  81. },
  82. ForOfStatement(node) {
  83. if (!scopeInfo) {
  84. return;
  85. }
  86. if (node.await) {
  87. scopeInfo.hasAwait = true;
  88. }
  89. }
  90. };
  91. }
  92. };