Repository: eslint/eslint
Pull request #11027 (2018-10-28 15:09:53)

Build: Add karma-chrome-launcher support
<!--
    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).
-->

**What is the purpose of this pull request? (put an "X" next to item)**

[ ] Documentation update
[ ] Bug fix ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/bug-report.md))
[ ] New rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-proposal.md))
[ ] Changes an existing rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-change-proposal.md))
[ ] Add autofixing to a rule
[ ] Add a CLI option
[ ] Add something to the core
[x ] Other, please explain:

<!--
    If the item you've checked above has a template, please paste the template questions below and answer them. (If this pull request is addressing an issue, you can just paste a link to the issue here instead.)
-->

<!--
    Please ensure your pull request is ready:

    - Read the pull request guide (https://eslint.org/docs/developer-guide/contributing/pull-requests)
    - Include tests for this change
    - Update documentation for this change (if appropriate)
-->

<!--
    The following is required for all pull requests:
-->

**What changes did you make? (Give an overview)**
the change was merged in https://github.com/eslint/eslint/pull/10898, but was reverted in https://github.com/eslint/eslint/pull/10973, due to a release build failing on Jenkins.

the change added it back again, and added `puppeteer ` in dev, to fix the build failing.



**Is there anything you'd like reviewers to focus on?**

what can we do to make sure it fixed the issue? (e.g. run on Jenkins)


Aladdin-ADD: I think it was discussed in https://github.com/eslint/eslint/pull/10898. it was introduced as Phantomjs no longer being maintained, than to help validate our unofficial browser capability.

Patch:
diff --git a/.eslintrc.js b/.eslintrc.js
index 793772f08..780368769 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -21,10 +21,10 @@ module.exports = {
         "eslint-plugin/prefer-output-null": "error",
         "eslint-plugin/prefer-placeholders": "error",
         "eslint-plugin/report-message-format": ["error", "[^a-z].*\\.$"],
+        "eslint-plugin/require-meta-type": "error",
         "eslint-plugin/test-case-property-ordering": "error",
         "eslint-plugin/test-case-shorthand-strings": "error",
-        "rulesdir/multiline-comment-style": "error",
-        "rulesdir/no-useless-catch": "error"
+        "rulesdir/multiline-comment-style": "error"
     },
     overrides: [
         {
diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.md b/.github/ISSUE_TEMPLATE/BUG_REPORT.md
index a614d6b2f..1132aab25 100644
--- a/.github/ISSUE_TEMPLATE/BUG_REPORT.md
+++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.md
@@ -1,6 +1,9 @@
 ---
 name: "\U0001F41E  Bug report"
 about: Report an issue with ESLint or rules bundled with ESLint
+title: ''
+labels: bug, triage
+assignees: ''
 
 ---
 
@@ -56,5 +59,3 @@ about: Report an issue with ESLint or rules bundled with ESLint
 
 
 **Are you willing to submit a pull request to fix this bug?**
-
-
diff --git a/.github/ISSUE_TEMPLATE/CHANGE.md b/.github/ISSUE_TEMPLATE/CHANGE.md
index 3fe2fe241..6cf642542 100644
--- a/.github/ISSUE_TEMPLATE/CHANGE.md
+++ b/.github/ISSUE_TEMPLATE/CHANGE.md
@@ -1,6 +1,9 @@
 ---
 name: "\U0001F4DD Non-rule change request"
 about: Request a change that is not a bug fix, rule change, or new rule
+title: ''
+labels: enhancement, triage, core
+assignees: ''
 
 ---
 
@@ -27,4 +30,3 @@ about: Request a change that is not a bug fix, rule change, or new rule
 
 
 **Are you willing to submit a pull request to implement this change?**
-
diff --git a/.github/ISSUE_TEMPLATE/NEW_RULE.md b/.github/ISSUE_TEMPLATE/NEW_RULE.md
index 5a50001b0..598e89c0f 100644
--- a/.github/ISSUE_TEMPLATE/NEW_RULE.md
+++ b/.github/ISSUE_TEMPLATE/NEW_RULE.md
@@ -1,6 +1,9 @@
 ---
-/name: "\U0001F680 New rule proposal"
+name: "\U0001F680 New rule proposal"
 about: Propose a new rule to be added to ESLint
+title: ''
+labels: triage, rule, feature
+assignees: ''
 
 ---
 
@@ -37,4 +40,3 @@ about: Propose a new rule to be added to ESLint
 
 
 **Are you willing to submit a pull request to implement this rule?**
-
diff --git a/.github/ISSUE_TEMPLATE/QUESTION.md b/.github/ISSUE_TEMPLATE/QUESTION.md
index ba96b4104..375e2170a 100644
--- a/.github/ISSUE_TEMPLATE/QUESTION.md
+++ b/.github/ISSUE_TEMPLATE/QUESTION.md
@@ -1,6 +1,9 @@
 ---
 name: "⛔ Question"
 about: Please go to https://gitter.im/eslint/eslint
+title: ''
+labels: ''
+assignees: ''
 
 ---
 
diff --git a/.github/ISSUE_TEMPLATE/RULE_CHANGE.md b/.github/ISSUE_TEMPLATE/RULE_CHANGE.md
index 9ecb2d002..d735010f6 100644
--- a/.github/ISSUE_TEMPLATE/RULE_CHANGE.md
+++ b/.github/ISSUE_TEMPLATE/RULE_CHANGE.md
@@ -1,6 +1,9 @@
 ---
 name: "\U0001F4DD Rule change request"
 about: Request a change to an existing rule
+title: ''
+labels: enhancement, triage, rule
+assignees: ''
 
 ---
 
@@ -34,4 +37,4 @@ about: Request a change to an existing rule
 
 **What will the rule do after it's changed?**
 
-**Are you willing to submit a pull request to implement this change?**
\ No newline at end of file
+**Are you willing to submit a pull request to implement this change?**
diff --git a/.github/ISSUE_TEMPLATE/SECURITY.md b/.github/ISSUE_TEMPLATE/SECURITY.md
index 8cc33ec6e..c04f52536 100644
--- a/.github/ISSUE_TEMPLATE/SECURITY.md
+++ b/.github/ISSUE_TEMPLATE/SECURITY.md
@@ -1,6 +1,9 @@
 ---
 name: "⛔ Security issue"
 about: Please file security issues at https://hackerone.com/eslint
+title: ''
+labels: ''
+assignees: ''
 
 ---
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f91359ef4..eb63794e1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,68 @@
+v5.11.1 - December 26, 2018
+
+* [`de79f10`](https://github.com/eslint/eslint/commit/de79f1026b7035f0296d7876f1db64f225cca1b8) Fix: handle optional catch bindings in no-useless-catch (#11205) (Colin Ihrig)
+
+v5.11.0 - December 22, 2018
+
+* [`b4395f6`](https://github.com/eslint/eslint/commit/b4395f671442a7e0be956382c24cce38025a6df6) New: add option `first` for VariableDeclarator in indent (fixes #8976) (#11193) (Pig Fang)
+* [`2b5a602`](https://github.com/eslint/eslint/commit/2b5a60284670a3ab1281b206941ed38faf2ea10c) New: no-useless-catch rule (fixes #11174) (#11198) (Alexander Grasley)
+* [`06b3b5b`](https://github.com/eslint/eslint/commit/06b3b5bfcf0429c5078d4f4af3c03bb777e4f022) Fix: Account for comments in implicit-arrow-linebreak (#10545) (Mark de Dios)
+* [`4242314`](https://github.com/eslint/eslint/commit/4242314215a6f35e432860433906f47af1a29724) Update: handle computed properties in camelcase (fixes #11084) (#11113) (Bence Dányi)
+* [`1009304`](https://github.com/eslint/eslint/commit/100930493d9ab802a94dac5c761515b12241ddd2) Docs: add a note for no-unused-expressions (fixes #11169) (#11192) (Pig Fang)
+* [`88f99d3`](https://github.com/eslint/eslint/commit/88f99d31b88a4cde4563bc4a6f4c41f0cc557885) Docs: clarify how to use configs in plugins (#11199) (Kai Cataldo)
+* [`bcf558b`](https://github.com/eslint/eslint/commit/bcf558b2f7036f487af2bdb2b2d34b6cdf7fc174) Docs: Clarify the no-unused-vars docs (#11195) (Jed Fox)
+* [`a470eb7`](https://github.com/eslint/eslint/commit/a470eb73d52fae0f0bc48de5a487e23cf78fcfa9) Docs: Fix no-irregular-whitespace description (#11196) (Jed Fox)
+* [`8abc8af`](https://github.com/eslint/eslint/commit/8abc8afe71691b747cbd1819a13d896e8aa5b92a) Docs: Remove a misleading example (#11204) (Bogdan Gradinariu)
+* [`733d936`](https://github.com/eslint/eslint/commit/733d93618a99758a05453ab94505a9f1330950e0) Docs: link to JSDoc EOL blogpost in valid-jsdoc and require-jsdoc (#11191) (Nathan Diddle)
+* [`d5eb108`](https://github.com/eslint/eslint/commit/d5eb108e17f676d0e4fcddeb1211b4bdfac760c1) Docs: Ensure `triage` label is added to new issues (#11182) (Teddy Katz)
+* [`617a287`](https://github.com/eslint/eslint/commit/617a2874ed085bca36ca289aac55e3b7f7ce937e) Docs: add missing deprecation notices for jsdoc rules (#11171) (Teddy Katz)
+
+v5.10.0 - December 8, 2018
+
+* [`4b0f517`](https://github.com/eslint/eslint/commit/4b0f517cd317e5f1b99a1e8a0392332bd8a2e231) Upgrade: single- and multiline const, let, var statements (fixes #10721) (#10919) (Tom Panier)
+* [`9666aba`](https://github.com/eslint/eslint/commit/9666abaf46c841fba7b5d4e53c6998cd25b9bc33) Update: space-infix-ops reports violating operator (#10934) (Bence Dányi)
+* [`c14f717`](https://github.com/eslint/eslint/commit/c14f717f4c32860766185da47f64f8eb0c2d2998) Fix: Update all-files-ignored.txt message to be less confusing (#11075) (z.ky)
+* [`9f3573d`](https://github.com/eslint/eslint/commit/9f3573dda3dc35bc220e945686cc835eaad0ac2c) Docs: Clarify the CLIEngine options (#10995) (Ed Morley)
+* [`dd7b0cb`](https://github.com/eslint/eslint/commit/dd7b0cb019d94964930d30fec36f7b22ef072822) Chore: refactor template literal feature detection in 'quotes' rule (#11125) (Bryan)
+* [`3bf0332`](https://github.com/eslint/eslint/commit/3bf0332508b921cb660c2e8a1ab7ddf46a2013b6) Fix: fix the fixer of lone comma with comments (fixes #10632) (#11154) (Pig Fang)
+* [`f850726`](https://github.com/eslint/eslint/commit/f8507260c2091d18488fde20e466639d1a7f913c) Upgrade: Espree v5.0.0 (#11161) (Kai Cataldo)
+* [`4490d7a`](https://github.com/eslint/eslint/commit/4490d7af529d4ecc18b6874f1d838869656da58a) Update: deprecate valid-jsdoc and require-jsdoc (#11145) (Teddy Katz)
+* [`60dfb6c`](https://github.com/eslint/eslint/commit/60dfb6c623dfe829e5350dabe507e7850c1beacf) Docs: Update issue templates (#11163) (Teddy Katz)
+* [`958987a`](https://github.com/eslint/eslint/commit/958987aa6f5630faa051d8f822f0200faff41924) Docs: Fix link to rule no-useless-rename (#11165) (Brian)
+* [`62fd2b9`](https://github.com/eslint/eslint/commit/62fd2b93448966331db3eb2dfbe4e1273eb032b2) Update: Amend keyword-spacing to validate `default` keywords (#11097) (Bin Ury)
+* [`4bcdfd0`](https://github.com/eslint/eslint/commit/4bcdfd07d514fd7a6b8672d33703d0b6c606f214) Chore: fix some jsdoc-related issues (#11148) (薛定谔的猫)
+* [`c6471ed`](https://github.com/eslint/eslint/commit/c6471ed6feb3e71e239379a7042deb9b8ab3cf39) Docs: fix typo in issue-templates/new-rule (#11149) (薛定谔的猫)
+* [`5d451c5`](https://github.com/eslint/eslint/commit/5d451c510c15abc41b5bb14b4955a7db96aeb100) Chore: Remove dependency on is-resolvable (#11128) (Matt Grande)
+* [`bc50dc7`](https://github.com/eslint/eslint/commit/bc50dc7737496712463220e662946eb516e36ae1) Chore: Move ignored-paths, report-translator to lib/util (refs #10559) (#11116) (Kevin Partington)
+* [`c0a80d0`](https://github.com/eslint/eslint/commit/c0a80d0ca3c80ca27694fc8aedcf84b72bfd9465) Fix: Do not strip underscores in camelcase allow (fixes #11000) (#11001) (Luke Page)
+* [`a675c89`](https://github.com/eslint/eslint/commit/a675c89573836adaf108a932696b061946abf1e6) Docs: (Grammar) "the setup" -> "to set up" (#11117) (MarvinJWendt)
+* [`54dfa60`](https://github.com/eslint/eslint/commit/54dfa602f62e6d183d57d60d5fdd417a263f479e) Fix: Typo in function comment parameters (#11111) (Pierre Maoui)
+* [`cf296bd`](https://github.com/eslint/eslint/commit/cf296bdabf0dbbfbae491419e38aee4ecd63ec71) Docs: switch incorrect example with correct one (#11107) (Romain Le Quellec)
+* [`d2d500c`](https://github.com/eslint/eslint/commit/d2d500ca5dff307189b9d4161a5e7b8282557dd6) Docs: no-console#When-Not-To-Use provides incorrect rule snippet (#11093) (Lawrence Chou)
+* [`f394a1d`](https://github.com/eslint/eslint/commit/f394a1dfc5eb4874f899b7bc19685896893af7b8) Chore: Extract config comment parsing (#11091) (Nicholas C. Zakas)
+* [`709190f`](https://github.com/eslint/eslint/commit/709190f8c5d7559b1e0915e25af60b50a94ba1c7) Build: fix test failure on Node 11 (#11100) (Teddy Katz)
+* [`3025cdd`](https://github.com/eslint/eslint/commit/3025cddf0a2ea8461ce05575098a5714fcf6278d) Update: don't indent leading semi in line after import (fixes #11082) (#11085) (Pig Fang)
+* [`e18c827`](https://github.com/eslint/eslint/commit/e18c827cc12cb1c52e5d0aa993f572cb56238704) Chore: refactor linter#parseBooleanConfig to improve readability (#11074) (薛定谔的猫)
+* [`5da378a`](https://github.com/eslint/eslint/commit/5da378ac922d732ca1765f08edee0face1b1b924) Upgrade: eslint-release@1.2.0 (#11073) (Teddy Katz)
+
+v5.9.0 - November 9, 2018
+
+* 9436712 Fix: Unused recursive function expressions (fixes #10982) (#11032) (Sergei Startsev)
+* c832cd5 Update: add `ignoreDestructuring` option to `id-match` rule (#10554) (一名宅。)
+* 54687a8 Fix: prefer-const autofix multiline assignment (fixes #10582) (#10987) (Scott Stern)
+* ae2b61d Update: "off" options for "space-before-blocks" (refs #10906) (#10907) (Sophie Kirschner)
+* 57f357e Docs: Update require-await docs with exception (fixes #9540) (#11063) (Nicholas C. Zakas)
+* 79a2797 Update: no-restricted-imports to check re-export (fixes #9678) (#11064) (Nicholas C. Zakas)
+* 3dd7493 Docs: update ecmaVersion to include 2019/10 values (#11059) (Vse Mozhet Byt)
+* 607635d Upgrade: eslint-plugin-node & eslint-plugin (#11067) (薛定谔的猫)
+* dcc6233 Fix: Ignore empty statements in no-unreachable (fixes #9081) (#11058) (Nicholas C. Zakas)
+* 7ad86de New: Add --fix-type option to CLI (fixes #10855) (#10912) (Nicholas C. Zakas)
+* 0800b20 Chore: fix invalid super() calls in tests (#11054) (Teddy Katz)
+* 4fe3287 Docs: Cross-reference two rules (refs #11041) (#11042) (Paul Melnikow)
+* 5525eb6 Fix: rule deprecation warnings did not consider all rules (#11044) (Teddy Katz)
+* 44d37ca Docs: Update steps for adding new TSC member (#11038) (Nicholas C. Zakas)
+* 802e926 Update: Warn for deprecation in Node output (fixes #7443) (#10953) (Colin Chang)
+
 v5.8.0 - October 26, 2018
 
 * 9152417 Fix: deprecation warning in RuleTester using Node v11 (#11009) (Teddy Katz)
diff --git a/Makefile.js b/Makefile.js
index e468d0a16..eb2c586a7 100644
--- a/Makefile.js
+++ b/Makefile.js
@@ -350,7 +350,7 @@ function publishRelease() {
 /**
  * Splits a command result to separate lines.
  * @param {string} result The command result string.
- * @returns {array} The separated lines.
+ * @returns {Array} The separated lines.
  */
 function splitCommandResultToLines(result) {
     return result.trim().split("\n");
@@ -416,7 +416,7 @@ function getFirstVersionOfDeletion(filePath) {
 
 /**
  * Lints Markdown files.
- * @param {array} files Array of file names to lint.
+ * @param {Array} files Array of file names to lint.
  * @returns {Object} exec-style exit code object.
  * @private
  */
diff --git a/README.md b/README.md
index 572cd8a07..65ee43400 100644
--- a/README.md
+++ b/README.md
@@ -38,7 +38,7 @@ If you want to include ESLint as part of your project's build system, we recomme
 $ npm install eslint --save-dev
 ```
 
-You should then setup a configuration file:
+You should then set up a configuration file:
 
 ```
 $ ./node_modules/.bin/eslint --init
@@ -60,7 +60,7 @@ If you want to make ESLint available to tools that run across all of your projec
 $ npm install -g eslint
 ```
 
-You should then setup a configuration file:
+You should then set up a configuration file:
 
 ```
 $ eslint --init
diff --git a/conf/eslint-recommended.js b/conf/eslint-recommended.js
index 847cd44c1..ca0ca8fa9 100644
--- a/conf/eslint-recommended.js
+++ b/conf/eslint-recommended.js
@@ -207,6 +207,7 @@ module.exports = {
         "no-unused-vars": "error",
         "no-use-before-define": "off",
         "no-useless-call": "off",
+        "no-useless-catch": "off",
         "no-useless-computed-key": "off",
         "no-useless-concat": "off",
         "no-useless-constructor": "off",
diff --git a/docs/developer-guide/nodejs-api.md b/docs/developer-guide/nodejs-api.md
index 834fecefd..7b9ecb6ec 100644
--- a/docs/developer-guide/nodejs-api.md
+++ b/docs/developer-guide/nodejs-api.md
@@ -339,17 +339,17 @@ var CLIEngine = require("eslint").CLIEngine;
 The `CLIEngine` is a constructor, and you can create a new instance by passing in the options you want to use. The available options are:
 
 * `allowInlineConfig` - Set to `false` to disable the use of configuration comments (such as `/*eslint-disable*/`). Corresponds to `--no-inline-config`.
-* `baseConfig` - Can optionally be set to a config object. This will used as a default config, and will be merged with any configuration defined in `.eslintrc.*` files, with the `.eslintrc.*` files having precedence.
+* `baseConfig` - Can optionally be set to a config object that has the same schema as `.eslintrc.*`. This will used as a default config, and will be merged with any configuration defined in `.eslintrc.*` files, with the `.eslintrc.*` files having precedence.
 * `cache` - Operate only on changed files (default: `false`). Corresponds to `--cache`.
 * `cacheFile` - Name of the file where the cache will be stored (default: `.eslintcache`). Corresponds to `--cache-file`. Deprecated: use `cacheLocation` instead.
 * `cacheLocation` - Name of the file or directory where the cache will be stored (default: `.eslintcache`). Corresponds to `--cache-location`.
 * `configFile` - The configuration file to use (default: null). If `useEslintrc` is true or not specified, this configuration will be merged with any configuration defined in `.eslintrc.*` files, with options in this configuration having precedence. Corresponds to `-c`.
 * `cwd` - Path to a directory that should be considered as the current working directory.
-* `envs` - An array of environments to load (default: empty array). Corresponds to `--env`.
-* `extensions` - An array of filename extensions that should be checked for code. The default is an array containing just `".js"`. Corresponds to `--ext`. It is only used in conjunction with directories, not with filenames or glob patterns.
+* `envs` - An array of environments to load (default: empty array). Corresponds to `--env`. Note: This differs from `.eslintrc.*` / `baseConfig`, where instead the option is called `env` and is an object.
+* `extensions` - An array of filename extensions that should be checked for code. The default is an array containing just `".js"`. Corresponds to `--ext`. It is only used in conjunction with directories, not with filenames, glob patterns or when using `executeOnText()`.
 * `fix` - A boolean or a function (default: `false`). If a function, it will be passed each linting message and should return a boolean indicating whether the fix should be included with the output report (errors and warnings will not be listed if fixed). Files on disk are never changed regardless of the value of `fix`. To persist changes to disk, call [`outputFixes()`](#cliengineoutputfixes).
 * `fixTypes` - An array of rule types for which fixes should be applied (default: `null`). This array acts like a filter, only allowing rules of the given types to apply fixes. Possible array values are `"problem"`, `"suggestion"`, and `"layout"`.
-* `globals` - An array of global variables to declare (default: empty array). Corresponds to `--global`.
+* `globals` - An array of global variables to declare (default: empty array). Corresponds to `--global`, and similarly supports passing `'name:true'` to denote a writeable global. Note: This differs from `.eslintrc.*` / `baseConfig`, where `globals` is an object.
 * `ignore` - False disables use of `.eslintignore`, `ignorePath` and `ignorePattern` (default: true). Corresponds to `--no-ignore`.
 * `ignorePath` - The ignore file to use instead of `.eslintignore` (default: null). Corresponds to `--ignore-path`.
 * `ignorePattern` - Glob patterns for paths to ignore. String or array of strings.
@@ -362,7 +362,8 @@ The `CLIEngine` is a constructor, and you can create a new instance by passing i
 * `useEslintrc` - Set to false to disable use of `.eslintrc` files (default: true). Corresponds to `--no-eslintrc`.
 * `globInputPaths` - Set to false to skip glob resolution of input file paths to lint (default: true). If false, each input file paths is assumed to be a non-glob path to an existing file.
 
-
+To programmatically set `.eslintrc.*` options not supported above (such as `extends`,
+`overrides` and `settings`), define them in a config object passed to `baseConfig` instead.
 
 For example:
 
@@ -370,6 +371,12 @@ For example:
 var CLIEngine = require("eslint").CLIEngine;
 
 var cli = new CLIEngine({
+    baseConfig: {
+        extends: ["eslint-config-shared"],
+        settings: {
+            sharedData: "Hello"
+        }
+    },
     envs: ["browser", "mocha"],
     useEslintrc: false,
     rules: {
@@ -378,7 +385,13 @@ var cli = new CLIEngine({
 });
 ```
 
-In this code, a new `CLIEngine` instance is created that sets two environments, `"browser"` and `"mocha"`, disables loading of `.eslintrc` and `package.json` files, and enables the `semi` rule as an error. You can then call methods on `cli` and these options will be used to perform the correct action.
+In this example, a new `CLIEngine` instance is created that extends a configuration called
+`"eslint-config-shared"`, a setting named `"sharedData"` and two environments (`"browser"`
+and `"mocha"`) are defined, loading of `.eslintrc` and `package.json` files are disabled,
+and the `semi` rule enabled as an error. You can then call methods on `cli` and these options
+will be used to perform the correct action.
+
+Note: Currently `CLIEngine` does not validate options passed to it, but may start doing so in the future.
 
 ### CLIEngine#executeOnFiles()
 
diff --git a/docs/developer-guide/working-with-plugins.md b/docs/developer-guide/working-with-plugins.md
index 4d0ab55d5..83f107512 100644
--- a/docs/developer-guide/working-with-plugins.md
+++ b/docs/developer-guide/working-with-plugins.md
@@ -52,31 +52,33 @@ Plugin environments can define the following objects:
 You can also create plugins that would tell ESLint how to process files other than JavaScript. In order to create a processor, the object that is exported from your module has to conform to the following interface:
 
 ```js
-processors: {
+module.exports = {
+    processors: {
 
-    // assign to the file extension you want (.js, .jsx, .html, etc.)
-    ".ext": {
-        // takes text of the file and filename
-        preprocess: function(text, filename) {
-            // here, you can strip out any non-JS content
-            // and split into multiple strings to lint
+        // assign to the file extension you want (.js, .jsx, .html, etc.)
+        ".ext": {
+            // takes text of the file and filename
+            preprocess: function(text, filename) {
+                // here, you can strip out any non-JS content
+                // and split into multiple strings to lint
 
-            return [string];  // return an array of strings to lint
-        },
+                return [string];  // return an array of strings to lint
+            },
 
-        // takes a Message[][] and filename
-        postprocess: function(messages, filename) {
-            // `messages` argument contains two-dimensional array of Message objects
-            // where each top-level array item contains array of lint messages related
-            // to the text that was returned in array from preprocess() method
+            // takes a Message[][] and filename
+            postprocess: function(messages, filename) {
+                // `messages` argument contains two-dimensional array of Message objects
+                // where each top-level array item contains array of lint messages related
+                // to the text that was returned in array from preprocess() method
 
-            // you need to return a one-dimensional array of the messages you want to keep
-            return [Message];
-        },
+                // you need to return a one-dimensional array of the messages you want to keep
+                return messages[0];
+            },
 
-        supportsAutofix: true // (optional, defaults to false)
+            supportsAutofix: true // (optional, defaults to false)
+        }
     }
-}
+};
 ```
 
 The `preprocess` method takes the file contents and filename as arguments, and returns an array of strings to lint. The strings will be linted separately but still be registered to the filename. It's up to the plugin to decide if it needs to return just one part, or multiple pieces. For example in the case of processing `.html` files, you might want to return just one item in the array by combining all scripts, but for `.md` file where each JavaScript block might be independent, you can return multiple items.
@@ -117,22 +119,45 @@ To support multiple extensions, add each one to the `processors` element and poi
 
 ### Configs in Plugins
 
-You can bundle configurations inside a plugin. This can be useful when you want to provide not just code style, but also some custom rules to support it. You can specify configurations under `configs` key. Please note that when exposing configurations, you have to name each one, and there is no default. So your users will have to specify the name of the configuration they want to use.
+You can bundle configurations inside a plugin by specifying them under the `configs` key. This can be useful when you want to provide not just code style, but also some custom rules to support it. Multiple configurations are supported per plugin. Note that it is not possible to specify a default configuration for a given plugin and that users must specify in their configuration file when they want to use one.
 
 ```js
-configs: {
-    myConfig: {
-        env: ["browser"],
-        rules: {
-            semi: 2,
-            "myPlugin/my-rule": 2,
-            "eslint-plugin-myPlugin/another-rule": 2
+// eslint-plugin-myPlugin
+
+module.exports = {
+    configs: {
+        myConfig: {
+            plugins: ["myPlugin"],
+            env: ["browser"],
+            rules: {
+                semi: "error",
+                "myPlugin/my-rule": "error",
+                "eslint-plugin-myPlugin/another-rule": "error"
+            }
+        },
+        myOtherConfig: {
+            plugins: ["myPlugin"],
+            env: ["node"],
+            rules: {
+                "myPlugin/my-rule": "off",
+                "eslint-plugin-myPlugin/another-rule": "off"
+                "eslint-plugin-myPlugin/yet-another-rule": "error"
+            }
         }
     }
+};
+```
+
+If the example plugin above were called `eslint-plugin-myPlugin`, the `myConfig` and `myOtherConfig` configurations would then be usable by extending off of `"plugin:myPlugin/myConfig"` and `"plugin:myPlugin/myOtherConfig"`, respectively.
+
+```json
+{
+    "extends": ["plugin:myPlugin/myConfig"]
 }
+
 ```
 
-**Note:** Please note that configuration will not automatically attach your rules and you have to specify your plugin name and any rules you want to enable that are part of the plugin. Any plugin rules must be prefixed with the short or long plugin name. See [Configuring Plugins](../user-guide/configuring.md#configuring-plugins)
+**Note:** Please note that configuration will not enable any of the plugin's rules by default, and instead should be treated as a standalone config. This means that you must specify your plugin name in the `plugins` array as well as any rules you want to enable that are part of the plugin. Any plugin rules must be prefixed with the short or long plugin name. See [Configuring Plugins](../user-guide/configuring.md#configuring-plugins) for more information.
 
 ### Peer Dependency
 
diff --git a/docs/rules/id-match.md b/docs/rules/id-match.md
index bb56847f3..0d9deebd7 100644
--- a/docs/rules/id-match.md
+++ b/docs/rules/id-match.md
@@ -23,20 +23,6 @@ For example, to enforce a camelcase naming convention:
 }
 ```
 
-Examples of **correct** code for this rule with the `"^[a-z]+([A-Z][a-z]+)*$"` option:
-
-```js
-/*eslint id-match: ["error", "^[a-z]+([A-Z][a-z]+)*$"]*/
-
-var myFavoriteColor   = "#112C85";
-var foo = bar.baz_boom;
-var foo = { qux: bar.baz_boom };
-do_something();
-var obj = {
-    my_pref: 1
-};
-```
-
 Examples of **incorrect** code for this rule with the `"^[a-z]+([A-Z][a-z]+)*$"` option:
 
 ```js
@@ -54,10 +40,27 @@ obj.do_something = function() {
 };
 ```
 
+Examples of **correct** code for this rule with the `"^[a-z]+([A-Z][a-z]+)*$"` option:
+
+```js
+/*eslint id-match: ["error", "^[a-z]+([A-Z][a-z]+)*$"]*/
+
+var myFavoriteColor   = "#112C85";
+var foo = bar.baz_boom;
+var foo = { qux: bar.baz_boom };
+do_something();
+var obj = {
+    my_pref: 1
+};
+```
+
 This rule has an object option:
 
 * `"properties": true` requires object properties to match the specified regular expression
 * `"onlyDeclarations": true` requires only `var`, `function`, and `class` declarations to match the specified regular expression
+* `"onlyDeclarations": false` requires all variable names to match the specified regular expression
+* `"ignoreDestructuring": false` (default) enforces `id-match` for destructured identifiers
+* `"ignoreDestructuring": true` does not check destructured identifiers
 
 ### properties
 
@@ -81,6 +84,48 @@ Examples of **correct** code for this rule with the `"^[a-z]+([A-Z][a-z]+)*$", {
 do_something(__dirname);
 ```
 
+### ignoreDestructuring: false
+
+Examples of **incorrect** code for this rule with the default `"^[^_]+$", { "ignoreDestructuring": false }` option:
+
+```js
+/*eslint id-match: [2, "^[^_]+$", { "ignoreDestructuring": false }]*/
+
+var { category_id } = query;
+
+var { category_id = 1 } = query;
+
+var { category_id: category_id } = query;
+
+var { category_id: category_alias } = query;
+
+var { category_id: categoryId, ...other_props } = query;
+```
+
+### ignoreDestructuring: true
+
+Examples of **incorrect** code for this rule with the `"^[^_]+$", { "ignoreDestructuring": true }` option:
+
+```js
+/*eslint id-match: [2, "^[^_]+$", { "ignoreDestructuring": true }]*/
+
+var { category_id: category_alias } = query;
+
+var { category_id, ...other_props } = query;
+```
+
+Examples of **correct** code for this rule with the `"^[^_]+$", { "ignoreDestructuring": true }` option:
+
+```js
+/*eslint id-match: [2, "^[^_]+$", { "ignoreDestructuring": true }]*/
+
+var { category_id } = query;
+
+var { category_id = 1 } = query;
+
+var { category_id: category_id } = query;
+```
+
 ## When Not To Use It
 
 If you don't want to enforce any particular naming convention for all identifiers, or your naming convention is too complex to be enforced by configuring this rule, then you should not enable this rule.
diff --git a/docs/rules/indent.md b/docs/rules/indent.md
index 748b72523..38f744732 100644
--- a/docs/rules/indent.md
+++ b/docs/rules/indent.md
@@ -69,7 +69,7 @@ if (a) {
 This rule has an object option:
 
 * `"SwitchCase"` (default: 0) enforces indentation level for `case` clauses in `switch` statements
-* `"VariableDeclarator"` (default: 1) enforces indentation level for `var` declarators; can also take an object to define separate rules for `var`, `let` and `const` declarations.
+* `"VariableDeclarator"` (default: 1) enforces indentation level for `var` declarators; can also take an object to define separate rules for `var`, `let` and `const` declarations. It can also be `"first"`, indicating all the declarators should be aligned with the first declarator.
 * `"outerIIFEBody"` (default: 1) enforces indentation level for file-level IIFEs.
 * `"MemberExpression"` (default: 1) enforces indentation level for multi-line property chains. This can also be set to `"off"` to disable checking for MemberExpression indentation.
 * `"FunctionDeclaration"` takes an object to define rules for function declarations.
@@ -213,6 +213,40 @@ const a = 1,
     c = 3;
 ```
 
+Examples of **incorrect** code for this rule with the `2, { "VariableDeclarator": "first" }` options:
+
+```js
+/*eslint indent: ["error", 2, { "VariableDeclarator": "first" }]*/
+/*eslint-env es6*/
+
+var a,
+  b,
+  c;
+let a,
+  b,
+  c;
+const a = 1,
+  b = 2,
+  c = 3;
+```
+
+Examples of **correct** code for this rule with the `2, { "VariableDeclarator": "first" }` options:
+
+```js
+/*eslint indent: ["error", 2, { "VariableDeclarator": "first" }]*/
+/*eslint-env es6*/
+
+var a,
+    b,
+    c;
+let a,
+    b,
+    c;
+const a = 1,
+      b = 2,
+      c = 3;
+```
+
 Examples of **correct** code for this rule with the `2, { "VariableDeclarator": { "var": 2, "let": 2, "const": 3 } }` options:
 
 ```js
diff --git a/docs/rules/no-console.md b/docs/rules/no-console.md
index 1c36a85f9..bc163b937 100644
--- a/docs/rules/no-console.md
+++ b/docs/rules/no-console.md
@@ -78,10 +78,11 @@ However, you might not want to manually add `eslint-disable-next-line` or `eslin
 ```json
 {
     "rules": {
+        "no-console": "off",
         "no-restricted-syntax": [
             "error",
             {
-                "selector": "CallExpression[callee.object.name='console'][callee.property.name=/^(log|warn|error|info|trace)$/]",
+                "selector": "CallExpression[callee.object.name='console'][callee.property.name!=/^(log|warn|error|info|trace)$/]",
                 "message": "Unexpected property on console object was called"
             }
         ]
diff --git a/docs/rules/no-restricted-imports.md b/docs/rules/no-restricted-imports.md
index 66b8095a0..62747ebce 100644
--- a/docs/rules/no-restricted-imports.md
+++ b/docs/rules/no-restricted-imports.md
@@ -1,6 +1,6 @@
 # Disallow specific imports (no-restricted-imports)
 
-Imports are an ES6/ES2015 standard for making the functionality of other modules available in your current module. In CommonJS this is implemented through the require() call which makes this ESLint rule roughly equivalent to its CommonJS counterpart `no-restricted-modules`.
+Imports are an ES6/ES2015 standard for making the functionality of other modules available in your current module. In CommonJS this is implemented through the `require()` call which makes this ESLint rule roughly equivalent to its CommonJS counterpart `no-restricted-modules`.
 
 Why would you want to restrict imports?
 
@@ -87,6 +87,18 @@ Examples of **incorrect** code for this rule:
 import fs from 'fs';
 ```
 
+```js
+/*eslint no-restricted-imports: ["error", "fs"]*/
+
+export { fs } from 'fs';
+```
+
+```js
+/*eslint no-restricted-imports: ["error", "fs"]*/
+
+export * from 'fs';
+```
+
 ```js
 /*eslint no-restricted-imports: ["error", { "paths": ["cluster"] }]*/
 
@@ -135,6 +147,7 @@ Examples of **correct** code for this rule:
 /*eslint no-restricted-imports: ["error", "fs"]*/
 
 import crypto from 'crypto';
+export { foo } from "bar";
 ```
 
 ```js
@@ -142,6 +155,7 @@ import crypto from 'crypto';
 
 import crypto from 'crypto';
 import eslint from 'eslint';
+export * from "path";
 ```
 
 ```js
diff --git a/docs/rules/no-unused-expressions.md b/docs/rules/no-unused-expressions.md
index 480915ee2..8a9748d3d 100644
--- a/docs/rules/no-unused-expressions.md
+++ b/docs/rules/no-unused-expressions.md
@@ -2,7 +2,7 @@
 
 An unused expression which has no effect on the state of the program indicates a logic error.
 
-For example, `n + 1;` is not a syntax error, but it might be a typing mistake where a programmer meant an assignment statement `n += 1;` instead.
+For example, `n + 1;` is not a syntax error, but it might be a typing mistake where a programmer meant an assignment statement `n += 1;` instead. Sometimes, such unused expressions may be eliminated by some build tools in production environment, which possibly breaks application logic.
 
 ## Rule Details
 
diff --git a/docs/rules/no-unused-vars.md b/docs/rules/no-unused-vars.md
index 996dea181..2b3f093cc 100644
--- a/docs/rules/no-unused-vars.md
+++ b/docs/rules/no-unused-vars.md
@@ -4,16 +4,16 @@ Variables that are declared and not used anywhere in the code are most likely an
 
 ## Rule Details
 
-This rule is aimed at eliminating unused variables, functions, and parameters of functions.
+This rule is aimed at eliminating unused variables, functions, and function parameters.
 
-A variable is considered to be used if any of the following are true:
+A variable `foo` is considered to be used if any of the following are true:
 
-* It represents a function that is called (`doSomething()`)
-* It is read (`var y = x`)
-* It is passed into a function as an argument (`doSomething(x)`)
+* It is called (`foo()`) or constructed (`new foo()`)
+* It is read (`var bar = foo`)
+* It is passed into a function as an argument (`doSomething(foo)`)
 * It is read inside of a function that is passed to another function (`doSomething(function() { foo(); })`)
 
-A variable is *not* considered to be used if it is only ever assigned to (`var x = 5`) or declared.
+A variable is *not* considered to be used if it is only ever declared (`var foo = 5`) or assigned to (`foo = 7`).
 
 Examples of **incorrect** code for this rule:
 
diff --git a/docs/rules/no-useless-catch.md b/docs/rules/no-useless-catch.md
new file mode 100644
index 000000000..d320e561d
--- /dev/null
+++ b/docs/rules/no-useless-catch.md
@@ -0,0 +1,50 @@
+# Disallow unnecessary catch clauses (no-useless-catch)
+
+A `catch` clause that only rethrows the original error is redundant, and has no effect on the runtime behavior of the program. These redundant clauses can be a source of confusion and code bloat, so it's better to disallow these unnecessary `catch` clauses.
+
+## Rule Details
+
+This rule reports `catch` clauses that only `throw` the caught error.
+
+Examples of **incorrect** code for this rule:
+
+```js
+/*eslint no-useless-catch: "error"*/
+
+try {
+  doSomethingThatMightThrow();
+} catch (e) {
+  throw e;
+}
+
+try {
+  doSomethingThatMightThrow();
+} catch (e) {
+  throw e;
+} finally {
+  cleanUp();
+}
+```
+
+Examples of **correct** code for this rule:
+
+```js
+/*eslint no-useless-catch: "error"*/
+
+try {
+  doSomethingThatMightThrow();
+} catch (e) {
+  doSomethingBeforeRethrow();
+  throw e;
+}
+
+try {
+  doSomethingThatMightThrow();
+} catch (e) {
+  handleError(e);
+}
+```
+
+## When Not To Use It
+
+If you don't want to be notified about unnecessary catch clauses, you can safely disable this rule.
diff --git a/docs/rules/object-shorthand.md b/docs/rules/object-shorthand.md
index 6f2471faf..79e76655c 100644
--- a/docs/rules/object-shorthand.md
+++ b/docs/rules/object-shorthand.md
@@ -84,7 +84,7 @@ var foo = {
 
 See Also:
 
-- [`no-useless-rename`](https://eslint.org/docs/rules/object-shorthand) which disallows renaming import, export, and destructured assignments to the same name.
+- [`no-useless-rename`](https://eslint.org/docs/rules/no-useless-rename) which disallows renaming import, export, and destructured assignments to the same name.
 
 ## Options
 
diff --git a/docs/rules/padded-blocks.md b/docs/rules/padded-blocks.md
index 3393d090e..5c7908cff 100644
--- a/docs/rules/padded-blocks.md
+++ b/docs/rules/padded-blocks.md
@@ -51,11 +51,6 @@ if (a)
     b();
 }
 
-if (a) {
-
-    b();
-}
-
 if (a) {
     b();
 
diff --git a/docs/rules/padding-line-between-statements.md b/docs/rules/padding-line-between-statements.md
index 390dada29..1f2c4ab89 100644
--- a/docs/rules/padding-line-between-statements.md
+++ b/docs/rules/padding-line-between-statements.md
@@ -52,7 +52,7 @@ You can supply any number of configurations. If a statement pair matches multipl
     - `"cjs-export"` is `export` statements of CommonJS; e.g. `module.exports = 0`, `module.exports.foo = 1`, and `exports.foo = 2`. This is a special case of assignment.
     - `"cjs-import"` is `import` statements of CommonJS; e.g. `const foo = require("foo")`. This is a special case of variable declarations.
     - `"class"` is `class` declarations.
-    - `"const"` is `const` variable declarations.
+    - `"const"` is `const` variable declarations, both single-line and multiline.
     - `"continue"` is `continue` statements.
     - `"debugger"` is `debugger` statements.
     - `"default"` is `default` labels.
@@ -66,14 +66,20 @@ You can supply any number of configurations. If a statement pair matches multipl
     - `"if"` is `if` statements.
     - `"iife"` is immediately invoked function expression statements. This matches calls on a function expression, optionally prefixed with a unary operator.
     - `"import"` is `import` declarations.
-    - `"let"` is `let` variable declarations.
+    - `"let"` is `let` variable declarations, both single-line and multiline.
     - `"multiline-block-like"` is block like statements. This is the same as `block-like` type, but only if the block is multiline.
+    - `"multiline-const"` is multiline `const` variable declarations.
     - `"multiline-expression"` is expression statements. This is the same as `expression` type, but only if the statement is multiline.
+    - `"multiline-let"` is multiline `let` variable declarations.
+    - `"multiline-var"` is multiline `var` variable declarations.
     - `"return"` is `return` statements.
+    - `"singleline-const"` is single-line `const` variable declarations.
+    - `"singleline-let"` is single-line `let` variable declarations.
+    - `"singleline-var"` is single-line `var` variable declarations.
     - `"switch"` is `switch` statements.
     - `"throw"` is `throw` statements.
     - `"try"` is `try` statements.
-    - `"var"` is `var` variable declarations.
+    - `"var"` is `var` variable declarations, both single-line and multiline.
     - `"while"` is `while` loop statements.
     - `"with"` is `with` statements.
 
diff --git a/docs/rules/require-await.md b/docs/rules/require-await.md
index 4f1e4441e..2fb871cf1 100644
--- a/docs/rules/require-await.md
+++ b/docs/rules/require-await.md
@@ -1,6 +1,23 @@
 # Disallow async functions which have no `await` expression (require-await)
 
-Async functions which have no `await` expression may be the unintentional result of refactoring.
+Asynchronous functions in JavaScript behave differently than other functions in two important ways:
+
+1. The return value is always a `Promise`.
+2. You can use the `await` operator inside of them.
+
+The primary reason to use asynchronous functions is typically to use the `await` operator, such as this:
+
+```js
+async function fetchData(processDataItem) {
+    const response = await fetch(DATA_URL);
+    const data = await response.json();
+
+    return data.map(processDataItem);
+}
+```
+
+Asynchronous functions that don't use `await` might not need to be asynchronous functions and could be the unintentional result of refactoring.
+
 
 ## Rule Details
 
@@ -47,7 +64,22 @@ async function noop() {}
 
 ## When Not To Use It
 
-If you don't want to notify async functions which have no `await` expression, then it's safe to disable this rule.
+Asynchronous functions are designed to work with promises such that throwing an error will cause a promise's rejection handler (such as `catch()`) to be called. For example:
+
+```js
+async function fail() {
+    throw new Error("Failure!");
+}
+
+fail().catch(error => {
+    console.log(error.message);
+});
+```
+
+In this case, the `fail()` function throws an error that is intended to be caught by the `catch()` handler assigned later. Converting the `fail()` function into a synchronous function would require the call to `fail()` to be refactored to use a `try-catch` statement instead of a promise.
+
+If you are throwing an error inside of an asynchronous function for this purpose, then you may want to disable this rule.
+
 
 ## Related Rules
 
diff --git a/docs/rules/require-jsdoc.md b/docs/rules/require-jsdoc.md
index b9deb7daa..1e31aedf7 100644
--- a/docs/rules/require-jsdoc.md
+++ b/docs/rules/require-jsdoc.md
@@ -1,5 +1,7 @@
 # require JSDoc comments (require-jsdoc)
 
+This rule was [**deprecated**](https://eslint.org/blog/2018/11/jsdoc-end-of-life) in ESLint v5.10.0.
+
 [JSDoc](http://usejsdoc.org) is a JavaScript API documentation generator. It uses specially-formatted comments inside of code to generate API documentation automatically. For example, this is what a JSDoc comment looks like for a function:
 
 ```js
diff --git a/docs/rules/space-before-blocks.md b/docs/rules/space-before-blocks.md
index 60f0717b3..ab4c2a2b4 100644
--- a/docs/rules/space-before-blocks.md
+++ b/docs/rules/space-before-blocks.md
@@ -17,7 +17,7 @@ This rule will enforce consistency of spacing before blocks. It is only applied
 This rule takes one argument. If it is `"always"` then blocks must always have at least one preceding space. If `"never"`
 then all blocks should never have any preceding space. If different spacing is desired for function
 blocks, keyword blocks and classes, an optional configuration object can be passed as the rule argument to
-configure the cases separately.
+configure the cases separately. If any value in the configuration object is `"off"`, then neither style will be enforced for blocks of that kind.
 
 ( e.g. `{ "functions": "never", "keywords": "always", "classes": "always" }` )
 
diff --git a/docs/rules/valid-jsdoc.md b/docs/rules/valid-jsdoc.md
index 4e23a5eee..2d503828f 100644
--- a/docs/rules/valid-jsdoc.md
+++ b/docs/rules/valid-jsdoc.md
@@ -1,5 +1,7 @@
 # enforce valid JSDoc comments (valid-jsdoc)
 
+This rule was [**deprecated**](https://eslint.org/blog/2018/11/jsdoc-end-of-life) in ESLint v5.10.0.
+
 [JSDoc](http://usejsdoc.org) generates application programming interface (API) documentation from specially-formatted comments in JavaScript code. For example, this is a JSDoc comment for a function:
 
 ```js
diff --git a/docs/user-guide/configuring.md b/docs/user-guide/configuring.md
index 3bb64faf8..13ec086ae 100644
--- a/docs/user-guide/configuring.md
+++ b/docs/user-guide/configuring.md
@@ -26,7 +26,7 @@ For ES6 syntax, use `{ "parserOptions": { "ecmaVersion": 6 } }`; for new ES6 glo
 { "es6": true } }` (this setting enables ES6 syntax automatically).
 Parser options are set in your `.eslintrc.*` file by using the `parserOptions` property. The available options are:
 
-* `ecmaVersion` - set to 3, 5 (default), 6, 7, 8, or 9 to specify the version of ECMAScript syntax you want to use. You can also set to 2015 (same as 6), 2016 (same as 7), 2017 (same as 8), or 2018 (same as 9) to use the year-based naming.
+* `ecmaVersion` - set to 3, 5 (default), 6, 7, 8, 9, or 10 to specify the version of ECMAScript syntax you want to use. You can also set to 2015 (same as 6), 2016 (same as 7), 2017 (same as 8), 2018 (same as 9), or 2019 (same as 10) to use the year-based naming.
 * `sourceType` - set to `"script"` (default) or `"module"` if your code is in ECMAScript modules.
 * `ecmaFeatures` - an object indicating which additional language features you'd like to use:
     * `globalReturn` - allow `return` statements in the global scope
diff --git a/karma.conf.js b/karma.conf.js
index 0ffab8bc5..e8a027e54 100644
--- a/karma.conf.js
+++ b/karma.conf.js
@@ -1,5 +1,7 @@
 "use strict";
 
+process.env.CHROME_BIN = require("puppeteer").executablePath();
+
 module.exports = function(config) {
     config.set({
 
@@ -67,8 +69,13 @@ module.exports = function(config) {
 
         // start these browsers
         // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
-        browsers: ["PhantomJS"],
-
+        browsers: ["HeadlessChrome"],
+        customLaunchers: {
+          HeadlessChrome: {
+            base: 'ChromeHeadless',
+            flags: [ '--no-sandbox', ],
+             },
+            },
 
         // Continuous Integration mode
         // if true, Karma captures browsers, runs the tests and exits
diff --git a/lib/cli-engine.js b/lib/cli-engine.js
index 652d68b59..ce9fe289b 100644
--- a/lib/cli-engine.js
+++ b/lib/cli-engine.js
@@ -20,7 +20,7 @@ const fs = require("fs"),
     defaultOptions = require("../conf/default-cli-options"),
     Linter = require("./linter"),
     lodash = require("lodash"),
-    IgnoredPaths = require("./ignored-paths"),
+    IgnoredPaths = require("./util/ignored-paths"),
     Config = require("./config"),
     ConfigOps = require("./config/config-ops"),
     LintResultCache = require("./util/lint-result-cache"),
diff --git a/lib/config.js b/lib/config.js
index 8ea9aeb6f..abcb38b50 100644
--- a/lib/config.js
+++ b/lib/config.js
@@ -15,8 +15,7 @@ const path = require("path"),
     ConfigFile = require("./config/config-file"),
     ConfigCache = require("./config/config-cache"),
     Plugins = require("./config/plugins"),
-    FileFinder = require("./util/file-finder"),
-    isResolvable = require("is-resolvable");
+    FileFinder = require("./util/file-finder");
 
 const debug = require("debug")("eslint:config");
 
@@ -41,6 +40,20 @@ function hasRules(options) {
     return options.rules && Object.keys(options.rules).length > 0;
 }
 
+/**
+ * Determines if a module is can be resolved.
+ * @param {string} moduleId The ID (name) of the module
+ * @returns {boolean} True if it is resolvable; False otherwise.
+ */
+function isResolvable(moduleId) {
+    try {
+        require.resolve(moduleId);
+        return true;
+    } catch (err) {
+        return false;
+    }
+}
+
 //------------------------------------------------------------------------------
 // API
 //------------------------------------------------------------------------------
diff --git a/lib/config/autoconfig.js b/lib/config/autoconfig.js
index 8536fdc55..f2c707be8 100644
--- a/lib/config/autoconfig.js
+++ b/lib/config/autoconfig.js
@@ -102,7 +102,6 @@ class Registry {
      *
      * The length of the returned array will be <= MAX_CONFIG_COMBINATIONS.
      *
-     * @param   {Object}   registry The autoconfig registry
      * @returns {Object[]}          "rules" configurations to use for linting
      */
     buildRuleSets() {
diff --git a/lib/config/config-file.js b/lib/config/config-file.js
index d09b36688..dde79cb40 100644
--- a/lib/config/config-file.js
+++ b/lib/config/config-file.js
@@ -18,7 +18,7 @@ const fs = require("fs"),
     pathIsInside = require("path-is-inside"),
     stripComments = require("strip-json-comments"),
     stringify = require("json-stable-stringify-without-jsonify"),
-    requireUncached = require("require-uncached");
+    importFresh = require("import-fresh");
 
 const debug = require("debug")("eslint:config-file");
 
@@ -156,7 +156,7 @@ function loadLegacyConfigFile(filePath) {
 function loadJSConfigFile(filePath) {
     debug(`Loading JS config file: ${filePath}`);
     try {
-        return requireUncached(filePath);
+        return importFresh(filePath);
     } catch (e) {
         debug(`Error reading JavaScript file: ${filePath}`);
         e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
diff --git a/lib/config/config-rule.js b/lib/config/config-rule.js
index 27d29446d..e4221406d 100644
--- a/lib/config/config-rule.js
+++ b/lib/config/config-rule.js
@@ -37,9 +37,9 @@ function explodeArray(xs) {
  * For example:
  * combineArrays([a, [b, c]], [x, y]); // -> [[a, x], [a, y], [b, c, x], [b, c, y]]
  *
- * @param   {array} arr1 The first array to combine.
- * @param   {array} arr2 The second array to combine.
- * @returns {array}      A mixture of the elements of the first and second arrays.
+ * @param   {Array} arr1 The first array to combine.
+ * @param   {Array} arr2 The second array to combine.
+ * @returns {Array}      A mixture of the elements of the first and second arrays.
  */
 function combineArrays(arr1, arr2) {
     const res = [];
@@ -268,7 +268,7 @@ class RuleConfigSet {
 /**
  * Generate valid rule configurations based on a schema object
  * @param   {Object} schema  A rule's schema object
- * @returns {array[]}        Valid rule configurations
+ * @returns {Array[]}        Valid rule configurations
  */
 function generateConfigsFromSchema(schema) {
     const configSet = new RuleConfigSet();
diff --git a/lib/config/config-validator.js b/lib/config/config-validator.js
index 6b151f46a..0c63b68f7 100644
--- a/lib/config/config-validator.js
+++ b/lib/config/config-validator.js
@@ -83,7 +83,7 @@ function validateRuleSeverity(options) {
 /**
  * Validates the non-severity options passed to a rule, based on its schema.
  * @param {{create: Function}} rule The rule to validate
- * @param {array} localOptions The options for the rule, excluding severity
+ * @param {Array} localOptions The options for the rule, excluding severity
  * @returns {void}
  */
 function validateRuleSchema(rule, localOptions) {
@@ -111,7 +111,7 @@ function validateRuleSchema(rule, localOptions) {
  * Validates a rule's options against its schema.
  * @param {{create: Function}|null} rule The rule that the config is being validated for
  * @param {string} ruleId The rule's unique name.
- * @param {array|number} options The given options for the rule.
+ * @param {Array|number} options The given options for the rule.
  * @param {string|null} source The name of the configuration source to report in any errors. If null or undefined,
  * no source is prepended to the message.
  * @returns {void}
diff --git a/lib/linter.js b/lib/linter.js
index b47e6eb1f..d6d635f9f 100644
--- a/lib/linter.js
+++ b/lib/linter.js
@@ -11,7 +11,6 @@
 
 const eslintScope = require("eslint-scope"),
     evk = require("eslint-visitor-keys"),
-    levn = require("levn"),
     lodash = require("lodash"),
     CodePathAnalyzer = require("./code-path-analysis/code-path-analyzer"),
     ConfigOps = require("./config/config-ops"),
@@ -22,9 +21,10 @@ const eslintScope = require("eslint-scope"),
     NodeEventGenerator = require("./util/node-event-generator"),
     SourceCode = require("./util/source-code"),
     Traverser = require("./util/traverser"),
-    createReportTranslator = require("./report-translator"),
+    createReportTranslator = require("./util/report-translator"),
     Rules = require("./rules"),
     timing = require("./util/timing"),
+    ConfigCommentParser = require("./util/config-comment-parser"),
     astUtils = require("./util/ast-utils"),
     pkg = require("../package.json"),
     SourceCodeFixer = require("./util/source-code-fixer");
@@ -32,6 +32,7 @@ const eslintScope = require("eslint-scope"),
 const debug = require("debug")("eslint:linter");
 const MAX_AUTOFIX_PASSES = 10;
 const DEFAULT_PARSER_NAME = "espree";
+const commentParser = new ConfigCommentParser();
 
 //------------------------------------------------------------------------------
 // Typedefs
@@ -59,117 +60,6 @@ const DEFAULT_PARSER_NAME = "espree";
 // Helpers
 //------------------------------------------------------------------------------
 
-/**
- * Parses a list of "name:boolean_value" or/and "name" options divided by comma or
- * whitespace.
- * @param {string} string The string to parse.
- * @param {Comment} comment The comment node which has the string.
- * @returns {Object} Result map object of names and boolean values
- */
-function parseBooleanConfig(string, comment) {
-    const items = {};
-
-    // Collapse whitespace around `:` and `,` to make parsing easier
-    const trimmedString = string.replace(/\s*([:,])\s*/g, "$1");
-
-    trimmedString.split(/\s|,+/).forEach(name => {
-        if (!name) {
-            return;
-        }
-        const pos = name.indexOf(":");
-
-        if (pos === -1) {
-            items[name] = {
-                value: false,
-                comment
-            };
-        } else {
-            items[name.slice(0, pos)] = {
-                value: name.slice(pos + 1) === "true",
-                comment
-            };
-        }
-    });
-    return items;
-}
-
-/**
- * Parses a JSON-like config.
- * @param {string} string The string to parse.
- * @param {Object} location Start line and column of comments for potential error message.
- * @returns {({success: true, config: Object}|{success: false, error: Problem})} Result map object
- */
-function parseJsonConfig(string, location) {
-    let items = {};
-
-    // Parses a JSON-like comment by the same way as parsing CLI option.
-    try {
-        items = levn.parse("Object", string) || {};
-
-        // Some tests say that it should ignore invalid comments such as `/*eslint no-alert:abc*/`.
-        // Also, commaless notations have invalid severity:
-        //     "no-alert: 2 no-console: 2" --> {"no-alert": "2 no-console: 2"}
-        // Should ignore that case as well.
-        if (ConfigOps.isEverySeverityValid(items)) {
-            return {
-                success: true,
-                config: items
-            };
-        }
-    } catch (ex) {
-
-        // ignore to parse the string by a fallback.
-    }
-
-    /*
-     * Optionator cannot parse commaless notations.
-     * But we are supporting that. So this is a fallback for that.
-     */
-    items = {};
-    const normalizedString = string.replace(/([a-zA-Z0-9\-/]+):/g, "\"$1\":").replace(/(]|[0-9])\s+(?=")/, "$1,");
-
-    try {
-        items = JSON.parse(`{${normalizedString}}`);
-    } catch (ex) {
-        return {
-            success: false,
-            error: {
-                ruleId: null,
-                fatal: true,
-                severity: 2,
-                message: `Failed to parse JSON from '${normalizedString}': ${ex.message}`,
-                line: location.start.line,
-                column: location.start.column + 1
-            }
-        };
-
-    }
-
-    return {
-        success: true,
-        config: items
-    };
-}
-
-/**
- * Parses a config of values separated by comma.
- * @param {string} string The string to parse.
- * @returns {Object} Result map of values and true values
- */
-function parseListConfig(string) {
-    const items = {};
-
-    // Collapse whitespace around ,
-    string.replace(/\s*,\s*/g, ",").split(/,+/).forEach(name => {
-        const trimmedName = name.trim();
-
-        if (trimmedName) {
-            items[trimmedName] = true;
-        }
-    });
-    return items;
-}
-
 /**
  * Ensures that variables representing built-in properties of the Global Object,
  * and any globals declared by special block comments, are present in the global
@@ -248,7 +138,7 @@ function addDeclaredGlobals(globalScope, configGlobals, commentDirectives) {
  * @returns {DisableDirective[]} Directives from the comment
  */
 function createDisableDirectives(type, loc, value) {
-    const ruleIds = Object.keys(parseListConfig(value));
+    const ruleIds = Object.keys(commentParser.parseListConfig(value));
     const directiveRules = ruleIds.length ? ruleIds : [null];
 
     return directiveRules.map(ruleId => ({ type, line: loc.line, column: loc.column + 1, ruleId }));
@@ -301,12 +191,12 @@ function getDirectiveComments(filename, ast, ruleMapper) {
         } else if (comment.type === "Block") {
             switch (match[1]) {
                 case "exported":
-                    Object.assign(exportedVariables, parseBooleanConfig(directiveValue, comment));
+                    Object.assign(exportedVariables, commentParser.parseBooleanConfig(directiveValue, comment));
                     break;
 
                 case "globals":
                 case "global":
-                    Object.assign(enabledGlobals, parseBooleanConfig(directiveValue, comment));
+                    Object.assign(enabledGlobals, commentParser.parseBooleanConfig(directiveValue, comment));
                     break;
 
                 case "eslint-disable":
@@ -318,7 +208,7 @@ function getDirectiveComments(filename, ast, ruleMapper) {
                     break;
 
                 case "eslint": {
-                    const parseResult = parseJsonConfig(directiveValue, comment.loc);
+                    const parseResult = commentParser.parseJsonConfig(directiveValue, comment.loc);
 
                     if (parseResult.success) {
                         Object.keys(parseResult.config).forEach(name => {
@@ -398,7 +288,7 @@ function findEslintEnv(text) {
     eslintEnvPattern.lastIndex = 0;
 
     while ((match = eslintEnvPattern.exec(text))) {
-        retv = Object.assign(retv || {}, parseListConfig(match[1]));
+        retv = Object.assign(retv || {}, commentParser.parseListConfig(match[1]));
     }
 
     return retv;
@@ -1032,8 +922,6 @@ module.exports = class Linter {
      * @param {(string|Object)} [filenameOrOptions] The optional filename of the file being checked.
      *      If this is not set, the filename will default to '<input>' in the rule context. If
      *      an object, then it has "filename", "saveState", and "allowInlineConfig" properties.
-     * @param {boolean} [saveState] Indicates if the state from the last run should be saved.
-     *      Mostly useful for testing purposes.
      * @param {boolean} [filenameOrOptions.allowInlineConfig] Allow/disallow inline comments' ability to change config once it is set. Defaults to true if not supplied.
      *      Useful if you want to validate JS without comments overriding rules.
      * @param {function(string): string[]} [filenameOrOptions.preprocess] preprocessor for source text. If provided,
diff --git a/lib/rules/array-element-newline.js b/lib/rules/array-element-newline.js
index 440290917..dadb26fdd 100644
--- a/lib/rules/array-element-newline.js
+++ b/lib/rules/array-element-newline.js
@@ -173,7 +173,6 @@ module.exports = {
          * Reports a given node if it violated this rule.
          *
          * @param {ASTNode} node - A node to check. This is an ObjectExpression node or an ObjectPattern node.
-         * @param {{multiline: boolean, minItems: number}} options - An option object.
          * @returns {void}
          */
         function check(node) {
diff --git a/lib/rules/block-spacing.js b/lib/rules/block-spacing.js
index 6496f8596..864bfc0c5 100644
--- a/lib/rules/block-spacing.js
+++ b/lib/rules/block-spacing.js
@@ -29,8 +29,8 @@ module.exports = {
         ],
 
         messages: {
-            missing: "Requires a space {{location}} '{{token}}'",
-            extra: "Unexpected space(s) {{location}} '{{token}}'"
+            missing: "Requires a space {{location}} '{{token}}'.",
+            extra: "Unexpected space(s) {{location}} '{{token}}'."
         }
     },
 
diff --git a/lib/rules/camelcase.js b/lib/rules/camelcase.js
index 8aeb4b5bd..a8341c84b 100644
--- a/lib/rules/camelcase.js
+++ b/lib/rules/camelcase.js
@@ -100,14 +100,20 @@ module.exports = {
          * @private
          */
         function isInsideObjectPattern(node) {
-            let { parent } = node;
+            let current = node;
 
-            while (parent) {
-                if (parent.type === "ObjectPattern") {
+            while (current) {
+                const parent = current.parent;
+
+                if (parent && parent.type === "Property" && parent.computed && parent.key === current) {
+                    return false;
+                }
+
+                if (current.type === "ObjectPattern") {
                     return true;
                 }
 
-                parent = parent.parent;
+                current = parent;
             }
 
             return false;
@@ -132,9 +138,10 @@ module.exports = {
 
                 /*
                  * Leading and trailing underscores are commonly used to flag
-                 * private/protected identifiers, strip them
+                 * private/protected identifiers, strip them before checking if underscored
                  */
-                const name = node.name.replace(/^_+|_+$/g, ""),
+                const name = node.name,
+                    nameIsUnderscored = isUnderscored(name.replace(/^_+|_+$/g, "")),
                     effectiveParent = (node.parent.type === "MemberExpression") ? node.parent.parent : node.parent;
 
                 // First, we ignore the node if it match the ignore list
@@ -151,11 +158,11 @@ module.exports = {
                     }
 
                     // Always report underscored object names
-                    if (node.parent.object.type === "Identifier" && node.parent.object.name === node.name && isUnderscored(name)) {
+                    if (node.parent.object.type === "Identifier" && node.parent.object.name === node.name && nameIsUnderscored) {
                         report(node);
 
                     // Report AssignmentExpressions only if they are the left side of the assignment
-                    } else if (effectiveParent.type === "AssignmentExpression" && isUnderscored(name) && (effectiveParent.right.type !== "MemberExpression" || effectiveParent.left.type === "MemberExpression" && effectiveParent.left.property.name === node.name)) {
+                    } else if (effectiveParent.type === "AssignmentExpression" && nameIsUnderscored && (effectiveParent.right.type !== "MemberExpression" || effectiveParent.left.type === "MemberExpression" && effectiveParent.left.property.name === node.name)) {
                         report(node);
                     }
 
@@ -167,19 +174,22 @@ module.exports = {
                 } else if (node.parent.type === "Property" || node.parent.type === "AssignmentPattern") {
 
                     if (node.parent.parent && node.parent.parent.type === "ObjectPattern") {
-                        if (node.parent.shorthand && node.parent.value.left && isUnderscored(name)) {
-
+                        if (node.parent.shorthand && node.parent.value.left && nameIsUnderscored) {
                             report(node);
                         }
 
                         const assignmentKeyEqualsValue = node.parent.key.name === node.parent.value.name;
 
+                        if (isUnderscored(name) && node.parent.computed) {
+                            report(node);
+                        }
+
                         // prevent checking righthand side of destructured object
                         if (node.parent.key === node && node.parent.value !== node) {
                             return;
                         }
 
-                        const valueIsUnderscored = node.parent.value.name && isUnderscored(name);
+                        const valueIsUnderscored = node.parent.value.name && nameIsUnderscored;
 
                         // ignore destructuring if the option is set, unless a new identifier is created
                         if (valueIsUnderscored && !(assignmentKeyEqualsValue && ignoreDestructuring)) {
@@ -193,7 +203,7 @@ module.exports = {
                     }
 
                     // don't check right hand side of AssignmentExpression to prevent duplicate warnings
-                    if (isUnderscored(name) && !ALLOWED_PARENT_TYPES.has(effectiveParent.type) && !(node.parent.right === node)) {
+                    if (nameIsUnderscored && !ALLOWED_PARENT_TYPES.has(effectiveParent.type) && !(node.parent.right === node)) {
                         report(node);
                     }
 
@@ -201,12 +211,12 @@ module.exports = {
                 } else if (["ImportSpecifier", "ImportNamespaceSpecifier", "ImportDefaultSpecifier"].indexOf(node.parent.type) >= 0) {
 
                     // Report only if the local imported identifier is underscored
-                    if (node.parent.local && node.parent.local.name === node.name && isUnderscored(name)) {
+                    if (node.parent.local && node.parent.local.name === node.name && nameIsUnderscored) {
                         report(node);
                     }
 
                 // Report anything that is underscored that isn't a CallExpression
-                } else if (isUnderscored(name) && !ALLOWED_PARENT_TYPES.has(effectiveParent.type)) {
+                } else if (nameIsUnderscored && !ALLOWED_PARENT_TYPES.has(effectiveParent.type)) {
                     report(node);
                 }
             }
diff --git a/lib/rules/capitalized-comments.js b/lib/rules/capitalized-comments.js
index 86427ba7a..7947833b2 100644
--- a/lib/rules/capitalized-comments.js
+++ b/lib/rules/capitalized-comments.js
@@ -137,8 +137,8 @@ module.exports = {
         ],
 
         messages: {
-            unexpectedLowercaseComment: "Comments should not begin with a lowercase character",
-            unexpectedUppercaseComment: "Comments should not begin with an uppercase character"
+            unexpectedLowercaseComment: "Comments should not begin with a lowercase character.",
+            unexpectedUppercaseComment: "Comments should not begin with an uppercase character."
         }
     },
 
diff --git a/lib/rules/comma-style.js b/lib/rules/comma-style.js
index 2586cf66e..78438a858 100644
--- a/lib/rules/comma-style.js
+++ b/lib/rules/comma-style.js
@@ -85,7 +85,7 @@ module.exports = {
         function getReplacedText(styleType, text) {
             switch (styleType) {
                 case "between":
-                    return `,${text.replace("\n", "")}`;
+                    return `,${text.replace(astUtils.LINEBREAK_MATCHER, "")}`;
 
                 case "first":
                     return `${text},`;
@@ -138,6 +138,11 @@ module.exports = {
             } else if (!astUtils.isTokenOnSameLine(commaToken, currentItemToken) &&
                     !astUtils.isTokenOnSameLine(previousItemToken, commaToken)) {
 
+                const comment = sourceCode.getCommentsAfter(commaToken)[0];
+                const styleType = comment && comment.type === "Block" && astUtils.isTokenOnSameLine(commaToken, comment)
+                    ? style
+                    : "between";
+
                 // lone comma
                 context.report({
                     node: reportItem,
@@ -146,7 +151,7 @@ module.exports = {
                         column: commaToken.loc.start.column
                     },
                     messageId: "unexpectedLineBeforeAndAfterComma",
-                    fix: getFixerFunction("between", previousItemToken, commaToken, currentItemToken)
+                    fix: getFixerFunction(styleType, previousItemToken, commaToken, currentItemToken)
                 });
 
             } else if (style === "first" && !astUtils.isTokenOnSameLine(commaToken, currentItemToken)) {
diff --git a/lib/rules/eqeqeq.js b/lib/rules/eqeqeq.js
index 715c5ce7c..3e8a392cf 100644
--- a/lib/rules/eqeqeq.js
+++ b/lib/rules/eqeqeq.js
@@ -119,7 +119,6 @@ module.exports = {
         /**
          * Gets the location (line and column) of the binary expression's operator
          * @param {ASTNode} node The binary expression node to check
-         * @param {string} operator The operator to find
          * @returns {Object} { line, column } location of operator
          * @private
          */
diff --git a/lib/rules/func-name-matching.js b/lib/rules/func-name-matching.js
index f14c998dc..5560c6920 100644
--- a/lib/rules/func-name-matching.js
+++ b/lib/rules/func-name-matching.js
@@ -92,10 +92,10 @@ module.exports = {
         },
 
         messages: {
-            matchProperty: "Function name `{{funcName}}` should match property name `{{name}}`",
-            matchVariable: "Function name `{{funcName}}` should match variable name `{{name}}`",
-            notMatchProperty: "Function name `{{funcName}}` should not match property name `{{name}}`",
-            notMatchVariable: "Function name `{{funcName}}` should not match variable name `{{name}}`"
+            matchProperty: "Function name `{{funcName}}` should match property name `{{name}}`.",
+            matchVariable: "Function name `{{funcName}}` should match variable name `{{name}}`.",
+            notMatchProperty: "Function name `{{funcName}}` should not match property name `{{name}}`.",
+            notMatchVariable: "Function name `{{funcName}}` should not match variable name `{{name}}`."
         }
     },
 
diff --git a/lib/rules/handle-callback-err.js b/lib/rules/handle-callback-err.js
index c62016d58..5845aff4b 100644
--- a/lib/rules/handle-callback-err.js
+++ b/lib/rules/handle-callback-err.js
@@ -59,7 +59,7 @@ module.exports = {
         /**
          * Get the parameters of a given function scope.
          * @param {Object} scope The function scope.
-         * @returns {array} All parameters of the given scope.
+         * @returns {Array} All parameters of the given scope.
          */
         function getParameters(scope) {
             return scope.variables.filter(variable => variable.defs[0] && variable.defs[0].type === "Parameter");
diff --git a/lib/rules/id-match.js b/lib/rules/id-match.js
index 17dfbc05b..4755c779c 100644
--- a/lib/rules/id-match.js
+++ b/lib/rules/id-match.js
@@ -29,6 +29,12 @@ module.exports = {
                 properties: {
                     properties: {
                         type: "boolean"
+                    },
+                    onlyDeclarations: {
+                        type: "boolean"
+                    },
+                    ignoreDestructuring: {
+                        type: "boolean"
                     }
                 }
             }
@@ -38,15 +44,25 @@ module.exports = {
     create(context) {
 
         //--------------------------------------------------------------------------
-        // Helpers
+        // Options
         //--------------------------------------------------------------------------
-
         const pattern = context.options[0] || "^.+$",
             regexp = new RegExp(pattern);
 
         const options = context.options[1] || {},
             properties = !!options.properties,
-            onlyDeclarations = !!options.onlyDeclarations;
+            onlyDeclarations = !!options.onlyDeclarations,
+            ignoreDestructuring = !!options.ignoreDestructuring;
+
+        //--------------------------------------------------------------------------
+        // Helpers
+        //--------------------------------------------------------------------------
+
+        // contains reported nodes to avoid reporting twice on destructuring with shorthand notation
+        const reported = new Map();
+        const ALLOWED_PARENT_TYPES = new Set(["CallExpression", "NewExpression"]);
+        const DECLARATION_TYPES = new Set(["FunctionDeclaration", "VariableDeclarator"]);
+        const IMPORT_TYPES = new Set(["ImportSpecifier", "ImportNamespaceSpecifier", "ImportDefaultSpecifier"]);
 
         /**
          * Checks if a string matches the provided pattern
@@ -58,6 +74,26 @@ module.exports = {
             return !regexp.test(name);
         }
 
+        /**
+         * Checks if a parent of a node is an ObjectPattern.
+         * @param {ASTNode} node The node to check.
+         * @returns {boolean} if the node is inside an ObjectPattern
+         * @private
+         */
+        function isInsideObjectPattern(node) {
+            let { parent } = node;
+
+            while (parent) {
+                if (parent.type === "ObjectPattern") {
+                    return true;
+                }
+
+                parent = parent.parent;
+            }
+
+            return false;
+        }
+
         /**
          * Verifies if we should report an error or not based on the effective
          * parent node and the identifier name.
@@ -66,9 +102,8 @@ module.exports = {
          * @returns {boolean} whether an error should be reported or not
          */
         function shouldReport(effectiveParent, name) {
-            return effectiveParent.type !== "CallExpression" &&
-                effectiveParent.type !== "NewExpression" &&
-                isInvalid(name);
+            return (!onlyDeclarations || DECLARATION_TYPES.has(effectiveParent.type)) &&
+                !ALLOWED_PARENT_TYPES.has(effectiveParent.type) && isInvalid(name);
         }
 
         /**
@@ -78,14 +113,17 @@ module.exports = {
          * @private
          */
         function report(node) {
-            context.report({
-                node,
-                message: "Identifier '{{name}}' does not match the pattern '{{pattern}}'.",
-                data: {
-                    name: node.name,
-                    pattern
-                }
-            });
+            if (!reported.has(node)) {
+                context.report({
+                    node,
+                    message: "Identifier '{{name}}' does not match the pattern '{{pattern}}'.",
+                    data: {
+                        name: node.name,
+                        pattern
+                    }
+                });
+                reported.set(node, true);
+            }
         }
 
         return {
@@ -108,36 +146,70 @@ module.exports = {
                             report(node);
                         }
 
-                    // Report AssignmentExpressions only if they are the left side of the assignment
+                    // Report AssignmentExpressions left side's assigned variable id
                     } else if (effectiveParent.type === "AssignmentExpression" &&
-                        (effectiveParent.right.type !== "MemberExpression" ||
                         effectiveParent.left.type === "MemberExpression" &&
-                        effectiveParent.left.property.name === name)) {
+                        effectiveParent.left.property.name === node.name) {
+                        if (isInvalid(name)) {
+                            report(node);
+                        }
+
+                    // Report AssignmentExpressions only if they are the left side of the assignment
+                    } else if (effectiveParent.type === "AssignmentExpression" && effectiveParent.right.type !== "MemberExpression") {
                         if (isInvalid(name)) {
                             report(node);
                         }
                     }
 
-                } else if (parent.type === "Property") {
+                /*
+                 * Properties have their own rules, and
+                 * AssignmentPattern nodes can be treated like Properties:
+                 * e.g.: const { no_camelcased = false } = bar;
+                 */
+                } else if (parent.type === "Property" || parent.type === "AssignmentPattern") {
+
+                    if (parent.parent && parent.parent.type === "ObjectPattern") {
+                        if (parent.shorthand && parent.value.left && isInvalid(name)) {
+
+                            report(node);
+                        }
+
+                        const assignmentKeyEqualsValue = parent.key.name === parent.value.name;
 
-                    if (!properties || parent.key.name !== name) {
+                        // prevent checking righthand side of destructured object
+                        if (!assignmentKeyEqualsValue && parent.key === node) {
+                            return;
+                        }
+
+                        const valueIsInvalid = parent.value.name && isInvalid(name);
+
+                        // ignore destructuring if the option is set, unless a new identifier is created
+                        if (valueIsInvalid && !(assignmentKeyEqualsValue && ignoreDestructuring)) {
+                            report(node);
+                        }
+                    }
+
+                    // never check properties or always ignore destructuring
+                    if (!properties || (ignoreDestructuring && isInsideObjectPattern(node))) {
                         return;
                     }
 
-                    if (shouldReport(effectiveParent, name)) {
+                    // don't check right hand side of AssignmentExpression to prevent duplicate warnings
+                    if (parent.right !== node && shouldReport(effectiveParent, name)) {
                         report(node);
                     }
 
-                } else {
-                    const isDeclaration = effectiveParent.type === "FunctionDeclaration" || effectiveParent.type === "VariableDeclarator";
+                // Check if it's an import specifier
+                } else if (IMPORT_TYPES.has(parent.type)) {
 
-                    if (onlyDeclarations && !isDeclaration) {
-                        return;
-                    }
-
-                    if (shouldReport(effectiveParent, name)) {
+                    // Report only if the local imported identifier is invalid
+                    if (parent.local && parent.local.name === node.name && isInvalid(name)) {
                         report(node);
                     }
+
+                // Report anything that is invalid that isn't a CallExpression
+                } else if (shouldReport(effectiveParent, name)) {
+                    report(node);
                 }
             }
 
diff --git a/lib/rules/implicit-arrow-linebreak.js b/lib/rules/implicit-arrow-linebreak.js
index cd729f8ad..fb7d603a3 100644
--- a/lib/rules/implicit-arrow-linebreak.js
+++ b/lib/rules/implicit-arrow-linebreak.js
@@ -4,6 +4,12 @@
  */
 "use strict";
 
+const {
+    isArrowToken,
+    isParenthesised,
+    isOpeningParenToken
+} = require("../util/ast-utils");
+
 //------------------------------------------------------------------------------
 // Rule Definition
 //------------------------------------------------------------------------------
@@ -41,10 +47,145 @@ module.exports = {
             return context.options[0] || "beside";
         }
 
+        /**
+         * Formats the comments depending on whether it's a line or block comment.
+         * @param {Comment[]} comments The array of comments between the arrow and body
+         * @param {Integer} column The column number of the first token
+         * @returns {string} A string of comment text joined by line breaks
+         */
+        function formatComments(comments, column) {
+            const whiteSpaces = " ".repeat(column);
+
+            return `${comments.map(comment => {
+
+                if (comment.type === "Line") {
+                    return `//${comment.value}`;
+                }
+
+                return `/*${comment.value}*/`;
+            }).join(`\n${whiteSpaces}`)}\n${whiteSpaces}`;
+        }
+
+        /**
+         * Finds the first token to prepend comments to depending on the parent type
+         * @param {Node} node The validated node
+         * @returns {Token|Node} The node to prepend comments to
+         */
+        function findFirstToken(node) {
+            switch (node.parent.type) {
+                case "VariableDeclarator":
+
+                    // If the parent is first or only declarator, return the declaration, else, declarator
+                    return sourceCode.getFirstToken(
+                        node.parent.parent.declarations.length === 1 ||
+                        node.parent.parent.declarations[0].id.name === node.parent.id.name
+                            ? node.parent.parent : node.parent
+                    );
+                case "CallExpression":
+                case "Property":
+
+                    // find the object key
+                    return sourceCode.getFirstToken(node.parent);
+                default:
+                    return node;
+            }
+        }
+
+        /**
+         * Helper function for adding parentheses fixes for nodes containing nested arrow functions
+         * @param {Fixer} fixer Fixer
+         * @param {Token} arrow - The arrow token
+         * @param {ASTNode} arrowBody - The arrow function body
+         * @returns {Function[]} autofixer -- wraps function bodies with parentheses
+         */
+        function addParentheses(fixer, arrow, arrowBody) {
+            const parenthesesFixes = [];
+            let closingParentheses = "";
+
+            let followingBody = arrowBody;
+            let currentArrow = arrow;
+
+            while (currentArrow) {
+                if (!isParenthesised(sourceCode, followingBody)) {
+                    parenthesesFixes.push(
+                        fixer.insertTextAfter(currentArrow, " (")
+                    );
+
+                    const paramsToken = sourceCode.getTokenBefore(currentArrow, token =>
+                        isOpeningParenToken(token) || token.type === "Identifier");
+
+                    const whiteSpaces = " ".repeat(paramsToken.loc.start.column);
+
+                    closingParentheses = `\n${whiteSpaces})${closingParentheses}`;
+                }
+
+                currentArrow = sourceCode.getTokenAfter(currentArrow, isArrowToken);
+
+                if (currentArrow) {
+                    followingBody = sourceCode.getTokenAfter(currentArrow, token => !isOpeningParenToken(token));
+                }
+            }
+
+            return [...parenthesesFixes,
+                fixer.insertTextAfter(arrowBody, closingParentheses)
+            ];
+        }
+
+        /**
+         * Autofixes the function body to collapse onto the same line as the arrow.
+         * If comments exist, prepends the comments before the arrow function.
+         * If the function body contains arrow functions, appends the function bodies with parentheses.
+         * @param {Token} arrowToken The arrow token.
+         * @param {ASTNode} arrowBody the function body
+         * @param {ASTNode} node The evaluated node
+         * @returns {Function} autofixer -- validates the node to adhere to besides
+         */
+        function autoFixBesides(arrowToken, arrowBody, node) {
+            return fixer => {
+                const placeBesides = fixer.replaceTextRange([arrowToken.range[1], arrowBody.range[0]], " ");
+
+                const comments = sourceCode.getCommentsInside(node).filter(comment =>
+                    comment.loc.start.line < arrowBody.loc.start.line);
+
+                if (comments.length) {
+
+                    // If the grandparent is not a variable declarator
+                    if (
+                        arrowBody.parent &&
+                        arrowBody.parent.parent &&
+                        arrowBody.parent.parent.type !== "VariableDeclarator"
+                    ) {
+
+                        // If any arrow functions follow, return the necessary parens fixes.
+                        if (sourceCode.getTokenAfter(arrowToken, isArrowToken) && arrowBody.parent.parent.type !== "VariableDeclarator") {
+                            return addParentheses(fixer, arrowToken, arrowBody);
+                        }
+
+                        // If any arrow functions precede, the necessary fixes have already been returned, so return null.
+                        if (sourceCode.getTokenBefore(arrowToken, isArrowToken) && arrowBody.parent.parent.type !== "VariableDeclarator") {
+                            return null;
+                        }
+                    }
+
+                    const firstToken = findFirstToken(node);
+
+                    const commentText = formatComments(comments, firstToken.loc.start.column);
+
+                    const commentBeforeExpression = fixer.insertTextBeforeRange(
+                        firstToken.range,
+                        commentText
+                    );
+
+                    return [placeBesides, commentBeforeExpression];
+                }
+
+                return placeBesides;
+            };
+        }
+
         /**
          * Validates the location of an arrow function body
          * @param {ASTNode} node The arrow function body
-         * @param {string} keywordName The applicable keyword name for the arrow function body
          * @returns {void}
          */
         function validateExpression(node) {
@@ -76,7 +217,7 @@ module.exports = {
                 context.report({
                     node: fixerTarget,
                     message: "Expected no linebreak before this expression.",
-                    fix: fixer => fixer.replaceTextRange([tokenBefore.range[1], fixerTarget.range[0]], " ")
+                    fix: autoFixBesides(tokenBefore, fixerTarget, node)
                 });
             }
         }
diff --git a/lib/rules/indent-legacy.js b/lib/rules/indent-legacy.js
index 16687b521..cfb807e34 100644
--- a/lib/rules/indent-legacy.js
+++ b/lib/rules/indent-legacy.js
@@ -300,7 +300,6 @@ module.exports = {
          * @param {int} gottenTabs Indentation tab count in the actual node/code
          * @param {Object=} loc Error line and column location
          * @param {boolean} isLastNodeCheck Is the error for last node check
-         * @param {int} lastNodeCheckEndOffset Number of charecters to skip from the end
          * @returns {void}
          */
         function report(node, needed, gottenSpaces, gottenTabs, loc, isLastNodeCheck) {
@@ -365,7 +364,6 @@ module.exports = {
          * Check indent for node
          * @param {ASTNode} node Node to check
          * @param {int} neededIndent needed indent
-         * @param {boolean} [excludeCommas=false] skip comma on start of line
          * @returns {void}
          */
         function checkNodeIndent(node, neededIndent) {
@@ -413,7 +411,6 @@ module.exports = {
          * Check indent for nodes list
          * @param {ASTNode[]} nodes list of node objects
          * @param {int} indent needed indent
-         * @param {boolean} [excludeCommas=false] skip comma on start of line
          * @returns {void}
          */
         function checkNodesIndent(nodes, indent) {
diff --git a/lib/rules/indent.js b/lib/rules/indent.js
index dc9fbaf90..af7e2b147 100644
--- a/lib/rules/indent.js
+++ b/lib/rules/indent.js
@@ -522,25 +522,13 @@ module.exports = {
                     },
                     VariableDeclarator: {
                         oneOf: [
-                            {
-                                type: "integer",
-                                minimum: 0
-                            },
+                            ELEMENT_LIST_SCHEMA,
                             {
                                 type: "object",
                                 properties: {
-                                    var: {
-                                        type: "integer",
-                                        minimum: 0
-                                    },
-                                    let: {
-                                        type: "integer",
-                                        minimum: 0
-                                    },
-                                    const: {
-                                        type: "integer",
-                                        minimum: 0
-                                    }
+                                    var: ELEMENT_LIST_SCHEMA,
+                                    let: ELEMENT_LIST_SCHEMA,
+                                    const: ELEMENT_LIST_SCHEMA
                                 },
                                 additionalProperties: false
                             }
@@ -661,7 +649,7 @@ module.exports = {
             if (context.options[1]) {
                 lodash.merge(options, context.options[1]);
 
-                if (typeof options.VariableDeclarator === "number") {
+                if (typeof options.VariableDeclarator === "number" || options.VariableDeclarator === "first") {
                     options.VariableDeclarator = {
                         var: options.VariableDeclarator,
                         let: options.VariableDeclarator,
@@ -1229,9 +1217,13 @@ module.exports = {
                 }
 
                 const fromToken = sourceCode.getLastToken(node, token => token.type === "Identifier" && token.value === "from");
+                const sourceToken = sourceCode.getLastToken(node, token => token.type === "String");
+                const semiToken = sourceCode.getLastToken(node, token => token.type === "Punctuator" && token.value === ";");
 
                 if (fromToken) {
-                    offsets.setDesiredOffsets([fromToken.range[0], node.range[1]], sourceCode.getFirstToken(node), 1);
+                    const end = semiToken && semiToken.range[1] === sourceToken.range[1] ? node.range[1] : sourceToken.range[1];
+
+                    offsets.setDesiredOffsets([fromToken.range[0], end], sourceCode.getFirstToken(node), 1);
                 }
             },
 
@@ -1345,10 +1337,27 @@ module.exports = {
             },
 
             VariableDeclaration(node) {
-                const variableIndent = Object.prototype.hasOwnProperty.call(options.VariableDeclarator, node.kind)
+                let variableIndent = Object.prototype.hasOwnProperty.call(options.VariableDeclarator, node.kind)
                     ? options.VariableDeclarator[node.kind]
                     : DEFAULT_VARIABLE_INDENT;
 
+                const firstToken = sourceCode.getFirstToken(node),
+                    lastToken = sourceCode.getLastToken(node);
+
+                if (options.VariableDeclarator[node.kind] === "first") {
+                    if (node.declarations.length > 1) {
+                        addElementListIndent(
+                            node.declarations,
+                            firstToken,
+                            lastToken,
+                            "first"
+                        );
+                        return;
+                    }
+
+                    variableIndent = DEFAULT_VARIABLE_INDENT;
+                }
+
                 if (node.declarations[node.declarations.length - 1].loc.start.line > node.loc.start.line) {
 
                     /*
@@ -1370,13 +1379,10 @@ module.exports = {
                      * on the same line as the start of the declaration, provided that there are declarators that
                      * follow this one.
                      */
-                    const firstToken = sourceCode.getFirstToken(node);
-
                     offsets.setDesiredOffsets(node.range, firstToken, variableIndent, true);
                 } else {
-                    offsets.setDesiredOffsets(node.range, sourceCode.getFirstToken(node), variableIndent);
+                    offsets.setDesiredOffsets(node.range, firstToken, variableIndent);
                 }
-                const lastToken = sourceCode.getLastToken(node);
 
                 if (astUtils.isSemicolonToken(lastToken)) {
                     offsets.ignoreToken(lastToken);
diff --git a/lib/rules/keyword-spacing.js b/lib/rules/keyword-spacing.js
index 66ce2cb34..790d7b031 100644
--- a/lib/rules/keyword-spacing.js
+++ b/lib/rules/keyword-spacing.js
@@ -453,6 +453,10 @@ module.exports = {
             checkSpacingBefore(firstToken, PREV_TOKEN_M);
             checkSpacingAfter(firstToken, NEXT_TOKEN_M);
 
+            if (node.type === "ExportDefaultDeclaration") {
+                checkSpacingAround(sourceCode.getTokenAfter(firstToken));
+            }
+
             if (node.source) {
                 const fromToken = sourceCode.getTokenBefore(node.source);
 
@@ -554,7 +558,7 @@ module.exports = {
             // Statements - Declarations
             ClassDeclaration: checkSpacingForClass,
             ExportNamedDeclaration: checkSpacingForModuleDeclaration,
-            ExportDefaultDeclaration: checkSpacingAroundFirstToken,
+            ExportDefaultDeclaration: checkSpacingForModuleDeclaration,
             ExportAllDeclaration: checkSpacingForModuleDeclaration,
             FunctionDeclaration: checkSpacingForFunction,
             ImportDeclaration: checkSpacingForModuleDeclaration,
diff --git a/lib/rules/max-classes-per-file.js b/lib/rules/max-classes-per-file.js
index 3193a731c..ae7be904f 100644
--- a/lib/rules/max-classes-per-file.js
+++ b/lib/rules/max-classes-per-file.js
@@ -32,7 +32,7 @@ module.exports = {
         ],
 
         messages: {
-            maximumExceeded: "Number of classes per file must not exceed {{ max }}"
+            maximumExceeded: "Number of classes per file must not exceed {{ max }}."
         }
     },
     create(context) {
diff --git a/lib/rules/newline-before-return.js b/lib/rules/newline-before-return.js
index 2743bf7a8..6a0ec8d5e 100644
--- a/lib/rules/newline-before-return.js
+++ b/lib/rules/newline-before-return.js
@@ -36,7 +36,7 @@ module.exports = {
         /**
          * Tests whether node is preceded by supplied tokens
          * @param {ASTNode} node - node to check
-         * @param {array} testTokens - array of tokens to test against
+         * @param {Array} testTokens - array of tokens to test against
          * @returns {boolean} Whether or not the node is preceded by one of the supplied tokens
          * @private
          */
diff --git a/lib/rules/no-constant-condition.js b/lib/rules/no-constant-condition.js
index 88984c36e..8d7934d8a 100644
--- a/lib/rules/no-constant-condition.js
+++ b/lib/rules/no-constant-condition.js
@@ -173,7 +173,6 @@ module.exports = {
 
         /**
          * Reports when the set still contains stored constant conditions
-         * @param {ASTNode} node The AST node to check.
          * @returns {void}
          * @private
          */
diff --git a/lib/rules/no-else-return.js b/lib/rules/no-else-return.js
index eebdec76e..5ba02de29 100644
--- a/lib/rules/no-else-return.js
+++ b/lib/rules/no-else-return.js
@@ -183,7 +183,6 @@ module.exports = {
          * code paths.
          *
          * @param {Node} node The consequent or body node
-         * @param {Node} alternate The alternate node
          * @returns {boolean} `true` if it is a Return/If node that always returns.
          */
         function checkForReturnOrIf(node) {
diff --git a/lib/rules/no-implied-eval.js b/lib/rules/no-implied-eval.js
index d31b5dfee..afa24ab8e 100644
--- a/lib/rules/no-implied-eval.js
+++ b/lib/rules/no-implied-eval.js
@@ -38,7 +38,7 @@ module.exports = {
 
         /**
          * Get the last element of an array, without modifying arr, like pop(), but non-destructive.
-         * @param {array} arr What to inspect
+         * @param {Array} arr What to inspect
          * @returns {*} The last element of arr
          * @private
          */
diff --git a/lib/rules/no-irregular-whitespace.js b/lib/rules/no-irregular-whitespace.js
index 7920ebdc5..90d1a79a1 100644
--- a/lib/rules/no-irregular-whitespace.js
+++ b/lib/rules/no-irregular-whitespace.js
@@ -30,7 +30,7 @@ module.exports = {
         type: "problem",
 
         docs: {
-            description: "disallow irregular whitespace outside of strings and comments",
+            description: "disallow irregular whitespace",
             category: "Possible Errors",
             recommended: true,
             url: "https://eslint.org/docs/rules/no-irregular-whitespace"
diff --git a/lib/rules/no-param-reassign.js b/lib/rules/no-param-reassign.js
index 243bb6412..349345c14 100644
--- a/lib/rules/no-param-reassign.js
+++ b/lib/rules/no-param-reassign.js
@@ -107,6 +107,14 @@ module.exports = {
 
                         break;
 
+                    // EXCLUDES: e.g. (foo ? a : b).c = bar;
+                    case "ConditionalExpression":
+                        if (parent.test === node) {
+                            return false;
+                        }
+
+                        break;
+
                     // no default
                 }
 
diff --git a/lib/rules/no-restricted-imports.js b/lib/rules/no-restricted-imports.js
index e4563172e..b8917ee9c 100644
--- a/lib/rules/no-restricted-imports.js
+++ b/lib/rules/no-restricted-imports.js
@@ -195,7 +195,7 @@ module.exports = {
         /**
          * Check if the given importNames are restricted given a list of restrictedImportNames.
          * @param {Set.<string>} importNames - Set of import names that are being imported
-         * @param {[string]} restrictedImportNames - array of import names that are restricted for this import
+         * @param {string[]} restrictedImportNames - array of import names that are restricted for this import
          * @returns {boolean} whether the objectName is restricted
          * @private
          */
@@ -236,31 +236,47 @@ module.exports = {
             return restrictedPatterns.length > 0 && restrictedPatternsMatcher.ignores(importSource);
         }
 
-        return {
-            ImportDeclaration(node) {
-                const importSource = node.source.value.trim();
-                const importNames = node.specifiers.reduce((set, specifier) => {
-                    if (specifier.type === "ImportDefaultSpecifier") {
-                        set.add("default");
-                    } else if (specifier.type === "ImportNamespaceSpecifier") {
-                        set.add("*");
-                    } else {
-                        set.add(specifier.imported.name);
-                    }
-                    return set;
-                }, new Set());
-
-                if (isRestrictedForEverythingImported(importSource, importNames)) {
-                    reportPathForEverythingImported(importSource, node);
+        /**
+         * Checks a node to see if any problems should be reported.
+         * @param {ASTNode} node The node to check.
+         * @returns {void}
+         * @private
+         */
+        function checkNode(node) {
+            const importSource = node.source.value.trim();
+            const importNames = node.specifiers ? node.specifiers.reduce((set, specifier) => {
+                if (specifier.type === "ImportDefaultSpecifier") {
+                    set.add("default");
+                } else if (specifier.type === "ImportNamespaceSpecifier") {
+                    set.add("*");
+                } else if (specifier.imported) {
+                    set.add(specifier.imported.name);
+                } else if (specifier.local) {
+                    set.add(specifier.local.name);
                 }
+                return set;
+            }, new Set()) : new Set();
 
-                if (isRestrictedPath(importSource, importNames)) {
-                    reportPath(node);
-                }
-                if (isRestrictedPattern(importSource)) {
-                    reportPathForPatterns(node);
-                }
+            if (isRestrictedForEverythingImported(importSource, importNames)) {
+                reportPathForEverythingImported(importSource, node);
+            }
+
+            if (isRestrictedPath(importSource, importNames)) {
+                reportPath(node);
+            }
+            if (isRestrictedPattern(importSource)) {
+                reportPathForPatterns(node);
             }
+        }
+
+        return {
+            ImportDeclaration: checkNode,
+            ExportNamedDeclaration(node) {
+                if (node.source) {
+                    checkNode(node);
+                }
+            },
+            ExportAllDeclaration: checkNode
         };
     }
 };
diff --git a/lib/rules/no-this-before-super.js b/lib/rules/no-this-before-super.js
index 93fb094e9..bca379bf9 100644
--- a/lib/rules/no-this-before-super.js
+++ b/lib/rules/no-this-before-super.js
@@ -171,7 +171,6 @@ module.exports = {
              * invalid node.
              *
              * @param {CodePath} codePath - A code path which was ended.
-             * @param {ASTNode} node - The current node.
              * @returns {void}
              */
             onCodePathEnd(codePath) {
diff --git a/lib/rules/no-unreachable.js b/lib/rules/no-unreachable.js
index 5f90500a0..8ea2583f7 100644
--- a/lib/rules/no-unreachable.js
+++ b/lib/rules/no-unreachable.js
@@ -182,7 +182,6 @@ module.exports = {
             ContinueStatement: reportIfUnreachable,
             DebuggerStatement: reportIfUnreachable,
             DoWhileStatement: reportIfUnreachable,
-            EmptyStatement: reportIfUnreachable,
             ExpressionStatement: reportIfUnreachable,
             ForInStatement: reportIfUnreachable,
             ForOfStatement: reportIfUnreachable,
diff --git a/lib/rules/no-unused-vars.js b/lib/rules/no-unused-vars.js
index 4bd4146ce..e76e32510 100644
--- a/lib/rules/no-unused-vars.js
+++ b/lib/rules/no-unused-vars.js
@@ -225,6 +225,32 @@ module.exports = {
             return false;
         }
 
+        /**
+         * Gets a list of function definitions for a specified variable.
+         * @param {Variable} variable - eslint-scope variable object.
+         * @returns {ASTNode[]} Function nodes.
+         * @private
+         */
+        function getFunctionDefinitions(variable) {
+            const functionDefinitions = [];
+
+            variable.defs.forEach(def => {
+                const { type, node } = def;
+
+                // FunctionDeclarations
+                if (type === "FunctionName") {
+                    functionDefinitions.push(node);
+                }
+
+                // FunctionExpressions
+                if (type === "Variable" && node.init &&
+                    (node.init.type === "FunctionExpression" || node.init.type === "ArrowFunctionExpression")) {
+                    functionDefinitions.push(node.init);
+                }
+            });
+            return functionDefinitions;
+        }
+
         /**
          * Checks the position of given nodes.
          *
@@ -433,7 +459,7 @@ module.exports = {
          * @private
          */
         function isUsedVariable(variable) {
-            const functionNodes = variable.defs.filter(def => def.type === "FunctionName").map(def => def.node),
+            const functionNodes = getFunctionDefinitions(variable),
                 isFunctionDefinition = functionNodes.length > 0;
             let rhsNode = null;
 
diff --git a/tools/internal-rules/no-useless-catch.js b/lib/rules/no-useless-catch.js
similarity index 72%
rename from tools/internal-rules/no-useless-catch.js
rename to lib/rules/no-useless-catch.js
index 86e0e2a70..e4284cfb4 100644
--- a/tools/internal-rules/no-useless-catch.js
+++ b/lib/rules/no-useless-catch.js
@@ -5,12 +5,19 @@
 
 "use strict";
 
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
 module.exports = {
     meta: {
+        type: "suggestion",
+
         docs: {
             description: "disallow unnecessary `catch` clauses",
-            category: "Internal",
-            recommended: false
+            category: "Best Practices",
+            recommended: false,
+            url: "https://eslint.org/docs/rules/no-useless-catch"
         },
 
         schema: []
@@ -20,6 +27,7 @@ module.exports = {
         return {
             CatchClause(node) {
                 if (
+                    node.param &&
                     node.param.type === "Identifier" &&
                     node.body.body.length &&
                     node.body.body[0].type === "ThrowStatement" &&
@@ -33,7 +41,7 @@ module.exports = {
                         });
                     } else {
                         context.report({
-                            node,
+                            node: node.parent,
                             message: "Unnecessary try/catch wrapper."
                         });
                     }
diff --git a/lib/rules/object-curly-newline.js b/lib/rules/object-curly-newline.js
index c460ea56b..d1a6bc20f 100644
--- a/lib/rules/object-curly-newline.js
+++ b/lib/rules/object-curly-newline.js
@@ -172,7 +172,6 @@ module.exports = {
         /**
          * Reports a given node if it violated this rule.
          * @param {ASTNode} node - A node to check. This is an ObjectExpression, ObjectPattern, ImportDeclaration or ExportNamedDeclaration node.
-         * @param {{multiline: boolean, minProperties: number, consistent: boolean}} options - An option object.
          * @returns {void}
          */
         function check(node) {
diff --git a/lib/rules/one-var.js b/lib/rules/one-var.js
index 44f05fb70..0e9dff416 100644
--- a/lib/rules/one-var.js
+++ b/lib/rules/one-var.js
@@ -310,7 +310,6 @@ module.exports = {
         /**
          * Fixer to split a VariableDeclaration into individual declarations
          * @param   {VariableDeclaration}   declaration The `VariableDeclaration` to split
-         * @param   {?Function}             filter      Function to filter the declarations
          * @returns {Function}                          The fixer function
          */
         function splitDeclarations(declaration) {
diff --git a/lib/rules/padding-line-between-statements.js b/lib/rules/padding-line-between-statements.js
index 3e55a2516..c99958854 100644
--- a/lib/rules/padding-line-between-statements.js
+++ b/lib/rules/padding-line-between-statements.js
@@ -36,6 +36,36 @@ function newKeywordTester(keyword) {
     };
 }
 
+/**
+ * Creates tester which check if a node starts with specific keyword and spans a single line.
+ *
+ * @param {string} keyword The keyword to test.
+ * @returns {Object} the created tester.
+ * @private
+ */
+function newSinglelineKeywordTester(keyword) {
+    return {
+        test: (node, sourceCode) =>
+            node.loc.start.line === node.loc.end.line &&
+            sourceCode.getFirstToken(node).value === keyword
+    };
+}
+
+/**
+ * Creates tester which check if a node starts with specific keyword and spans multiple lines.
+ *
+ * @param {string} keyword The keyword to test.
+ * @returns {Object} the created tester.
+ * @private
+ */
+function newMultilineKeywordTester(keyword) {
+    return {
+        test: (node, sourceCode) =>
+            node.loc.start.line !== node.loc.end.line &&
+            sourceCode.getFirstToken(node).value === keyword
+    };
+}
+
 /**
  * Creates tester which check if a node is specific type.
  *
@@ -368,6 +398,13 @@ const StatementTypes = {
             !isDirectivePrologue(node, sourceCode)
     },
 
+    "multiline-const": newMultilineKeywordTester("const"),
+    "multiline-let": newMultilineKeywordTester("let"),
+    "multiline-var": newMultilineKeywordTester("var"),
+    "singleline-const": newSinglelineKeywordTester("const"),
+    "singleline-let": newSinglelineKeywordTester("let"),
+    "singleline-var": newSinglelineKeywordTester("var"),
+
     block: newNodeTypeTester("BlockStatement"),
     empty: newNodeTypeTester("EmptyStatement"),
     function: newNodeTypeTester("FunctionDeclaration"),
diff --git a/lib/rules/prefer-const.js b/lib/rules/prefer-const.js
index acf846c99..a40ad3539 100644
--- a/lib/rules/prefer-const.js
+++ b/lib/rules/prefer-const.js
@@ -359,6 +359,8 @@ module.exports = {
         const shouldMatchAnyDestructuredVariable = options.destructuring !== "all";
         const ignoreReadBeforeAssign = options.ignoreReadBeforeAssign === true;
         const variables = [];
+        let reportCount = 0;
+        let name = "";
 
         /**
          * Reports given identifier nodes if all of the nodes should be declared
@@ -379,14 +381,41 @@ module.exports = {
 
             if (nodes.length && (shouldMatchAnyDestructuredVariable || nodesToReport.length === nodes.length)) {
                 const varDeclParent = findUp(nodes[0], "VariableDeclaration", parentNode => parentNode.type.endsWith("Statement"));
-                const shouldFix = varDeclParent &&
+                const isVarDecParentNull = varDeclParent === null;
+
+                if (!isVarDecParentNull && varDeclParent.declarations.length > 0) {
+                    const firstDeclaration = varDeclParent.declarations[0];
+
+                    if (firstDeclaration.init) {
+                        const firstDecParent = firstDeclaration.init.parent;
+
+                        /*
+                         * First we check the declaration type and then depending on
+                         * if the type is a "VariableDeclarator" or its an "ObjectPattern"
+                         * we compare the name from the first identifier, if the names are different
+                         * we assign the new name and reset the count of reportCount and nodeCount in
+                         * order to check each block for the number of reported errors and base our fix
+                         * based on comparing nodes.length and nodesToReport.length.
+                         */
+
+                        if (firstDecParent.type === "VariableDeclarator") {
+
+                            if (firstDecParent.id.name !== name) {
+                                name = firstDecParent.id.name;
+                                reportCount = 0;
+                            }
+
+                            if (firstDecParent.id.type === "ObjectPattern") {
+                                if (firstDecParent.init.name !== name) {
+                                    name = firstDecParent.init.name;
+                                    reportCount = 0;
+                                }
+                            }
+                        }
+                    }
+                }
 
-                    /*
-                     * If there are multiple variable declarations, like {let a = 1, b = 2}, then
-                     * do not attempt to fix if one of the declarations should be `const`. It's
-                     * too hard to know how the developer would want to automatically resolve the issue.
-                     */
-                    varDeclParent.declarations.length === 1 &&
+                let shouldFix = varDeclParent &&
 
                     // Don't do a fix unless the variable is initialized (or it's in a for-in or for-of loop)
                     (varDeclParent.parent.type === "ForInStatement" || varDeclParent.parent.type === "ForOfStatement" || varDeclParent.declarations[0].init) &&
@@ -398,6 +427,21 @@ module.exports = {
                      */
                     nodesToReport.length === nodes.length;
 
+                if (!isVarDecParentNull && varDeclParent.declarations && varDeclParent.declarations.length !== 1) {
+
+                    if (varDeclParent && varDeclParent.declarations && varDeclParent.declarations.length >= 1) {
+
+                        /*
+                         * Add nodesToReport.length to a count, then comparing the count to the length
+                         * of the declarations in the current block.
+                         */
+
+                        reportCount += nodesToReport.length;
+
+                        shouldFix = shouldFix && (reportCount === varDeclParent.declarations.length);
+                    }
+                }
+
                 nodesToReport.forEach(node => {
                     context.report({
                         node,
diff --git a/lib/rules/prefer-object-spread.js b/lib/rules/prefer-object-spread.js
index a8dac696b..4d724339d 100644
--- a/lib/rules/prefer-object-spread.js
+++ b/lib/rules/prefer-object-spread.js
@@ -226,8 +226,8 @@ module.exports = {
         fixable: "code",
 
         messages: {
-            useSpreadMessage: "Use an object spread instead of `Object.assign` eg: `{ ...foo }`",
-            useLiteralMessage: "Use an object literal instead of `Object.assign`. eg: `{ foo: bar }`"
+            useSpreadMessage: "Use an object spread instead of `Object.assign` eg: `{ ...foo }`.",
+            useLiteralMessage: "Use an object literal instead of `Object.assign`. eg: `{ foo: bar }`."
         }
     },
 
diff --git a/lib/rules/quotes.js b/lib/rules/quotes.js
index e0db17fcb..c3c077822 100644
--- a/lib/rules/quotes.js
+++ b/lib/rules/quotes.js
@@ -228,6 +228,34 @@ module.exports = {
             }
         }
 
+        /**
+         * Checks whether or not a given TemplateLiteral node is actually using any of the special features provided by template literal strings.
+         * @param {ASTNode} node - A TemplateLiteral node to check.
+         * @returns {boolean} Whether or not the TemplateLiteral node is using any of the special features provided by template literal strings.
+         * @private
+         */
+        function isUsingFeatureOfTemplateLiteral(node) {
+            const hasTag = node.parent.type === "TaggedTemplateExpression" && node === node.parent.quasi;
+
+            if (hasTag) {
+                return true;
+            }
+
+            const hasStringInterpolation = node.expressions.length > 0;
+
+            if (hasStringInterpolation) {
+                return true;
+            }
+
+            const isMultilineString = node.quasis.length >= 1 && UNESCAPED_LINEBREAK_PATTERN.test(node.quasis[0].value.raw);
+
+            if (isMultilineString) {
+                return true;
+            }
+
+            return false;
+        }
+
         return {
 
             Literal(node) {
@@ -260,39 +288,34 @@ module.exports = {
 
             TemplateLiteral(node) {
 
-                // If backticks are expected or it's a tagged template, then this shouldn't throw an errors
+                // Don't throw an error if backticks are expected or a template literal feature is in use.
                 if (
                     allowTemplateLiterals ||
                     quoteOption === "backtick" ||
-                    node.parent.type === "TaggedTemplateExpression" && node === node.parent.quasi
+                    isUsingFeatureOfTemplateLiteral(node)
                 ) {
                     return;
                 }
 
-                // A warning should be produced if the template literal only has one TemplateElement, and has no unescaped newlines.
-                const shouldWarn = node.quasis.length === 1 && !UNESCAPED_LINEBREAK_PATTERN.test(node.quasis[0].value.raw);
-
-                if (shouldWarn) {
-                    context.report({
-                        node,
-                        message: "Strings must use {{description}}.",
-                        data: {
-                            description: settings.description
-                        },
-                        fix(fixer) {
-                            if (isPartOfDirectivePrologue(node)) {
-
-                                /*
-                                 * TemplateLiterals in a directive prologue aren't actually directives, but if they're
-                                 * in the directive prologue, then fixing them might turn them into directives and change
-                                 * the behavior of the code.
-                                 */
-                                return null;
-                            }
-                            return fixer.replaceText(node, settings.convert(sourceCode.getText(node)));
+                context.report({
+                    node,
+                    message: "Strings must use {{description}}.",
+                    data: {
+                        description: settings.description
+                    },
+                    fix(fixer) {
+                        if (isPartOfDirectivePrologue(node)) {
+
+                            /*
+                             * TemplateLiterals in a directive prologue aren't actually directives, but if they're
+                             * in the directive prologue, then fixing them might turn them into directives and change
+                             * the behavior of the code.
+                             */
+                            return null;
                         }
-                    });
-                }
+                        return fixer.replaceText(node, settings.convert(sourceCode.getText(node)));
+                    }
+                });
             }
         };
 
diff --git a/lib/rules/require-jsdoc.js b/lib/rules/require-jsdoc.js
index 949314993..389bfb692 100644
--- a/lib/rules/require-jsdoc.js
+++ b/lib/rules/require-jsdoc.js
@@ -43,7 +43,10 @@ module.exports = {
                 },
                 additionalProperties: false
             }
-        ]
+        ],
+
+        deprecated: true,
+        replacedBy: []
     },
 
     create(context) {
diff --git a/lib/rules/space-before-blocks.js b/lib/rules/space-before-blocks.js
index 195c75659..872338eff 100644
--- a/lib/rules/space-before-blocks.js
+++ b/lib/rules/space-before-blocks.js
@@ -34,13 +34,13 @@ module.exports = {
                         type: "object",
                         properties: {
                             keywords: {
-                                enum: ["always", "never"]
+                                enum: ["always", "never", "off"]
                             },
                             functions: {
-                                enum: ["always", "never"]
+                                enum: ["always", "never", "off"]
                             },
                             classes: {
-                                enum: ["always", "never"]
+                                enum: ["always", "never", "off"]
                             }
                         },
                         additionalProperties: false
@@ -53,18 +53,27 @@ module.exports = {
     create(context) {
         const config = context.options[0],
             sourceCode = context.getSourceCode();
-        let checkFunctions = true,
-            checkKeywords = true,
-            checkClasses = true;
+        let alwaysFunctions = true,
+            alwaysKeywords = true,
+            alwaysClasses = true,
+            neverFunctions = false,
+            neverKeywords = false,
+            neverClasses = false;
 
         if (typeof config === "object") {
-            checkFunctions = config.functions !== "never";
-            checkKeywords = config.keywords !== "never";
-            checkClasses = config.classes !== "never";
+            alwaysFunctions = config.functions === "always";
+            alwaysKeywords = config.keywords === "always";
+            alwaysClasses = config.classes === "always";
+            neverFunctions = config.functions === "never";
+            neverKeywords = config.keywords === "never";
+            neverClasses = config.classes === "never";
         } else if (config === "never") {
-            checkFunctions = false;
-            checkKeywords = false;
-            checkClasses = false;
+            alwaysFunctions = false;
+            alwaysKeywords = false;
+            alwaysClasses = false;
+            neverFunctions = true;
+            neverKeywords = true;
+            neverClasses = true;
         }
 
         /**
@@ -90,35 +99,35 @@ module.exports = {
                 const hasSpace = sourceCode.isSpaceBetweenTokens(precedingToken, node);
                 const parent = context.getAncestors().pop();
                 let requireSpace;
+                let requireNoSpace;
 
                 if (parent.type === "FunctionExpression" || parent.type === "FunctionDeclaration") {
-                    requireSpace = checkFunctions;
+                    requireSpace = alwaysFunctions;
+                    requireNoSpace = neverFunctions;
                 } else if (node.type === "ClassBody") {
-                    requireSpace = checkClasses;
+                    requireSpace = alwaysClasses;
+                    requireNoSpace = neverClasses;
                 } else {
-                    requireSpace = checkKeywords;
+                    requireSpace = alwaysKeywords;
+                    requireNoSpace = neverKeywords;
                 }
 
-                if (requireSpace) {
-                    if (!hasSpace) {
-                        context.report({
-                            node,
-                            message: "Missing space before opening brace.",
-                            fix(fixer) {
-                                return fixer.insertTextBefore(node, " ");
-                            }
-                        });
-                    }
-                } else {
-                    if (hasSpace) {
-                        context.report({
-                            node,
-                            message: "Unexpected space before opening brace.",
-                            fix(fixer) {
-                                return fixer.removeRange([precedingToken.range[1], node.range[0]]);
-                            }
-                        });
-                    }
+                if (requireSpace && !hasSpace) {
+                    context.report({
+                        node,
+                        message: "Missing space before opening brace.",
+                        fix(fixer) {
+                            return fixer.insertTextBefore(node, " ");
+                        }
+                    });
+                } else if (requireNoSpace && hasSpace) {
+                    context.report({
+                        node,
+                        message: "Unexpected space before opening brace.",
+                        fix(fixer) {
+                            return fixer.removeRange([precedingToken.range[1], node.range[0]]);
+                        }
+                    });
                 }
             }
         }
diff --git a/lib/rules/space-in-parens.js b/lib/rules/space-in-parens.js
index 88f4f0b50..306866263 100644
--- a/lib/rules/space-in-parens.js
+++ b/lib/rules/space-in-parens.js
@@ -61,7 +61,6 @@ module.exports = {
 
         /**
          * Produces an object with the opener and closer exception values
-         * @param {Object} opts The exception options
          * @returns {Object} `openers` and `closers` exception values
          * @private
          */
diff --git a/lib/rules/space-infix-ops.js b/lib/rules/space-infix-ops.js
index 45b76795e..254616d99 100644
--- a/lib/rules/space-infix-ops.js
+++ b/lib/rules/space-infix-ops.js
@@ -69,7 +69,10 @@ module.exports = {
             context.report({
                 node: mainNode,
                 loc: culpritToken.loc.start,
-                message: "Infix operators must be spaced.",
+                message: "Operator '{{operator}}' must be spaced.",
+                data: {
+                    operator: culpritToken.value
+                },
                 fix(fixer) {
                     const previousToken = sourceCode.getTokenBefore(culpritToken);
                     const afterToken = sourceCode.getTokenAfter(culpritToken);
diff --git a/lib/rules/valid-jsdoc.js b/lib/rules/valid-jsdoc.js
index b434491bf..b40a20f6b 100644
--- a/lib/rules/valid-jsdoc.js
+++ b/lib/rules/valid-jsdoc.js
@@ -64,7 +64,10 @@ module.exports = {
             }
         ],
 
-        fixable: "code"
+        fixable: "code",
+
+        deprecated: true,
+        replacedBy: []
     },
 
     create(context) {
diff --git a/lib/util/config-comment-parser.js b/lib/util/config-comment-parser.js
new file mode 100644
index 000000000..88504caf1
--- /dev/null
+++ b/lib/util/config-comment-parser.js
@@ -0,0 +1,144 @@
+/**
+ * @fileoverview Config Comment Parser
+ * @author Nicholas C. Zakas
+ */
+
+/* eslint-disable class-methods-use-this*/
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const levn = require("levn"),
+    ConfigOps = require("../config/config-ops");
+
+const debug = require("debug")("eslint:config-comment-parser");
+
+//------------------------------------------------------------------------------
+// Public Interface
+//------------------------------------------------------------------------------
+
+/**
+ * Object to parse ESLint configuration comments inside JavaScript files.
+ * @name ConfigCommentParser
+ */
+module.exports = class ConfigCommentParser {
+
+    /**
+     * Parses a list of "name:boolean_value" or/and "name" options divided by comma or
+     * whitespace. Used for "global" and "exported" comments.
+     * @param {string} string The string to parse.
+     * @param {Comment} comment The comment node which has the string.
+     * @returns {Object} Result map object of names and boolean values
+     */
+    parseBooleanConfig(string, comment) {
+        debug("Parsing Boolean config");
+
+        const items = {};
+
+        // Collapse whitespace around `:` and `,` to make parsing easier
+        const trimmedString = string.replace(/\s*([:,])\s*/g, "$1");
+
+        trimmedString.split(/\s|,+/).forEach(name => {
+            if (!name) {
+                return;
+            }
+
+            // value defaults to "false" (if not provided), e.g: "foo" => ["foo", "false"]
+            const [key, value = "false"] = name.split(":");
+
+            items[key] = {
+                value: value === "true",
+                comment
+            };
+        });
+        return items;
+    }
+
+    /**
+     * Parses a JSON-like config.
+     * @param {string} string The string to parse.
+     * @param {Object} location Start line and column of comments for potential error message.
+     * @returns {({success: true, config: Object}|{success: false, error: Problem})} Result map object
+     */
+    parseJsonConfig(string, location) {
+        debug("Parsing JSON config");
+
+        let items = {};
+
+        // Parses a JSON-like comment by the same way as parsing CLI option.
+        try {
+            items = levn.parse("Object", string) || {};
+
+            // Some tests say that it should ignore invalid comments such as `/*eslint no-alert:abc*/`.
+            // Also, commaless notations have invalid severity:
+            //     "no-alert: 2 no-console: 2" --> {"no-alert": "2 no-console: 2"}
+            // Should ignore that case as well.
+            if (ConfigOps.isEverySeverityValid(items)) {
+                return {
+                    success: true,
+                    config: items
+                };
+            }
+        } catch (ex) {
+
+            debug("Levn parsing failed; falling back to manual parsing.");
+
+            // ignore to parse the string by a fallback.
+        }
+
+        /*
+         * Optionator cannot parse commaless notations.
+         * But we are supporting that. So this is a fallback for that.
+         */
+        items = {};
+        const normalizedString = string.replace(/([a-zA-Z0-9\-/]+):/g, "\"$1\":").replace(/(]|[0-9])\s+(?=")/, "$1,");
+
+        try {
+            items = JSON.parse(`{${normalizedString}}`);
+        } catch (ex) {
+            debug("Manual parsing failed.");
+
+            return {
+                success: false,
+                error: {
+                    ruleId: null,
+                    fatal: true,
+                    severity: 2,
+                    message: `Failed to parse JSON from '${normalizedString}': ${ex.message}`,
+                    line: location.start.line,
+                    column: location.start.column + 1
+                }
+            };
+
+        }
+
+        return {
+            success: true,
+            config: items
+        };
+    }
+
+    /**
+     * Parses a config of values separated by comma.
+     * @param {string} string The string to parse.
+     * @returns {Object} Result map of values and true values
+     */
+    parseListConfig(string) {
+        debug("Parsing list config");
+
+        const items = {};
+
+        // Collapse whitespace around commas
+        string.replace(/\s*,\s*/g, ",").split(/,+/).forEach(name => {
+            const trimmedName = name.trim();
+
+            if (trimmedName) {
+                items[trimmedName] = true;
+            }
+        });
+        return items;
+    }
+
+};
diff --git a/lib/util/glob-utils.js b/lib/util/glob-utils.js
index a2be0f042..fd4cfa008 100644
--- a/lib/util/glob-utils.js
+++ b/lib/util/glob-utils.js
@@ -14,7 +14,7 @@ const lodash = require("lodash"),
     GlobSync = require("./glob"),
 
     pathUtils = require("./path-utils"),
-    IgnoredPaths = require("../ignored-paths");
+    IgnoredPaths = require("./ignored-paths");
 
 const debug = require("debug")("eslint:glob-utils");
 
diff --git a/lib/ignored-paths.js b/lib/util/ignored-paths.js
similarity index 98%
rename from lib/ignored-paths.js
rename to lib/util/ignored-paths.js
index 8520090af..de4a79cde 100644
--- a/lib/ignored-paths.js
+++ b/lib/util/ignored-paths.js
@@ -12,7 +12,7 @@
 const fs = require("fs"),
     path = require("path"),
     ignore = require("ignore"),
-    pathUtils = require("./util/path-utils");
+    pathUtils = require("./path-utils");
 
 const debug = require("debug")("eslint:ignored-paths");
 
@@ -296,7 +296,7 @@ class IgnoredPaths {
     /**
      * read ignore filepath
      * @param {string} filePath, file to add to ig
-     * @returns {array} raw ignore rules
+     * @returns {Array} raw ignore rules
      */
     readIgnoreFile(filePath) {
         if (typeof this.cache[filePath] === "undefined") {
@@ -307,8 +307,8 @@ class IgnoredPaths {
 
     /**
      * add ignore file to node-ignore instance
-     * @param {Object} ig, instance of node-ignore
-     * @param {string} filePath, file to add to ig
+     * @param {Object} ig instance of node-ignore
+     * @param {string} filePath file to add to ig
      * @returns {void}
      */
     addIgnoreFile(ig, filePath) {
diff --git a/lib/report-translator.js b/lib/util/report-translator.js
similarity index 99%
rename from lib/report-translator.js
rename to lib/util/report-translator.js
index f82830586..3dfdca0e4 100644
--- a/lib/report-translator.js
+++ b/lib/util/report-translator.js
@@ -10,8 +10,8 @@
 //------------------------------------------------------------------------------
 
 const assert = require("assert");
-const ruleFixer = require("./util/rule-fixer");
-const interpolate = require("./util/interpolate");
+const ruleFixer = require("./rule-fixer");
+const interpolate = require("./interpolate");
 
 //------------------------------------------------------------------------------
 // Typedefs
diff --git a/lib/util/source-code.js b/lib/util/source-code.js
index dd45f6112..4e90ac1aa 100644
--- a/lib/util/source-code.js
+++ b/lib/util/source-code.js
@@ -87,7 +87,7 @@ class SourceCode extends TokenStore {
      * @param {string|Object} textOrConfig - The source code text or config object.
      * @param {string} textOrConfig.text - The source code text.
      * @param {ASTNode} textOrConfig.ast - The Program node of the AST representing the code. This AST should be created from the text that BOM was stripped.
-     * @param {Object|null} textOrConfig.parserServices - The parser srevices.
+     * @param {Object|null} textOrConfig.parserServices - The parser services.
      * @param {ScopeManager|null} textOrConfig.scopeManager - The scope of this source code.
      * @param {Object|null} textOrConfig.visitorKeys - The visitor keys to traverse AST.
      * @param {ASTNode} [astIfNoConfig] - The Program node of the AST representing the code. This AST should be created from the text that BOM was stripped.
@@ -316,6 +316,7 @@ class SourceCode extends TokenStore {
      * @returns {Token|null} The Block comment token containing the JSDoc comment
      *      for the given node or null if not found.
      * @public
+     * @deprecated
      */
     getJSDocComment(node) {
 
diff --git a/messages/all-files-ignored.txt b/messages/all-files-ignored.txt
index 3b741a03e..3f4c8ced4 100644
--- a/messages/all-files-ignored.txt
+++ b/messages/all-files-ignored.txt
@@ -1,4 +1,4 @@
-All of the files matching the glob pattern "<%= pattern %>" are ignored.
+You are linting "<%= pattern %>", but all of the files matching the glob pattern "<%= pattern %>" are ignored.
 
 If you don't want to lint these files, remove the pattern "<%= pattern %>" from the list of arguments passed to ESLint.
 
diff --git a/package.json b/package.json
index c2f7626dc..7e3cf2fc6 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "eslint",
-  "version": "5.8.0",
+  "version": "5.11.1",
   "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
   "description": "An AST-based pattern checker for JavaScript.",
   "bin": {
@@ -44,7 +44,7 @@
     "eslint-scope": "^4.0.0",
     "eslint-utils": "^1.3.1",
     "eslint-visitor-keys": "^1.0.0",
-    "espree": "^4.0.0",
+    "espree": "^5.0.0",
     "esquery": "^1.0.1",
     "esutils": "^2.0.2",
     "file-entry-cache": "^2.0.0",
@@ -52,9 +52,9 @@
     "glob": "^7.1.2",
     "globals": "^11.7.0",
     "ignore": "^4.0.6",
+    "import-fresh": "^3.0.0",
     "imurmurhash": "^0.1.4",
     "inquirer": "^6.1.0",
-    "is-resolvable": "^1.1.0",
     "js-yaml": "^3.12.0",
     "json-stable-stringify-without-jsonify": "^1.0.1",
     "levn": "^0.3.0",
@@ -67,7 +67,6 @@
     "pluralize": "^7.0.0",
     "progress": "^2.0.0",
     "regexpp": "^2.0.1",
-    "require-uncached": "^1.0.3",
     "semver": "^5.5.1",
     "strip-ansi": "^4.0.0",
     "strip-json-comments": "^2.0.1",
@@ -87,10 +86,10 @@
     "coveralls": "^3.0.1",
     "dateformat": "^3.0.3",
     "ejs": "^2.6.1",
-    "eslint-plugin-eslint-plugin": "^1.2.0",
-    "eslint-plugin-node": "^7.0.1",
+    "eslint-plugin-eslint-plugin": "^2.0.1",
+    "eslint-plugin-node": "^8.0.0",
     "eslint-plugin-rulesdir": "^0.1.0",
-    "eslint-release": "^1.0.0",
+    "eslint-release": "^1.2.0",
     "eslint-rule-composer": "^0.3.0",
     "eslump": "^1.6.2",
     "esprima": "^4.0.1",
@@ -98,17 +97,17 @@
     "jsdoc": "^3.5.5",
     "karma": "^3.0.0",
     "karma-babel-preprocessor": "^7.0.0",
+    "karma-chrome-launcher": "^2.2.0",
     "karma-mocha": "^1.3.0",
     "karma-mocha-reporter": "^2.2.3",
-    "karma-phantomjs-launcher": "^1.0.4",
     "leche": "^2.2.3",
     "load-perf": "^0.2.0",
     "markdownlint": "^0.11.0",
     "mocha": "^5.0.5",
     "mock-fs": "^4.6.0",
     "npm-license": "^0.3.3",
-    "phantomjs-prebuilt": "^2.1.16",
     "proxyquire": "^2.0.1",
+    "puppeteer": "^1.9.0",
     "shelljs": "^0.8.2",
     "sinon": "^3.3.0",
     "temp": "^0.8.3",
diff --git a/packages/eslint-config-eslint/default.yml b/packages/eslint-config-eslint/default.yml
index 30444d640..9fdb4c767 100644
--- a/packages/eslint-config-eslint/default.yml
+++ b/packages/eslint-config-eslint/default.yml
@@ -118,6 +118,7 @@ rules:
     no-unused-vars: ["error", {vars: "all", args: "after-used"}]
     no-use-before-define: "error"
     no-useless-call: "error"
+    no-useless-catch: "error"
     no-useless-computed-key: "error"
     no-useless-concat: "error"
     no-useless-constructor: "error"
@@ -181,6 +182,7 @@ rules:
             "String": "string",
             "Number": "number",
             "Boolean": "boolean",
+            "array": "Array",
             "object": "Object",
             "function": "Function"
         }
diff --git a/packages/eslint-config-eslint/package.json b/packages/eslint-config-eslint/package.json
index e6e0bfe4e..a12cf52a9 100644
--- a/packages/eslint-config-eslint/package.json
+++ b/packages/eslint-config-eslint/package.json
@@ -23,7 +23,7 @@
     "js-yaml": "^3.5.1"
   },
   "peerDependencies": {
-    "eslint-plugin-node": "^6.0.1 || ^7.0.1"
+    "eslint-plugin-node": "^6.0.1 || ^7.0.1 || ^8.0.0"
   },
   "keywords": [
     "eslintconfig",
diff --git a/templates/blogpost.md.ejs b/templates/blogpost.md.ejs
index b583afa36..80235073a 100644
--- a/templates/blogpost.md.ejs
+++ b/templates/blogpost.md.ejs
@@ -15,7 +15,6 @@ const RULE_REGEX = new RegExp(`\`?\\b(${ruleList.join("|")})\\b\`?`, "g");
 function linkify(line) {
     return line
         .replace(/#(\d+)/g, "[#$1](https://github.com/eslint/eslint/issues/$1)")
-        .replace(/([a-z0-9]+)/, "[$1](https://github.com/eslint/eslint/commit/$1)")
         .replace(RULE_REGEX, "[$&](/docs/rules/$1)");
 }
 
diff --git a/tools/internal-rules/consistent-docs-description.js b/tools/internal-rules/consistent-docs-description.js
index b56c641a3..b3ee52241 100644
--- a/tools/internal-rules/consistent-docs-description.js
+++ b/tools/internal-rules/consistent-docs-description.js
@@ -115,7 +115,7 @@ module.exports = {
             category: "Internal",
             recommended: false
         },
-
+        type: "suggestion",
         schema: []
     },
 
diff --git a/tools/internal-rules/consistent-docs-url.js b/tools/internal-rules/consistent-docs-url.js
index 8e6652fc4..4d1344116 100644
--- a/tools/internal-rules/consistent-docs-url.js
+++ b/tools/internal-rules/consistent-docs-url.js
@@ -94,7 +94,7 @@ module.exports = {
             category: "Internal",
             recommended: false
         },
-
+        type: "suggestion",
         schema: []
     },
 
diff --git a/tools/internal-rules/consistent-meta-messages.js b/tools/internal-rules/consistent-meta-messages.js
index 43711c6ec..24facb189 100644
--- a/tools/internal-rules/consistent-meta-messages.js
+++ b/tools/internal-rules/consistent-meta-messages.js
@@ -65,8 +65,9 @@ module.exports = {
             recommended: false
         },
         schema: [],
+        type: "suggestion",
         messages: {
-            expectedMessages: "Expected `meta.messages` property"
+            expectedMessages: "Expected `meta.messages` property."
         }
     },
 
diff --git a/tools/internal-rules/no-invalid-meta.js b/tools/internal-rules/no-invalid-meta.js
index c0a9bc907..973b2a480 100644
--- a/tools/internal-rules/no-invalid-meta.js
+++ b/tools/internal-rules/no-invalid-meta.js
@@ -161,7 +161,7 @@ module.exports = {
             category: "Internal",
             recommended: false
         },
-
+        type: "problem",
         schema: []
     },
 
diff --git a/tools/rule-types.json b/tools/rule-types.json
index 40010c896..44c1d48ab 100644
--- a/tools/rule-types.json
+++ b/tools/rule-types.json
@@ -196,6 +196,7 @@
     "no-unused-vars": "problem",
     "no-use-before-define": "problem",
     "no-useless-call": "suggestion",
+    "no-useless-catch": "suggestion",
     "no-useless-computed-key": "suggestion",
     "no-useless-concat": "suggestion",
     "no-useless-constructor": "suggestion",


Test patch:
diff --git a/tests/lib/cli-engine.js b/tests/lib/cli-engine.js
index d5b0b3728..9a57e86df 100644
--- a/tests/lib/cli-engine.js
+++ b/tests/lib/cli-engine.js
@@ -733,6 +733,7 @@ describe("CLIEngine", () => {
         it("should warn when deprecated rules are found in a config", () => {
             engine = new CLIEngine({
                 cwd: originalDir,
+                useEslintrc: false,
                 configFile: "tests/fixtures/cli-engine/deprecated-rule-config/.eslintrc.yml"
             });
 
@@ -1530,7 +1531,11 @@ describe("CLIEngine", () => {
 
             assert.deepStrictEqual(
                 report.usedDeprecatedRules,
-                [{ ruleId: "indent-legacy", replacedBy: ["indent"] }]
+                [
+                    { ruleId: "indent-legacy", replacedBy: ["indent"] },
+                    { ruleId: "require-jsdoc", replacedBy: [] },
+                    { ruleId: "valid-jsdoc", replacedBy: [] }
+                ]
             );
         });
 
@@ -1538,7 +1543,7 @@ describe("CLIEngine", () => {
             engine = new CLIEngine({
                 cwd: originalDir,
                 configFile: ".eslintrc.js",
-                rules: { indent: 1 }
+                rules: { indent: 1, "valid-jsdoc": 0, "require-jsdoc": 0 }
             });
 
             const report = engine.executeOnFiles(["lib/cli*.js"]);
@@ -1549,7 +1554,8 @@ describe("CLIEngine", () => {
         it("should warn when deprecated rules are found in a config", () => {
             engine = new CLIEngine({
                 cwd: originalDir,
-                configFile: "tests/fixtures/cli-engine/deprecated-rule-config/.eslintrc.yml"
+                configFile: "tests/fixtures/cli-engine/deprecated-rule-config/.eslintrc.yml",
+                useEslintrc: false
             });
 
             const report = engine.executeOnFiles(["lib/cli*.js"]);
diff --git a/tests/lib/config/config-file.js b/tests/lib/config/config-file.js
index 21fd94583..944ed8426 100644
--- a/tests/lib/config/config-file.js
+++ b/tests/lib/config/config-file.js
@@ -181,7 +181,7 @@ describe("ConfigFile", () => {
 
                 // Hacky: need to override isFile for each call for testing
                 "../util/module-resolver": createStubModuleResolver({ "eslint-config-foo": resolvedPath }),
-                "require-uncached"(filename) {
+                "import-fresh"(filename) {
                     return configDeps[filename];
                 }
             };
@@ -265,7 +265,7 @@ describe("ConfigFile", () => {
                 "../util/module-resolver": createStubModuleResolver({
                     "eslint-plugin-test": resolvedPath
                 }),
-                "require-uncached"(filename) {
+                "import-fresh"(filename) {
                     return configDeps[filename];
                 }
             };
@@ -296,7 +296,7 @@ describe("ConfigFile", () => {
                 "../util/module-resolver": createStubModuleResolver({
                     "eslint-plugin-test": resolvedPath
                 }),
-                "require-uncached"(filename) {
+                "import-fresh"(filename) {
                     return configDeps[filename];
                 }
             };
@@ -331,7 +331,7 @@ describe("ConfigFile", () => {
                     "eslint-config-foo": resolvedPaths[0],
                     "eslint-config-bar": resolvedPaths[1]
                 }),
-                "require-uncached"(filename) {
+                "import-fresh"(filename) {
                     return configDeps[filename];
                 }
             };
@@ -932,7 +932,7 @@ describe("ConfigFile", () => {
                 const resolvedPath = path.resolve(PROJECT_PATH, "./node_modules/eslint-plugin-test/index.js");
 
                 const configDeps = {
-                    "require-uncached"(filename) {
+                    "import-fresh"(filename) {
                         return configDeps[filename];
                     }
                 };
diff --git a/tests/lib/rules/camelcase.js b/tests/lib/rules/camelcase.js
index 3d2b7516c..eb80b4ef4 100644
--- a/tests/lib/rules/camelcase.js
+++ b/tests/lib/rules/camelcase.js
@@ -106,6 +106,11 @@ ruleTester.run("camelcase", rule, {
             options: [{ ignoreDestructuring: true }],
             parserOptions: { ecmaVersion: 6 }
         },
+        {
+            code: "var { [{category_id} = query]: categoryId } = query;",
+            options: [{ ignoreDestructuring: true }],
+            parserOptions: { ecmaVersion: 6 }
+        },
         {
             code: "var { category_id: category } = query;",
             parserOptions: { ecmaVersion: 6 }
@@ -193,6 +198,10 @@ ruleTester.run("camelcase", rule, {
         {
             code: "user_id = 0;",
             options: [{ allow: ["_id$"] }]
+        },
+        {
+            code: "__option_foo__ = 0;",
+            options: [{ allow: ["__option_foo__"] }]
         }
     ],
     invalid: [
@@ -341,6 +350,29 @@ ruleTester.run("camelcase", rule, {
                 }
             ]
         },
+        {
+            code: "var { [category_id]: categoryId } = query;",
+            options: [{ ignoreDestructuring: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                {
+                    messageId: "notCamelCase",
+                    data: { name: "category_id" },
+                    type: "Identifier"
+                }
+            ]
+        },
+        {
+            code: "var { [category_id]: categoryId } = query;",
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                {
+                    messageId: "notCamelCase",
+                    data: { name: "category_id" },
+                    type: "Identifier"
+                }
+            ]
+        },
         {
             code: "var { category_id: categoryId, ...other_props } = query;",
             options: [{ ignoreDestructuring: true }],
diff --git a/tests/lib/rules/comma-style.js b/tests/lib/rules/comma-style.js
index 83a1ca2c9..a63d80ae8 100644
--- a/tests/lib/rules/comma-style.js
+++ b/tests/lib/rules/comma-style.js
@@ -612,6 +612,13 @@ ruleTester.run("comma-style", rule, {
             code: "[\n[foo(3)],\n,\nbar\n];",
             output: "[\n[foo(3)],,\nbar\n];",
             errors: [{ messageId: "unexpectedLineBeforeAndAfterComma" }]
+        },
+        {
+
+            // https://github.com/eslint/eslint/issues/10632
+            code: "[foo//\n,/*block\ncomment*/];",
+            output: "[foo,//\n/*block\ncomment*/];",
+            errors: [{ messageId: "unexpectedLineBeforeAndAfterComma" }]
         }
     ]
 });
diff --git a/tests/lib/rules/id-match.js b/tests/lib/rules/id-match.js
index 36d60e9df..c3a12f6af 100644
--- a/tests/lib/rules/id-match.js
+++ b/tests/lib/rules/id-match.js
@@ -112,9 +112,41 @@ ruleTester.run("id-match", rule, {
         {
             code: "var obj = {key: no_under}",
             options: ["^[^_]+$", {
-                properties: true
+                properties: true,
+                onlyDeclarations: true
             }]
         },
+        {
+            code: "var {key_no_under: key} = {}",
+            options: ["^[^_]+$", {
+                properties: true
+            }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var { category_id } = query;",
+            options: ["^[^_]+$", {
+                properties: true,
+                ignoreDestructuring: true
+            }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var { category_id: category_id } = query;",
+            options: ["^[^_]+$", {
+                properties: true,
+                ignoreDestructuring: true
+            }],
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "var { category_id = 1 } = query;",
+            options: ["^[^_]+$", {
+                properties: true,
+                ignoreDestructuring: true
+            }],
+            parserOptions: { ecmaVersion: 6 }
+        },
         {
             code: "var o = {key: 1}",
             options: ["^[^_]+$", {
@@ -198,6 +230,18 @@ ruleTester.run("id-match", rule, {
                 }
             ]
         },
+        {
+            code: "var obj = {key: no_under}",
+            options: ["^[^_]+$", {
+                properties: true
+            }],
+            errors: [
+                {
+                    message: "Identifier 'no_under' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
+        },
         {
             code: "function no_under21(){}",
             options: ["^[^_]+$"],
@@ -315,6 +359,298 @@ ruleTester.run("id-match", rule, {
                     type: "Identifier"
                 }
             ]
+        },
+        {
+            code: "var { category_id: category_alias } = query;",
+            options: ["^[^_]+$", {
+                properties: true
+            }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                {
+                    message: "Identifier 'category_alias' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
+        },
+        {
+            code: "var { category_id: category_alias } = query;",
+            options: ["^[^_]+$", {
+                properties: true,
+                ignoreDestructuring: true
+            }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                {
+                    message: "Identifier 'category_alias' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
+        },
+        {
+            code: "var { category_id: categoryId, ...other_props } = query;",
+            options: ["^[^_]+$", {
+                properties: true,
+                ignoreDestructuring: true
+            }],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [
+                {
+                    message: "Identifier 'other_props' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
+        },
+        {
+            code: "var { category_id } = query;",
+            options: ["^[^_]+$", {
+                properties: true
+            }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                {
+                    message: "Identifier 'category_id' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
+        },
+        {
+            code: "var { category_id = 1 } = query;",
+            options: ["^[^_]+$", {
+                properties: true
+            }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                {
+                    message: "Identifier 'category_id' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
+        },
+        {
+            code: "import no_camelcased from \"external-module\";",
+            options: ["^[^_]+$", {
+                properties: true
+            }],
+            parserOptions: { ecmaVersion: 6, sourceType: "module" },
+            errors: [
+                {
+                    message: "Identifier 'no_camelcased' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
+        },
+        {
+            code: "import * as no_camelcased from \"external-module\";",
+            options: ["^[^_]+$", {
+                properties: true
+            }],
+            parserOptions: { ecmaVersion: 6, sourceType: "module" },
+            errors: [
+                {
+                    message: "Identifier 'no_camelcased' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
+        },
+        {
+            code: "import { no_camelcased } from \"external-module\";",
+            options: ["^[^_]+$", {
+                properties: true
+            }],
+            parserOptions: { ecmaVersion: 6, sourceType: "module" },
+            errors: [
+                {
+                    message: "Identifier 'no_camelcased' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
+        },
+        {
+            code: "import { no_camelcased as no_camel_cased } from \"external module\";",
+            options: ["^[^_]+$", {
+                properties: true
+            }],
+            parserOptions: { ecmaVersion: 6, sourceType: "module" },
+            errors: [
+                {
+                    message: "Identifier 'no_camel_cased' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
+        },
+        {
+            code: "import { camelCased as no_camel_cased } from \"external module\";",
+            options: ["^[^_]+$", {
+                properties: true
+            }],
+            parserOptions: { ecmaVersion: 6, sourceType: "module" },
+            errors: [
+                {
+                    message: "Identifier 'no_camel_cased' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
+        },
+        {
+            code: "import { camelCased, no_camelcased } from \"external-module\";",
+            options: ["^[^_]+$", {
+                properties: true
+            }],
+            parserOptions: { ecmaVersion: 6, sourceType: "module" },
+            errors: [
+                {
+                    message: "Identifier 'no_camelcased' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
+        },
+        {
+            code: "import { no_camelcased as camelCased, another_no_camelcased } from \"external-module\";",
+            options: ["^[^_]+$", {
+                properties: true
+            }],
+            parserOptions: { ecmaVersion: 6, sourceType: "module" },
+            errors: [
+                {
+                    message: "Identifier 'another_no_camelcased' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
+        },
+        {
+            code: "import camelCased, { no_camelcased } from \"external-module\";",
+            options: ["^[^_]+$", {
+                properties: true
+            }],
+            parserOptions: { ecmaVersion: 6, sourceType: "module" },
+            errors: [
+                {
+                    message: "Identifier 'no_camelcased' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
+        },
+        {
+            code: "import no_camelcased, { another_no_camelcased as camelCased } from \"external-module\";",
+            options: ["^[^_]+$", {
+                properties: true
+            }],
+            parserOptions: { ecmaVersion: 6, sourceType: "module" },
+            errors: [
+                {
+                    message: "Identifier 'no_camelcased' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
+        },
+        {
+            code: "function foo({ no_camelcased }) {};",
+            options: ["^[^_]+$", {
+                properties: true
+            }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                {
+                    message: "Identifier 'no_camelcased' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
+        },
+        {
+            code: "function foo({ no_camelcased = 'default value' }) {};",
+            options: ["^[^_]+$", {
+                properties: true
+            }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                {
+                    message: "Identifier 'no_camelcased' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
+        },
+        {
+            code: "const no_camelcased = 0; function foo({ camelcased_value = no_camelcased }) {}",
+            options: ["^[^_]+$", {
+                properties: true
+            }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                {
+                    message: "Identifier 'no_camelcased' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                },
+                {
+                    message: "Identifier 'camelcased_value' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
+        },
+        {
+            code: "const { bar: no_camelcased } = foo;",
+            options: ["^[^_]+$", {
+                properties: true
+            }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                {
+                    message: "Identifier 'no_camelcased' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
+        },
+        {
+            code: "function foo({ value_1: my_default }) {}",
+            options: ["^[^_]+$", {
+                properties: true
+            }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                {
+                    message: "Identifier 'my_default' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
+        },
+        {
+            code: "function foo({ isCamelcased: no_camelcased }) {};",
+            options: ["^[^_]+$", {
+                properties: true
+            }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                {
+                    message: "Identifier 'no_camelcased' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
+        },
+        {
+            code: "var { foo: bar_baz = 1 } = quz;",
+            options: ["^[^_]+$", {
+                properties: true
+            }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                {
+                    message: "Identifier 'bar_baz' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
+        },
+        {
+            code: "const { no_camelcased = false } = bar;",
+            options: ["^[^_]+$", {
+                properties: true
+            }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                {
+                    message: "Identifier 'no_camelcased' does not match the pattern '^[^_]+$'.",
+                    type: "Identifier"
+                }
+            ]
         }
     ]
 });
diff --git a/tests/lib/rules/implicit-arrow-linebreak.js b/tests/lib/rules/implicit-arrow-linebreak.js
index 7212e083f..f07182c1b 100644
--- a/tests/lib/rules/implicit-arrow-linebreak.js
+++ b/tests/lib/rules/implicit-arrow-linebreak.js
@@ -37,9 +37,76 @@ ruleTester.run("implicit-arrow-linebreak", rule, {
         `(foo) => (
             bar
         )`,
+        "(foo) => bar();",
+        `
+        //comment
+        foo => bar;
+        `,
+        `
+        foo => (
+            // comment
+            bar => (
+                // another comment
+                baz
+            )       
+        )
+        `,
+        `
+        foo => (
+            // comment
+            bar => baz
+        )
+        `,
+        `
+        /* text */
+        () => bar; 
+        `,
+        `
+        /* foo */
+        const bar = () => baz;
+        `,
+        `
+        (foo) => (
+                //comment
+                    bar
+                )
+        `,
+        `
+          [ // comment
+            foo => 'bar'
+          ]
+        `,
+        `
+         /*
+         One two three four
+         Five six seven nine.
+         */
+         (foo) => bar
+        `,
+        `
+        const foo = {
+          id: 'bar',
+          // comment
+          prop: (foo1) => 'returning this string', 
+        }
+        `,
+        `
+        // comment
+         "foo".split('').map((char) => char
+         )
+        `,
         {
-            code: "(foo) => bar();",
-            options: ["beside"]
+            code: `
+            async foo => () => bar;
+            `,
+            parserOptions: { ecmaVersion: 8 }
+        },
+        {
+            code: `
+            // comment
+            async foo => 'string'        
+            `,
+            parserOptions: { ecmaVersion: 8 }
         },
 
         // 'below' option
@@ -132,6 +199,371 @@ ruleTester.run("implicit-arrow-linebreak", rule, {
                     )
             `,
             errors: [UNEXPECTED_LINEBREAK]
+        }, {
+            code: `
+                (foo) =>
+                  // test comment
+                  bar
+            `,
+            output: `
+                // test comment
+                (foo) => bar
+            `,
+            errors: [UNEXPECTED_LINEBREAK]
+        }, {
+            code: `
+                const foo = () =>
+                // comment
+                []
+            `,
+            output: `
+                // comment
+                const foo = () => []
+            `,
+            errors: [UNEXPECTED_LINEBREAK]
+        }, {
+            code: `
+                (foo) =>
+                    (
+                    //comment
+                        bar
+                    )
+            `,
+            output: `
+                (foo) => (
+                    //comment
+                        bar
+                    )
+            `,
+            errors: [UNEXPECTED_LINEBREAK]
+        }, {
+            code: `
+                (foo) =>
+                    (
+                        bar
+                    //comment
+                    )
+            
+            `,
+            output: `
+                (foo) => (
+                        bar
+                    //comment
+                    )
+            
+            `,
+            errors: [UNEXPECTED_LINEBREAK]
+
+        }, {
+            code: `
+            (foo) =>
+             // comment
+             // another comment
+                bar`,
+            output: `
+            // comment
+            // another comment
+            (foo) => bar`,
+            errors: [UNEXPECTED_LINEBREAK]
+        }, {
+            code: `
+            (foo) =>
+            // comment
+            (
+            // another comment
+            bar
+            )`,
+            output: `
+            // comment
+            (foo) => (
+            // another comment
+            bar
+            )`,
+            errors: [UNEXPECTED_LINEBREAK]
+        },
+        {
+            code: "() => // comment \n bar",
+            output: "// comment \n() => bar",
+            errors: [UNEXPECTED_LINEBREAK]
+        }, {
+            code: "(foo) => //comment \n bar",
+            output: "//comment \n(foo) => bar",
+            errors: [UNEXPECTED_LINEBREAK]
+        }, {
+            code: `
+                (foo) =>
+                  /* test comment */
+                  bar
+            `,
+            output: `
+                /* test comment */
+                (foo) => bar
+            `,
+            errors: [UNEXPECTED_LINEBREAK]
+        }, {
+            code: `
+                (foo) =>
+                  // hi
+                     bar =>
+                       // there
+                         baz;
+            `,
+            output: `
+                (foo) => (
+                  // hi
+                     bar => (
+                       // there
+                         baz
+                     )
+                 );
+            `,
+            errors: [UNEXPECTED_LINEBREAK, UNEXPECTED_LINEBREAK]
+        }, {
+            code: `
+                (foo) =>
+                  // hi
+                     bar => (
+                       // there
+                         baz
+                     )
+            `,
+            output: `
+                (foo) => (
+                  // hi
+                     bar => (
+                       // there
+                         baz
+                     )
+                 )
+            `,
+            errors: [UNEXPECTED_LINEBREAK]
+        }, {
+            code: `
+            const foo = {
+              id: 'bar',
+              prop: (foo1) =>
+                // comment
+                'returning this string', 
+            }
+            `,
+            output: `
+            const foo = {
+              id: 'bar',
+              // comment
+              prop: (foo1) => 'returning this string', 
+            }
+            `,
+            errors: [UNEXPECTED_LINEBREAK]
+        }, {
+            code: `
+            [ foo => 
+              // comment
+              'bar'
+            ]
+            `,
+            output: `
+            [ // comment
+              foo => 'bar'
+            ]
+            `,
+            errors: [UNEXPECTED_LINEBREAK]
+        }, {
+            code: `
+             "foo".split('').map((char) =>
+                // comment
+                char
+             )
+            `,
+            output: `
+             // comment
+             "foo".split('').map((char) => char
+             )
+            `,
+            errors: [UNEXPECTED_LINEBREAK]
+        }, {
+            code: `
+                new Promise((resolve, reject) =>
+                    // comment
+                    resolve()
+                )
+            `,
+            output: `
+                new Promise(// comment
+                            (resolve, reject) => resolve()
+                )
+            `,
+            errors: [UNEXPECTED_LINEBREAK]
+        }, {
+            code: `
+                () =>
+                /*
+                succinct
+                explanation
+                of code
+                */
+                bar
+            `,
+            output: `
+                /*
+                succinct
+                explanation
+                of code
+                */
+                () => bar
+            `,
+            errors: [UNEXPECTED_LINEBREAK]
+        }, {
+            code: `
+                stepOne =>
+                    /*
+                    here is
+                    what is
+                    happening
+                    */
+                    stepTwo =>
+                        // then this happens
+                        stepThree`,
+            output: `
+                stepOne => (
+                    /*
+                    here is
+                    what is
+                    happening
+                    */
+                    stepTwo => (
+                        // then this happens
+                        stepThree
+                    )
+                )`,
+            errors: [UNEXPECTED_LINEBREAK, UNEXPECTED_LINEBREAK]
+        }, {
+            code: `
+            () =>
+                /*
+                multi
+                line
+                */
+                bar =>
+                    /*
+                    many
+                    lines
+                    */
+                    baz
+            `,
+            output: `
+            () => (
+                /*
+                multi
+                line
+                */
+                bar => (
+                    /*
+                    many
+                    lines
+                    */
+                    baz
+                )
+            )
+            `,
+            errors: [UNEXPECTED_LINEBREAK, UNEXPECTED_LINEBREAK]
+        }, {
+            code: `
+               foo('', boo =>
+                  // comment
+                  bar
+               )
+            `,
+            output: `
+               // comment
+               foo('', boo => bar
+               )
+            `,
+            errors: [UNEXPECTED_LINEBREAK]
+        }, {
+            code: `
+            async foo =>
+                // comment
+                'string'
+            `,
+            output: `
+            // comment
+            async foo => 'string'
+            `,
+            parserOptions: { ecmaVersion: 8 },
+            errors: [UNEXPECTED_LINEBREAK]
+        }, {
+            code: `
+            async foo =>
+                // comment
+                // another
+                bar;
+            `,
+            output: `
+            // comment
+            // another
+            async foo => bar;
+            `,
+            parserOptions: { ecmaVersion: 8 },
+            errors: [UNEXPECTED_LINEBREAK]
+        }, {
+            code: `
+            async (foo) =>
+                // comment
+                'string'
+            `,
+            output: `
+            // comment
+            async (foo) => 'string'
+            `,
+            parserOptions: { ecmaVersion: 8 },
+            errors: [UNEXPECTED_LINEBREAK]
+        }, {
+            code: `
+              const foo = 1,
+                  bar = 2,
+                  baz = () => // comment
+                    qux
+            `,
+            output: `
+              const foo = 1,
+                  bar = 2,
+                  // comment
+                  baz = () => qux
+            `,
+            errors: [UNEXPECTED_LINEBREAK]
+        }, {
+            code: `
+              const foo = () =>
+                  //comment
+                  qux,
+                  bar = 2,
+                  baz = 3
+            `,
+            output: `
+              //comment
+              const foo = () => qux,
+                  bar = 2,
+                  baz = 3
+            `,
+            errors: [UNEXPECTED_LINEBREAK]
+        }, {
+            code: `
+            const foo = () =>
+                //two
+                1,
+                boo = () => 
+                //comment
+                2,
+                bop = "what"
+            `,
+            output: `
+            //two
+            const foo = () => 1,
+                //comment
+                boo = () => 2,
+                bop = "what"
+            `,
+            errors: [UNEXPECTED_LINEBREAK, UNEXPECTED_LINEBREAK]
         },
 
         // 'below' option
diff --git a/tests/lib/rules/indent-legacy.js b/tests/lib/rules/indent-legacy.js
index 17a1f62a4..3e3a21684 100644
--- a/tests/lib/rules/indent-legacy.js
+++ b/tests/lib/rules/indent-legacy.js
@@ -24,7 +24,7 @@ const fixedFixture = fs.readFileSync(path.join(__dirname, "../../fixtures/rules/
 /**
  * Create error message object for failure cases with a single 'found' indentation type
  * @param {string} providedIndentType indent type of string or tab
- * @param {array} providedErrors error info
+ * @param {Array} providedErrors error info
  * @returns {Object} returns the error messages collection
  * @private
  */
diff --git a/tests/lib/rules/indent.js b/tests/lib/rules/indent.js
index b25e25949..2690830b9 100644
--- a/tests/lib/rules/indent.js
+++ b/tests/lib/rules/indent.js
@@ -25,7 +25,7 @@ const parser = require("../../fixtures/fixture-parser");
 /**
  * Create error message object for failure cases with a single 'found' indentation type
  * @param {string} providedIndentType indent type of string or tab
- * @param {array} providedErrors error info
+ * @param {Array} providedErrors error info
  * @returns {Object} returns the error messages collection
  * @private
  */
@@ -271,6 +271,17 @@ ruleTester.run("indent", rule, {
             `,
             options: [4]
         },
+        {
+
+            // https://github.com/eslint/eslint/issues/11802
+            code: unIndent`
+                import foo from "foo"
+
+                ;(() => {})()
+            `,
+            options: [4],
+            parserOptions: { sourceType: "module" }
+        },
         {
             code: unIndent`
                 function test() {
@@ -603,6 +614,24 @@ ruleTester.run("indent", rule, {
             `,
             options: [2, { VariableDeclarator: 1 }]
         },
+        {
+            code: unIndent`
+                let foo = 'foo',
+                    bar = bar;
+                const a = 'a',
+                      b = 'b';
+            `,
+            options: [2, { VariableDeclarator: "first" }]
+        },
+        {
+            code: unIndent`
+                let foo = 'foo',
+                    bar = bar  // <-- no semicolon here
+                const a = 'a',
+                      b = 'b'  // <-- no semicolon here
+            `,
+            options: [2, { VariableDeclarator: "first" }]
+        },
         {
             code: unIndent`
                 var foo = 1,
@@ -621,6 +650,43 @@ ruleTester.run("indent", rule, {
             `,
             options: [2, { VariableDeclarator: { var: 2 } }]
         },
+        {
+            code: unIndent`
+                var foo = 'foo',
+                    bar = bar;
+            `,
+            options: [2, { VariableDeclarator: { var: "first" } }]
+        },
+        {
+            code: unIndent`
+                var foo = 'foo',
+                    bar = 'bar'  // <-- no semicolon here
+            `,
+            options: [2, { VariableDeclarator: { var: "first" } }]
+        },
+        {
+            code: unIndent`
+            let foo = 1,
+                bar = 2,
+                baz
+            `,
+            options: [2, { VariableDeclarator: "first" }]
+        },
+        {
+            code: unIndent`
+            let
+                foo
+            `,
+            options: [4, { VariableDeclarator: "first" }]
+        },
+        {
+            code: unIndent`
+            let foo = 1,
+                bar =
+                2
+            `,
+            options: [2, { VariableDeclarator: "first" }]
+        },
         {
             code: unIndent`
                 var abc =
@@ -5922,6 +5988,39 @@ ruleTester.run("indent", rule, {
                 [2, 4, 2, "Identifier"]
             ])
         },
+        {
+            code: unIndent`
+                let foo = 'foo',
+                  bar = bar;
+                const a = 'a',
+                  b = 'b';
+            `,
+            output: unIndent`
+                let foo = 'foo',
+                    bar = bar;
+                const a = 'a',
+                      b = 'b';
+            `,
+            options: [2, { VariableDeclarator: "first" }],
+            errors: expectedErrors([
+                [2, 4, 2, "Identifier"],
+                [4, 6, 2, "Identifier"]
+            ])
+        },
+        {
+            code: unIndent`
+                var foo = 'foo',
+                  bar = bar;
+            `,
+            output: unIndent`
+                var foo = 'foo',
+                    bar = bar;
+            `,
+            options: [2, { VariableDeclarator: { var: "first" } }],
+            errors: expectedErrors([
+                [2, 4, 2, "Identifier"]
+            ])
+        },
         {
             code: unIndent`
                 if(true)
diff --git a/tests/lib/rules/keyword-spacing.js b/tests/lib/rules/keyword-spacing.js
index 33a9d5068..cebd16367 100644
--- a/tests/lib/rules/keyword-spacing.js
+++ b/tests/lib/rules/keyword-spacing.js
@@ -2023,6 +2023,12 @@ ruleTester.run("keyword-spacing", rule, {
             parserOptions: { sourceType: "module" },
             errors: expectedBefore("export")
         },
+        {
+            code: "export default{a}",
+            output: "export default {a}",
+            parserOptions: { sourceType: "module" },
+            errors: expectedAfter("default")
+        },
         {
             code: "{}export* from \"a\"",
             output: "{} export * from \"a\"",
diff --git a/tests/lib/rules/no-empty-function.js b/tests/lib/rules/no-empty-function.js
index 416a47da6..21f1bdae0 100644
--- a/tests/lib/rules/no-empty-function.js
+++ b/tests/lib/rules/no-empty-function.js
@@ -31,9 +31,9 @@ const ALLOW_OPTIONS = Object.freeze([
  * Folds test items to `{valid: [], invalid: []}`.
  * One item would be converted to 4 valid patterns and 8 invalid patterns.
  *
- * @param {{valid: object[], invalid: object[]}} patterns - The result.
+ * @param {{valid: Object[], invalid: Object[]}} patterns - The result.
  * @param {{code: string, message: string, allow: string}} item - A test item.
- * @returns {{valid: object[], invalid: object[]}} The result.
+ * @returns {{valid: Object[], invalid: Object[]}} The result.
  */
 function toValidInvalid(patterns, item) {
 
diff --git a/tests/lib/rules/no-param-reassign.js b/tests/lib/rules/no-param-reassign.js
index 5d009c338..40156f481 100644
--- a/tests/lib/rules/no-param-reassign.js
+++ b/tests/lib/rules/no-param-reassign.js
@@ -32,6 +32,8 @@ ruleTester.run("no-param-reassign", rule, {
         { code: "function foo(a) { bar(a.b).c = 0; }", options: [{ props: true }] },
         { code: "function foo(a) { data[a.b] = 0; }", options: [{ props: true }] },
         { code: "function foo(a) { +a.b; }", options: [{ props: true }] },
+        { code: "function foo(a) { (a ? [] : [])[0] = 1; }", options: [{ props: true }] },
+        { code: "function foo(a) { (a.b ? [] : [])[0] = 1; }", options: [{ props: true }] },
         { code: "function foo(a) { a.b = 0; }", options: [{ props: true, ignorePropertyModificationsFor: ["a"] }] },
         { code: "function foo(a) { ++a.b; }", options: [{ props: true, ignorePropertyModificationsFor: ["a"] }] },
         { code: "function foo(a) { delete a.b; }", options: [{ props: true, ignorePropertyModificationsFor: ["a"] }] },
@@ -87,6 +89,11 @@ ruleTester.run("no-param-reassign", rule, {
             options: [{ props: true }],
             errors: [{ message: "Assignment to property of function parameter 'bar'." }]
         },
+        {
+            code: "function foo(bar) { (bar ? bar : [])[0] = 1; }",
+            options: [{ props: true }],
+            errors: [{ message: "Assignment to property of function parameter 'bar'." }]
+        },
         {
             code: "function foo(bar) { [bar.a] = []; }",
             options: [{ props: true }],
diff --git a/tests/lib/rules/no-restricted-imports.js b/tests/lib/rules/no-restricted-imports.js
index 5d279d5a3..c4f2abb60 100644
--- a/tests/lib/rules/no-restricted-imports.js
+++ b/tests/lib/rules/no-restricted-imports.js
@@ -193,6 +193,24 @@ ruleTester.run("no-restricted-imports", rule, {
         code: "import withGitignores from \"foo/bar\";",
         options: [{ patterns: ["foo/*", "!foo/baz"] }],
         errors: [{ message: "'foo/bar' import is restricted from being used by a pattern.", type: "ImportDeclaration" }]
+    }, {
+        code: "export * from \"fs\";",
+        options: ["fs"],
+        errors: [{ message: "'fs' import is restricted from being used.", type: "ExportAllDeclaration" }]
+    }, {
+        code: "export {a} from \"fs\";",
+        options: ["fs"],
+        errors: [{ message: "'fs' import is restricted from being used.", type: "ExportNamedDeclaration" }]
+    }, {
+        code: "export {foo as b} from \"fs\";",
+        options: [{
+            paths: [{
+                name: "fs",
+                importNames: ["foo"],
+                message: "Don't import 'foo'."
+            }]
+        }],
+        errors: [{ message: "'fs' import is restricted from being used. Don't import 'foo'.", type: "ExportNamedDeclaration" }]
     }, {
         code: "import withGitignores from \"foo\";",
         options: [{
diff --git a/tests/lib/rules/no-unreachable.js b/tests/lib/rules/no-unreachable.js
index 54575cc00..1e04d687c 100644
--- a/tests/lib/rules/no-unreachable.js
+++ b/tests/lib/rules/no-unreachable.js
@@ -32,6 +32,13 @@ ruleTester.run("no-unreachable", rule, {
         "while (true) { if (true) break; var x = 1; }",
         "while (true) continue;",
         "switch (foo) { case 1: break; var x; }",
+        "switch (foo) { case 1: break; var x; default: throw true; };",
+        {
+            code: "const arrow_direction = arrow => {  switch (arrow) { default: throw new Error();  };}",
+            parserOptions: {
+                ecmaVersion: 6
+            }
+        },
         "var x = 1; y = 2; throw 'uh oh'; var y;",
         "function foo() { var x = 1; if (x) { return; } x = 2; }",
         "function foo() { var x = 1; if (x) { } else { return; } x = 2; }",
@@ -63,6 +70,20 @@ ruleTester.run("no-unreachable", rule, {
         { code: "function foo() { var x = 1; while (x) { if (x) break; else continue; x = 2; } }", errors: [{ message: "Unreachable code.", type: "ExpressionStatement" }] },
         { code: "function foo() { var x = 1; for (;;) { if (x) continue; } x = 2; }", errors: [{ message: "Unreachable code.", type: "ExpressionStatement" }] },
         { code: "function foo() { var x = 1; while (true) { } x = 2; }", errors: [{ message: "Unreachable code.", type: "ExpressionStatement" }] },
+        {
+            code: "const arrow_direction = arrow => {  switch (arrow) { default: throw new Error();  }; g() }",
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                {
+                    message: "Unreachable code.",
+                    type: "ExpressionStatement",
+                    line: 1,
+                    column: 86,
+                    endLine: 1,
+                    endColumn: 89
+                }
+            ]
+        },
 
         // Merge the warnings of continuous unreachable nodes.
         {
diff --git a/tests/lib/rules/no-unused-vars.js b/tests/lib/rules/no-unused-vars.js
index 316df18e0..9b6733cac 100644
--- a/tests/lib/rules/no-unused-vars.js
+++ b/tests/lib/rules/no-unused-vars.js
@@ -274,8 +274,19 @@ ruleTester.run("no-unused-vars", rule, {
         },
 
         // https://github.com/eslint/eslint/issues/10952
-        "/*eslint use-every-a:1*/ !function(b, a) { return 1 }"
+        "/*eslint use-every-a:1*/ !function(b, a) { return 1 }",
 
+        // https://github.com/eslint/eslint/issues/10982
+        "var a = function () { a(); }; a();",
+        "var a = function(){ return function () { a(); } }; a();",
+        {
+            code: "const a = () => { a(); }; a();",
+            parserOptions: { ecmaVersion: 2015 }
+        },
+        {
+            code: "const a = () => () => { a(); }; a();",
+            parserOptions: { ecmaVersion: 2015 }
+        }
     ],
     invalid: [
         { code: "function foox() { return foox(); }", errors: [definedError("foox")] },
@@ -717,6 +728,28 @@ ruleTester.run("no-unused-vars", rule, {
             code: "(function(_a) {})();",
             options: [{ args: "all", caughtErrorsIgnorePattern: "^_" }],
             errors: [{ message: "'_a' is defined but never used." }]
+        },
+
+        // https://github.com/eslint/eslint/issues/10982
+        {
+            code: "var a = function() { a(); };",
+            errors: [{ message: "'a' is assigned a value but never used." }]
+        },
+        {
+            code: "var a = function(){ return function() { a(); } };",
+            errors: [
+                { message: "'a' is assigned a value but never used." }
+            ]
+        },
+        {
+            code: "const a = () => { a(); };",
+            parserOptions: { ecmaVersion: 2015 },
+            errors: [{ message: "'a' is assigned a value but never used." }]
+        },
+        {
+            code: "const a = () => () => { a(); };",
+            parserOptions: { ecmaVersion: 2015 },
+            errors: [{ message: "'a' is assigned a value but never used." }]
         }
     ]
 });
diff --git a/tests/lib/rules/no-useless-catch.js b/tests/lib/rules/no-useless-catch.js
new file mode 100644
index 000000000..93989a403
--- /dev/null
+++ b/tests/lib/rules/no-useless-catch.js
@@ -0,0 +1,195 @@
+/**
+ * @fileoverview Tests for no-useless-throw rule
+ * @author Teddy Katz
+ * @author Alex Grasley
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const rule = require("../../../lib/rules/no-useless-catch"),
+    RuleTester = require("../../../lib/testers/rule-tester");
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+
+ruleTester.run("no-useless-catch", rule, {
+    valid: [
+        `
+            try {
+                foo();
+            } catch (err) {
+                console.error(err);
+            }
+        `,
+        `
+            try {
+                foo();
+            } catch (err) {
+                console.error(err);
+            } finally {
+                bar();
+            }
+        `,
+        `
+            try {
+                foo();
+            } catch (err) {
+                doSomethingBeforeRethrow();
+                throw err;
+            }
+        `,
+        `
+            try {
+                foo();
+            } catch (err) {
+                throw err.msg;
+            }
+        `,
+        `
+            try {
+                foo();
+            } catch (err) {
+                throw new Error("whoops!");
+            }
+        `,
+        `
+            try {
+                foo();
+            } catch (err) {
+                throw bar;
+            }
+        `,
+        `
+            try {
+                foo();
+            } catch (err) { }
+        `,
+        {
+            code: `
+                try {
+                    foo();
+                } catch ({ err }) {
+                    throw err;
+                }
+            `,
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: `
+                try {
+                    foo();
+                } catch ([ err ]) {
+                    throw err;
+                }
+            `,
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: `
+                async () => {
+                    try {
+                        await doSomething();
+                    } catch (e) {
+                        doSomethingAfterCatch();
+                        throw e;
+                    }
+                }
+            `,
+            parserOptions: { ecmaVersion: 8 }
+        },
+        {
+            code: `
+                try {
+                    throw new Error('foo');
+                } catch {
+                    throw new Error('foo');
+                }
+            `,
+            parserOptions: { ecmaVersion: 2019 }
+        }
+
+    ],
+    invalid: [
+        {
+            code: `
+                try {
+                    foo();
+                } catch (err) {
+                    throw err;
+                }
+            `,
+            errors: [{
+                message: "Unnecessary try/catch wrapper.",
+                type: "TryStatement"
+            }]
+        },
+        {
+            code: `
+                try {
+                    foo();
+                } catch (err) {
+                    throw err;
+                } finally {
+                    foo();
+                }
+            `,
+            errors: [{
+                message: "Unnecessary catch clause.",
+                type: "CatchClause"
+            }]
+        },
+        {
+            code: `
+                try {
+                    foo();
+                } catch (err) {
+                    /* some comment */
+                    throw err;
+                }
+            `,
+            errors: [{
+                message: "Unnecessary try/catch wrapper.",
+                type: "TryStatement"
+            }]
+        },
+        {
+            code: `
+                try {
+                    foo();
+                } catch (err) {
+                    /* some comment */
+                    throw err;
+                } finally {
+                    foo();
+                }
+            `,
+            errors: [{
+                message: "Unnecessary catch clause.",
+                type: "CatchClause"
+            }]
+        },
+        {
+            code: `
+                async () => {
+                    try {
+                        await doSomething();
+                    } catch (e) {
+                        throw e;
+                    }
+                }
+            `,
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{
+                message: "Unnecessary try/catch wrapper.",
+                type: "TryStatement"
+            }]
+        }
+    ]
+});
diff --git a/tests/lib/rules/padding-line-between-statements.js b/tests/lib/rules/padding-line-between-statements.js
index 82147d389..dc5d81c42 100644
--- a/tests/lib/rules/padding-line-between-statements.js
+++ b/tests/lib/rules/padding-line-between-statements.js
@@ -1071,6 +1071,204 @@ ruleTester.run("padding-line-between-statements", rule, {
             ]
         },
 
+        //----------------------------------------------------------------------
+        // multiline-const
+        //----------------------------------------------------------------------
+
+        {
+            code: "const a={\nb:1,\nc:2\n}\n\nconst d=3",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "multiline-const", next: "*" }
+            ]
+        },
+        {
+            code: "const a=1\n\nconst b={\nc:2,\nd:3\n}",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "*", next: "multiline-const" }
+            ]
+        },
+        {
+            code: "const a=1\nconst b=2",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "multiline-const", next: "*" }
+            ]
+        },
+        {
+            code: "const a=1\nconst b=2",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "*", next: "multiline-const" }
+            ]
+        },
+
+        //----------------------------------------------------------------------
+        // multiline-let
+        //----------------------------------------------------------------------
+
+        {
+            code: "let a={\nb:1,\nc:2\n}\n\nlet d=3",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "multiline-let", next: "*" }
+            ]
+        },
+        {
+            code: "let a=1\n\nlet b={\nc:2,\nd:3\n}",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "*", next: "multiline-let" }
+            ]
+        },
+        {
+            code: "let a=1\nlet b=2",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "multiline-let", next: "*" }
+            ]
+        },
+        {
+            code: "let a=1\nlet b=2",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "*", next: "multiline-let" }
+            ]
+        },
+
+        //----------------------------------------------------------------------
+        // multiline-var
+        //----------------------------------------------------------------------
+
+        {
+            code: "var a={\nb:1,\nc:2\n}\n\nvar d=3",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "multiline-var", next: "*" }
+            ]
+        },
+        {
+            code: "var a=1\n\nvar b={\nc:2,\nd:3\n}",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "*", next: "multiline-var" }
+            ]
+        },
+        {
+            code: "var a=1\nvar b=2",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "multiline-var", next: "*" }
+            ]
+        },
+        {
+            code: "var a=1\nvar b=2",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "*", next: "multiline-var" }
+            ]
+        },
+
+        //----------------------------------------------------------------------
+        // singleline-const
+        //----------------------------------------------------------------------
+
+        {
+            code: "const a=1\n\nconst b=2",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "singleline-const", next: "*" }
+            ]
+        },
+        {
+            code: "const a=1\n\nconst b=2",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "*", next: "singleline-const" }
+            ]
+        },
+        {
+            code: "const a={\nb:1,\nc:2\n}\nconst d={\ne:3,\nf:4\n}",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "singleline-const", next: "*" }
+            ]
+        },
+        {
+            code: "const a={\nb:1,\nc:2\n}\nconst d={\ne:3,\nf:4\n}",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "*", next: "singleline-const" }
+            ]
+        },
+
+        //----------------------------------------------------------------------
+        // singleline-let
+        //----------------------------------------------------------------------
+
+        {
+            code: "let a=1\n\nlet b=2",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "singleline-let", next: "*" }
+            ]
+        },
+        {
+            code: "let a=1\n\nlet b=2",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "*", next: "singleline-let" }
+            ]
+        },
+        {
+            code: "let a={\nb:1,\nc:2\n}\nlet d={\ne:3,\nf:4\n}",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "singleline-let", next: "*" }
+            ]
+        },
+        {
+            code: "let a={\nb:1,\nc:2\n}\nlet d={\ne:3,\nf:4\n}",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "*", next: "singleline-let" }
+            ]
+        },
+
+        //----------------------------------------------------------------------
+        // singleline-var
+        //----------------------------------------------------------------------
+
+        {
+            code: "var a=1\n\nvar b=2",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "singleline-var", next: "*" }
+            ]
+        },
+        {
+            code: "var a=1\n\nvar b=2",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "*", next: "singleline-var" }
+            ]
+        },
+        {
+            code: "var a={\nb:1,\nc:2\n}\nvar d={\ne:3,\nf:4\n}",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "singleline-var", next: "*" }
+            ]
+        },
+        {
+            code: "var a={\nb:1,\nc:2\n}\nvar d={\ne:3,\nf:4\n}",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "*", next: "singleline-var" }
+            ]
+        },
+
         //----------------------------------------------------------------------
         // Tests from newline-after-var
         //----------------------------------------------------------------------
@@ -3696,6 +3894,228 @@ ruleTester.run("padding-line-between-statements", rule, {
             errors: [MESSAGE_ALWAYS]
         },
 
+        //----------------------------------------------------------------------
+        // multiline-const
+        //----------------------------------------------------------------------
+
+        {
+            code: "const a={\nb:1,\nc:2\n}\n\nconst d=3",
+            output: "const a={\nb:1,\nc:2\n}\nconst d=3",
+            options: [
+                { blankLine: "never", prev: "multiline-const", next: "*" }
+            ],
+            errors: [MESSAGE_NEVER]
+        },
+        {
+            code: "const a={\nb:1,\nc:2\n}\nconst d=3",
+            output: "const a={\nb:1,\nc:2\n}\n\nconst d=3",
+            options: [
+                { blankLine: "always", prev: "multiline-const", next: "*" }
+            ],
+            errors: [MESSAGE_ALWAYS]
+        },
+        {
+            code: "const a=1\n\nconst b={\nc:2,\nd:3\n}",
+            output: "const a=1\nconst b={\nc:2,\nd:3\n}",
+            options: [
+                { blankLine: "never", prev: "*", next: "multiline-const" }
+            ],
+            errors: [MESSAGE_NEVER]
+        },
+        {
+            code: "const a=1\nconst b={\nc:2,\nd:3\n}",
+            output: "const a=1\n\nconst b={\nc:2,\nd:3\n}",
+            options: [
+                { blankLine: "always", prev: "*", next: "multiline-const" }
+            ],
+            errors: [MESSAGE_ALWAYS]
+        },
+
+        //----------------------------------------------------------------------
+        // multiline-let
+        //----------------------------------------------------------------------
+
+        {
+            code: "let a={\nb:1,\nc:2\n}\n\nlet d=3",
+            output: "let a={\nb:1,\nc:2\n}\nlet d=3",
+            options: [
+                { blankLine: "never", prev: "multiline-let", next: "*" }
+            ],
+            errors: [MESSAGE_NEVER]
+        },
+        {
+            code: "let a={\nb:1,\nc:2\n}\nlet d=3",
+            output: "let a={\nb:1,\nc:2\n}\n\nlet d=3",
+            options: [
+                { blankLine: "always", prev: "multiline-let", next: "*" }
+            ],
+            errors: [MESSAGE_ALWAYS]
+        },
+        {
+            code: "let a=1\n\nlet b={\nc:2,\nd:3\n}",
+            output: "let a=1\nlet b={\nc:2,\nd:3\n}",
+            options: [
+                { blankLine: "never", prev: "*", next: "multiline-let" }
+            ],
+            errors: [MESSAGE_NEVER]
+        },
+        {
+            code: "let a=1\nlet b={\nc:2,\nd:3\n}",
+            output: "let a=1\n\nlet b={\nc:2,\nd:3\n}",
+            options: [
+                { blankLine: "always", prev: "*", next: "multiline-let" }
+            ],
+            errors: [MESSAGE_ALWAYS]
+        },
+
+        //----------------------------------------------------------------------
+        // multiline-var
+        //----------------------------------------------------------------------
+
+        {
+            code: "var a={\nb:1,\nc:2\n}\n\nvar d=3",
+            output: "var a={\nb:1,\nc:2\n}\nvar d=3",
+            options: [
+                { blankLine: "never", prev: "multiline-var", next: "*" }
+            ],
+            errors: [MESSAGE_NEVER]
+        },
+        {
+            code: "var a={\nb:1,\nc:2\n}\nvar d=3",
+            output: "var a={\nb:1,\nc:2\n}\n\nvar d=3",
+            options: [
+                { blankLine: "always", prev: "multiline-var", next: "*" }
+            ],
+            errors: [MESSAGE_ALWAYS]
+        },
+        {
+            code: "var a=1\n\nvar b={\nc:2,\nd:3\n}",
+            output: "var a=1\nvar b={\nc:2,\nd:3\n}",
+            options: [
+                { blankLine: "never", prev: "*", next: "multiline-var" }
+            ],
+            errors: [MESSAGE_NEVER]
+        },
+        {
+            code: "var a=1\nvar b={\nc:2,\nd:3\n}",
+            output: "var a=1\n\nvar b={\nc:2,\nd:3\n}",
+            options: [
+                { blankLine: "always", prev: "*", next: "multiline-var" }
+            ],
+            errors: [MESSAGE_ALWAYS]
+        },
+
+        //----------------------------------------------------------------------
+        // singleline-const
+        //----------------------------------------------------------------------
+
+        {
+            code: "const a=1\n\nconst b=2",
+            output: "const a=1\nconst b=2",
+            options: [
+                { blankLine: "never", prev: "singleline-const", next: "*" }
+            ],
+            errors: [MESSAGE_NEVER]
+        },
+        {
+            code: "const a=1\nconst b=2",
+            output: "const a=1\n\nconst b=2",
+            options: [
+                { blankLine: "always", prev: "singleline-const", next: "*" }
+            ],
+            errors: [MESSAGE_ALWAYS]
+        },
+        {
+            code: "const a=1\n\nconst b=2",
+            output: "const a=1\nconst b=2",
+            options: [
+                { blankLine: "never", prev: "*", next: "singleline-const" }
+            ],
+            errors: [MESSAGE_NEVER]
+        },
+        {
+            code: "const a=1\nconst b=2",
+            output: "const a=1\n\nconst b=2",
+            options: [
+                { blankLine: "always", prev: "*", next: "singleline-const" }
+            ],
+            errors: [MESSAGE_ALWAYS]
+        },
+
+        //----------------------------------------------------------------------
+        // singleline-let
+        //----------------------------------------------------------------------
+
+        {
+            code: "let a=1\n\nlet b=2",
+            output: "let a=1\nlet b=2",
+            options: [
+                { blankLine: "never", prev: "singleline-let", next: "*" }
+            ],
+            errors: [MESSAGE_NEVER]
+        },
+        {
+            code: "let a=1\nlet b=2",
+            output: "let a=1\n\nlet b=2",
+            options: [
+                { blankLine: "always", prev: "singleline-let", next: "*" }
+            ],
+            errors: [MESSAGE_ALWAYS]
+        },
+        {
+            code: "let a=1\n\nlet b=2",
+            output: "let a=1\nlet b=2",
+            options: [
+                { blankLine: "never", prev: "*", next: "singleline-let" }
+            ],
+            errors: [MESSAGE_NEVER]
+        },
+        {
+            code: "let a=1\nlet b=2",
+            output: "let a=1\n\nlet b=2",
+            options: [
+                { blankLine: "always", prev: "*", next: "singleline-let" }
+            ],
+            errors: [MESSAGE_ALWAYS]
+        },
+
+        //----------------------------------------------------------------------
+        // singleline-var
+        //----------------------------------------------------------------------
+
+        {
+            code: "var a=1\n\nvar b=2",
+            output: "var a=1\nvar b=2",
+            options: [
+                { blankLine: "never", prev: "singleline-var", next: "*" }
+            ],
+            errors: [MESSAGE_NEVER]
+        },
+        {
+            code: "var a=1\nvar b=2",
+            output: "var a=1\n\nvar b=2",
+            options: [
+                { blankLine: "always", prev: "singleline-var", next: "*" }
+            ],
+            errors: [MESSAGE_ALWAYS]
+        },
+        {
+            code: "var a=1\n\nvar b=2",
+            output: "var a=1\nvar b=2",
+            options: [
+                { blankLine: "never", prev: "*", next: "singleline-var" }
+            ],
+            errors: [MESSAGE_NEVER]
+        },
+        {
+            code: "var a=1\nvar b=2",
+            output: "var a=1\n\nvar b=2",
+            options: [
+                { blankLine: "always", prev: "*", next: "singleline-var" }
+            ],
+            errors: [MESSAGE_ALWAYS]
+        },
+
         //----------------------------------------------------------------------
         // Tests from newline-after-var
         //----------------------------------------------------------------------
diff --git a/tests/lib/rules/prefer-const.js b/tests/lib/rules/prefer-const.js
index f97320234..a16ac38c3 100644
--- a/tests/lib/rules/prefer-const.js
+++ b/tests/lib/rules/prefer-const.js
@@ -454,6 +454,60 @@ ruleTester.run("prefer-const", rule, {
             errors: [
                 { message: "'predicate' is never reassigned. Use 'const' instead.", type: "Identifier" }
             ]
+        },
+        {
+            code: "let x = 'x', y = 'y';",
+            output: "const x = 'x', y = 'y';",
+            errors: [
+                { message: "'x' is never reassigned. Use 'const' instead.", type: "Identifier" },
+                { message: "'y' is never reassigned. Use 'const' instead.", type: "Identifier" }
+            ]
+        },
+        {
+            code: "let x = 'x', y = 'y'; x = 1",
+            output: null,
+            errors: [
+                { message: "'y' is never reassigned. Use 'const' instead.", type: "Identifier" }
+            ]
+        },
+        {
+            code: "let x = 1, y = 'y'; let z = 1;",
+            output: "const x = 1, y = 'y'; const z = 1;",
+            errors: [
+                { message: "'x' is never reassigned. Use 'const' instead.", type: "Identifier" },
+                { message: "'y' is never reassigned. Use 'const' instead.", type: "Identifier" },
+                { message: "'z' is never reassigned. Use 'const' instead.", type: "Identifier" }
+            ]
+        },
+        {
+            code: "let { a, b, c} = obj; let { x, y, z} = anotherObj; x = 2;",
+            output: "const { a, b, c} = obj; let { x, y, z} = anotherObj; x = 2;",
+            errors: [
+                { message: "'a' is never reassigned. Use 'const' instead.", type: "Identifier" },
+                { message: "'b' is never reassigned. Use 'const' instead.", type: "Identifier" },
+                { message: "'c' is never reassigned. Use 'const' instead.", type: "Identifier" },
+                { message: "'y' is never reassigned. Use 'const' instead.", type: "Identifier" },
+                { message: "'z' is never reassigned. Use 'const' instead.", type: "Identifier" }
+            ]
+        },
+        {
+            code: "let x = 'x', y = 'y'; function someFunc() { let a = 1, b = 2; foo(a, b) }",
+            output: "const x = 'x', y = 'y'; function someFunc() { const a = 1, b = 2; foo(a, b) }",
+            errors: [
+                { message: "'x' is never reassigned. Use 'const' instead.", type: "Identifier" },
+                { message: "'y' is never reassigned. Use 'const' instead.", type: "Identifier" },
+                { message: "'a' is never reassigned. Use 'const' instead.", type: "Identifier" },
+                { message: "'b' is never reassigned. Use 'const' instead.", type: "Identifier" }
+            ]
+        },
+        {
+            code: "let someFunc = () => { let a = 1, b = 2; foo(a, b) }",
+            output: "const someFunc = () => { const a = 1, b = 2; foo(a, b) }",
+            errors: [
+                { message: "'someFunc' is never reassigned. Use 'const' instead.", type: "Identifier" },
+                { message: "'a' is never reassigned. Use 'const' instead.", type: "Identifier" },
+                { message: "'b' is never reassigned. Use 'const' instead.", type: "Identifier" }
+            ]
         }
 
     ]
diff --git a/tests/lib/rules/space-before-blocks.js b/tests/lib/rules/space-before-blocks.js
index e0ccb67ad..9b33f03a7 100644
--- a/tests/lib/rules/space-before-blocks.js
+++ b/tests/lib/rules/space-before-blocks.js
@@ -21,6 +21,12 @@ const ruleTester = new RuleTester(),
     functionsOnlyArgs = [{ functions: "always", keywords: "never", classes: "never" }],
     keywordOnlyArgs = [{ functions: "never", keywords: "always", classes: "never" }],
     classesOnlyArgs = [{ functions: "never", keywords: "never", classes: "always" }],
+    functionsAlwaysOthersOffArgs = [{ functions: "always", keywords: "off", classes: "off" }],
+    keywordAlwaysOthersOffArgs = [{ functions: "off", keywords: "always", classes: "off" }],
+    classesAlwaysOthersOffArgs = [{ functions: "off", keywords: "off", classes: "always" }],
+    functionsNeverOthersOffArgs = [{ functions: "never", keywords: "off", classes: "off" }],
+    keywordNeverOthersOffArgs = [{ functions: "off", keywords: "never", classes: "off" }],
+    classesNeverOthersOffArgs = [{ functions: "off", keywords: "off", classes: "never" }],
     expectedSpacingErrorMessage = "Missing space before opening brace.",
     expectedSpacingError = { message: expectedSpacingErrorMessage },
     expectedNoSpacingErrorMessage = "Unexpected space before opening brace.",
@@ -131,6 +137,54 @@ ruleTester.run("space-before-blocks", rule, {
             code: "class test {}",
             parserOptions: { ecmaVersion: 6 }
         },
+        { code: "function a(){if(b) {}}", options: keywordAlwaysOthersOffArgs },
+        { code: "function a() {if(b) {}}", options: keywordAlwaysOthersOffArgs },
+        { code: "function a() {if(b){}}", options: functionsAlwaysOthersOffArgs },
+        { code: "function a() {if(b) {}}", options: functionsAlwaysOthersOffArgs },
+        {
+            code: "class test { constructor(){if(a){}} }",
+            options: classesAlwaysOthersOffArgs,
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "class test { constructor() {if(a){}} }",
+            options: classesAlwaysOthersOffArgs,
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "class test { constructor(){if(a) {}} }",
+            options: classesAlwaysOthersOffArgs,
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "class test { constructor() {if(a) {}} }",
+            options: classesAlwaysOthersOffArgs,
+            parserOptions: { ecmaVersion: 6 }
+        },
+        { code: "function a(){if(b){}}", options: keywordNeverOthersOffArgs },
+        { code: "function a() {if(b){}}", options: keywordNeverOthersOffArgs },
+        { code: "function a(){if(b){}}", options: functionsNeverOthersOffArgs },
+        { code: "function a(){if(b) {}}", options: functionsNeverOthersOffArgs },
+        {
+            code: "class test{ constructor(){if(a){}} }",
+            options: classesNeverOthersOffArgs,
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "class test{ constructor() {if(a){}} }",
+            options: classesNeverOthersOffArgs,
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "class test{ constructor(){if(a) {}} }",
+            options: classesNeverOthersOffArgs,
+            parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "class test{ constructor() {if(a) {}} }",
+            options: classesNeverOthersOffArgs,
+            parserOptions: { ecmaVersion: 6 }
+        },
 
         // https://github.com/eslint/eslint/issues/3769
         { code: "()=>{};", options: ["always"], parserOptions: { ecmaVersion: 6 } },
@@ -427,6 +481,82 @@ ruleTester.run("space-before-blocks", rule, {
             options: neverArgs,
             parserOptions: { ecmaVersion: 6 },
             errors: [expectedNoSpacingError]
+        },
+        {
+            code: "if(a){ function a(){} }",
+            output: "if(a){ function a() {} }",
+            options: functionsAlwaysOthersOffArgs,
+            errors: [expectedSpacingError]
+        },
+        {
+            code: "if(a) { function a(){} }",
+            output: "if(a) { function a() {} }",
+            options: functionsAlwaysOthersOffArgs,
+            errors: [expectedSpacingError]
+        },
+        {
+            code: "if(a){ function a(){} }",
+            output: "if(a) { function a(){} }",
+            options: keywordAlwaysOthersOffArgs,
+            errors: [expectedSpacingError]
+        },
+        {
+            code: "if(a){ function a() {} }",
+            output: "if(a) { function a() {} }",
+            options: keywordAlwaysOthersOffArgs,
+            errors: [expectedSpacingError]
+        },
+        {
+            code: "class test{ constructor(){} }",
+            output: "class test { constructor(){} }",
+            options: classesAlwaysOthersOffArgs,
+            parserOptions: { ecmaVersion: 6 },
+            errors: [expectedSpacingError]
+        },
+        {
+            code: "class test{ constructor() {} }",
+            output: "class test { constructor() {} }",
+            options: classesAlwaysOthersOffArgs,
+            parserOptions: { ecmaVersion: 6 },
+            errors: [expectedSpacingError]
+        },
+        {
+            code: "if(a){ function a() {} }",
+            output: "if(a){ function a(){} }",
+            options: functionsNeverOthersOffArgs,
+            errors: [expectedNoSpacingError]
+        },
+        {
+            code: "if(a) { function a() {} }",
+            output: "if(a) { function a(){} }",
+            options: functionsNeverOthersOffArgs,
+            errors: [expectedNoSpacingError]
+        },
+        {
+            code: "if(a) { function a(){} }",
+            output: "if(a){ function a(){} }",
+            options: keywordNeverOthersOffArgs,
+            errors: [expectedNoSpacingError]
+        },
+        {
+            code: "if(a) { function a() {} }",
+            output: "if(a){ function a() {} }",
+            options: keywordNeverOthersOffArgs,
+            errors: [expectedNoSpacingError]
+        },
+        {
+            code: "class test { constructor(){} }",
+            output: "class test{ constructor(){} }",
+            options: classesNeverOthersOffArgs,
+            parserOptions: { ecmaVersion: 6 },
+            errors: [expectedNoSpacingError]
+        },
+        {
+            code: "class test { constructor() {} }",
+            output: "class test{ constructor() {} }",
+            options: classesNeverOthersOffArgs,
+            parserOptions: { ecmaVersion: 6 },
+            errors: [expectedNoSpacingError]
         }
     ]
 });
diff --git a/tests/lib/rules/space-infix-ops.js b/tests/lib/rules/space-infix-ops.js
index 34eada46e..76939f7fe 100644
--- a/tests/lib/rules/space-infix-ops.js
+++ b/tests/lib/rules/space-infix-ops.js
@@ -54,7 +54,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "a+b",
             output: "a + b",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '+' must be spaced.",
                 type: "BinaryExpression",
                 line: 1,
                 column: 2
@@ -64,7 +64,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "a +b",
             output: "a + b",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '+' must be spaced.",
                 type: "BinaryExpression",
                 line: 1,
                 column: 3
@@ -74,7 +74,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "a+ b",
             output: "a + b",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '+' must be spaced.",
                 type: "BinaryExpression",
                 line: 1,
                 column: 2
@@ -84,7 +84,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "a||b",
             output: "a || b",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '||' must be spaced.",
                 type: "LogicalExpression",
                 line: 1,
                 column: 2
@@ -94,7 +94,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "a ||b",
             output: "a || b",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '||' must be spaced.",
                 type: "LogicalExpression",
                 line: 1,
                 column: 3
@@ -104,7 +104,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "a|| b",
             output: "a || b",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '||' must be spaced.",
                 type: "LogicalExpression",
                 line: 1,
                 column: 2
@@ -114,7 +114,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "a=b",
             output: "a = b",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '=' must be spaced.",
                 type: "AssignmentExpression",
                 line: 1,
                 column: 2
@@ -124,7 +124,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "a= b",
             output: "a = b",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '=' must be spaced.",
                 type: "AssignmentExpression",
                 line: 1,
                 column: 2
@@ -134,7 +134,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "a =b",
             output: "a = b",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '=' must be spaced.",
                 type: "AssignmentExpression",
                 line: 1,
                 column: 3
@@ -144,7 +144,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "a?b:c",
             output: "a ? b:c",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '?' must be spaced.",
                 type: "ConditionalExpression",
                 line: 1,
                 column: 2
@@ -154,7 +154,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "a?b : c",
             output: "a ? b : c",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '?' must be spaced.",
                 type: "ConditionalExpression",
                 line: 1,
                 column: 2
@@ -164,7 +164,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "a ? b:c",
             output: "a ? b : c",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator ':' must be spaced.",
                 type: "ConditionalExpression",
                 line: 1,
                 column: 6
@@ -174,7 +174,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "a? b : c",
             output: "a ? b : c",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '?' must be spaced.",
                 type: "ConditionalExpression",
                 line: 1,
                 column: 2
@@ -184,7 +184,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "a ?b : c",
             output: "a ? b : c",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '?' must be spaced.",
                 type: "ConditionalExpression",
                 line: 1,
                 column: 3
@@ -194,7 +194,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "a ? b: c",
             output: "a ? b : c",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator ':' must be spaced.",
                 type: "ConditionalExpression",
                 line: 1,
                 column: 6
@@ -204,7 +204,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "a ? b :c",
             output: "a ? b : c",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator ':' must be spaced.",
                 type: "ConditionalExpression",
                 line: 1,
                 column: 7
@@ -214,7 +214,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "var a=b;",
             output: "var a = b;",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '=' must be spaced.",
                 type: "VariableDeclarator",
                 line: 1,
                 column: 6
@@ -224,7 +224,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "var a= b;",
             output: "var a = b;",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '=' must be spaced.",
                 type: "VariableDeclarator",
                 line: 1,
                 column: 6
@@ -234,7 +234,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "var a =b;",
             output: "var a = b;",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '=' must be spaced.",
                 type: "VariableDeclarator",
                 line: 1,
                 column: 7
@@ -244,7 +244,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "var a = b, c=d;",
             output: "var a = b, c = d;",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '=' must be spaced.",
                 type: "VariableDeclarator",
                 line: 1,
                 column: 13
@@ -257,7 +257,7 @@ ruleTester.run("space-infix-ops", rule, {
                 int32Hint: true
             }],
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '|' must be spaced.",
                 type: "BinaryExpression",
                 line: 1,
                 column: 2
@@ -267,7 +267,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "var output = test || (test && test.value) ||(test2 && test2.value);",
             output: "var output = test || (test && test.value) || (test2 && test2.value);",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '||' must be spaced.",
                 type: "LogicalExpression",
                 line: 1,
                 column: 43
@@ -277,7 +277,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "var output = a ||(b && c.value) || (d && e.value);",
             output: "var output = a || (b && c.value) || (d && e.value);",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '||' must be spaced.",
                 type: "LogicalExpression",
                 line: 1,
                 column: 16
@@ -287,7 +287,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "var output = a|| (b && c.value) || (d && e.value);",
             output: "var output = a || (b && c.value) || (d && e.value);",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '||' must be spaced.",
                 type: "LogicalExpression",
                 line: 1,
                 column: 15
@@ -298,7 +298,7 @@ ruleTester.run("space-infix-ops", rule, {
             output: "const my_object = {key: 'value'}",
             parserOptions: { ecmaVersion: 6 },
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '=' must be spaced.",
                 type: "VariableDeclarator",
                 line: 1,
                 column: 16
@@ -309,12 +309,12 @@ ruleTester.run("space-infix-ops", rule, {
             output: "var {a = 0} = bar;",
             parserOptions: { ecmaVersion: 6 },
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '=' must be spaced.",
                 line: 1,
                 column: 7,
                 nodeType: "AssignmentPattern"
             }, {
-                message: "Infix operators must be spaced.",
+                message: "Operator '=' must be spaced.",
                 line: 1,
                 column: 10,
                 nodeType: "VariableDeclarator"
@@ -325,7 +325,7 @@ ruleTester.run("space-infix-ops", rule, {
             output: "function foo(a = 0) { }",
             parserOptions: { ecmaVersion: 6 },
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '=' must be spaced.",
                 line: 1,
                 column: 15,
                 nodeType: "AssignmentPattern"
@@ -336,7 +336,7 @@ ruleTester.run("space-infix-ops", rule, {
             output: "a ** b",
             parserOptions: { ecmaVersion: 7 },
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '**' must be spaced.",
                 line: 1,
                 column: 2,
                 nodeType: "BinaryExpression"
@@ -346,7 +346,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "'foo'in{}",
             output: "'foo' in {}",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator 'in' must be spaced.",
                 line: 1,
                 column: 6,
                 nodeType: "BinaryExpression"
@@ -356,7 +356,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "'foo'instanceof{}",
             output: "'foo' instanceof {}",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator 'instanceof' must be spaced.",
                 line: 1,
                 column: 6,
                 nodeType: "BinaryExpression"
@@ -369,7 +369,7 @@ ruleTester.run("space-infix-ops", rule, {
             code: "var a: Foo= b;",
             output: "var a: Foo = b;",
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '=' must be spaced.",
                 type: "VariableDeclarator",
                 line: 1,
                 column: 11
@@ -381,7 +381,7 @@ ruleTester.run("space-infix-ops", rule, {
             output: "function foo(a: number = 0): Foo { }",
             parserOptions: { ecmaVersion: 6 },
             errors: [{
-                message: "Infix operators must be spaced.",
+                message: "Operator '=' must be spaced.",
                 line: 1,
                 column: 23,
                 nodeType: "AssignmentPattern"
diff --git a/tests/lib/util/config-comment-parser.js b/tests/lib/util/config-comment-parser.js
new file mode 100644
index 000000000..6dbe9381a
--- /dev/null
+++ b/tests/lib/util/config-comment-parser.js
@@ -0,0 +1,229 @@
+/**
+ * @fileoverview Tests for ConfigCommentParser object.
+ * @author Nicholas C. Zakas
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const assert = require("chai").assert,
+    ConfigCommentParser = require("../../../lib/util/config-comment-parser");
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+
+describe("ConfigCommentParser", () => {
+
+    let commentParser;
+    const location = {
+        start: {
+            line: 1,
+            column: 0
+        }
+    };
+
+    beforeEach(() => {
+        commentParser = new ConfigCommentParser();
+    });
+
+    describe("parseJsonConfig", () => {
+
+        it("should parse JSON config with one item", () => {
+            const code = "no-alert:0";
+            const result = commentParser.parseJsonConfig(code, location);
+
+
+            assert.deepStrictEqual(result, {
+                success: true,
+                config: {
+                    "no-alert": 0
+                }
+            });
+        });
+
+        it("should parse JSON config with two items", () => {
+            const code = "no-alert:0 semi: 2";
+            const result = commentParser.parseJsonConfig(code, location);
+
+
+            assert.deepStrictEqual(result, {
+                success: true,
+                config: {
+                    "no-alert": 0,
+                    semi: 2
+                }
+            });
+        });
+
+        it("should parse JSON config with two comma-separated items", () => {
+            const code = "no-alert:0,semi: 2";
+            const result = commentParser.parseJsonConfig(code, location);
+
+
+            assert.deepStrictEqual(result, {
+                success: true,
+                config: {
+                    "no-alert": 0,
+                    semi: 2
+                }
+            });
+        });
+
+        it("should parse JSON config with two items and a string severity", () => {
+            const code = "no-alert:off,semi: 2";
+            const result = commentParser.parseJsonConfig(code, location);
+
+
+            assert.deepStrictEqual(result, {
+                success: true,
+                config: {
+                    "no-alert": "off",
+                    semi: 2
+                }
+            });
+        });
+
+        it("should parse JSON config with two items and options", () => {
+            const code = "no-alert:off, semi: [2, always]";
+            const result = commentParser.parseJsonConfig(code, location);
+
+
+            assert.deepStrictEqual(result, {
+                success: true,
+                config: {
+                    "no-alert": "off",
+                    semi: [2, "always"]
+                }
+            });
+        });
+
+        it("should parse JSON config with two items and options from plugins", () => {
+            const code = "plugin/no-alert:off, plugin/semi: [2, always]";
+            const result = commentParser.parseJsonConfig(code, location);
+
+            assert.deepStrictEqual(result, {
+                success: true,
+                config: {
+                    "plugin/no-alert": "off",
+                    "plugin/semi": [2, "always"]
+                }
+            });
+        });
+
+
+    });
+
+    describe("parseBooleanConfig", () => {
+
+        const comment = {};
+
+        it("should parse Boolean config with one item", () => {
+            const code = "a: true";
+            const result = commentParser.parseBooleanConfig(code, comment);
+
+            assert.deepStrictEqual(result, {
+                a: {
+                    value: true,
+                    comment
+                }
+            });
+        });
+
+        it("should parse Boolean config with one item and no value", () => {
+            const code = "a";
+            const result = commentParser.parseBooleanConfig(code, comment);
+
+            assert.deepStrictEqual(result, {
+                a: {
+                    value: false,
+                    comment
+                }
+            });
+        });
+
+        it("should parse Boolean config with two items", () => {
+            const code = "a: true b:false";
+            const result = commentParser.parseBooleanConfig(code, comment);
+
+            assert.deepStrictEqual(result, {
+                a: {
+                    value: true,
+                    comment
+                },
+                b: {
+                    value: false,
+                    comment
+                }
+            });
+        });
+
+        it("should parse Boolean config with two comma-separated items", () => {
+            const code = "a: true, b:false";
+            const result = commentParser.parseBooleanConfig(code, comment);
+
+            assert.deepStrictEqual(result, {
+                a: {
+                    value: true,
+                    comment
+                },
+                b: {
+                    value: false,
+                    comment
+                }
+            });
+        });
+
+        it("should parse Boolean config with two comma-separated items and no values", () => {
+            const code = "a , b";
+            const result = commentParser.parseBooleanConfig(code, comment);
+
+            assert.deepStrictEqual(result, {
+                a: {
+                    value: false,
+                    comment
+                },
+                b: {
+                    value: false,
+                    comment
+                }
+            });
+        });
+    });
+
+    describe("parseListConfig", () => {
+
+        it("should parse list config with one item", () => {
+            const code = "a";
+            const result = commentParser.parseListConfig(code);
+
+            assert.deepStrictEqual(result, {
+                a: true
+            });
+        });
+
+        it("should parse list config with two items", () => {
+            const code = "a, b";
+            const result = commentParser.parseListConfig(code);
+
+            assert.deepStrictEqual(result, {
+                a: true,
+                b: true
+            });
+        });
+
+        it("should parse list config with two items and exta whitespace", () => {
+            const code = "  a , b  ";
+            const result = commentParser.parseListConfig(code);
+
+            assert.deepStrictEqual(result, {
+                a: true,
+                b: true
+            });
+        });
+    });
+
+});
diff --git a/tests/lib/ignored-paths.js b/tests/lib/util/ignored-paths.js
similarity index 99%
rename from tests/lib/ignored-paths.js
rename to tests/lib/util/ignored-paths.js
index b03314e61..acf007b18 100644
--- a/tests/lib/ignored-paths.js
+++ b/tests/lib/util/ignored-paths.js
@@ -12,7 +12,7 @@
 const assert = require("chai").assert,
     path = require("path"),
     os = require("os"),
-    IgnoredPaths = require("../../lib/ignored-paths.js"),
+    IgnoredPaths = require("../../../lib/util/ignored-paths.js"),
     sinon = require("sinon"),
     fs = require("fs"),
     includes = require("lodash").includes;
@@ -29,7 +29,7 @@ let fixtureDir;
 
 /**
  * get raw rules from IgnorePaths instance
- * @param {IgnoredPaths} ignoredPaths, instance of IgnoredPaths
+ * @param {IgnoredPaths} ignoredPaths instance of IgnoredPaths
  * @returns {string[]} raw ignore rules
  */
 function getIgnoreRules(ignoredPaths) {
@@ -78,7 +78,7 @@ function getIgnorePatterns(ignoredPaths) {
 
 /**
  * count the number of default patterns applied to IgnoredPaths instance
- * @param {IgnoredPaths} ignoredPaths, instance of IgnoredPaths
+ * @param {IgnoredPaths} ignoredPaths instance of IgnoredPaths
  * @returns {integer} count of default patterns
  */
 function countDefaultPatterns(ignoredPaths) {
diff --git a/tests/lib/util/npm-utils.js b/tests/lib/util/npm-utils.js
index 1b07f3715..5c8e4cc84 100644
--- a/tests/lib/util/npm-utils.js
+++ b/tests/lib/util/npm-utils.js
@@ -162,8 +162,15 @@ describe("npmUtils", () => {
         });
 
         it("should return false if package.json does not exist", () => {
-            mockFs({});
-            assert.strictEqual(npmUtils.checkPackageJson(), false);
+
+            /*
+             * Checking local file system directly, which does not
+             * contains package.json. This is necessary because mock-fs
+             * doesn't work in Node.js 11: it throws an error when
+             * a file is missing rather than returning false.
+             * TODO: Find a replacement for mock-fs that works in Node 11.
+             */
+            assert.strictEqual(npmUtils.checkPackageJson("/"), false);
         });
     });
 
diff --git a/tests/lib/report-translator.js b/tests/lib/util/report-translator.js
similarity index 99%
rename from tests/lib/report-translator.js
rename to tests/lib/util/report-translator.js
index e009e4e82..cd600934d 100644
--- a/tests/lib/report-translator.js
+++ b/tests/lib/util/report-translator.js
@@ -9,9 +9,9 @@
 //------------------------------------------------------------------------------
 
 const assert = require("chai").assert;
-const SourceCode = require("../../lib/util/source-code");
+const SourceCode = require("../../../lib/util/source-code");
 const espree = require("espree");
-const createReportTranslator = require("../../lib/report-translator");
+const createReportTranslator = require("../../../lib/util/report-translator");
 
 //------------------------------------------------------------------------------
 // Tests
diff --git a/tests/tools/internal-rules/no-useless-catch.js b/tests/tools/internal-rules/no-useless-catch.js
deleted file mode 100644
index 6e1a65099..000000000
--- a/tests/tools/internal-rules/no-useless-catch.js
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * @fileoverview Tests for no-useless-throw rule
- * @author Teddy Katz
- */
-
-"use strict";
-
-//------------------------------------------------------------------------------
-// Requirements
-//------------------------------------------------------------------------------
-
-const rule = require("../../../tools/internal-rules/no-useless-catch");
-const RuleTester = require("../../../lib/testers/rule-tester");
-
-//------------------------------------------------------------------------------
-// Tests
-//------------------------------------------------------------------------------
-
-new RuleTester({ parserOptions: { ecmaVersion: 6 } }).run("rulesdir/no-useless-catch", rule, {
-    valid: [
-        `
-            try {
-                foo();
-            } catch (err) {
-                console.error(err);
-            } finally {
-                foo;
-            }
-        `,
-        `
-            try {
-                foo();
-            } catch ({ err }) {
-                throw err;
-            }
-        `
-    ],
-    invalid: [
-        {
-            code: `
-                try {
-                    foo();
-                } catch (e) {
-                    throw e;
-                }
-            `,
-            errors: [{ message: "Unnecessary try/catch wrapper." }]
-        },
-        {
-            code: `
-                try {
-                    foo();
-                } catch (e) {
-                    throw e;
-                } finally {
-                    foo();
-                }
-            `,
-            errors: [{ message: "Unnecessary catch clause." }]
-        }
-    ]
-});