Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork2.8k
fix(eslint-plugin): [promise-function-async] handle function overloading#10304
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Merged
JoshuaKGoldberg merged 14 commits intotypescript-eslint:mainfromronami:promise-function-async-overloadingDec 1, 2024
Uh oh!
There was an error while loading.Please reload this page.
Merged
Changes fromall commits
Commits
Show all changes
14 commits Select commitHold shift + click to select a range
9ba3bf7 initial implementation
ronami5619a87 remove unnecessary comment
ronami5f79c06 rework the code to use a single signature
ronami1c0d222 reduce changes footprint
ronami294711e reduce changes footprint further
ronami481a136 use nullThrows rather than an unreachable conditional
ronami75ffdc5 revert implementation to check every function signature
ronamib6aeec1 add missing test
ronami2b0f1a7 remove unnecessary export syntax from tests
ronamibb9eeec correct a comment
ronami53cdca6 fix unknown => any on a test
ronamid433280 move code that requires type checking to run after the static ast checks
ronamia67b11c refactor code to not use a double-negative check
ronami8f790ba remove the unnecessary double check of allowAny
ronamiFile filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
156 changes: 82 additions & 74 deletionspackages/eslint-plugin/src/rules/promise-function-async.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 |
|---|---|---|
| @@ -115,26 +115,6 @@ export default createRule<Options, MessageIds>({ | ||
| | TSESTree.FunctionDeclaration | ||
| | TSESTree.FunctionExpression, | ||
| ): void { | ||
| if (node.parent.type === AST_NODE_TYPES.TSAbstractMethodDefinition) { | ||
| // Abstract method can't be async | ||
| return; | ||
| @@ -149,7 +129,21 @@ export default createRule<Options, MessageIds>({ | ||
| return; | ||
| } | ||
| const signatures = services.getTypeAtLocation(node).getCallSignatures(); | ||
| if (!signatures.length) { | ||
| return; | ||
| } | ||
| const returnTypes = signatures.map(signature => | ||
kirkwaiblinger marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| checker.getReturnTypeOfSignature(signature), | ||
| ); | ||
| if ( | ||
| !allowAny && | ||
| returnTypes.some(type => | ||
| isTypeFlagSet(type, ts.TypeFlags.Any | ts.TypeFlags.Unknown), | ||
| ) | ||
| ) { | ||
| // Report without auto fixer because the return type is unknown | ||
| return context.report({ | ||
| loc: getFunctionHeadLoc(node, context.sourceCode), | ||
| @@ -158,67 +152,81 @@ export default createRule<Options, MessageIds>({ | ||
| }); | ||
| } | ||
| if ( | ||
kirkwaiblinger marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| // require all potential return types to be promise/any/unknown | ||
| returnTypes.every(type => | ||
| containsAllTypesByName( | ||
| type, | ||
| true, | ||
| allAllowedPromiseNames, | ||
| // If no return type is explicitly set, we check if any parts of the return type match a Promise (instead of requiring all to match). | ||
| node.returnType == null, | ||
| ), | ||
| ) | ||
| ) { | ||
| context.report({ | ||
| loc: getFunctionHeadLoc(node, context.sourceCode), | ||
| node, | ||
| messageId: 'missingAsync', | ||
| fix: fixer => { | ||
| if ( | ||
| node.parent.type === AST_NODE_TYPES.MethodDefinition || | ||
| (node.parent.type === AST_NODE_TYPES.Property && | ||
| node.parent.method) | ||
| ) { | ||
| // this function is a class method or object function property shorthand | ||
| const method = node.parent; | ||
| // the token to put `async` before | ||
| let keyToken = nullThrows( | ||
| context.sourceCode.getFirstToken(method), | ||
| NullThrowsReasons.MissingToken('key token', 'method'), | ||
| ); | ||
| // if there are decorators then skip past them | ||
| if ( | ||
| method.type === AST_NODE_TYPES.MethodDefinition && | ||
| method.decorators.length | ||
| ) { | ||
| const lastDecorator = | ||
| method.decorators[method.decorators.length - 1]; | ||
| keyToken = nullThrows( | ||
| context.sourceCode.getTokenAfter(lastDecorator), | ||
| NullThrowsReasons.MissingToken('key token', 'last decorator'), | ||
| ); | ||
| } | ||
| // if current token is a keyword like `static` or `public` then skip it | ||
| while ( | ||
| keyToken.type === AST_TOKEN_TYPES.Keyword && | ||
| keyToken.range[0] < method.key.range[0] | ||
| ) { | ||
| keyToken = nullThrows( | ||
| context.sourceCode.getTokenAfter(keyToken), | ||
| NullThrowsReasons.MissingToken('token', 'keyword'), | ||
| ); | ||
| } | ||
| // check if there is a space between key and previous token | ||
| const insertSpace = !context.sourceCode.isSpaceBetween( | ||
| nullThrows( | ||
| context.sourceCode.getTokenBefore(keyToken), | ||
| NullThrowsReasons.MissingToken('token', 'keyword'), | ||
| ), | ||
| keyToken, | ||
| ); | ||
| let code = 'async '; | ||
| if (insertSpace) { | ||
| code = ` ${code}`; | ||
| } | ||
| return fixer.insertTextBefore(keyToken, code); | ||
| } | ||
| return fixer.insertTextBefore(node, 'async '); | ||
| }, | ||
| }); | ||
| } | ||
| } | ||
| return { | ||
101 changes: 101 additions & 0 deletionspackages/eslint-plugin/tests/rules/promise-function-async.test.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
Oops, something went wrong.
Uh oh!
There was an error while loading.Please reload this page.
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.