22c111b6dc852e8e37c0047ab4ae04f14ee30eea
[dotfiles/.git] / require-await.js
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
12 const 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  */
23 function capitalizeFirstLetter(text) {
24     return text[0].toUpperCase() + text.slice(1);
25 }
26
27 //------------------------------------------------------------------------------
28 // Rule Definition
29 //------------------------------------------------------------------------------
30
31 module.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
45     create(context) {
46         const sourceCode = context.getSourceCode();
47         let scopeInfo = null;
48
49         /**
50          * Push the scope info object to the stack.
51          * @returns {void}
52          */
53         function enterFunction() {
54             scopeInfo = {
55                 upper: scopeInfo,
56                 hasAwait: false
57             };
58         }
59
60         /**
61          * Pop the top scope info object from the stack.
62          * Also, it reports the function if needed.
63          * @param {ASTNode} node The node to report.
64          * @returns {void}
65          */
66         function exitFunction(node) {
67             if (node.async && !scopeInfo.hasAwait && !astUtils.isEmptyFunction(node)) {
68                 context.report({
69                     node,
70                     loc: astUtils.getFunctionHeadLoc(node, sourceCode),
71                     message: "{{name}} has no 'await' expression.",
72                     data: {
73                         name: capitalizeFirstLetter(
74                             astUtils.getFunctionNameWithKind(node)
75                         )
76                     }
77                 });
78             }
79
80             scopeInfo = scopeInfo.upper;
81         }
82
83         return {
84             FunctionDeclaration: enterFunction,
85             FunctionExpression: enterFunction,
86             ArrowFunctionExpression: enterFunction,
87             "FunctionDeclaration:exit": exitFunction,
88             "FunctionExpression:exit": exitFunction,
89             "ArrowFunctionExpression:exit": exitFunction,
90
91             AwaitExpression() {
92                 if (!scopeInfo) {
93                     return;
94                 }
95
96                 scopeInfo.hasAwait = true;
97             },
98             ForOfStatement(node) {
99                 if (!scopeInfo) {
100                     return;
101                 }
102
103                 if (node.await) {
104                     scopeInfo.hasAwait = true;
105                 }
106             }
107         };
108     }
109 };