2 * @fileoverview Disallows unnecessary `return await`
3 * @author Jordan Harband
7 const astUtils = require("./utils/ast-utils");
9 //------------------------------------------------------------------------------
11 //------------------------------------------------------------------------------
13 const message = "Redundant use of `await` on a return value.";
20 description: "disallow unnecessary `return await`",
21 category: "Best Practices",
25 url: "https://eslint.org/docs/rules/no-return-await"
37 * Reports a found unnecessary `await` expression.
38 * @param {ASTNode} node The node representing the `await` expression to report
41 function reportUnnecessaryAwait(node) {
43 node: context.getSourceCode().getFirstToken(node),
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
56 function hasErrorHandler(node) {
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)) {
63 ancestor = ancestor.parent;
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
74 function isInTailCallPosition(node) {
75 if (node.parent.type === "ArrowFunctionExpression") {
78 if (node.parent.type === "ReturnStatement") {
79 return !hasErrorHandler(node.parent);
81 if (node.parent.type === "ConditionalExpression" && (node === node.parent.consequent || node === node.parent.alternate)) {
82 return isInTailCallPosition(node.parent);
84 if (node.parent.type === "LogicalExpression" && node === node.parent.right) {
85 return isInTailCallPosition(node.parent);
87 if (node.parent.type === "SequenceExpression" && node === node.parent.expressions[node.parent.expressions.length - 1]) {
88 return isInTailCallPosition(node.parent);
94 AwaitExpression(node) {
95 if (isInTailCallPosition(node) && !hasErrorHandler(node)) {
96 reportUnnecessaryAwait(node);