6652b5932dc1b8ada0f63a2429d31d98795b5425
[dotfiles/.git] / no-return-await.js
1 /**
2  * @fileoverview Disallows unnecessary `return await`
3  * @author Jordan Harband
4  */
5 "use strict";
6
7 const astUtils = require("./utils/ast-utils");
8
9 //------------------------------------------------------------------------------
10 // Rule Definition
11 //------------------------------------------------------------------------------
12
13 const message = "Redundant use of `await` on a return value.";
14
15 module.exports = {
16     meta: {
17         type: "suggestion",
18
19         docs: {
20             description: "disallow unnecessary `return await`",
21             category: "Best Practices",
22
23             recommended: false,
24
25             url: "https://eslint.org/docs/rules/no-return-await"
26         },
27
28         fixable: null,
29
30         schema: [
31         ]
32     },
33
34     create(context) {
35
36         /**
37          * Reports a found unnecessary `await` expression.
38          * @param {ASTNode} node The node representing the `await` expression to report
39          * @returns {void}
40          */
41         function reportUnnecessaryAwait(node) {
42             context.report({
43                 node: context.getSourceCode().getFirstToken(node),
44                 loc: node.loc,
45                 message
46             });
47         }
48
49         /**
50          * Determines whether a thrown error from this node will be caught/handled within this function rather than immediately halting
51          * this function. For example, a statement in a `try` block will always have an error handler. A statement in
52          * a `catch` block will only have an error handler if there is also a `finally` block.
53          * @param {ASTNode} node A node representing a location where an could be thrown
54          * @returns {boolean} `true` if a thrown error will be caught/handled in this function
55          */
56         function hasErrorHandler(node) {
57             let ancestor = node;
58
59             while (!astUtils.isFunction(ancestor) && ancestor.type !== "Program") {
60                 if (ancestor.parent.type === "TryStatement" && (ancestor === ancestor.parent.block || ancestor === ancestor.parent.handler && ancestor.parent.finalizer)) {
61                     return true;
62                 }
63                 ancestor = ancestor.parent;
64             }
65             return false;
66         }
67
68         /**
69          * Checks if a node is placed in tail call position. Once `return` arguments (or arrow function expressions) can be a complex expression,
70          * an `await` expression could or could not be unnecessary by the definition of this rule. So we're looking for `await` expressions that are in tail position.
71          * @param {ASTNode} node A node representing the `await` expression to check
72          * @returns {boolean} The checking result
73          */
74         function isInTailCallPosition(node) {
75             if (node.parent.type === "ArrowFunctionExpression") {
76                 return true;
77             }
78             if (node.parent.type === "ReturnStatement") {
79                 return !hasErrorHandler(node.parent);
80             }
81             if (node.parent.type === "ConditionalExpression" && (node === node.parent.consequent || node === node.parent.alternate)) {
82                 return isInTailCallPosition(node.parent);
83             }
84             if (node.parent.type === "LogicalExpression" && node === node.parent.right) {
85                 return isInTailCallPosition(node.parent);
86             }
87             if (node.parent.type === "SequenceExpression" && node === node.parent.expressions[node.parent.expressions.length - 1]) {
88                 return isInTailCallPosition(node.parent);
89             }
90             return false;
91         }
92
93         return {
94             AwaitExpression(node) {
95                 if (isInTailCallPosition(node) && !hasErrorHandler(node)) {
96                     reportUnnecessaryAwait(node);
97                 }
98             }
99         };
100     }
101 };