You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
106 lines
2.7 KiB
106 lines
2.7 KiB
/** |
|
* @fileoverview Rule to disallow uses of await inside of loops. |
|
* @author Nat Mote (nmote) |
|
*/ |
|
"use strict"; |
|
|
|
/** |
|
* Check whether it should stop traversing ancestors at the given node. |
|
* @param {ASTNode} node A node to check. |
|
* @returns {boolean} `true` if it should stop traversing. |
|
*/ |
|
function isBoundary(node) { |
|
const t = node.type; |
|
|
|
return ( |
|
t === "FunctionDeclaration" || |
|
t === "FunctionExpression" || |
|
t === "ArrowFunctionExpression" || |
|
|
|
/* |
|
* Don't report the await expressions on for-await-of loop since it's |
|
* asynchronous iteration intentionally. |
|
*/ |
|
(t === "ForOfStatement" && node.await === true) |
|
); |
|
} |
|
|
|
/** |
|
* Check whether the given node is in loop. |
|
* @param {ASTNode} node A node to check. |
|
* @param {ASTNode} parent A parent node to check. |
|
* @returns {boolean} `true` if the node is in loop. |
|
*/ |
|
function isLooped(node, parent) { |
|
switch (parent.type) { |
|
case "ForStatement": |
|
return ( |
|
node === parent.test || |
|
node === parent.update || |
|
node === parent.body |
|
); |
|
|
|
case "ForOfStatement": |
|
case "ForInStatement": |
|
return node === parent.body; |
|
|
|
case "WhileStatement": |
|
case "DoWhileStatement": |
|
return node === parent.test || node === parent.body; |
|
|
|
default: |
|
return false; |
|
} |
|
} |
|
|
|
/** @type {import('../shared/types').Rule} */ |
|
module.exports = { |
|
meta: { |
|
type: "problem", |
|
|
|
docs: { |
|
description: "Disallow `await` inside of loops", |
|
recommended: false, |
|
url: "https://eslint.org/docs/rules/no-await-in-loop" |
|
}, |
|
|
|
schema: [], |
|
|
|
messages: { |
|
unexpectedAwait: "Unexpected `await` inside a loop." |
|
} |
|
}, |
|
create(context) { |
|
|
|
/** |
|
* Validate an await expression. |
|
* @param {ASTNode} awaitNode An AwaitExpression or ForOfStatement node to validate. |
|
* @returns {void} |
|
*/ |
|
function validate(awaitNode) { |
|
if (awaitNode.type === "ForOfStatement" && !awaitNode.await) { |
|
return; |
|
} |
|
|
|
let node = awaitNode; |
|
let parent = node.parent; |
|
|
|
while (parent && !isBoundary(parent)) { |
|
if (isLooped(node, parent)) { |
|
context.report({ |
|
node: awaitNode, |
|
messageId: "unexpectedAwait" |
|
}); |
|
return; |
|
} |
|
node = parent; |
|
parent = parent.parent; |
|
} |
|
} |
|
|
|
return { |
|
AwaitExpression: validate, |
|
ForOfStatement: validate |
|
}; |
|
} |
|
};
|
|
|