Skip to content

Commit d6e9de1

Browse files
authored
feat: new rule spec-only to check for non-spec Promise methods (#502)
**What is the purpose of this pull request?** - [x] New rule **What changes did you make? (Give an overview)** Add a new rule `spec-only` to check for non-spec Promise methods Fixes #46.
1 parent 943f162 commit d6e9de1

File tree

8 files changed

+143
-1
lines changed

8 files changed

+143
-1
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ or start with the recommended rule set:
115115
| [param-names](docs/rules/param-names.md) | Enforce consistent param names and ordering when creating new promises. || | | |
116116
| [prefer-await-to-callbacks](docs/rules/prefer-await-to-callbacks.md) | Prefer `async`/`await` to the callback pattern. | | | | |
117117
| [prefer-await-to-then](docs/rules/prefer-await-to-then.md) | Prefer `await` to `then()`/`catch()`/`finally()` for reading Promise values. | | | | |
118+
| [spec-only](docs/rules/spec-only.md) | Disallow use of non-standard Promise static methods. | | | | |
118119
| [valid-params](docs/rules/valid-params.md) | Enforces the proper number of arguments are passed to Promise functions. | || | |
119120

120121
<!-- end auto-generated rules list -->

__tests__/no-new-statics.js

+6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ ruleTester.run('no-new-statics', rule, {
1010
'Promise.reject()',
1111
'Promise.all()',
1212
'Promise.race()',
13+
'Promise.withResolvers()',
1314
'new Promise(function (resolve, reject) {})',
1415
'new SomeClass()',
1516
'SomeClass.resolve()',
@@ -46,6 +47,11 @@ ruleTester.run('no-new-statics', rule, {
4647
output: 'Promise.race()',
4748
errors: [{ message: "Avoid calling 'new' on 'Promise.race()'" }],
4849
},
50+
{
51+
code: 'new Promise.withResolvers()',
52+
output: 'Promise.withResolvers()',
53+
errors: [{ message: "Avoid calling 'new' on 'Promise.withResolvers()'" }],
54+
},
4955
{
5056
code: [
5157
'function foo() {',

__tests__/spec-only.js

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
'use strict'
2+
3+
const rule = require('../rules/spec-only')
4+
const { RuleTester } = require('./rule-tester')
5+
const ruleTester = new RuleTester()
6+
7+
ruleTester.run('spec-only', rule, {
8+
valid: [
9+
'Promise.resolve()',
10+
'Promise.reject()',
11+
'Promise.all()',
12+
'Promise.race()',
13+
'Promise.withResolvers()',
14+
'new Promise(function (resolve, reject) {})',
15+
'SomeClass.resolve()',
16+
'doSomething(Promise.all)',
17+
{
18+
code: 'Promise.permittedMethod()',
19+
options: [
20+
{
21+
allowedMethods: ['permittedMethod'],
22+
},
23+
],
24+
},
25+
],
26+
invalid: [
27+
{
28+
code: 'Promise.done()',
29+
errors: [{ message: "Avoid using non-standard 'Promise.done'" }],
30+
},
31+
{
32+
code: 'Promise.something()',
33+
errors: [{ message: "Avoid using non-standard 'Promise.something'" }],
34+
},
35+
{
36+
code: 'new Promise.done()',
37+
errors: [{ message: "Avoid using non-standard 'Promise.done'" }],
38+
},
39+
{
40+
code: `
41+
function foo() {
42+
var a = getA()
43+
return Promise.done(a)
44+
}
45+
`,
46+
errors: [{ message: "Avoid using non-standard 'Promise.done'" }],
47+
},
48+
{
49+
code: `
50+
function foo() {
51+
getA(Promise.done)
52+
}
53+
`,
54+
errors: [{ message: "Avoid using non-standard 'Promise.done'" }],
55+
},
56+
],
57+
})

docs/rules/spec-only.md

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Disallow use of non-standard Promise static methods (`promise/spec-only`)
2+
3+
<!-- end auto-generated rule header -->
4+
5+
It may become difficult to migrate code depending on non-standard Promise
6+
extensions. This rule reports any such method usage.
7+
8+
## Valid
9+
10+
```js
11+
const x = Promise.resolve('good')
12+
```
13+
14+
## Invalid
15+
16+
```js
17+
const x = Promise.done('bad')
18+
```
19+
20+
## Options
21+
22+
### `allowedMethods`
23+
24+
An array of allowed non-standard methods. Defaults to an empty array.

index.js

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const pluginPromise = {
3232
'no-return-in-finally': require('./rules/no-return-in-finally'),
3333
'valid-params': require('./rules/valid-params'),
3434
'no-multiple-resolved': require('./rules/no-multiple-resolved'),
35+
'spec-only': require('./rules/spec-only'),
3536
},
3637
rulesConfig: {
3738
'param-names': 1,

rules/lib/is-promise.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ function isPromise(expression) {
2929
expression.callee.type === 'MemberExpression' &&
3030
expression.callee.object.type === 'Identifier' &&
3131
expression.callee.object.name === 'Promise' &&
32-
PROMISE_STATICS[expression.callee.property.name])
32+
PROMISE_STATICS[expression.callee.property.name] &&
33+
expression.callee.property.name !== 'withResolvers')
3334
)
3435
}
3536

rules/lib/promise-statics.js

+1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ module.exports = {
77
race: true,
88
reject: true,
99
resolve: true,
10+
withResolvers: true,
1011
}

rules/spec-only.js

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
'use strict'
2+
3+
const PROMISE_STATICS = require('./lib/promise-statics')
4+
const getDocsUrl = require('./lib/get-docs-url')
5+
6+
module.exports = {
7+
meta: {
8+
type: 'problem',
9+
docs: {
10+
description: 'Disallow use of non-standard Promise static methods.',
11+
url: getDocsUrl('spec-only'),
12+
},
13+
schema: [
14+
{
15+
type: 'object',
16+
properties: {
17+
allowedMethods: {
18+
type: 'array',
19+
items: {
20+
type: 'string',
21+
},
22+
},
23+
},
24+
additionalProperties: false,
25+
},
26+
],
27+
messages: {
28+
avoidNonStandard: "Avoid using non-standard 'Promise.{{ name }}'",
29+
},
30+
},
31+
create(context) {
32+
const { allowedMethods = [] } = context.options[0] || {}
33+
34+
return {
35+
MemberExpression(node) {
36+
if (
37+
node.object.type === 'Identifier' &&
38+
node.object.name === 'Promise' &&
39+
!(node.property.name in PROMISE_STATICS) &&
40+
!allowedMethods.includes(node.property.name)
41+
) {
42+
context.report({
43+
node,
44+
messageId: 'avoidNonStandard',
45+
data: { name: node.property.name },
46+
})
47+
}
48+
},
49+
}
50+
},
51+
}

0 commit comments

Comments
 (0)