Skip to content

Commit

Permalink
feat: new rule spec-only to check for non-spec Promise methods (#502)
Browse files Browse the repository at this point in the history
**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.
  • Loading branch information
brettz9 committed Jul 24, 2024
1 parent 943f162 commit d6e9de1
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 1 deletion.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ or start with the recommended rule set:
| [param-names](docs/rules/param-names.md) | Enforce consistent param names and ordering when creating new promises. | ✅ | | | |
| [prefer-await-to-callbacks](docs/rules/prefer-await-to-callbacks.md) | Prefer `async`/`await` to the callback pattern. | | | | |
| [prefer-await-to-then](docs/rules/prefer-await-to-then.md) | Prefer `await` to `then()`/`catch()`/`finally()` for reading Promise values. | | | | |
| [spec-only](docs/rules/spec-only.md) | Disallow use of non-standard Promise static methods. | | | | |
| [valid-params](docs/rules/valid-params.md) | Enforces the proper number of arguments are passed to Promise functions. | | ✅ | | |

<!-- end auto-generated rules list -->
Expand Down
6 changes: 6 additions & 0 deletions __tests__/no-new-statics.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ ruleTester.run('no-new-statics', rule, {
'Promise.reject()',
'Promise.all()',
'Promise.race()',
'Promise.withResolvers()',
'new Promise(function (resolve, reject) {})',
'new SomeClass()',
'SomeClass.resolve()',
Expand Down Expand Up @@ -46,6 +47,11 @@ ruleTester.run('no-new-statics', rule, {
output: 'Promise.race()',
errors: [{ message: "Avoid calling 'new' on 'Promise.race()'" }],
},
{
code: 'new Promise.withResolvers()',
output: 'Promise.withResolvers()',
errors: [{ message: "Avoid calling 'new' on 'Promise.withResolvers()'" }],
},
{
code: [
'function foo() {',
Expand Down
57 changes: 57 additions & 0 deletions __tests__/spec-only.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
'use strict'

const rule = require('../rules/spec-only')
const { RuleTester } = require('./rule-tester')
const ruleTester = new RuleTester()

ruleTester.run('spec-only', rule, {
valid: [
'Promise.resolve()',
'Promise.reject()',
'Promise.all()',
'Promise.race()',
'Promise.withResolvers()',
'new Promise(function (resolve, reject) {})',
'SomeClass.resolve()',
'doSomething(Promise.all)',
{
code: 'Promise.permittedMethod()',
options: [
{
allowedMethods: ['permittedMethod'],
},
],
},
],
invalid: [
{
code: 'Promise.done()',
errors: [{ message: "Avoid using non-standard 'Promise.done'" }],
},
{
code: 'Promise.something()',
errors: [{ message: "Avoid using non-standard 'Promise.something'" }],
},
{
code: 'new Promise.done()',
errors: [{ message: "Avoid using non-standard 'Promise.done'" }],
},
{
code: `
function foo() {
var a = getA()
return Promise.done(a)
}
`,
errors: [{ message: "Avoid using non-standard 'Promise.done'" }],
},
{
code: `
function foo() {
getA(Promise.done)
}
`,
errors: [{ message: "Avoid using non-standard 'Promise.done'" }],
},
],
})
24 changes: 24 additions & 0 deletions docs/rules/spec-only.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Disallow use of non-standard Promise static methods (`promise/spec-only`)

<!-- end auto-generated rule header -->

It may become difficult to migrate code depending on non-standard Promise
extensions. This rule reports any such method usage.

## Valid

```js
const x = Promise.resolve('good')
```

## Invalid

```js
const x = Promise.done('bad')
```

## Options

### `allowedMethods`

An array of allowed non-standard methods. Defaults to an empty array.
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const pluginPromise = {
'no-return-in-finally': require('./rules/no-return-in-finally'),
'valid-params': require('./rules/valid-params'),
'no-multiple-resolved': require('./rules/no-multiple-resolved'),
'spec-only': require('./rules/spec-only'),
},
rulesConfig: {
'param-names': 1,
Expand Down
3 changes: 2 additions & 1 deletion rules/lib/is-promise.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ function isPromise(expression) {
expression.callee.type === 'MemberExpression' &&
expression.callee.object.type === 'Identifier' &&
expression.callee.object.name === 'Promise' &&
PROMISE_STATICS[expression.callee.property.name])
PROMISE_STATICS[expression.callee.property.name] &&
expression.callee.property.name !== 'withResolvers')
)
}

Expand Down
1 change: 1 addition & 0 deletions rules/lib/promise-statics.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ module.exports = {
race: true,
reject: true,
resolve: true,
withResolvers: true,
}
51 changes: 51 additions & 0 deletions rules/spec-only.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
'use strict'

const PROMISE_STATICS = require('./lib/promise-statics')
const getDocsUrl = require('./lib/get-docs-url')

module.exports = {
meta: {
type: 'problem',
docs: {
description: 'Disallow use of non-standard Promise static methods.',
url: getDocsUrl('spec-only'),
},
schema: [
{
type: 'object',
properties: {
allowedMethods: {
type: 'array',
items: {
type: 'string',
},
},
},
additionalProperties: false,
},
],
messages: {
avoidNonStandard: "Avoid using non-standard 'Promise.{{ name }}'",
},
},
create(context) {
const { allowedMethods = [] } = context.options[0] || {}

return {
MemberExpression(node) {
if (
node.object.type === 'Identifier' &&
node.object.name === 'Promise' &&
!(node.property.name in PROMISE_STATICS) &&
!allowedMethods.includes(node.property.name)
) {
context.report({
node,
messageId: 'avoidNonStandard',
data: { name: node.property.name },
})
}
},
}
},
}

0 comments on commit d6e9de1

Please sign in to comment.