]>
Commit | Line | Data |
---|---|---|
eb39fafa DC |
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 | ||
34eeec05 | 31 | /** @type {import('../shared/types').Rule} */ |
eb39fafa DC |
32 | module.exports = { |
33 | meta: { | |
34 | type: "suggestion", | |
35 | ||
36 | docs: { | |
8f9d1d4d | 37 | description: "Disallow async functions which have no `await` expression", |
eb39fafa DC |
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 | }; |