-
-
Notifications
You must be signed in to change notification settings - Fork 367
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
no-await-in-promise-methods
rule
- Loading branch information
1 parent
eb5af8b
commit b384e43
Showing
5 changed files
with
192 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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 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,42 @@ | ||
# Disallow Promise methods containing an await | ||
|
||
🚫 This rule is _disabled_ in the ✅ `recommended` [config](https:/sindresorhus/eslint-plugin-unicorn#preset-configs). | ||
|
||
🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). | ||
|
||
<!-- end auto-generated rule header --> | ||
<!-- Do not manually modify this header. Run: `npm run fix:eslint-docs` --> | ||
|
||
It's useless to use an await in a Promise all, allSettled, any, or race method and this reduces the code readability. | ||
|
||
## Fail | ||
|
||
```js | ||
const fn = () => Promise.resolve('fn'); | ||
const pr = fn(); | ||
|
||
await Promise.all([fn(), await fn(), await pr, pr]); | ||
|
||
await Promise.allSettled([fn(), await fn(), await pr, pr]); | ||
|
||
await Promise.any([fn(), await fn(), await pr, pr]); | ||
|
||
await Promise.race([fn(), await fn(), await pr, pr]); | ||
``` | ||
|
||
## Pass | ||
|
||
```js | ||
const fn = () => Promise.resolve('fn'); | ||
const pr = fn(); | ||
|
||
await Promise.all([fn(), fn(), pr, pr]); | ||
|
||
await Promise.allSettled([fn(), fn(), pr, pr]); | ||
|
||
await Promise.any([fn(), fn(), pr, pr]); | ||
|
||
await Promise.race([fn(), fn(), pr, pr]); | ||
|
||
await Promise.resolve([await fn()]); | ||
``` |
This file contains 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 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,56 @@ | ||
'use strict'; | ||
const MESSAGE_ID = 'no-await-in-promise-methods'; | ||
const messages = { | ||
[MESSAGE_ID]: 'Promise.{{ method }} contains an await.', | ||
}; | ||
|
||
const isPromiseMethodWithArray = node => | ||
node.callee.type === 'MemberExpression' | ||
&& node.callee.object.type === 'Identifier' | ||
&& node.callee.object.name === 'Promise' | ||
&& node.callee.property.type === 'Identifier' | ||
&& ['all', 'allSettled', 'any', 'race'].includes(node.callee.property.name) | ||
&& node.arguments.length === 1 | ||
&& node.arguments[0].type === 'ArrayExpression'; | ||
|
||
const getArrayElements = node => node.arguments[0].elements; | ||
|
||
const isAwait = element => element.type === 'AwaitExpression'; | ||
|
||
const getMethodName = node => node.callee.property.name; | ||
|
||
const getFixer = ({sourceCode}, element) => fixer => | ||
fixer.replaceText(element, sourceCode.getText(element.argument)); | ||
|
||
/** @param {import('eslint').Rule.RuleContext} context */ | ||
const create = context => ({ | ||
CallExpression(node) { | ||
if (isPromiseMethodWithArray(node)) { | ||
for (const element of getArrayElements(node)) { | ||
if (isAwait(element)) { | ||
context.report({ | ||
node: element, | ||
messageId: MESSAGE_ID, | ||
data: { | ||
method: getMethodName(node), | ||
}, | ||
fix: getFixer(context, element), | ||
}); | ||
} | ||
} | ||
} | ||
}, | ||
}); | ||
|
||
/** @type {import('eslint').Rule.RuleModule} */ | ||
module.exports = { | ||
create, | ||
meta: { | ||
type: 'suggestion', | ||
docs: { | ||
description: 'Disallow Promise methods containing an await.', | ||
}, | ||
fixable: 'code', | ||
messages, | ||
}, | ||
}; |
This file contains 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,92 @@ | ||
import outdent from 'outdent'; | ||
import {getTester} from './utils/test.mjs'; | ||
|
||
const {test} = getTester(import.meta); | ||
|
||
const error = { | ||
messageId: 'no-await-in-promise-methods', | ||
}; | ||
|
||
test({ | ||
valid: [ | ||
outdent` | ||
const fn = () => Promise.resolve('fn'); | ||
const pr = fn(); | ||
await Promise.all([fn(), fn(), pr, pr]); | ||
`, | ||
outdent` | ||
const fn = () => Promise.resolve('fn'); | ||
const pr = fn(); | ||
await Promise.allSettled([fn(), fn(), pr, pr]); | ||
`, | ||
outdent` | ||
const fn = () => Promise.resolve('fn'); | ||
const pr = fn(); | ||
await Promise.any([fn(), fn(), pr, pr]); | ||
`, | ||
outdent` | ||
const fn = () => Promise.resolve('fn'); | ||
const pr = fn(); | ||
await Promise.race([fn(), fn(), pr, pr]); | ||
`, | ||
outdent` | ||
const fn = () => Promise.resolve('fn'); | ||
await Promise.resolve([await fn()]); | ||
`, | ||
], | ||
|
||
invalid: [ | ||
{ | ||
code: outdent` | ||
const fn = () => Promise.resolve('fn'); | ||
const pr = fn(); | ||
await Promise.all([fn(), await fn(), await pr, pr]); | ||
`, | ||
errors: [error, error], | ||
output: outdent` | ||
const fn = () => Promise.resolve('fn'); | ||
const pr = fn(); | ||
await Promise.all([fn(), fn(), pr, pr]); | ||
`, | ||
}, | ||
{ | ||
code: outdent` | ||
const fn = () => Promise.resolve('fn'); | ||
const pr = fn(); | ||
await Promise.allSettled([fn(), await fn(), await pr, pr]); | ||
`, | ||
errors: [error, error], | ||
output: outdent` | ||
const fn = () => Promise.resolve('fn'); | ||
const pr = fn(); | ||
await Promise.allSettled([fn(), fn(), pr, pr]); | ||
`, | ||
}, | ||
{ | ||
code: outdent` | ||
const fn = () => Promise.resolve('fn'); | ||
const pr = fn(); | ||
await Promise.any([fn(), await fn(), await pr, pr]); | ||
`, | ||
errors: [error, error], | ||
output: outdent` | ||
const fn = () => Promise.resolve('fn'); | ||
const pr = fn(); | ||
await Promise.any([fn(), fn(), pr, pr]); | ||
`, | ||
}, | ||
{ | ||
code: outdent` | ||
const fn = () => Promise.resolve('fn'); | ||
const pr = fn(); | ||
await Promise.race([fn(), await fn(), await pr, pr]); | ||
`, | ||
errors: [error, error], | ||
output: outdent` | ||
const fn = () => Promise.resolve('fn'); | ||
const pr = fn(); | ||
await Promise.race([fn(), fn(), pr, pr]); | ||
`, | ||
}, | ||
], | ||
}); |