Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

eslint-plugin-promise

Package Overview
Dependencies
Maintainers
2
Versions
47
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

eslint-plugin-promise - npm Package Compare versions

Comparing version 3.6.0 to 3.7.0

rules/lib/get-docs-url.js

83

CHANGELOG.md

@@ -0,99 +1,112 @@

## 3.7.0
* Added `promise/valid-params` rule
([#85](https://github.com/xjamundx/eslint-plugin-promise/pull/85))
* Added `promise/no-new-statics` rule
([#82](https://github.com/xjamundx/eslint-plugin-promise/pull/82))
* Added fixer for `promise/param-names` rule
([#99](https://github.com/xjamundx/eslint-plugin-promise/pull/99))
* Added rule documentation to each rule
([#91](https://github.com/xjamundx/eslint-plugin-promise/pull/91))
## 3.6.0
- Added `['catch']` support in `catch-or-return`
- Added `no-return-in-finally` rule
- Fixed some formatting in the docs
- Added `allowReject` option to `no-return-wrap`
- Added exceptions for `no-callback-in-promise`
* Added `['catch']` support in `catch-or-return`
* Added `no-return-in-finally` rule
* Fixed some formatting in the docs
* Added `allowReject` option to `no-return-wrap`
* Added exceptions for `no-callback-in-promise`
## 3.5.0
- Addded support for recommended settings using `extends: plugin:promise/recommended`
* Added support for recommended settings using
`extends: plugin:promise/recommended`
## 3.4.2
- Fixed always return false positive with ternary (#31)
* Fixed always return false positive with ternary (#31)
## 3.4.1
- fixed #49
* fixed #49
## 3.4.0
- new rule: avoid-new
- new rule: no-promise-in-callback
- new rule: no-callback-in-promise
- new rule: no-nesting
* new rule: avoid-new
* new rule: no-promise-in-callback
* new rule: no-callback-in-promise
* new rule: no-nesting
## 3.3.2
- Removed eslint from peerDeps
* Removed eslint from peerDeps
## 3.3.1
- Updated engines with proper stuff
- Fixed bug for unreachable code
* Updated engines with proper stuff
* Fixed bug for unreachable code
## 3.3.0
- Rule: `prefer-async-to-callbacks` added
- Rule: `prefer-async-to-then` added
* Rule: `prefer-async-to-callbacks` added
* Rule: `prefer-async-to-then` added
## 3.2.1
- Fix: `no-return-wrap` rule missing from index.js
* Fix: `no-return-wrap` rule missing from index.js
## 3.2.0
- Added `no-return-wrap` rule
* Added `no-return-wrap` rule
## 3.1.0
- Added multiple terminationMethods
* Added multiple terminationMethods
## 3.0.1
- Removed deprecated `always-catch` rule
- FIX: always-return error with "fn && fn()"
* Removed deprecated `always-catch` rule
* FIX: always-return error with "fn && fn()"
## 3.0.0
- Updated column and line numbers
- Added flow analysis for better handling of if statements
* Updated column and line numbers
* Added flow analysis for better handling of if statements
## 2.0.1
- Fixed type in docs
* Fixed type in docs
## 2.0.0
- ESLint 3.0 Support
* ESLint 3.0 Support
## 1.3.2
- Updated tests to run on eslint 2.0
- Fixed some issues with `no-native` rule
* Updated tests to run on eslint 2.0
* Fixed some issues with `no-native` rule
## 1.3.1
- Actually added `no-native` rule
* Actually added `no-native` rule
## 1.3.0
- Added `no-native` rule
* Added `no-native` rule
## 1.2.0
- Allow `throw` in `always-return` rule
- Added `terminationMethod` option to `catch-or-return` rule
* Allow `throw` in `always-return` rule
* Added `terminationMethod` option to `catch-or-return` rule
## 1.1.0
- Added `catch-or-return` rule
* Added `catch-or-return` rule
## 1.0.8
- Fixed crash issues
* Fixed crash issues
## 1.0.0 - 1.0.7
- Lots of basic feature updates and doc changes
* Lots of basic feature updates and doc changes

@@ -0,1 +1,3 @@

'use strict'
module.exports = {

@@ -14,3 +16,5 @@ rules: {

'avoid-new': require('./rules/avoid-new'),
'no-return-in-finally': require('./rules/no-return-in-finally')
'no-new-statics': require('./rules/no-new-statics'),
'no-return-in-finally': require('./rules/no-return-in-finally'),
'valid-params': require('./rules/valid-params')
},

@@ -36,3 +40,5 @@ rulesConfig: {

'promise/avoid-new': 'warn',
'promise/no-return-in-finally': 'warn'
'promise/no-new-statics': 'error',
'promise/no-return-in-finally': 'warn',
'promise/valid-params': 'warn'
}

@@ -39,0 +45,0 @@ }

{
"name": "eslint-plugin-promise",
"version": "3.6.0",
"version": "3.7.0",
"description": "Enforce best practices for JavaScript promises",

@@ -15,9 +15,23 @@ "keywords": [

"scripts": {
"pretest": "standard",
"test": "mocha test"
"precommit": "lint-staged",
"test": "jest",
"lint": "eslint index.js rules __tests__ --ignore-pattern '**/*.json'"
},
"devDependencies": {
"eslint": "^3.0",
"mocha": "^2.3.4",
"standard": "^7.1.2"
"doctoc": "^1.3.0",
"eslint": "^4.17.0",
"eslint-config-prettier": "^2.9.0",
"eslint-config-standard": "^11.0.0-beta.0",
"eslint-plugin-eslint-plugin": "^1.4.0",
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-jest": "^21.12.2",
"eslint-plugin-node": "^6.0.0",
"eslint-plugin-prettier": "^2.6.0",
"eslint-plugin-promise": "./",
"eslint-plugin-standard": "^3.0.1",
"husky": "^0.14.3",
"jest": "^22.4.2",
"jest-runner-eslint": "^0.4.0",
"lint-staged": "^6.1.0",
"prettier": "^1.10.2"
},

@@ -27,3 +41,36 @@ "engines": {

},
"license": "ISC"
"license": "ISC",
"lint-staged": {
"concurrent": false,
"linters": {
"{README.md,CONTRIBUTING.md}": [
"doctoc --maxlevel 3 --notitle",
"git add"
],
"*.js": ["prettier --write", "eslint --fix", "git add"],
"*.+(json|md)": ["prettier --write", "git add"]
}
},
"prettier": {
"semi": false,
"singleQuote": true,
"proseWrap": "always"
},
"jest": {
"projects": [
{
"displayName": "test",
"testEnvironment": "node"
},
{
"runner": "jest-runner-eslint",
"displayName": "lint",
"testMatch": [
"<rootDir>/rules/**/*.js",
"<rootDir>/__tests__/**/*.js",
"<rootDir>/index.js"
]
}
]
}
}

@@ -5,7 +5,19 @@ # eslint-plugin-promise

[![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard)
[![travis-ci](https://travis-ci.org/xjamundx/eslint-plugin-promise.svg)](https://travis-ci.org/xjamundx/eslint-plugin-promise)
[![travis-ci](https://travis-ci.org/xjamundx/eslint-plugin-promise.svg)](https://travis-ci.org/xjamundx/eslint-plugin-promise)
[![npm version](https://badge.fury.io/js/eslint-plugin-promise.svg)](https://www.npmjs.com/package/eslint-plugin-promise)
[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier)
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
* [Installation](#installation)
* [Usage](#usage)
* [Rules](#rules)
* [Maintainers](#maintainers)
* [License](#license)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Installation

@@ -16,3 +28,3 @@

```
$ npm i eslint --save-dev
$ npm install eslint --save-dev
```

@@ -26,17 +38,16 @@

**Note:** If you installed ESLint globally (using the `-g` flag) then you must also install `eslint-plugin-promise` globally.
**Note:** If you installed ESLint globally (using the `-g` flag) then you must
also install `eslint-plugin-promise` globally.
## Usage
Add `promise` to the plugins section of your `.eslintrc` configuration file. You can omit the `eslint-plugin-` prefix:
Add `promise` to the plugins section of your `.eslintrc` configuration file. You
can omit the `eslint-plugin-` prefix:
```json
{
"plugins": [
"promise"
]
"plugins": ["promise"]
}
```
Then configure the rules you want to use under the rules section.

@@ -46,14 +57,16 @@

{
"rules": {
"promise/always-return": "error",
"promise/no-return-wrap": "error",
"promise/param-names": "error",
"promise/catch-or-return": "error",
"promise/no-native": "off",
"promise/no-nesting": "warn",
"promise/no-promise-in-callback": "warn",
"promise/no-callback-in-promise": "warn",
"promise/avoid-new": "warn",
"promise/no-return-in-finally": "warn"
}
"rules": {
"promise/always-return": "error",
"promise/no-return-wrap": "error",
"promise/param-names": "error",
"promise/catch-or-return": "error",
"promise/no-native": "off",
"promise/no-nesting": "warn",
"promise/no-promise-in-callback": "warn",
"promise/no-callback-in-promise": "warn",
"promise/avoid-new": "warn",
"promise/no-new-statics": "error",
"promise/no-return-in-finally": "warn",
"promise/valid-params": "warn"
}
}

@@ -66,5 +79,3 @@ ```

{
"extends": [
"plugin:promise/recommended"
]
"extends": ["plugin:promise/recommended"]
}

@@ -75,19 +86,19 @@ ```

### Promise Rules
| 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 when creating new promises. | :bangbang: | :wrench: |
| [`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) | :warning: | |
| [`no-new-statics`][no-new-statics] | Avoid calling `new` on a Promise static method | :bangbang: | |
| [`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()` for reading Promise values | :seven: | |
| [`prefer-await-to-callbacks`][prefer-await-to-callbacks] | Prefer async/await to the callback pattern | :seven: | |
| recommended | rule | description |
| ----------- | --------------------------- | -------------------------------------------------------------------------------- |
| :bangbang: | `catch-or-return` | Enforces the use of `catch()` on un-returned promises. |
| :bangbang: | `no-return-wrap` | Avoid wrapping values in `Promise.resolve` or `Promise.reject` when not needed. |
| :bangbang: | `param-names` | Enforce consistent param names when creating new promises. |
| :bangbang: | `always-return` | Return inside each `then()` to create readable and reusable Promise chains. |
| | `no-native` | In an ES5 environment, make sure to create a `Promise` constructor before using. |
| :warning: | `no-nesting` | Avoid nested `then()` or `catch()` statements |
| :warning: | `no-promise-in-callback` | Avoid using promises inside of callbacks |
| :warning: | `no-callback-in-promise` | Avoid calling `cb()` inside of a `then()` (use [nodeify][] instead) |
| :warning: | `avoid-new` | Avoid creating `new` promises outside of utility libs (use [pify][] instead) |
| :warning: | `no-return-in-finally` | Disallow return statements in `finally()` |
| :seven: | `prefer-await-to-then` | Prefer `await` to `then()` for reading Promise values |
| :seven: | `prefer-await-to-callbacks` | Prefer async/await to the callback pattern |
**Key**

@@ -100,166 +111,31 @@

| :seven: | ES2017 Async Await rules |
| :wrench: | Rule is fixable with `eslint --fix` |
[nodeify]: https://www.npmjs.com/package/nodeify
[pify]: https://www.npmjs.com/package/pify
## Maintainers
### Rule: `catch-or-return`
* Jamund Ferguson - [@xjamundx][]
* Macklin Underdown - [@macklinu][]
Ensure that each time a `then()` is applied to a promise, a
`catch()` is applied as well. Exceptions are made if you are
returning that promise.
## License
#### Valid
* (c) MMXV jden <mailto:jason@denizac.org> - ISC license.
* (c) 2016 Jamund Ferguson <mailto:jamund@gmail.com> - ISC license.
```js
myPromise.then(doSomething).catch(errors);
myPromise.then(doSomething).then(doSomethingElse).catch(errors);
function doSomethingElse() { return myPromise.then(doSomething) }
```
#### Invalid
```js
myPromise.then(doSomething);
myPromise.then(doSomething, catchErrors); // catch() may be a little better
function doSomethingElse() { myPromise.then(doSomething) }
```
#### Options
#### `allowThen`
You can pass an `{ allowThen: true }` as an option to this rule
to allow for `.then(null, fn)` to be used instead of `catch()` at
the end of the promise chain.
#### `terminationMethod`
You can pass a `{ terminationMethod: 'done' }` as an option to this rule
to require `done()` instead of `catch()` at the end of the promise chain.
This is useful for many non-standard Promise implementations.
You can also pass an array of methods such as
`{ terminationMethod: ['catch', 'asCallback', 'finally'] }`.
This will allow any of
```js
Promise.resolve(1).then(() => { throw new Error('oops') }).catch(logerror)
Promise.resolve(1).then(() => { throw new Error('oops') }).asCallback(cb)
Promise.resolve(1).then(() => { throw new Error('oops') }).finally(cleanUp)
```
### Rule: `always-return`
Ensure that inside a `then()` you make sure to `return` a new promise or value.
See http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html (rule #5)
for more info on why that's a good idea.
We also allow someone to `throw` inside a `then()` which is essentially the same as `return Promise.reject()`.
#### Valid
```js
myPromise.then((val) => val * 2));
myPromise.then(function(val) { return val * 2; });
myPromise.then(doSomething); // could be either
myPromise.then((b) => { if (b) { return "yes" } else { return "no" } });
```
#### Invalid
```js
myPromise.then(function(val) {});
myPromise.then(() => { doSomething(); });
myPromise.then((b) => { if (b) { return "yes" } else { forgotToReturn(); } });
```
### `param-names`
Enforce standard parameter names for Promise constructors
#### Valid
```js
new Promise(function (resolve) { ... })
new Promise(function (resolve, reject) { ... })
```
#### Invalid
```js
new Promise(function (reject, resolve) { ... }) // incorrect order
new Promise(function (ok, fail) { ... }) // non-standard parameter names
```
Ensures that `new Promise()` is instantiated with the parameter names `resolve, reject` to avoid confusion with order such as `reject, resolve`. The Promise constructor uses the [RevealingConstructor pattern](https://blog.domenic.me/the-revealing-constructor-pattern/). Using the same parameter names as the language specification makes code more uniform and easier to understand.
### `no-native`
Ensure that `Promise` is included fresh in each file instead of relying
on the existence of a native promise implementation. Helpful if you want
to use `bluebird` or if you don't intend to use an ES6 Promise shim.
#### Valid
```js
var Promise = require("bluebird");
var x = Promise.resolve("good");
```
#### Invalid
```js
var x = Promise.resolve("bad");
```
### Rule: `no-return-wrap`
Ensure that inside a `then()` or a `catch()` we always `return`
or `throw` a raw value instead of wrapping in `Promise.resolve`
or `Promise.reject`
#### Valid
```js
myPromise.then(function(val) {
return val * 2;
});
myPromise.then(function(val) {
throw "bad thing";
});
```
#### Invalid
```js
myPromise.then(function(val) {
return Promise.resolve(val * 2);
});
myPromise.then(function(val) {
return Promise.reject("bad thing");
})
```
#### Options
#### `allowReject`
Pass `{ allowReject: true }` as an option to this rule to permit wrapping returned values with `Promise.reject`, such as when you would use it as another way to reject the promise.
### Rule: `no-return-in-finally`
Disallow return statements inside a callback passed to `finally()`, since nothing would consume what's returned.
#### Valid
```js
myPromise.finally(function(val) {
console.log('value:', val);
});
```
#### Invalid
```js
myPromise.finally(function(val) {
return val;
})
```
## Etc
- (c) MMXV jden <jason@denizac.org> - ISC license.
- (c) 2016 Jamund Ferguson <jamund@gmail.com> - ISC license.
[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
[nodeify]: https://www.npmjs.com/package/nodeify
[pify]: https://www.npmjs.com/package/pify
[@macklinu]: https://github.com/macklinu
[@xjamundx]: https://github.com/xjamundx

@@ -1,2 +0,6 @@

function isFunctionWithBlockStatement (node) {
'use strict'
const getDocsUrl = require('./lib/get-docs-url')
function isFunctionWithBlockStatement(node) {
if (node.type === 'FunctionExpression') {

@@ -11,27 +15,25 @@ return true

function isThenCallExpression (node) {
function isThenCallExpression(node) {
return (
node.type === 'CallExpression' &&
node.callee.type === 'MemberExpression' &&
node.callee.property.name === 'then'
node.type === 'CallExpression' &&
node.callee.type === 'MemberExpression' &&
node.callee.property.name === 'then'
)
}
function isFirstArgument (node) {
function isFirstArgument(node) {
return (
node.parent &&
node.parent.arguments &&
node.parent.arguments[0] === node
node.parent && node.parent.arguments && node.parent.arguments[0] === node
)
}
function isInlineThenFunctionExpression (node) {
function isInlineThenFunctionExpression(node) {
return (
isFunctionWithBlockStatement(node) &&
isThenCallExpression(node.parent) &&
isFirstArgument(node)
isFunctionWithBlockStatement(node) &&
isThenCallExpression(node.parent) &&
isFirstArgument(node)
)
}
function hasParentReturnStatement (node) {
function hasParentReturnStatement(node) {
if (node && node.parent && node.parent.type) {

@@ -52,3 +54,3 @@ // if the parent is a then, and we haven't returned anything, fail

function peek (arr) {
function peek(arr) {
return arr[arr.length - 1]

@@ -58,3 +60,8 @@ }

module.exports = {
create: function (context) {
meta: {
docs: {
url: getDocsUrl('always-return')
}
},
create: function(context) {
// funcInfoStack is a stack representing the stack of currently executing

@@ -89,7 +96,7 @@ // functions

// loc: <loc> } } } ]
var funcInfoStack = []
const funcInfoStack = []
function markCurrentBranchAsGood () {
var funcInfo = peek(funcInfoStack)
var currentBranchID = peek(funcInfo.branchIDStack)
function markCurrentBranchAsGood() {
const funcInfo = peek(funcInfoStack)
const currentBranchID = peek(funcInfo.branchIDStack)
if (funcInfo.branchInfoMap[currentBranchID]) {

@@ -105,14 +112,14 @@ funcInfo.branchInfoMap[currentBranchID].good = true

onCodePathSegmentStart: function (segment, node) {
var funcInfo = peek(funcInfoStack)
onCodePathSegmentStart: function(segment, node) {
const funcInfo = peek(funcInfoStack)
funcInfo.branchIDStack.push(segment.id)
funcInfo.branchInfoMap[segment.id] = {good: false, node: node}
funcInfo.branchInfoMap[segment.id] = { good: false, node: node }
},
onCodePathSegmentEnd: function (segment, node) {
var funcInfo = peek(funcInfoStack)
onCodePathSegmentEnd: function(segment, node) {
const funcInfo = peek(funcInfoStack)
funcInfo.branchIDStack.pop()
},
onCodePathStart: function (path, node) {
onCodePathStart: function(path, node) {
funcInfoStack.push({

@@ -124,4 +131,4 @@ branchIDStack: [],

onCodePathEnd: function (path, node) {
var funcInfo = funcInfoStack.pop()
onCodePathEnd: function(path, node) {
const funcInfo = funcInfoStack.pop()

@@ -132,5 +139,5 @@ if (!isInlineThenFunctionExpression(node)) {

path.finalSegments.forEach((segment) => {
var id = segment.id
var branch = funcInfo.branchInfoMap[id]
path.finalSegments.forEach(segment => {
const id = segment.id
const branch = funcInfo.branchInfoMap[id]
if (!branch.good) {

@@ -142,5 +149,5 @@ if (hasParentReturnStatement(branch.node)) {

// check shortcircuit syntax like `x && x()` and `y || x()``
var prevSegments = segment.prevSegments
for (var ii = prevSegments.length - 1; ii >= 0; --ii) {
var prevSegment = prevSegments[ii]
const prevSegments = segment.prevSegments
for (let ii = prevSegments.length - 1; ii >= 0; --ii) {
const prevSegment = prevSegments[ii]
if (funcInfo.branchInfoMap[prevSegment.id].good) return

@@ -147,0 +154,0 @@ }

@@ -6,7 +6,18 @@ /**

module.exports = function (context) {
return {
NewExpression: function (node) {
if (node.callee.name === 'Promise') {
context.report(node, 'Avoid creating new promises.')
'use strict'
const getDocsUrl = require('./lib/get-docs-url')
module.exports = {
meta: {
docs: {
url: getDocsUrl('avoid-new')
}
},
create: function(context) {
return {
NewExpression: function(node) {
if (node.callee.name === 'Promise') {
context.report({ node, message: 'Avoid creating new promises.' })
}
}

@@ -13,0 +24,0 @@ }

@@ -7,9 +7,17 @@ /**

var isPromise = require('./lib/is-promise')
'use strict'
const getDocsUrl = require('./lib/get-docs-url')
const isPromise = require('./lib/is-promise')
module.exports = {
create: function (context) {
var options = context.options[0] || {}
var allowThen = options.allowThen
var terminationMethod = options.terminationMethod || 'catch'
meta: {
docs: {
url: getDocsUrl('catch-or-return')
}
},
create: function(context) {
const options = context.options[0] || {}
const allowThen = options.allowThen
let terminationMethod = options.terminationMethod || 'catch'

@@ -21,3 +29,3 @@ if (typeof terminationMethod === 'string') {

return {
ExpressionStatement: function (node) {
ExpressionStatement: function(node) {
if (!isPromise(node.expression)) {

@@ -28,3 +36,4 @@ return

// somePromise.then(a, b)
if (allowThen &&
if (
allowThen &&
node.expression.type === 'CallExpression' &&

@@ -39,3 +48,4 @@ node.expression.callee.type === 'MemberExpression' &&

// somePromise.catch()
if (node.expression.type === 'CallExpression' &&
if (
node.expression.type === 'CallExpression' &&
node.expression.callee.type === 'MemberExpression' &&

@@ -48,3 +58,4 @@ terminationMethod.indexOf(node.expression.callee.property.name) !== -1

// somePromise['catch']()
if (node.expression.type === 'CallExpression' &&
if (
node.expression.type === 'CallExpression' &&
node.expression.callee.type === 'MemberExpression' &&

@@ -57,3 +68,7 @@ node.expression.callee.property.type === 'Literal' &&

context.report(node, 'Expected ' + terminationMethod + '() or return')
context.report({
node,
message: 'Expected {{ terminationMethod }}() or return',
data: { terminationMethod }
})
}

@@ -60,0 +75,0 @@ }

@@ -7,6 +7,8 @@ /**

function hasPromiseCallback (node) {
'use strict'
function hasPromiseCallback(node) {
if (node.type !== 'CallExpression') return
if (node.callee.type !== 'MemberExpression') return
var propertyName = node.callee.property.name
const propertyName = node.callee.property.name
return propertyName === 'then' || propertyName === 'catch'

@@ -13,0 +15,0 @@ }

@@ -1,8 +0,10 @@

var isNamedCallback = require('./is-named-callback')
'use strict'
function isCallingBack (node, exceptions) {
var isCallExpression = node.type === 'CallExpression'
var callee = node.callee || {}
var nameIsCallback = isNamedCallback(callee.name, exceptions)
var isCB = isCallExpression && nameIsCallback
const isNamedCallback = require('./is-named-callback')
function isCallingBack(node, exceptions) {
const isCallExpression = node.type === 'CallExpression'
const callee = node.callee || {}
const nameIsCallback = isNamedCallback(callee.name, exceptions)
const isCB = isCallExpression && nameIsCallback
return isCB

@@ -9,0 +11,0 @@ }

@@ -1,5 +0,8 @@

var isInsidePromise = require('./is-inside-promise')
'use strict'
function isInsideCallback (node) {
var isCallExpression = node.type === 'FunctionExpression' ||
const isInsidePromise = require('./is-inside-promise')
function isInsideCallback(node) {
const isCallExpression =
node.type === 'FunctionExpression' ||
node.type === 'ArrowFunctionExpression' ||

@@ -11,5 +14,5 @@ node.type === 'FunctionDeclaration' // this may be controversial

var name = node.params && node.params[0] && node.params[0].name
var firstArgIsError = name === 'err' || name === 'error'
var isInACallback = isCallExpression && firstArgIsError
const name = node.params && node.params[0] && node.params[0].name
const firstArgIsError = name === 'err' || name === 'error'
const isInACallback = isCallExpression && firstArgIsError
return isInACallback

@@ -16,0 +19,0 @@ }

@@ -1,9 +0,12 @@

function isInsidePromise (node) {
var isFunctionExpression = node.type === 'FunctionExpression' ||
node.type === 'ArrowFunctionExpression'
var parent = node.parent || {}
var callee = parent.callee || {}
var name = callee.property && callee.property.name || ''
var parentIsPromise = name === 'then' || name === 'catch'
var isInCB = isFunctionExpression && parentIsPromise
'use strict'
function isInsidePromise(node) {
const isFunctionExpression =
node.type === 'FunctionExpression' ||
node.type === 'ArrowFunctionExpression'
const parent = node.parent || {}
const callee = parent.callee || {}
const name = (callee.property && callee.property.name) || ''
const parentIsPromise = name === 'then' || name === 'catch'
const isInCB = isFunctionExpression && parentIsPromise
return isInCB

@@ -10,0 +13,0 @@ }

@@ -1,10 +0,14 @@

var callbacks = ['done', 'cb', 'callback', 'next']
'use strict'
module.exports = function isNamedCallback (potentialCallbackName, exceptions) {
for (var i = 0; i < exceptions.length; i++) {
callbacks = callbacks.filter(function (item) { return item !== exceptions[i] })
let callbacks = ['done', 'cb', 'callback', 'next']
module.exports = function isNamedCallback(potentialCallbackName, exceptions) {
for (let i = 0; i < exceptions.length; i++) {
callbacks = callbacks.filter(function(item) {
return item !== exceptions[i]
})
}
return callbacks.some(function (trueCallbackName) {
return callbacks.some(function(trueCallbackName) {
return potentialCallbackName === trueCallbackName
})
}

@@ -5,32 +5,30 @@ /**

*/
var STATIC_METHODS = [
'all',
'race',
'reject',
'resolve'
]
'use strict'
function isPromise (expression) {
return ( // hello.then()
expression.type === 'CallExpression' &&
expression.callee.type === 'MemberExpression' &&
expression.callee.property.name === 'then'
) || ( // hello.catch()
expression.type === 'CallExpression' &&
expression.callee.type === 'MemberExpression' &&
expression.callee.property.name === 'catch'
) || ( // hello.finally()
expression.type === 'CallExpression' &&
expression.callee.type === 'MemberExpression' &&
expression.callee.property.name === 'finally'
) || ( // somePromise.ANYTHING()
expression.type === 'CallExpression' &&
expression.callee.type === 'MemberExpression' &&
isPromise(expression.callee.object)
) || ( // Promise.STATIC_METHOD()
expression.type === 'CallExpression' &&
expression.callee.type === 'MemberExpression' &&
expression.callee.object.type === 'Identifier' &&
expression.callee.object.name === 'Promise' &&
STATIC_METHODS.indexOf(expression.callee.property.name) !== -1
const PROMISE_STATICS = require('./promise-statics')
function isPromise(expression) {
return (
// hello.then()
(expression.type === 'CallExpression' &&
expression.callee.type === 'MemberExpression' &&
expression.callee.property.name === 'then') ||
// hello.catch()
(expression.type === 'CallExpression' &&
expression.callee.type === 'MemberExpression' &&
expression.callee.property.name === 'catch') ||
// hello.finally()
(expression.type === 'CallExpression' &&
expression.callee.type === 'MemberExpression' &&
expression.callee.property.name === 'finally') ||
// somePromise.ANYTHING()
(expression.type === 'CallExpression' &&
expression.callee.type === 'MemberExpression' &&
isPromise(expression.callee.object)) ||
// Promise.STATIC_METHOD()
(expression.type === 'CallExpression' &&
expression.callee.type === 'MemberExpression' &&
expression.callee.object.type === 'Identifier' &&
expression.callee.object.name === 'Promise' &&
PROMISE_STATICS.indexOf(expression.callee.property.name) !== -1)
)

@@ -37,0 +35,0 @@ }

@@ -6,27 +6,49 @@ /**

var hasPromiseCallback = require('./lib/has-promise-callback')
var isInsidePromise = require('./lib/is-inside-promise')
var isCallback = require('./lib/is-callback')
'use strict'
module.exports = function (context) {
return {
CallExpression: function (node) {
var options = context.options[0] || {}
var exceptions = options.exceptions || []
if (!isCallback(node, exceptions)) {
// in general we send you packing if you're not a callback
// but we also need to watch out for whatever.then(cb)
if (hasPromiseCallback(node)) {
var name = node.arguments && node.arguments[0] && node.arguments[0].name
if (name === 'callback' || name === 'cb' || name === 'next' || name === 'done') {
context.report(node.arguments[0], 'Avoid calling back inside of a promise.')
const getDocsUrl = require('./lib/get-docs-url')
const hasPromiseCallback = require('./lib/has-promise-callback')
const isInsidePromise = require('./lib/is-inside-promise')
const isCallback = require('./lib/is-callback')
module.exports = {
meta: {
docs: {
url: getDocsUrl('no-callback-in-promise')
}
},
create: function(context) {
return {
CallExpression: function(node) {
const options = context.options[0] || {}
const exceptions = options.exceptions || []
if (!isCallback(node, exceptions)) {
// in general we send you packing if you're not a callback
// but we also need to watch out for whatever.then(cb)
if (hasPromiseCallback(node)) {
const name =
node.arguments && node.arguments[0] && node.arguments[0].name
if (
name === 'callback' ||
name === 'cb' ||
name === 'next' ||
name === 'done'
) {
context.report({
node: node.arguments[0],
message: 'Avoid calling back inside of a promise.'
})
}
}
return
}
return
if (context.getAncestors().some(isInsidePromise)) {
context.report({
node,
message: 'Avoid calling back inside of a promise.'
})
}
}
if (context.getAncestors().some(isInsidePromise)) {
context.report(node, 'Avoid calling back inside of a promise.')
}
}
}
}

@@ -6,4 +6,6 @@ // Borrowed from here:

function isDeclared (scope, ref) {
return scope.variables.some(function (variable) {
const getDocsUrl = require('./lib/get-docs-url')
function isDeclared(scope, ref) {
return scope.variables.some(function(variable) {
if (variable.name !== ref.identifier.name) {

@@ -22,4 +24,9 @@ return false

module.exports = {
create: function (context) {
var MESSAGE = '"{{name}}" is not defined.'
meta: {
docs: {
url: getDocsUrl('no-native')
}
},
create: function(context) {
const MESSAGE = '"{{name}}" is not defined.'

@@ -34,6 +41,6 @@ /**

return {
'Program:exit': function () {
var scope = context.getScope()
'Program:exit': function() {
const scope = context.getScope()
scope.implicit.left.forEach(function (ref) {
scope.implicit.left.forEach(function(ref) {
if (ref.identifier.name !== 'Promise') {

@@ -44,3 +51,7 @@ return

if (!isDeclared(scope, ref)) {
context.report(ref.identifier, MESSAGE, { name: ref.identifier.name })
context.report({
node: ref.identifier,
message: MESSAGE,
data: { name: ref.identifier.name }
})
}

@@ -47,0 +58,0 @@ })

@@ -6,11 +6,21 @@ /**

var hasPromiseCallback = require('./lib/has-promise-callback')
var isInsidePromise = require('./lib/is-inside-promise')
'use strict'
module.exports = function (context) {
return {
CallExpression: function (node) {
if (!hasPromiseCallback(node)) return
if (context.getAncestors().some(isInsidePromise)) {
context.report(node, 'Avoid nesting promises.')
const getDocsUrl = require('./lib/get-docs-url')
const hasPromiseCallback = require('./lib/has-promise-callback')
const isInsidePromise = require('./lib/is-inside-promise')
module.exports = {
meta: {
docs: {
url: getDocsUrl('no-nesting')
}
},
create: function(context) {
return {
CallExpression: function(node) {
if (!hasPromiseCallback(node)) return
if (context.getAncestors().some(isInsidePromise)) {
context.report({ node, message: 'Avoid nesting promises.' })
}
}

@@ -17,0 +27,0 @@ }

@@ -6,19 +6,32 @@ /**

var isPromise = require('./lib/is-promise')
var isInsideCallback = require('./lib/is-inside-callback')
'use strict'
module.exports = function (context) {
return {
CallExpression: function (node) {
if (!isPromise(node)) return
const getDocsUrl = require('./lib/get-docs-url')
const isPromise = require('./lib/is-promise')
const isInsideCallback = require('./lib/is-inside-callback')
// if i'm returning the promise, it's probably not really a callback
// function, and I should be okay....
if (node.parent.type === 'ReturnStatement') return
module.exports = {
meta: {
docs: {
url: getDocsUrl('no-promise-in-callback')
}
},
create: function(context) {
return {
CallExpression: function(node) {
if (!isPromise(node)) return
// what about if the parent is an ArrowFunctionExpression
// would that imply an implicit return?
// if i'm returning the promise, it's probably not really a callback
// function, and I should be okay....
if (node.parent.type === 'ReturnStatement') return
if (context.getAncestors().some(isInsideCallback)) {
context.report(node.callee, 'Avoid using promises inside of callbacks.')
// what about if the parent is an ArrowFunctionExpression
// would that imply an implicit return?
if (context.getAncestors().some(isInsideCallback)) {
context.report({
node: node.callee,
message: 'Avoid using promises inside of callbacks.'
})
}
}

@@ -25,0 +38,0 @@ }

@@ -1,12 +0,36 @@

var isPromise = require('./lib/is-promise')
'use strict'
const getDocsUrl = require('./lib/get-docs-url')
const isPromise = require('./lib/is-promise')
module.exports = {
create: function (context) {
meta: {
docs: {
url: getDocsUrl('no-return-in-finally')
}
},
create: function(context) {
return {
CallExpression: function (node) {
CallExpression: function(node) {
if (isPromise(node)) {
if (node.callee && node.callee.property && node.callee.property.name === 'finally') {
if (node.arguments && node.arguments[0] && node.arguments[0].body && node.arguments[0].body.body) {
if (node.arguments[0].body.body.some(function (statement) { return statement.type === 'ReturnStatement' })) {
context.report(node.callee.property, 'No return in finally')
if (
node.callee &&
node.callee.property &&
node.callee.property.name === 'finally'
) {
if (
node.arguments &&
node.arguments[0] &&
node.arguments[0].body &&
node.arguments[0].body.body
) {
if (
node.arguments[0].body.body.some(function(statement) {
return statement.type === 'ReturnStatement'
})
) {
context.report({
node: node.callee.property,
message: 'No return in finally'
})
}

@@ -13,0 +37,0 @@ }

@@ -9,8 +9,9 @@ /**

var isPromise = require('./lib/is-promise')
var rejectMessage = 'Expected throw instead of Promise.reject'
var resolveMessage = 'Avoid wrapping return values in Promise.resolve'
const getDocsUrl = require('./lib/get-docs-url')
const isPromise = require('./lib/is-promise')
const rejectMessage = 'Expected throw instead of Promise.reject'
const resolveMessage = 'Avoid wrapping return values in Promise.resolve'
function isInPromise (context) {
var expression = context.getAncestors().filter(function (node) {
function isInPromise(context) {
const expression = context.getAncestors().filter(function(node) {
return node.type === 'ExpressionStatement'

@@ -22,8 +23,13 @@ })[0]

module.exports = {
create: function (context) {
var options = context.options[0] || {}
var allowReject = options.allowReject
meta: {
docs: {
url: getDocsUrl('no-return-wrap')
}
},
create: function(context) {
const options = context.options[0] || {}
const allowReject = options.allowReject
return {
ReturnStatement: function (node) {
ReturnStatement: function(node) {
if (isInPromise(context)) {

@@ -35,5 +41,8 @@ if (node.argument) {

if (node.argument.callee.property.name === 'resolve') {
context.report(node, resolveMessage)
} else if (!allowReject && node.argument.callee.property.name === 'reject') {
context.report(node, rejectMessage)
context.report({ node, message: resolveMessage })
} else if (
!allowReject &&
node.argument.callee.property.name === 'reject'
) {
context.report({ node, message: rejectMessage })
}

@@ -40,0 +49,0 @@ }

@@ -0,16 +1,37 @@

'use strict'
const getDocsUrl = require('./lib/get-docs-url')
module.exports = {
create: function (context) {
meta: {
docs: {
url: getDocsUrl('param-names')
},
fixable: 'code'
},
create(context) {
return {
NewExpression: function (node) {
NewExpression(node) {
if (node.callee.name === 'Promise' && node.arguments.length === 1) {
var params = node.arguments[0].params
const params = node.arguments[0].params
if (!params || !params.length) { return }
if (params[0].name !== 'resolve') {
return context.report(node, 'Promise constructor parameters must be named resolve, reject')
if (!params || !params.length) {
return
}
if (params[1] && params[1].name !== 'reject') {
return context.report(node, 'Promise constructor parameters must be named resolve, reject')
if (
params[0].name !== 'resolve' ||
(params[1] && params[1].name !== 'reject')
) {
context.report({
node,
message:
'Promise constructor parameters must be named resolve, reject',
fix(fixer) {
return [
fixer.replaceText(params[0], 'resolve'),
params[1] && fixer.replaceText(params[1], 'reject')
].filter(Boolean)
}
})
}

@@ -17,0 +38,0 @@ }

@@ -6,41 +6,60 @@ /**

var errorMessage = 'Avoid callbacks. Prefer Async/Await.'
'use strict'
module.exports = function (context) {
function checkLastParamsForCallback (node) {
var len = node.params.length - 1
var lastParam = node.params[len]
if (lastParam && (lastParam.name === 'callback' || lastParam.name === 'cb')) {
context.report(lastParam, errorMessage)
const getDocsUrl = require('./lib/get-docs-url')
const errorMessage = 'Avoid callbacks. Prefer Async/Await.'
module.exports = {
meta: {
docs: {
url: getDocsUrl('prefer-await-to-callbacks')
}
}
function isInsideYieldOrAwait () {
return context.getAncestors().some(function (parent) {
return parent.type === 'AwaitExpression' || parent.type === 'YieldExpression'
})
}
return {
CallExpression: function (node) {
// callbacks aren't allowed
if (node.callee.name === 'cb' || node.callee.name === 'callback') {
context.report(node, errorMessage)
return
},
create: function(context) {
function checkLastParamsForCallback(node) {
const len = node.params.length - 1
const lastParam = node.params[len]
if (
lastParam &&
(lastParam.name === 'callback' || lastParam.name === 'cb')
) {
context.report({ node: lastParam, message: errorMessage })
}
}
function isInsideYieldOrAwait() {
return context.getAncestors().some(function(parent) {
return (
parent.type === 'AwaitExpression' || parent.type === 'YieldExpression'
)
})
}
return {
CallExpression: function(node) {
// callbacks aren't allowed
if (node.callee.name === 'cb' || node.callee.name === 'callback') {
context.report({ node, message: errorMessage })
return
}
// thennables aren't allowed either
var args = node.arguments
var num = args.length - 1
var arg = num > -1 && node.arguments && node.arguments[num]
if (arg && arg.type === 'FunctionExpression' || arg.type === 'ArrowFunctionExpression') {
if (arg.params && arg.params[0] && arg.params[0].name === 'err') {
if (!isInsideYieldOrAwait()) {
context.report(arg, errorMessage)
// thennables aren't allowed either
const args = node.arguments
const num = args.length - 1
const arg = num > -1 && node.arguments && node.arguments[num]
if (
(arg && arg.type === 'FunctionExpression') ||
arg.type === 'ArrowFunctionExpression'
) {
if (arg.params && arg.params[0] && arg.params[0].name === 'err') {
if (!isInsideYieldOrAwait()) {
context.report({ node: arg, message: errorMessage })
}
}
}
}
},
FunctionDeclaration: checkLastParamsForCallback,
FunctionExpression: checkLastParamsForCallback,
ArrowFunctionExpression: checkLastParamsForCallback
},
FunctionDeclaration: checkLastParamsForCallback,
FunctionExpression: checkLastParamsForCallback,
ArrowFunctionExpression: checkLastParamsForCallback
}
}
}

@@ -6,15 +6,34 @@ /**

module.exports = function (context) {
return {
MemberExpression: function (node) {
// you can then() if you are inside of a yield or await
if (context.getAncestors().some(function (parent) {
return parent.type === 'AwaitExpression' || parent.type === 'YieldExpression'
})) {
return
}
'use strict'
// if you're a then expression then you're probably a promise
if (node.property && node.property.name === 'then') {
context.report(node.property, 'Prefer await to then().')
const getDocsUrl = require('./lib/get-docs-url')
module.exports = {
meta: {
docs: {
url: getDocsUrl('prefer-await-to-then')
}
},
create: function(context) {
return {
MemberExpression: function(node) {
// you can then() if you are inside of a yield or await
if (
context.getAncestors().some(function(parent) {
return (
parent.type === 'AwaitExpression' ||
parent.type === 'YieldExpression'
)
})
) {
return
}
// if you're a then expression then you're probably a promise
if (node.property && node.property.name === 'then') {
context.report({
node: node.property,
message: 'Prefer await to then().'
})
}
}

@@ -21,0 +40,0 @@ }

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc