diff --git a/README.md b/README.md index 9fa9344e..73f63e03 100644 --- a/README.md +++ b/README.md @@ -14,18 +14,6 @@ Enforce best practices for JavaScript promises. * [Installation](#installation) * [Usage](#usage) * [Rules](#rules) - * [`catch-or-return`](#catch-or-return) - * [`no-return-wrap`](#no-return-wrap) - * [`param-names`](#param-names) - * [`always-return`](#always-return) - * [`no-native`](#no-native) - * [`no-nesting`](#no-nesting) - * [`no-promise-in-callback`](#no-promise-in-callback) - * [`no-callback-in-promise`](#no-callback-in-promise) - * [`avoid-new`](#avoid-new) - * [`no-return-in-finally`](#no-return-in-finally) - * [`prefer-await-to-then`](#prefer-await-to-then) - * [`prefer-await-to-callbacks`](#prefer-await-to-callbacks) * [Maintainers](#maintainers) * [License](#license) @@ -88,20 +76,20 @@ or start with the recommended rule set ## Rules -| rule | description | recommended | fixable | -| --------------------------- | -------------------------------------------------------------------------------- | ----------- | -------- | -| `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: | :wrench: | -| `always-return` | Return inside each `then()` to create readable and reusable Promise chains. | :bangbang: | | -| `no-native` | In an ES5 environment, make sure to create a `Promise` constructor before using. | | | -| `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()` | :warning: | | -| `prefer-await-to-then` | Prefer `await` to `then()` for reading Promise values | :seven: | | -| `prefer-await-to-callbacks` | Prefer async/await to the callback pattern | :seven: | | +| 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-return-in-finally`][no-return-in-finally] | Disallow return statements in `finally()` | :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: | | **Key** @@ -112,232 +100,6 @@ or start with the recommended rule set | :seven: | ES2017 Async Await rules | | :wrench: | Rule is fixable with `eslint --fix` | -### `catch-or-return` - -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. - -#### Valid - -```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) -``` - -### `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. - -### `param-names` - -Enforce standard parameter names for Promise constructors - -:wrench: The `--fix` option on the command line can automatically fix some of -the problems reported by this rule. - -#### 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. - -### `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() - } -}) -``` - -### `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') -``` - -### `no-nesting` - -Avoid nested `then()` or `catch()` statements - -### `no-promise-in-callback` - -Avoid using promises inside of callbacks - -### `no-callback-in-promise` - -Avoid calling `cb()` inside of a `then()` (use [nodeify][] instead) - -### `avoid-new` - -Avoid creating `new` promises outside of utility libs (use [pify][] instead) - -### `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 -}) -``` - -### `prefer-await-to-then` - -Prefer `await` to `then()` for reading Promise values - -### `prefer-await-to-callbacks` - -Prefer async/await to the callback pattern - ## Maintainers * Jamund Ferguson - [@xjamundx][] @@ -348,6 +110,18 @@ Prefer async/await to the callback pattern * (c) MMXV jden - ISC license. * (c) 2016 Jamund Ferguson - 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-return-in-finally]: docs/rules/no-return-in-finally.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 diff --git a/docs/rules/always-return.md b/docs/rules/always-return.md new file mode 100644 index 00000000..40527ec5 --- /dev/null +++ b/docs/rules/always-return.md @@ -0,0 +1,33 @@ +# Return inside each `then()` to create readable and reusable Promise chains (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() + } +}) +``` diff --git a/docs/rules/avoid-new.md b/docs/rules/avoid-new.md new file mode 100644 index 00000000..387623e9 --- /dev/null +++ b/docs/rules/avoid-new.md @@ -0,0 +1,3 @@ +# Avoid creating `new` promises outside of utility libs (use [pify][] instead) (avoid-new) + +[pify]: https://www.npmjs.com/package/pify diff --git a/docs/rules/catch-or-return.md b/docs/rules/catch-or-return.md new file mode 100644 index 00000000..30f1f768 --- /dev/null +++ b/docs/rules/catch-or-return.md @@ -0,0 +1,64 @@ +# Enforces the use of `catch()` on un-returned promises (catch-or-return) + +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. + +#### Valid + +```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) +``` diff --git a/docs/rules/no-callback-in-promise.md b/docs/rules/no-callback-in-promise.md new file mode 100644 index 00000000..5ae63cb1 --- /dev/null +++ b/docs/rules/no-callback-in-promise.md @@ -0,0 +1,3 @@ +# Avoid calling `cb()` inside of a `then()` (use [nodeify][] instead) (no-callback-in-promise) + +[nodeify]: https://www.npmjs.com/package/nodeify diff --git a/docs/rules/no-native.md b/docs/rules/no-native.md new file mode 100644 index 00000000..104dc297 --- /dev/null +++ b/docs/rules/no-native.md @@ -0,0 +1,18 @@ +# In an ES5 environment, make sure to create a `Promise` constructor before using (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') +``` diff --git a/docs/rules/no-nesting.md b/docs/rules/no-nesting.md new file mode 100644 index 00000000..1f459954 --- /dev/null +++ b/docs/rules/no-nesting.md @@ -0,0 +1 @@ +# Avoid nested `then()` or `catch()` statements (no-nesting) diff --git a/docs/rules/no-promise-in-callback.md b/docs/rules/no-promise-in-callback.md new file mode 100644 index 00000000..a5d56b5a --- /dev/null +++ b/docs/rules/no-promise-in-callback.md @@ -0,0 +1 @@ +# Avoid using promises inside of callbacks (no-promise-in-callback) diff --git a/docs/rules/no-return-in-finally.md b/docs/rules/no-return-in-finally.md new file mode 100644 index 00000000..8188f529 --- /dev/null +++ b/docs/rules/no-return-in-finally.md @@ -0,0 +1,20 @@ +# Disallow return statements in `finally()` (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 +}) +``` diff --git a/docs/rules/no-return-wrap.md b/docs/rules/no-return-wrap.md new file mode 100644 index 00000000..54194606 --- /dev/null +++ b/docs/rules/no-return-wrap.md @@ -0,0 +1,62 @@ +# Avoid wrapping values in `Promise.resolve` or `Promise.reject` when not needed (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. + +### `param-names` + +Enforce standard parameter names for Promise constructors + +:wrench: The `--fix` option on the command line can automatically fix some of +the problems reported by this rule. + +#### 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. diff --git a/docs/rules/param-names.md b/docs/rules/param-names.md new file mode 100644 index 00000000..5e201109 --- /dev/null +++ b/docs/rules/param-names.md @@ -0,0 +1 @@ +# Enforce consistent param names when creating new promises (param-names) diff --git a/docs/rules/prefer-await-to-callbacks.md b/docs/rules/prefer-await-to-callbacks.md new file mode 100644 index 00000000..ae61b4ba --- /dev/null +++ b/docs/rules/prefer-await-to-callbacks.md @@ -0,0 +1 @@ +# Prefer async/await to the callback pattern (prefer-await-to-callbacks) diff --git a/docs/rules/prefer-await-to-then.md b/docs/rules/prefer-await-to-then.md new file mode 100644 index 00000000..6ce3270b --- /dev/null +++ b/docs/rules/prefer-await-to-then.md @@ -0,0 +1 @@ +# Prefer `await` to `then()` for reading Promise values (prefer-await-to-then) diff --git a/rules/lib/.eslintrc.json b/rules/lib/.eslintrc.json deleted file mode 100644 index ee242439..00000000 --- a/rules/lib/.eslintrc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rules": { - "eslint-plugin/require-meta-docs-url": "off" - } -} diff --git a/rules/lib/get-docs-url.js b/rules/lib/get-docs-url.js index a96fb749..4ba7b5dc 100644 --- a/rules/lib/get-docs-url.js +++ b/rules/lib/get-docs-url.js @@ -13,7 +13,7 @@ const REPO_URL = 'https://github.com/xjamundx/eslint-plugin-promise' * @returns {string} URL to the documentation for the given rule */ function getDocsUrl(ruleName) { - return `${REPO_URL}/tree/v${pkg.version}#${ruleName}` + return `${REPO_URL}/tree/v${pkg.version}/docs/rules/${ruleName}.md` } module.exports = getDocsUrl