UNPKG

2.35 kBJavaScriptView Raw
1/**
2 * @fileoverview Rule to disallow uses of await inside of loops.
3 * @author Nat Mote
4 */
5"use strict";
6
7// Node types which are considered loops.
8var loopTypes = {
9 'ForStatement': true,
10 'ForOfStatement': true,
11 'ForInStatement': true,
12 'WhileStatement': true,
13 'DoWhileStatement': true,
14};
15
16// Node types at which we should stop looking for loops. For example, it is fine to declare an async
17// function within a loop, and use await inside of that.
18var boundaryTypes = {
19 'FunctionDeclaration': true,
20 'FunctionExpression': true,
21 'ArrowFunctionExpression': true,
22};
23
24module.exports = function(context) {
25 return {
26 AwaitExpression(node) {
27 var ancestors = context.getAncestors();
28 // Reverse so that we can traverse from the deepest node upwards.
29 ancestors.reverse();
30 // Create a set of all the ancestors plus this node so that we can check
31 // if this use of await appears in the body of the loop as opposed to
32 // the right-hand side of a for...of, for example.
33 //
34 // Implement the set with an Array since there are likely to be very few
35 // elements. An Object would not be appropriate since the elements are
36 // not strings.
37 var ancestorSet = [].concat(ancestors, [node]);
38 var ancestorSetHas = function(element) {
39 return ancestorSet.indexOf(element) !== -1;
40 }
41 for (var i = 0; i < ancestors.length; i++) {
42 var ancestor = ancestors[i];
43 if (boundaryTypes.hasOwnProperty(ancestor.type)) {
44 // Short-circuit out if we encounter a boundary type. Loops above
45 // this do not matter.
46 return;
47 }
48 if (loopTypes.hasOwnProperty(ancestor.type)) {
49 // Only report if we are actually in the body or another part that gets executed on
50 // every iteration.
51 if (
52 ancestorSetHas(ancestor.body) ||
53 ancestorSetHas(ancestor.test) ||
54 ancestorSetHas(ancestor.update)
55 ) {
56 context.report(
57 node,
58 'Avoid using await inside a loop. Consider refactoring to use Promise.all. If ' +
59 'you are sure you want to do this, add `// eslint-disable-line ' +
60 context.id + '` at the end of this line.'
61 );
62 return;
63 }
64 }
65 }
66 },
67 };
68}