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