-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
feat(eslint-plugin): add suggestion to require-await
to remove async
keyword
#9718
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
JoshuaKGoldberg
merged 16 commits into
typescript-eslint:main
from
reduckted:feature/require-await-suggestion
Aug 19, 2024
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
e02e2ea
Add suggestion to require-await to remove async keyword
reduckted 9ba5185
Include suggestion when there is a return type annotation.
reduckted c48b00f
Restructure suggestion range calculation.
reduckted d8b86a4
Suggestion will replace return type of `Promise<T>` with `T`.
reduckted 1faafdf
Merge branch 'main' into feature/require-await-suggestion
reduckted 0f75da3
use noFormat instead of suppressing lint errors.
reduckted 6808bb6
Remove unnecessary ecmaVersion from tests and correct test that had a…
reduckted 5cdcd4c
Corrected comment.
reduckted 5772812
Updated the copy of ESLint test cases.
reduckted 93c1dd0
Added better support for async generators.
reduckted de39386
Merge remote-tracking branch 'upstream/main' into feature/require-awa…
reduckted 93f2e78
Used nullThrows to avoid unnecessary conditionals.
reduckted 6981669
Added additional changes to end of array instead of inserting at the …
reduckted 9200af7
Use removeRange instead of replaceTextRange with empty replacement.
reduckted Aug 16, 2024
cbd4798
Change typeArguments null check.
reduckted 3a7065f
Replaced incorrect type guard.
reduckted File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
packages/eslint-plugin/src/util/isStartOfExpressionStatement.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import type { TSESTree } from '@typescript-eslint/utils'; | ||
import { AST_NODE_TYPES } from '@typescript-eslint/utils'; | ||
|
||
// The following is copied from `eslint`'s source code. | ||
// https://github.com/eslint/eslint/blob/3a4eaf921543b1cd5d1df4ea9dec02fab396af2a/lib/rules/utils/ast-utils.js#L1026-L1041 | ||
// Could be export { isStartOfExpressionStatement } from 'eslint/lib/rules/utils/ast-utils' | ||
/** | ||
* Tests if a node appears at the beginning of an ancestor ExpressionStatement node. | ||
* @param node The node to check. | ||
* @returns Whether the node appears at the beginning of an ancestor ExpressionStatement node. | ||
*/ | ||
export function isStartOfExpressionStatement(node: TSESTree.Node): boolean { | ||
const start = node.range[0]; | ||
let ancestor: TSESTree.Node | undefined = node; | ||
|
||
while ((ancestor = ancestor.parent) && ancestor.range[0] === start) { | ||
if (ancestor.type === AST_NODE_TYPES.ExpressionStatement) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} |
125 changes: 125 additions & 0 deletions
125
packages/eslint-plugin/src/util/needsPrecedingSemiColon.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
import type { TSESTree } from '@typescript-eslint/utils'; | ||
import { AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/utils'; | ||
import { | ||
isClosingBraceToken, | ||
isClosingParenToken, | ||
} from '@typescript-eslint/utils/ast-utils'; | ||
import type { SourceCode } from '@typescript-eslint/utils/ts-eslint'; | ||
|
||
// The following is adapted from `eslint`'s source code. | ||
// https://github.com/eslint/eslint/blob/3a4eaf921543b1cd5d1df4ea9dec02fab396af2a/lib/rules/utils/ast-utils.js#L1043-L1132 | ||
// Could be export { isStartOfExpressionStatement } from 'eslint/lib/rules/utils/ast-utils' | ||
|
||
const BREAK_OR_CONTINUE = new Set([ | ||
AST_NODE_TYPES.BreakStatement, | ||
AST_NODE_TYPES.ContinueStatement, | ||
]); | ||
|
||
// Declaration types that must contain a string Literal node at the end. | ||
const DECLARATIONS = new Set([ | ||
AST_NODE_TYPES.ExportAllDeclaration, | ||
AST_NODE_TYPES.ExportNamedDeclaration, | ||
AST_NODE_TYPES.ImportDeclaration, | ||
]); | ||
|
||
const IDENTIFIER_OR_KEYWORD = new Set([ | ||
AST_NODE_TYPES.Identifier, | ||
AST_TOKEN_TYPES.Keyword, | ||
]); | ||
|
||
// Keywords that can immediately precede an ExpressionStatement node, mapped to the their node types. | ||
const NODE_TYPES_BY_KEYWORD: Record<string, TSESTree.AST_NODE_TYPES | null> = { | ||
__proto__: null, | ||
break: AST_NODE_TYPES.BreakStatement, | ||
continue: AST_NODE_TYPES.ContinueStatement, | ||
debugger: AST_NODE_TYPES.DebuggerStatement, | ||
do: AST_NODE_TYPES.DoWhileStatement, | ||
else: AST_NODE_TYPES.IfStatement, | ||
return: AST_NODE_TYPES.ReturnStatement, | ||
yield: AST_NODE_TYPES.YieldExpression, | ||
}; | ||
|
||
/* | ||
* Before an opening parenthesis, postfix `++` and `--` always trigger ASI; | ||
* the tokens `:`, `;`, `{` and `=>` don't expect a semicolon, as that would count as an empty statement. | ||
*/ | ||
const PUNCTUATORS = new Set([':', ';', '{', '=>', '++', '--']); | ||
|
||
/* | ||
* Statements that can contain an `ExpressionStatement` after a closing parenthesis. | ||
* DoWhileStatement is an exception in that it always triggers ASI after the closing parenthesis. | ||
*/ | ||
const STATEMENTS = new Set([ | ||
AST_NODE_TYPES.DoWhileStatement, | ||
AST_NODE_TYPES.ForInStatement, | ||
AST_NODE_TYPES.ForOfStatement, | ||
AST_NODE_TYPES.ForStatement, | ||
AST_NODE_TYPES.IfStatement, | ||
AST_NODE_TYPES.WhileStatement, | ||
AST_NODE_TYPES.WithStatement, | ||
]); | ||
|
||
/** | ||
* Determines whether an opening parenthesis `(`, bracket `[` or backtick ``` ` ``` needs to be preceded by a semicolon. | ||
* This opening parenthesis or bracket should be at the start of an `ExpressionStatement`, a `MethodDefinition` or at | ||
* the start of the body of an `ArrowFunctionExpression`. | ||
* @param sourceCode The source code object. | ||
* @param node A node at the position where an opening parenthesis or bracket will be inserted. | ||
* @returns Whether a semicolon is required before the opening parenthesis or bracket. | ||
*/ | ||
export function needsPrecedingSemicolon( | ||
sourceCode: SourceCode, | ||
node: TSESTree.Node, | ||
): boolean { | ||
const prevToken = sourceCode.getTokenBefore(node); | ||
|
||
if ( | ||
!prevToken || | ||
(prevToken.type === AST_TOKEN_TYPES.Punctuator && | ||
PUNCTUATORS.has(prevToken.value)) | ||
) { | ||
return false; | ||
} | ||
|
||
const prevNode = sourceCode.getNodeByRangeIndex(prevToken.range[0]); | ||
|
||
if (!prevNode) { | ||
return false; | ||
} | ||
|
||
if (isClosingParenToken(prevToken)) { | ||
return !STATEMENTS.has(prevNode.type); | ||
} | ||
|
||
if (isClosingBraceToken(prevToken)) { | ||
return ( | ||
(prevNode.type === AST_NODE_TYPES.BlockStatement && | ||
prevNode.parent.type === AST_NODE_TYPES.FunctionExpression && | ||
prevNode.parent.parent.type !== AST_NODE_TYPES.MethodDefinition) || | ||
(prevNode.type === AST_NODE_TYPES.ClassBody && | ||
prevNode.parent.type === AST_NODE_TYPES.ClassExpression) || | ||
prevNode.type === AST_NODE_TYPES.ObjectExpression | ||
); | ||
} | ||
|
||
if (!prevNode.parent) { | ||
return false; | ||
} | ||
|
||
if (IDENTIFIER_OR_KEYWORD.has(prevToken.type)) { | ||
if (BREAK_OR_CONTINUE.has(prevNode.parent.type)) { | ||
return false; | ||
} | ||
|
||
const keyword = prevToken.value; | ||
const nodeType = NODE_TYPES_BY_KEYWORD[keyword]; | ||
|
||
return prevNode.type !== nodeType; | ||
} | ||
|
||
if (prevToken.type === AST_TOKEN_TYPES.String) { | ||
return !DECLARATIONS.has(prevNode.parent.type); | ||
} | ||
|
||
return true; | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.