1 | /**
|
2 | * @fileoverview Rule to disallow uses of await inside of loops.
|
3 | * @author Nat Mote (nmote)
|
4 | */
|
5 | ;
|
6 |
|
7 | /**
|
8 | * Check whether it should stop traversing ancestors at the given node.
|
9 | * @param {ASTNode} node A node to check.
|
10 | * @returns {boolean} `true` if it should stop traversing.
|
11 | */
|
12 | function isBoundary(node) {
|
13 | const t = node.type;
|
14 |
|
15 | return (
|
16 | t === "FunctionDeclaration" ||
|
17 | t === "FunctionExpression" ||
|
18 | t === "ArrowFunctionExpression" ||
|
19 |
|
20 | /*
|
21 | * Don't report the await expressions on for-await-of loop since it's
|
22 | * asynchronous iteration intentionally.
|
23 | */
|
24 | (t === "ForOfStatement" && node.await === true)
|
25 | );
|
26 | }
|
27 |
|
28 | /**
|
29 | * Check whether the given node is in loop.
|
30 | * @param {ASTNode} node A node to check.
|
31 | * @param {ASTNode} parent A parent node to check.
|
32 | * @returns {boolean} `true` if the node is in loop.
|
33 | */
|
34 | function isLooped(node, parent) {
|
35 | switch (parent.type) {
|
36 | case "ForStatement":
|
37 | return (
|
38 | node === parent.test ||
|
39 | node === parent.update ||
|
40 | node === parent.body
|
41 | );
|
42 |
|
43 | case "ForOfStatement":
|
44 | case "ForInStatement":
|
45 | return node === parent.body;
|
46 |
|
47 | case "WhileStatement":
|
48 | case "DoWhileStatement":
|
49 | return node === parent.test || node === parent.body;
|
50 |
|
51 | default:
|
52 | return false;
|
53 | }
|
54 | }
|
55 |
|
56 | module.exports = {
|
57 | meta: {
|
58 | docs: {
|
59 | description: "disallow `await` inside of loops",
|
60 | category: "Possible Errors",
|
61 | recommended: false,
|
62 | url: "https://eslint.org/docs/rules/no-await-in-loop"
|
63 | },
|
64 | schema: [],
|
65 | messages: {
|
66 | unexpectedAwait: "Unexpected `await` inside a loop."
|
67 | }
|
68 | },
|
69 | create(context) {
|
70 |
|
71 | /**
|
72 | * Validate an await expression.
|
73 | * @param {ASTNode} awaitNode An AwaitExpression or ForOfStatement node to validate.
|
74 | * @returns {void}
|
75 | */
|
76 | function validate(awaitNode) {
|
77 | if (awaitNode.type === "ForOfStatement" && !awaitNode.await) {
|
78 | return;
|
79 | }
|
80 |
|
81 | let node = awaitNode;
|
82 | let parent = node.parent;
|
83 |
|
84 | while (parent && !isBoundary(parent)) {
|
85 | if (isLooped(node, parent)) {
|
86 | context.report({
|
87 | node: awaitNode,
|
88 | messageId: "unexpectedAwait"
|
89 | });
|
90 | return;
|
91 | }
|
92 | node = parent;
|
93 | parent = parent.parent;
|
94 | }
|
95 | }
|
96 |
|
97 | return {
|
98 | AwaitExpression: validate,
|
99 | ForOfStatement: validate
|
100 | };
|
101 | }
|
102 | };
|