Skip to content

Commit 669a9cd

Browse files
committed
catch async defined functions
1 parent 25c42c7 commit 669a9cd

File tree

2 files changed

+39
-9
lines changed

2 files changed

+39
-9
lines changed

plugins/eslint-plugin-aws-toolkits/lib/rules/no-inline-async-foreach.ts

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,38 @@
66
import { ESLintUtils, TSESTree } from '@typescript-eslint/utils'
77
import { AST_NODE_TYPES } from '@typescript-eslint/types'
88
import { Rule } from 'eslint'
9+
import { RuleContext } from '@typescript-eslint/utils/ts-eslint'
910

1011
export const errMsg = 'Avoid using async methods with .forEach as it leads to race conditions'
1112

12-
function isAsyncFunction(node: TSESTree.CallExpressionArgument): boolean {
13+
function isAsyncFunction<T extends string, T2 extends readonly unknown[]>(
14+
context: RuleContext<T, T2>,
15+
funcNode: TSESTree.CallExpressionArgument
16+
) {
17+
if (funcNode.type === AST_NODE_TYPES.Identifier) {
18+
console.log('is identifier')
19+
const scope = context.sourceCode.getScope(funcNode)
20+
const maybeFNode =
21+
scope.variables.find((v) => v.name === funcNode.name)?.defs.find((d) => !!d)?.node ?? undefined
22+
console.log(maybeFNode)
23+
if (
24+
maybeFNode &&
25+
(maybeFNode.type === AST_NODE_TYPES.ArrowFunctionExpression ||
26+
maybeFNode.type === AST_NODE_TYPES.FunctionExpression ||
27+
maybeFNode.type === AST_NODE_TYPES.FunctionDeclaration) &&
28+
maybeFNode.async
29+
) {
30+
return true
31+
}
32+
return false
33+
}
1334
return (
14-
(node.type === AST_NODE_TYPES.ArrowFunctionExpression || node.type === AST_NODE_TYPES.FunctionExpression) &&
15-
node.async
35+
(funcNode.type === AST_NODE_TYPES.ArrowFunctionExpression ||
36+
funcNode.type === AST_NODE_TYPES.FunctionExpression) &&
37+
funcNode.async
1638
)
1739
}
40+
1841
export default ESLintUtils.RuleCreator.withoutDocs({
1942
meta: {
2043
docs: {
@@ -36,13 +59,14 @@ export default ESLintUtils.RuleCreator.withoutDocs({
3659
node.callee.type === AST_NODE_TYPES.MemberExpression &&
3760
node.callee.property.type === AST_NODE_TYPES.Identifier &&
3861
node.callee.property.name === 'forEach' &&
39-
node.arguments.length >= 1 &&
40-
isAsyncFunction(node.arguments[0])
62+
node.arguments.length >= 1
4163
) {
42-
return context.report({
43-
node: node,
44-
messageId: 'errMsg',
45-
})
64+
if (isAsyncFunction(context, node.arguments[0])) {
65+
return context.report({
66+
node: node,
67+
messageId: 'errMsg',
68+
})
69+
}
4670
}
4771
},
4872
}

plugins/eslint-plugin-aws-toolkits/test/rules/no-inline-async-foreach.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,18 @@ getRuleTester().run('no-inline-async-foreach', rules['no-inline-async-foreach'],
1313
'list.forEach(asyncFunctionOrNot)',
1414
'list.forEach(() => console.log(x))',
1515
'list.forEach(function () {})',
16+
'function f(){} \n list.forEach(f)',
17+
'const f = function () {} \n list.forEach(f)',
1618
],
1719

1820
invalid: [
1921
{ code: 'list.forEach(async (a) => await Promise.resolve(a * a))', errors: [errMsg] },
2022
{ code: 'list.forEach(async (a: any) => console.log(x))', errors: [errMsg] },
2123
{ code: 'list.forEach((a) => a.forEach(async (b) => a * b))', errors: [errMsg] },
2224
{ code: 'list.forEach(async function () {})', errors: [errMsg] },
25+
{ code: 'async function f(){} \n list.forEach(f)', errors: [errMsg] },
26+
{ code: 'const f = async () => {} \n list.forEach(f)', errors: [errMsg] },
27+
{ code: 'const f = async function () {} \n list.forEach(f)', errors: [errMsg] },
28+
{ code: 'const f = function () {} \n list.forEach(f)', errors: [errMsg] },
2329
],
2430
})

0 commit comments

Comments
 (0)