eslint-plugin-promise
Advanced tools
| 'use strict' | ||
| function getSourceCode(context) { | ||
| if (context.sourceCode != null) { | ||
| return context.sourceCode | ||
| } | ||
| return context.getSourceCode() | ||
| } | ||
| function getAncestors(context, node) { | ||
| const sourceCode = getSourceCode(context) | ||
| if (typeof sourceCode.getAncestors === 'function') { | ||
| return sourceCode.getAncestors(node) | ||
| } | ||
| return context.getAncestors(node) | ||
| } | ||
| function getScope(context, node) { | ||
| const sourceCode = getSourceCode(context) | ||
| if (typeof sourceCode.getScope === 'function') { | ||
| return sourceCode.getScope(node) | ||
| } | ||
| return context.getScope(node) | ||
| } | ||
| module.exports = { | ||
| getSourceCode, | ||
| getAncestors, | ||
| getScope, | ||
| } |
+24
-9
| { | ||
| "name": "eslint-plugin-promise", | ||
| "version": "6.1.1", | ||
| "version": "6.2.0", | ||
| "description": "Enforce best practices for JavaScript promises", | ||
@@ -26,5 +26,8 @@ "keywords": [ | ||
| "format": "prettier --write .", | ||
| "lint": "eslint --report-unused-disable-directives .", | ||
| "lint": "npm-run-all \"lint:*\"", | ||
| "lint:eslint-docs": "npm run update:eslint-docs && git diff --exit-code", | ||
| "lint:js": "eslint --report-unused-disable-directives .", | ||
| "prepare": "husky install", | ||
| "test": "jest --coverage" | ||
| "test": "jest --coverage", | ||
| "update:eslint-docs": "eslint-doc-generator && npm run format" | ||
| }, | ||
@@ -56,9 +59,18 @@ "lint-staged": { | ||
| } | ||
| } | ||
| }, | ||
| "collectCoverageFrom": [ | ||
| "rules/*.js", | ||
| "rules/*/*.js", | ||
| "!rules/lib/eslint-compat.js" | ||
| ], | ||
| "testPathIgnorePatterns": [ | ||
| "__tests__/rule-tester.js" | ||
| ] | ||
| }, | ||
| "devDependencies": { | ||
| "@typescript-eslint/parser": "^5.40.0", | ||
| "@typescript-eslint/parser": "^5.45.0", | ||
| "doctoc": "^2.2.1", | ||
| "eslint": "^8.24.0", | ||
| "eslint": "^8.28.0", | ||
| "eslint-config-prettier": "^8.5.0", | ||
| "eslint-doc-generator": "^0.25.0", | ||
| "eslint-plugin-eslint-plugin": "^4.4.1", | ||
@@ -68,14 +80,17 @@ "eslint-plugin-jest": "^26.9.0", | ||
| "eslint-plugin-prettier": "^4.2.1", | ||
| "globals": "^14.0.0", | ||
| "husky": "^7.0.4", | ||
| "jest": "^28.1.3", | ||
| "lint-staged": "^12.5.0", | ||
| "npm-run-all": "^4.1.5", | ||
| "prettier": "^2.7.1", | ||
| "typescript": "^4.8.4" | ||
| "typescript": "^4.9.3" | ||
| }, | ||
| "peerDependencies": { | ||
| "eslint": "^7.0.0 || ^8.0.0" | ||
| "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" | ||
| }, | ||
| "engines": { | ||
| "node": "^12.22.0 || ^14.17.0 || >=16.0.0" | ||
| } | ||
| }, | ||
| "funding": "https://opencollective.com/eslint" | ||
| } |
+30
-43
@@ -24,11 +24,11 @@ # eslint-plugin-promise | ||
| ```sh | ||
| npm install eslint --save-dev | ||
| ``` | ||
| $ npm install eslint --save-dev | ||
| ``` | ||
| Next, install `eslint-plugin-promise`: | ||
| ```sh | ||
| npm install eslint-plugin-promise --save-dev | ||
| ``` | ||
| $ npm install eslint-plugin-promise --save-dev | ||
| ``` | ||
@@ -80,29 +80,31 @@ **Note:** If you installed ESLint globally (using the `-g` flag) then you must | ||
| | rule | description | recommended | fixable | | ||
| | -------------------------------------------------------- | -------------------------------------------------------------------------------- | ----------- | -------- | | ||
| | [`catch-or-return`][catch-or-return] | Enforces the use of `catch()` on un-returned promises. | :bangbang: | | | ||
| | [`no-return-wrap`][no-return-wrap] | Avoid wrapping values in `Promise.resolve` or `Promise.reject` when not needed. | :bangbang: | | | ||
| | [`param-names`][param-names] | Enforce consistent param names and ordering when creating new promises. | :bangbang: | | | ||
| | [`always-return`][always-return] | Return inside each `then()` to create readable and reusable Promise chains. | :bangbang: | | | ||
| | [`no-native`][no-native] | In an ES5 environment, make sure to create a `Promise` constructor before using. | | | | ||
| | [`no-nesting`][no-nesting] | Avoid nested `then()` or `catch()` statements | :warning: | | | ||
| | [`no-promise-in-callback`][no-promise-in-callback] | Avoid using promises inside of callbacks | :warning: | | | ||
| | [`no-callback-in-promise`][no-callback-in-promise] | Avoid calling `cb()` inside of a `then()` (use [nodeify][] instead) | :warning: | | | ||
| | [`avoid-new`][avoid-new] | Avoid creating `new` promises outside of utility libs (use [pify][] instead) | | | | ||
| | [`no-new-statics`][no-new-statics] | Avoid calling `new` on a Promise static method | :bangbang: | :wrench: | | ||
| | [`no-return-in-finally`][no-return-in-finally] | Disallow return statements in `finally()` | :warning: | | | ||
| | [`valid-params`][valid-params] | Ensures the proper number of arguments are passed to Promise functions | :warning: | | | ||
| | [`prefer-await-to-then`][prefer-await-to-then] | Prefer `await` to `then()`/`catch()`/`finally()` for reading Promise values | :seven: | | | ||
| | [`prefer-await-to-callbacks`][prefer-await-to-callbacks] | Prefer async/await to the callback pattern | :seven: | | | ||
| | [`no-multiple-resolved`][no-multiple-resolved] | Disallow creating new promises with paths that resolve multiple times | | | | ||
| <!-- begin auto-generated rules list --> | ||
| **Key** | ||
| 💼 Configurations enabled in.\ | ||
| ⚠️ Configurations set to warn in.\ | ||
| 🚫 Configurations disabled in.\ | ||
| ✅ Set in the `recommended` configuration.\ | ||
| 🔧 Automatically fixable by the | ||
| [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix). | ||
| | icon | description | | ||
| | ---------- | ----------------------------------------------- | | ||
| | :bangbang: | Reports as error in recommended configuration | | ||
| | :warning: | Reports as warning in recommended configuration | | ||
| | :seven: | ES2017 Async Await rules | | ||
| | :wrench: | Rule is fixable with `eslint --fix` | | ||
| | Name | Description | 💼 | ⚠️ | 🚫 | 🔧 | | ||
| | :------------------------------------------------------------------- | :------------------------------------------------------------------------------------- | :-- | :-- | :-- | :-- | | ||
| | [always-return](docs/rules/always-return.md) | Require returning inside each `then()` to create readable and reusable Promise chains. | ✅ | | | | | ||
| | [avoid-new](docs/rules/avoid-new.md) | Disallow creating `new` promises outside of utility libs (use [pify][] instead). | | | ✅ | | | ||
| | [catch-or-return](docs/rules/catch-or-return.md) | Enforce the use of `catch()` on un-returned promises. | ✅ | | | | | ||
| | [no-callback-in-promise](docs/rules/no-callback-in-promise.md) | Disallow calling `cb()` inside of a `then()` (use [nodeify][] instead). | | ✅ | | | | ||
| | [no-multiple-resolved](docs/rules/no-multiple-resolved.md) | Disallow creating new promises with paths that resolve multiple times. | | | | | | ||
| | [no-native](docs/rules/no-native.md) | Require creating a `Promise` constructor before using it in an ES5 environment. | | | ✅ | | | ||
| | [no-nesting](docs/rules/no-nesting.md) | Disallow nested `then()` or `catch()` statements. | | ✅ | | | | ||
| | [no-new-statics](docs/rules/no-new-statics.md) | Disallow calling `new` on a Promise static method. | ✅ | | | 🔧 | | ||
| | [no-promise-in-callback](docs/rules/no-promise-in-callback.md) | Disallow using promises inside of callbacks. | | ✅ | | | | ||
| | [no-return-in-finally](docs/rules/no-return-in-finally.md) | Disallow return statements in `finally()`. | | ✅ | | | | ||
| | [no-return-wrap](docs/rules/no-return-wrap.md) | Disallow wrapping values in `Promise.resolve` or `Promise.reject` when not needed. | ✅ | | | | | ||
| | [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. | | | | | | ||
| | [valid-params](docs/rules/valid-params.md) | Enforces the proper number of arguments are passed to Promise functions. | | ✅ | | | | ||
| <!-- end auto-generated rules list --> | ||
| ## Maintainers | ||
@@ -119,17 +121,2 @@ | ||
| [catch-or-return]: docs/rules/catch-or-return.md | ||
| [no-return-wrap]: docs/rules/no-return-wrap.md | ||
| [param-names]: docs/rules/param-names.md | ||
| [always-return]: docs/rules/always-return.md | ||
| [no-native]: docs/rules/no-native.md | ||
| [no-nesting]: docs/rules/no-nesting.md | ||
| [no-promise-in-callback]: docs/rules/no-promise-in-callback.md | ||
| [no-callback-in-promise]: docs/rules/no-callback-in-promise.md | ||
| [avoid-new]: docs/rules/avoid-new.md | ||
| [no-new-statics]: docs/rules/no-new-statics.md | ||
| [no-return-in-finally]: docs/rules/no-return-in-finally.md | ||
| [valid-params]: docs/rules/valid-params.md | ||
| [prefer-await-to-then]: docs/rules/prefer-await-to-then.md | ||
| [prefer-await-to-callbacks]: docs/rules/prefer-await-to-callbacks.md | ||
| [no-multiple-resolved]: docs/rules/no-multiple-resolved.md | ||
| [nodeify]: https://www.npmjs.com/package/nodeify | ||
@@ -136,0 +123,0 @@ [pify]: https://www.npmjs.com/package/pify |
@@ -131,2 +131,4 @@ 'use strict' | ||
| docs: { | ||
| description: | ||
| 'Require returning inside each `then()` to create readable and reusable Promise chains.', | ||
| url: getDocsUrl('always-return'), | ||
@@ -133,0 +135,0 @@ }, |
@@ -14,2 +14,4 @@ /** | ||
| docs: { | ||
| description: | ||
| 'Disallow creating `new` promises outside of utility libs (use [pify][] instead).', | ||
| url: getDocsUrl('avoid-new'), | ||
@@ -16,0 +18,0 @@ }, |
@@ -16,2 +16,3 @@ /** | ||
| docs: { | ||
| description: 'Enforce the use of `catch()` on un-returned promises.', | ||
| url: getDocsUrl('catch-or-return'), | ||
@@ -18,0 +19,0 @@ }, |
@@ -8,2 +8,3 @@ /** | ||
| const { getAncestors } = require('./lib/eslint-compat') | ||
| const getDocsUrl = require('./lib/get-docs-url') | ||
@@ -14,2 +15,4 @@ const hasPromiseCallback = require('./lib/has-promise-callback') | ||
| const CB_BLACKLIST = ['callback', 'cb', 'next', 'done'] | ||
| module.exports = { | ||
@@ -19,2 +22,4 @@ meta: { | ||
| docs: { | ||
| description: | ||
| 'Disallow calling `cb()` inside of a `then()` (use [nodeify][] instead).', | ||
| url: getDocsUrl('no-callback-in-promise'), | ||
@@ -51,8 +56,3 @@ }, | ||
| node.arguments && node.arguments[0] && node.arguments[0].name | ||
| if ( | ||
| name === 'callback' || | ||
| name === 'cb' || | ||
| name === 'next' || | ||
| name === 'done' | ||
| ) { | ||
| if (!exceptions.includes(name) && CB_BLACKLIST.includes(name)) { | ||
| context.report({ | ||
@@ -66,3 +66,3 @@ node: node.arguments[0], | ||
| } | ||
| if (context.getAncestors().some(isInsidePromise)) { | ||
| if (getAncestors(context, node).some(isInsidePromise)) { | ||
| context.report({ | ||
@@ -69,0 +69,0 @@ node, |
@@ -8,2 +8,3 @@ /** | ||
| const { getScope } = require('./lib/eslint-compat') | ||
| const getDocsUrl = require('./lib/get-docs-url') | ||
@@ -337,2 +338,4 @@ const { | ||
| docs: { | ||
| description: | ||
| 'Disallow creating new promises with paths that resolve multiple times.', | ||
| url: getDocsUrl('no-multiple-resolved'), | ||
@@ -403,3 +406,3 @@ }, | ||
| for (const resolver of resolvers) { | ||
| const variable = context.getScope().set.get(resolver.name) | ||
| const variable = getScope(context, node).set.get(resolver.name) | ||
| // istanbul ignore next -- Usually always present. | ||
@@ -406,0 +409,0 @@ if (!variable) continue |
@@ -6,2 +6,3 @@ // Borrowed from here: | ||
| const { getScope } = require('./lib/eslint-compat') | ||
| const getDocsUrl = require('./lib/get-docs-url') | ||
@@ -31,2 +32,4 @@ | ||
| docs: { | ||
| description: | ||
| 'Require creating a `Promise` constructor before using it in an ES5 environment.', | ||
| url: getDocsUrl('no-native'), | ||
@@ -48,4 +51,4 @@ }, | ||
| return { | ||
| 'Program:exit'() { | ||
| const scope = context.getScope() | ||
| 'Program:exit'(node) { | ||
| const scope = getScope(context, node) | ||
| const leftToBeResolved = | ||
@@ -52,0 +55,0 @@ scope.implicit.left || |
@@ -8,2 +8,3 @@ /** | ||
| const { getScope } = require('./lib/eslint-compat') | ||
| const getDocsUrl = require('./lib/get-docs-url') | ||
@@ -17,2 +18,3 @@ const hasPromiseCallback = require('./lib/has-promise-callback') | ||
| docs: { | ||
| description: 'Disallow nested `then()` or `catch()` statements.', | ||
| url: getDocsUrl('no-nesting'), | ||
@@ -45,3 +47,3 @@ }, | ||
| if (isInsidePromise(node)) { | ||
| callbackScopes.unshift(context.getScope()) | ||
| callbackScopes.unshift(getScope(context, node)) | ||
| } | ||
@@ -48,0 +50,0 @@ }, |
@@ -10,2 +10,3 @@ 'use strict' | ||
| docs: { | ||
| description: 'Disallow calling `new` on a Promise static method.', | ||
| url: getDocsUrl('no-new-statics'), | ||
@@ -12,0 +13,0 @@ }, |
@@ -8,2 +8,3 @@ /** | ||
| const { getAncestors } = require('./lib/eslint-compat') | ||
| const getDocsUrl = require('./lib/get-docs-url') | ||
@@ -17,2 +18,3 @@ const isPromise = require('./lib/is-promise') | ||
| docs: { | ||
| description: 'Disallow using promises inside of callbacks.', | ||
| url: getDocsUrl('no-promise-in-callback'), | ||
@@ -34,3 +36,3 @@ }, | ||
| if (context.getAncestors().some(isInsideCallback)) { | ||
| if (getAncestors(context, node).some(isInsideCallback)) { | ||
| context.report({ | ||
@@ -37,0 +39,0 @@ node: node.callee, |
@@ -10,2 +10,3 @@ 'use strict' | ||
| docs: { | ||
| description: 'Disallow return statements in `finally()`.', | ||
| url: getDocsUrl('no-return-in-finally'), | ||
@@ -12,0 +13,0 @@ }, |
@@ -9,8 +9,8 @@ /** | ||
| const { getAncestors } = require('./lib/eslint-compat') | ||
| const getDocsUrl = require('./lib/get-docs-url') | ||
| const isPromise = require('./lib/is-promise') | ||
| function isInPromise(context) { | ||
| let functionNode = context | ||
| .getAncestors() | ||
| function isInPromise(context, node) { | ||
| let functionNode = getAncestors(context, node) | ||
| .filter((node) => { | ||
@@ -43,2 +43,4 @@ return ( | ||
| docs: { | ||
| description: | ||
| 'Disallow wrapping values in `Promise.resolve` or `Promise.reject` when not needed.', | ||
| url: getDocsUrl('no-return-wrap'), | ||
@@ -73,3 +75,3 @@ }, | ||
| if ( | ||
| isInPromise(context) && | ||
| isInPromise(context, node) && | ||
| callee.type === 'MemberExpression' && | ||
@@ -76,0 +78,0 @@ callee.object.name === 'Promise' |
@@ -12,2 +12,4 @@ 'use strict' | ||
| docs: { | ||
| description: | ||
| 'Enforce consistent param names and ordering when creating new promises.', | ||
| url: getDocsUrl('param-names'), | ||
@@ -14,0 +16,0 @@ }, |
| 'use strict' | ||
| const { getAncestors } = require('./lib/eslint-compat') | ||
| const getDocsUrl = require('./lib/get-docs-url') | ||
@@ -9,2 +10,3 @@ | ||
| docs: { | ||
| description: 'Prefer async/await to the callback pattern.', | ||
| url: getDocsUrl('prefer-await-to-callbacks'), | ||
@@ -24,4 +26,4 @@ }, | ||
| } | ||
| function isInsideYieldOrAwait() { | ||
| return context.getAncestors().some((parent) => { | ||
| function isInsideYieldOrAwait(node) { | ||
| return getAncestors(context, node).some((parent) => { | ||
| return ( | ||
@@ -86,3 +88,3 @@ parent.type === 'AwaitExpression' || parent.type === 'YieldExpression' | ||
| ) { | ||
| if (!isInsideYieldOrAwait()) { | ||
| if (!isInsideYieldOrAwait(node)) { | ||
| context.report({ node: arg, messageId: 'error' }) | ||
@@ -89,0 +91,0 @@ } |
@@ -8,2 +8,3 @@ /** | ||
| const { getAncestors, getScope } = require('./lib/eslint-compat') | ||
| const getDocsUrl = require('./lib/get-docs-url') | ||
@@ -15,2 +16,4 @@ | ||
| docs: { | ||
| description: | ||
| 'Prefer `await` to `then()`/`catch()`/`finally()` for reading Promise values.', | ||
| url: getDocsUrl('prefer-await-to-then'), | ||
@@ -22,4 +25,4 @@ }, | ||
| /** Returns true if node is inside yield or await expression. */ | ||
| function isInsideYieldOrAwait() { | ||
| return context.getAncestors().some((parent) => { | ||
| function isInsideYieldOrAwait(node) { | ||
| return getAncestors(context, node).some((parent) => { | ||
| return ( | ||
@@ -36,4 +39,4 @@ parent.type === 'AwaitExpression' || parent.type === 'YieldExpression' | ||
| */ | ||
| function isTopLevelScoped() { | ||
| return context.getScope().block.type === 'Program' | ||
| function isTopLevelScoped(node) { | ||
| return getScope(context, node).block.type === 'Program' | ||
| } | ||
@@ -43,3 +46,3 @@ | ||
| 'CallExpression > MemberExpression.callee'(node) { | ||
| if (isTopLevelScoped() || isInsideYieldOrAwait()) { | ||
| if (isTopLevelScoped(node) || isInsideYieldOrAwait(node)) { | ||
| return | ||
@@ -46,0 +49,0 @@ } |
@@ -11,3 +11,3 @@ 'use strict' | ||
| description: | ||
| 'Ensures the proper number of arguments are passed to Promise functions', | ||
| 'Enforces the proper number of arguments are passed to Promise functions.', | ||
| url: getDocsUrl('valid-params'), | ||
@@ -14,0 +14,0 @@ }, |
69610
3.71%30
3.45%1815
2.89%16
23.08%124
-9.49%