Skip to content
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ module.exports = {
'aws-toolkits/no-console-log': 'error',
'aws-toolkits/no-json-stringify-in-log': 'error',
'aws-toolkits/no-printf-mismatch': 'error',
'aws-toolkits/no-inline-async-foreach': 'error',
'no-restricted-imports': [
'error',
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,15 +269,7 @@ function closeSessionWhenAllEditorsClosed(
}

function isLiveTailSessionOpenInAnyTab(liveTailSession: LiveTailSession) {
let isOpen = false
vscode.window.tabGroups.all.forEach(async (tabGroup) => {
tabGroup.tabs.forEach((tab) => {
if (tab.input instanceof vscode.TabInputText) {
if (liveTailSession.uri.toString() === tab.input.uri.toString()) {
isOpen = true
}
}
})
})
return isOpen
const isOpen = (tab: vscode.Tab) =>
tab.input instanceof vscode.TabInputText && tab.input.uri.toString() === liveTailSession.uri.toString()
return vscode.window.tabGroups.all.some((tabGroup) => tabGroup.tabs.some(isOpen))
}
3 changes: 2 additions & 1 deletion packages/core/src/awsService/ec2/activation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
import { Ec2ConnecterMap } from './connectionManagerMap'
import { ec2LogsScheme } from '../../shared/constants'
import { Ec2LogDocumentProvider } from './ec2LogDocumentProvider'
import { mapOverMap } from '../../shared/utilities/collectionUtils'

const connectionManagers = new Ec2ConnecterMap()

Expand Down Expand Up @@ -83,5 +84,5 @@ export async function activate(ctx: ExtContext): Promise<void> {
}

export async function deactivate(): Promise<void> {
connectionManagers.forEach(async (manager) => await manager.dispose())
await mapOverMap(connectionManagers, async (_, manager) => await manager.dispose())
}
3 changes: 2 additions & 1 deletion packages/core/src/awsService/ec2/remoteSessionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import { EC2, SSM } from 'aws-sdk'
import { SsmClient } from '../../shared/clients/ssmClient'
import { Disposable } from 'vscode'
import { mapOverMap } from '../../shared/utilities/collectionUtils'

export class Ec2SessionTracker extends Map<EC2.InstanceId, SSM.SessionId> implements Disposable {
public constructor(
Expand All @@ -31,7 +32,7 @@ export class Ec2SessionTracker extends Map<EC2.InstanceId, SSM.SessionId> implem
}

public async dispose(): Promise<void> {
this.forEach(async (_sessionId, instanceId) => await this.disconnectEnv(instanceId))
await mapOverMap(this, async (instanceId, _sessionId) => await this.disconnectEnv(instanceId))
}

public isConnectedTo(instanceId: EC2.InstanceId): boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export class ImportAdderProvider implements vscode.CodeLensProvider {
) {
const line = findLineToInsertImportStatement(editor, firstLineOfRecommendation)
let mergedStatements = ``
r.mostRelevantMissingImports?.forEach(async (i) => {
r.mostRelevantMissingImports?.forEach((i) => {
// trust service response that this to-be-added import is necessary
if (i.statement) {
mergedStatements += i.statement + '\n'
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/shared/utilities/collectionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -566,3 +566,7 @@ export function createCollectionFromPages<T>(...pages: T[]): AsyncCollection<T>
export function isPresent<T>(value: T | undefined): value is T {
return value !== undefined
}

export async function mapOverMap<K, V, O>(m: Map<K, V>, f: (k: K, v: V) => Promise<O>): Promise<O[]> {
return await Promise.all(Array.from(m).map(async ([k, v]) => await f(k, v)))
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ describe('listSamResources', () => {
{ name: 'stringify array', value: '[]' },
{ name: 'array object', value: [] },
]
testcases.forEach(async ({ name, value }) => {
testcases.forEach(({ name, value }) => {
it(`returns empty array given SAM CLI return ${name} given any issue`, async () => {
runSamCliListResourceStub.resolves(value)

Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/test/shared/fs/fs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,15 +218,15 @@ describe('FileSystem', function () {
describe('mkdir()', function () {
const paths = ['a', 'a/b', 'a/b/c', 'a/b/c/d/']

paths.forEach(async function (p) {
paths.forEach(function (p) {
it(`creates folder: '${p}'`, async function () {
const dirPath = testFolder.pathFrom(p)
await fs.mkdir(dirPath)
assert(existsSync(dirPath))
})
})

paths.forEach(async function (p) {
paths.forEach(function (p) {
it(`creates folder but uses the "fs" module if in Cloud9: '${p}'`, async function () {
sandbox.stub(extensionUtilities, 'isCloud9').returns(true)
const dirPath = testFolder.pathFrom(p)
Expand Down
2 changes: 2 additions & 0 deletions plugins/eslint-plugin-aws-toolkits/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import NoStringExecForChildProcess from './lib/rules/no-string-exec-for-child-pr
import NoConsoleLog from './lib/rules/no-console-log'
import noJsonStringifyInLog from './lib/rules/no-json-stringify-in-log'
import noPrintfMismatch from './lib/rules/no-printf-mismatch'
import noInlineAsyncForEach from './lib/rules/no-inline-async-foreach'

const rules = {
'no-await-on-vscode-msg': NoAwaitOnVscodeMsg,
Expand All @@ -21,6 +22,7 @@ const rules = {
'no-console-log': NoConsoleLog,
'no-json-stringify-in-log': noJsonStringifyInLog,
'no-printf-mismatch': noPrintfMismatch,
'no-inline-async-foreach': noInlineAsyncForEach,
}

export { rules }
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*!
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

import { ESLintUtils, TSESTree } from '@typescript-eslint/utils'
import { AST_NODE_TYPES } from '@typescript-eslint/types'
import { Rule } from 'eslint'

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

function isAsyncFunction(node: TSESTree.CallExpressionArgument): boolean {
return (
(node.type === AST_NODE_TYPES.ArrowFunctionExpression || node.type === AST_NODE_TYPES.FunctionExpression) &&
node.async
)
}
export default ESLintUtils.RuleCreator.withoutDocs({
meta: {
docs: {
description: 'disallow inlining async functions with .forEach',
recommended: 'recommended',
},
messages: {
errMsg,
},
type: 'problem',
fixable: 'code',
schema: [],
},
defaultOptions: [],
create(context) {
return {
CallExpression(node: TSESTree.CallExpression) {
if (
node.callee.type === AST_NODE_TYPES.MemberExpression &&
node.callee.property.type === AST_NODE_TYPES.Identifier &&
node.callee.property.name === 'forEach' &&
node.arguments.length >= 1 &&
isAsyncFunction(node.arguments[0])
) {
return context.report({
node: node,
messageId: 'errMsg',
})
}
},
}
},
}) as unknown as Rule.RuleModule
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*!
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

import { rules } from '../../index'
import { errMsg } from '../../lib/rules/no-inline-async-foreach'
import { getRuleTester } from '../testUtil'

getRuleTester().run('no-inline-async-foreach', rules['no-inline-async-foreach'], {
valid: [
'list.forEach((a) => a * a)',
'list.forEach(asyncFunctionOrNot)',
'list.forEach(() => console.log(x))',
'list.forEach(function () {})',
],

invalid: [
{ code: 'list.forEach(async (a) => await Promise.resolve(a * a))', errors: [errMsg] },
{ code: 'list.forEach(async (a: any) => console.log(x))', errors: [errMsg] },
{ code: 'list.forEach((a) => a.forEach(async (b) => a * b))', errors: [errMsg] },
{ code: 'list.forEach(async function () {})', errors: [errMsg] },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about

const fn = async (item) => {}
list.forEach(fn)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See recent commits, also added a few more edge cases.

],
})
Loading