summaryrefslogtreecommitdiff
path: root/tools/node_modules/eslint/lib/rules/no-await-in-loop.js
blob: 7d4f8a0a6ba9e69e714962b52b4cf1fb260861e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/**
 * @fileoverview Rule to disallow uses of await inside of loops.
 * @author Nat Mote (nmote)
 */
"use strict";

// Node types which are considered loops.
const loopTypes = new Set([
    "ForStatement",
    "ForOfStatement",
    "ForInStatement",
    "WhileStatement",
    "DoWhileStatement"
]);

/*
 * Node types at which we should stop looking for loops. For example, it is fine to declare an async
 * function within a loop, and use await inside of that.
 */
const boundaryTypes = new Set([
    "FunctionDeclaration",
    "FunctionExpression",
    "ArrowFunctionExpression"
]);

module.exports = {
    meta: {
        docs: {
            description: "disallow `await` inside of loops",
            category: "Possible Errors",
            recommended: false,
            url: "https://eslint.org/docs/rules/no-await-in-loop"
        },
        schema: []
    },
    create(context) {
        return {
            AwaitExpression(node) {
                const ancestors = context.getAncestors();

                // Reverse so that we can traverse from the deepest node upwards.
                ancestors.reverse();

                /*
                 * Create a set of all the ancestors plus this node so that we can check
                 * if this use of await appears in the body of the loop as opposed to
                 * the right-hand side of a for...of, for example.
                 */
                const ancestorSet = new Set(ancestors).add(node);

                for (let i = 0; i < ancestors.length; i++) {
                    const ancestor = ancestors[i];

                    if (boundaryTypes.has(ancestor.type)) {

                        /*
                         * Short-circuit out if we encounter a boundary type. Loops above
                         * this do not matter.
                         */
                        return;
                    }
                    if (loopTypes.has(ancestor.type)) {

                        /*
                         * Only report if we are actually in the body or another part that gets executed on
                         * every iteration.
                         */
                        if (
                            ancestorSet.has(ancestor.body) ||
                            ancestorSet.has(ancestor.test) ||
                            ancestorSet.has(ancestor.update)
                        ) {
                            context.report({
                                node,
                                message: "Unexpected `await` inside a loop."
                            });
                            return;
                        }
                    }
                }
            }
        };
    }
};