Repository: eslint/eslint
Pull request #10163 (2018-04-01 12:09:06)

New: add max-classes-per-file rule
**What is the purpose of this pull request? (put an "X" next to item)**

[x] New rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-proposal.md))

**Please describe what the rule should do:**

Enforce a maximum number of classes per file.

**What category of rule is this? (place an "X" next to just one item)**

[x] Enforces code style

**Provide 2-3 code examples that this rule will warn about:**

```js
// incorrect with defaults
class Foo {}
class Bar {}

// correct with defaults
class Foo {}

// correct with excludeClassExpressions
class Foo {}
var Bar = class {};
```

**Why should this rule be included in ESLint (instead of a plugin)?**

It's a fairly common best practice many follow already.


jsf-clabot: [![CLA assistant check](https://cla.js.foundation/pull/badge/not_signed)](https://cla.js.foundation/eslint/eslint?pullRequest=10163) <br/>Thank you for your submission, we really appreciate it. Like many open source projects, we ask that you sign our [Contributor License Agreement](https://cla.js.foundation/eslint/eslint?pullRequest=10163) before we can accept your contribution.<br/>
platinumazure: I'll champion this. Just needs 2 more :+1:s from other team members.
43081j: its no problem, here you go.
43081j: should be sorted.

not too sure how you guys merge and so on, but i squashed into one commit seeing as it was getting a little messy.

if i didn't have to, do say so i know for future reference.
platinumazure: @43081j 

> not too sure how you guys merge and so on, but i squashed into one commit seeing as it was getting a little messy.

No worries, squashing is fine. That said, we also squash during merge, so it would have been okay to leave them un-squashed as well. We definitely like to keep the commit history simple but there are also advantages to reviewing new commits as they come in-- that said, the team is happy to work either way.
43081j: ah fair enough.

changed the docs now too FYI.
not-an-aardvark: Could you elaborate on the motivation for the `excludeClassExpressions` option? I notice that this wasn't mentioned in the proposal.
platinumazure: @not-an-aardvark @gyandeeps Any idea why the eslint-github-bot plugins didn't run on this PR? Was the bot down?
43081j: @not-an-aardvark  i included it because i imagine some people would want to be allowed something like:

```js
someFunction(class extends Foo { ... });
```

i personally wouldn't, but it sounds like something people may want, if anything.

another example is a custom element possibly:

```js
customElements.define('x-foo', class extends HTMLElement {});
```

for very simple elements. though i would still argue you should keep it in its own file /shrug
not-an-aardvark: I don't have strong opinions about the adding the option, although I wonder if there is a reasonable behavior we could pick that would satisfy all the necessary use cases without needing to add an option.

If we do add an option, can we name it something like `includeClassExpressions` rather than `excludeClassExpressions`? I think the double-negative from an option like `excludeClassExpressions: false` would be a bit difficult to read.
platinumazure: > If we do add an option, can we name it something like `includeClassExpressions` rather than `excludeClassExpressions`? I think the double-negative from an option like `excludeClassExpressions: false` would be a bit difficult to read.

I agree about the double negative, but I also don't particularly like options that are true by default. Could we compromise with `ignoreClassExpressions: true`?
43081j: i do agree that defaults to true are nasty.

i did just change it too, though. i'd rather use the ignore suggestion. ill wait this time until we're agreed
platinumazure: @not-an-aardvark Did you have anything in particular in mind, when you asked if there might be a default behavior that could satisfy everyone?
not-an-aardvark: Well, I suppose my concern is that we don't have any evidence that anyone who would enable this rule would actually want to ignore class expressions (@43081j mentioned in https://github.com/eslint/eslint/pull/10163#issuecomment-381727581 that they would not want to use that option). So I'm wondering if it's premature to add an option for it, and maybe we should wait and see if that is actually a need that people have.

The rule doesn't seem particularly useful to me if it's configured to ignore class expressions, because it would allow an unlimited number of statements like this:

```js
module.exports.Foo = class Foo {
  // lots of code
};

module.exports.Bar = class Bar {
  // lots of code
};
```

...which seems like it goes against the spirit of what the rule is trying to enforce.
43081j: ok i agree drop the option for now.
if anyone raises it as an issue it can be reintroduced.

if we're all fine with that, ill remove it and push later today
Aladdin-ADD: 👍 to @not-an-aardvark . Also, I was wondering if the option max is necessary -- in my view, few people would use it.
43081j: FYI ive removed the extra option.

so now you can only specify the number of classes. i dont think its really a problem leaving that in, some people may find it useful, some may not. who knows what peoples practices are.
43081j: @Aladdin-ADD this is all sorted no.

one of the CI builds failed due to a timeout, my guess is it'll pass on a re-run. not sure what went on there
platinumazure: Just needs one more :+1: from a team member to accept the proposal, then I think we can merge! (Assuming no one else on the team objects)

Patch:
diff --git a/.eslintrc.js b/.eslintrc.js
index ea75710e8..e17201ac0 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -9,12 +9,10 @@ module.exports = {
     root: true,
     plugins: [
         "eslint-plugin",
-        "node",
         "rulesdir"
     ],
     extends: [
         "./packages/eslint-config-eslint/default.yml",
-        "plugin:node/recommended",
         "plugin:eslint-plugin/recommended"
     ],
     rules: {
diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.md b/.github/ISSUE_TEMPLATE/BUG_REPORT.md
new file mode 100644
index 000000000..ef8c5101c
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.md
@@ -0,0 +1,54 @@
+---
+name: Bug report
+about: Report an issue with ESLint or rules bundled with ESLint
+
+---
+
+<!--
+    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).
+
+    This template is for bug reports. If you are here for another reason, please see below:
+
+    1. To propose a new rule: https://eslint.org/docs/developer-guide/contributing/new-rules
+    2. To request a rule change: https://eslint.org/docs/developer-guide/contributing/rule-changes
+    3. To request a change that is not a bug fix, rule change, or new rule: https://eslint.org/docs/developer-guide/contributing/changes
+    4. If you have any questions, please stop by our chatroom: https://gitter.im/eslint/eslint
+
+    Note that leaving sections blank will make it difficult for us to troubleshoot and we may have to close the issue.
+-->
+
+**Tell us about your environment**
+
+* **ESLint Version:**
+* **Node Version:**
+* **npm Version:**
+
+**What parser (default, Babel-ESLint, etc.) are you using?**
+
+**Please show your full configuration:**
+
+<details>
+<summary>Configuration</summary>
+
+<!-- Paste your configuration below: -->
+```js
+
+```
+
+</details>
+
+**What did you do? Please include the actual source code causing the issue, as well as the command that you used to run ESLint.**
+
+<!-- Paste the source code below: -->
+```js
+
+```
+
+<!-- Paste the command you used to run ESLint: -->
+```bash
+
+```
+
+**What did you expect to happen?**
+
+**What actually happened? Please include the actual, raw output from ESLint.**
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/CHANGE.md b/.github/ISSUE_TEMPLATE/CHANGE.md
index b8181f56c..14cff91b0 100644
--- a/.github/ISSUE_TEMPLATE/CHANGE.md
+++ b/.github/ISSUE_TEMPLATE/CHANGE.md
@@ -1,3 +1,9 @@
+---
+name: Non-rule change request
+about: Request a change that is not a bug fix, rule change, or new rule
+
+---
+
 <!--
     ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).
 
@@ -11,15 +17,9 @@
     Note that leaving sections blank will make it difficult for us to troubleshoot and we may have to close the issue.
 -->
 
-**Tell us about your environment**
-
-* **ESLint Version:**
-* **Node Version:**
-* **npm Version:**
-
-**What did you do?**
+**The version of ESLint you are using.**
 
-**What happened?**
+**The problem you want to solve.**
 
-**What did you expect to happen?**
+**Your take on the correct solution to problem.**
 
diff --git a/.github/ISSUE_TEMPLATE/NEW_RULE.md b/.github/ISSUE_TEMPLATE/NEW_RULE.md
index 81248324b..454b28e40 100644
--- a/.github/ISSUE_TEMPLATE/NEW_RULE.md
+++ b/.github/ISSUE_TEMPLATE/NEW_RULE.md
@@ -1,3 +1,9 @@
+---
+name: New rule proposal
+about: Propose a new rule to be added to ESLint
+
+---
+
 <!--
     ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).
 
diff --git a/.github/ISSUE_TEMPLATE/RULE_CHANGE.md b/.github/ISSUE_TEMPLATE/RULE_CHANGE.md
index b68b90714..7b0c65379 100644
--- a/.github/ISSUE_TEMPLATE/RULE_CHANGE.md
+++ b/.github/ISSUE_TEMPLATE/RULE_CHANGE.md
@@ -1,3 +1,9 @@
+---
+name: Rule change request
+about: Request a change to an existing rule
+
+---
+
 <!--
     ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 58c56344c..9ceed89e8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,26 @@
+v5.0.0-alpha.2 - April 27, 2018
+
+* 510ca8b Docs: make grammatical tweaks in migration guide (#10278) (Teddy Katz)
+* 02e44a5 Breaking: remove TDZ scopes (fixes #10245) (#10270) (Toru Nagashima)
+* c74933b Breaking: remove extra check in getScope (fixes #10246, fixes #10247) (#10252) (Toru Nagashima)
+* 7c2e83a Chore: improve tests and checking for equality (#10182) (Ruben Bridgewater)
+* 8799972 Docs: make template link wording more clear (#10219) (David Luzar)
+* 8b7c6ea Breaking: report fatal error for linting nonexistent files (fixes #7390) (#10143) (Teddy Katz)
+* 9100819 Breaking: fix plugin resolver in extends (fixes #9904) (#10236) (Toru Nagashima)
+* c45f1d0 Breaking: add rules to recommended (fixes #8865) (#10158) (薛定谔的猫)
+* 1d443a0 Fix: valid-jsdoc does not know async function returns (fixes #9881) (#10161) (Rachael Sim)
+* a82cbea Update: re-enable experimentalObjectRestSpread (fixes #9990) (#10230) (Toru Nagashima)
+* f9c7371 Fix: do not autofix object-shorthand with comments (fixes #10038) (#10238) (Malcolm Groves)
+* 4672b56 Docs: Correct wording in the `smart-tabs` docs page (#10277) (Jed Fox)
+* b32d1f4 Chore: upgrade eslump@1.6.2 (#10258) (薛定谔的猫)
+* 7938bf1 Chore: update eslint-fuzzer ecmaVersion to 2018 (#10255) (薛定谔的猫)
+* a2953ec Chore: small opt to improve readability (#10225) (薛定谔的猫)
+* 85a5191 Docs: Update JSCS FAQ (#10221) (alberto)
+* 8e89d5c Docs: Fix typo (#10223) (alberto)
+* c0c331e Docs: Add Prettier to FAQ (#10222) (alberto)
+* 2443627 Docs: add backticks in getter-return (#10218) (薛定谔的猫)
+* 74bb5b5 Docs: Fix misspelling in changelog (#10216) (Kevin Partington)
+
 v5.0.0-alpha.1 - April 13, 2018
 
 * b2a48a9 Breaking: stop using fake `context._linter` property (fixes #10140) (#10209) (Teddy Katz)
diff --git a/conf/default-cli-options.js b/conf/default-cli-options.js
index 7d46d46c5..9670a14b0 100644
--- a/conf/default-cli-options.js
+++ b/conf/default-cli-options.js
@@ -26,5 +26,6 @@ module.exports = {
     cacheFile: ".eslintcache",
     fix: false,
     allowInlineConfig: true,
-    reportUnusedDisableDirectives: false
+    reportUnusedDisableDirectives: false,
+    globInputPaths: true
 };
diff --git a/conf/eslint-recommended.js b/conf/eslint-recommended.js
index 0acee234a..422e01def 100644
--- a/conf/eslint-recommended.js
+++ b/conf/eslint-recommended.js
@@ -39,14 +39,14 @@ module.exports = {
         "dot-notation": "off",
         "eol-last": "off",
         eqeqeq: "off",
-        "for-direction": "off",
+        "for-direction": "error",
         "func-call-spacing": "off",
         "func-name-matching": "off",
         "func-names": "off",
         "func-style": "off",
         "function-paren-newline": "off",
         "generator-star-spacing": "off",
-        "getter-return": "off",
+        "getter-return": "error",
         "global-require": "off",
         "guard-for-in": "off",
         "handle-callback-err": "off",
@@ -65,6 +65,7 @@ module.exports = {
         "lines-around-comment": "off",
         "lines-around-directive": "off",
         "lines-between-class-members": "off",
+        "max-classes-per-file": "off",
         "max-depth": "off",
         "max-len": "off",
         "max-lines": "off",
diff --git a/docs/developer-guide/contributing/new-rules.md b/docs/developer-guide/contributing/new-rules.md
index c3fe9f454..a3513773d 100644
--- a/docs/developer-guide/contributing/new-rules.md
+++ b/docs/developer-guide/contributing/new-rules.md
@@ -19,7 +19,7 @@ Even though these are the formal criteria for inclusion, each rule is evaluated
 
 ## Proposing a Rule
 
-If you want to propose a new rule, [create a pull request](/docs/developer-guide/contributing/pull-requests.md) or [new issue](https://github.com/eslint/eslint/issues/new?template=NEW_RULE.md) and fill out the template.
+If you want to propose a new rule, please see how to [create a pull request](/docs/developer-guide/contributing/pull-requests) or submit an issue by filling out a [new rule template](https://github.com/eslint/eslint/issues/new?template=NEW_RULE.md).
 
 We need all of this information in order to determine whether or not the rule is a good core rule candidate.
 
diff --git a/docs/developer-guide/nodejs-api.md b/docs/developer-guide/nodejs-api.md
index 2eaeb322a..e56fd5789 100644
--- a/docs/developer-guide/nodejs-api.md
+++ b/docs/developer-guide/nodejs-api.md
@@ -350,6 +350,7 @@ The `CLIEngine` is a constructor, and you can create a new instance by passing i
 * `rulePaths` - An array of directories to load custom rules from (default: empty array). Corresponds to `--rulesdir`.
 * `rules` - An object of rules to use (default: null). Corresponds to `--rule`.
 * `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.
 
 
 
diff --git a/docs/developer-guide/working-with-custom-formatters.md b/docs/developer-guide/working-with-custom-formatters.md
index 2c4da7d32..8bf17bc29 100644
--- a/docs/developer-guide/working-with-custom-formatters.md
+++ b/docs/developer-guide/working-with-custom-formatters.md
@@ -7,7 +7,7 @@ The simplest formatter will be something like:
 ```javascript
 //my-awesome-formatter.js
 module.exports = function (results) {
-    console.log(JSON.stringify(results, null, 2));
+    return JSON.stringify(results, null, 2);
 }
 ```
 
@@ -43,13 +43,17 @@ The output of the previous command will be something like this
         ],
         "errorCount": 2,
         "warningCount": 0,
+        "fixableErrorCount": 0,
+        "fixableWarningCount": 0,
         "source": "var err = doStuff();\nif (err) console.log('failed tests: ' + err);\nprocess.exit(1);\n"
     },
     {
         "filePath": "Gruntfile.js",
         "messages": [],
         "errorCount": 0,
-        "warningCount": 0
+        "warningCount": 0,
+        "fixableErrorCount": 0,
+        "fixableWarningCount": 0
     }
 ]
 ```
@@ -89,7 +93,6 @@ A formatter that only cares about the total count of errors and warnings will lo
 
 ```javascript
 module.exports = function ( results ) {
-    var results = results || [ ];
 
     // accumulate the errors and warnings
     var summary = results.reduce( function ( seq, current ) {
@@ -99,8 +102,10 @@ module.exports = function ( results ) {
     }, { errors: 0, warnings: 0 } );
 
     if ( summary.errors > 0 || summary.warnings > 0 ) {
-        console.log( 'Errors: ' + summary.errors + ', Warnings: ' + summary.warnings + '\n' );
+        return 'Errors: ' + summary.errors + ', Warnings: ' + summary.warnings + '\n';
     }
+
+    return '';
 };
 ```
 
@@ -254,7 +259,7 @@ It is a bit more complicated, but using a simple formatter we can get the raw ou
 ```javascript
 // json.js
 module.exports = function ( results ) {
-    console.log( JSON.stringify( results ) );
+    return JSON.stringify( results );
 }
 ```
 
diff --git a/docs/developer-guide/working-with-rules.md b/docs/developer-guide/working-with-rules.md
index 7acb318b4..8b5c0d5ac 100644
--- a/docs/developer-guide/working-with-rules.md
+++ b/docs/developer-guide/working-with-rules.md
@@ -135,6 +135,31 @@ Additionally, the `context` object has the following methods:
 
 **Note:** Earlier versions of ESLint supported additional methods on the `context` object. Those methods were removed in the new format and should not be relied upon.
 
+### context.getScope()
+
+This method returns the scope which has the following types:
+
+| AST Node Type             | Scope Type |
+|:--------------------------|:-----------|
+| `Program`                 | `global`   |
+| `FunctionDeclaration`     | `function` |
+| `FunctionExpression`      | `function` |
+| `ArrowFunctionExpression` | `function` |
+| `ClassDeclaration`        | `class`    |
+| `ClassExpression`         | `class`    |
+| `BlockStatement` ※1      | `block`    |
+| `SwitchStatement` ※1     | `switch`   |
+| `ForStatement` ※2        | `for`      |
+| `ForInStatement` ※2      | `for`      |
+| `ForOfStatement` ※2      | `for`      |
+| `WithStatement`           | `with`     |
+| `CatchClause`             | `catch`    |
+| others                    | ※3        |
+
+**※1** Only if the configured parser provided the block-scope feature. The default parser provides the block-scope feature if `parserOptions.ecmaVersion` is not less than `6`.<br>
+**※2** Only if the `for` statement defines the iteration variable as a block-scoped variable (E.g., `for (let i = 0;;) {}`).<br>
+**※3** The scope of the closest ancestor node which has own scope. If the closest ancestor node has multiple scopes then it chooses the innermost scope (E.g., the `Program` node has a `global` scope and a `module` scope if `Program#sourceType` is `"module"`. The innermost scope is the `module` scope.).
+
 ### context.report()
 
 The main method you'll use is `context.report()`, which publishes a warning or error (depending on the configuration being used). This method accepts a single argument, which is an object containing the following properties:
diff --git a/docs/rules/array-callback-return.md b/docs/rules/array-callback-return.md
index c1ed80de9..58dd26c35 100644
--- a/docs/rules/array-callback-return.md
+++ b/docs/rules/array-callback-return.md
@@ -1,7 +1,7 @@
 # Enforces return statements in callbacks of array's methods (array-callback-return)
 
 `Array` has several methods for filtering, mapping, and folding.
-If we forget to write `return` statement in a callback of those, it's probably a mistake.
+If we forget to write `return` statement in a callback of those, it's probably a mistake. If you don't want to use a return or don't need the returned results, consider using [.forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) instead.
 
 ```js
 // example: convert ['a', 'b', 'c'] --> {a: 0, b: 1, c: 2}
diff --git a/docs/rules/max-classes-per-file.md b/docs/rules/max-classes-per-file.md
new file mode 100644
index 000000000..83608594d
--- /dev/null
+++ b/docs/rules/max-classes-per-file.md
@@ -0,0 +1,39 @@
+# enforce a maximum number of classes per file (max-classes-per-file)
+
+Files containing multiple classes can often result in a less navigable
+and poorly structured codebase. Best practice is to keep each file
+limited to a single responsibility.
+
+## Rule Details
+
+This rule enforces that each file may contain only a particular number
+of classes and no more.
+
+Examples of **incorrect** code for this rule:
+
+```js
+/*eslint max-classes-per-file: "error"*/
+
+class Foo {}
+class Bar {}
+```
+
+Examples of **correct** code for this rule:
+
+```js
+/*eslint max-classes-per-file: "error"*/
+
+class Foo {}
+```
+
+## Options
+
+This rule has a numeric option (defaulted to 1) to specify the
+maximum number of classes.
+
+Examples of **correct** code for this rule with the numeric option set to `2`:
+
+```js
+class Foo {}
+class Bar {}
+```
diff --git a/docs/rules/no-mixed-spaces-and-tabs.md b/docs/rules/no-mixed-spaces-and-tabs.md
index 4f76b2617..ba34dbe49 100644
--- a/docs/rules/no-mixed-spaces-and-tabs.md
+++ b/docs/rules/no-mixed-spaces-and-tabs.md
@@ -41,7 +41,7 @@ function add(x, y) {
 
 This rule has a string option.
 
-* `"smart-tabs"` allows mixed spaces and tabs when the latter are used for alignment.
+* `"smart-tabs"` allows mixed tabs and spaces when the spaces are used for alignment.
 
 ### smart-tabs
 
diff --git a/docs/rules/no-self-assign.md b/docs/rules/no-self-assign.md
index 1ef2a99fb..b80df6afc 100644
--- a/docs/rules/no-self-assign.md
+++ b/docs/rules/no-self-assign.md
@@ -39,6 +39,20 @@ let foo = foo;
 
 // The default values have an effect.
 [foo = 1] = [foo];
+
+// non-self-assignments with properties.
+obj.a = obj.b;
+obj.a.b = obj.c.b;
+obj.a.b = obj.a.c;
+obj[a] = obj["a"];
+
+// This ignores if there is a function call.
+obj.a().b = obj.a().b;
+a().b = a().b;
+
+// Known limitation: this does not support computed properties except single literal or single identifier.
+obj[a + b] = obj[a + b];
+obj["a" + "b"] = obj["a" + "b"];
 ```
 
 ## Options
@@ -47,15 +61,15 @@ This rule has the option to check properties as well.
 
 ```json
 {
-    "no-self-assign": ["error", {"props": false}]
+    "no-self-assign": ["error", {"props": true}]
 }
 ```
 
-- `props` - if this is `true`, `no-self-assign` rule warns self-assignments of properties. Default is `false`.
+- `props` - if this is `true`, `no-self-assign` rule warns self-assignments of properties. Default is `true`.
 
 ### props
 
-Examples of **incorrect** code for the `{ "props": true }` option:
+Examples of **correct** code with the `{ "props": false }` option:
 
 ```js
 /*eslint no-self-assign: ["error", {"props": true}]*/
@@ -67,26 +81,6 @@ obj["a"] = obj["a"];
 obj[a] = obj[a];
 ```
 
-Examples of **correct** code for the `{ "props": true }` option:
-
-```js
-/*eslint no-self-assign: ["error", {"props": true}]*/
-
-// non-self-assignments with properties.
-obj.a = obj.b;
-obj.a.b = obj.c.b;
-obj.a.b = obj.a.c;
-obj[a] = obj["a"]
-
-// This ignores if there is a function call.
-obj.a().b = obj.a().b
-a().b = a().b
-
-// Known limitation: this does not support computed properties except single literal or single identifier.
-obj[a + b] = obj[a + b];
-obj["a" + "b"] = obj["a" + "b"];
-```
-
 ## When Not To Use It
 
 If you don't want to notify about self assignments, then it's safe to disable this rule.
diff --git a/docs/rules/object-curly-newline.md b/docs/rules/object-curly-newline.md
index 61c0e6862..d62fdf996 100644
--- a/docs/rules/object-curly-newline.md
+++ b/docs/rules/object-curly-newline.md
@@ -15,9 +15,9 @@ This rule has either a string option:
 
 Or an object option:
 
-* `"multiline": true` (default) requires line breaks if there are line breaks inside properties or between properties
+* `"multiline": true` requires line breaks if there are line breaks inside properties or between properties
 * `"minProperties"` requires line breaks if the number of properties is at least the given integer. By default, an error will also be reported if an object contains linebreaks and has fewer properties than the given integer. However, the second behavior is disabled if the `consistent` option is set to `true`
-* `"consistent": true` requires that either both curly braces, or neither, directly enclose newlines. Note that enabling this option will also change the behavior of the `minProperties` option. (See `minProperties` above for more information)
+* `"consistent": true` (default) requires that either both curly braces, or neither, directly enclose newlines. Note that enabling this option will also change the behavior of the `minProperties` option. (See `minProperties` above for more information)
 
 You can specify different options for object literals, destructuring assignments, and named imports and exports:
 
@@ -179,7 +179,7 @@ let {k = function() {
 
 ### multiline
 
-Examples of **incorrect** code for this rule with the default `{ "multiline": true }` option:
+Examples of **incorrect** code for this rule with the `{ "multiline": true }` option:
 
 ```js
 /*eslint object-curly-newline: ["error", { "multiline": true }]*/
@@ -214,7 +214,7 @@ let {k = function() {
 }} = obj;
 ```
 
-Examples of **correct** code for this rule with the default `{ "multiline": true }` option:
+Examples of **correct** code for this rule with the `{ "multiline": true }` option:
 
 ```js
 /*eslint object-curly-newline: ["error", { "multiline": true }]*/
@@ -319,7 +319,7 @@ let {k = function() {
 
 ### consistent
 
-Examples of **incorrect** code for this rule with the `{ "consistent": true }` option:
+Examples of **incorrect** code for this rule with the default `{ "consistent": true }` option:
 
 ```js
 /*eslint object-curly-newline: ["error", { "consistent": true }]*/
@@ -354,7 +354,7 @@ let {o = function() {
 }} = obj;
 ```
 
-Examples of **correct** code for this rule with the `{ "consistent": true }` option:
+Examples of **correct** code for this rule with the default `{ "consistent": true }` option:
 
 ```js
 /*eslint object-curly-newline: ["error", { "consistent": true }]*/
diff --git a/docs/rules/valid-jsdoc.md b/docs/rules/valid-jsdoc.md
index 69375bf27..670f90fb9 100644
--- a/docs/rules/valid-jsdoc.md
+++ b/docs/rules/valid-jsdoc.md
@@ -158,7 +158,7 @@ This rule has an object option:
 * `"preferType"` enforces consistent type strings specified by an object whose properties mean instead of key use value (for example, `"object": "Object"` means instead of `object` use `Object`)
 * `"requireReturn"` requires a return tag:
     * `true` (default) **even if** the function or method does not have a `return` statement (this option value does not apply to constructors)
-    * `false` **if and only if** the function or method has a `return` statement (this option value does apply to constructors)
+    * `false` **if and only if** the function or method has a `return` statement or returns a value e.g. `async` function (this option value does apply to constructors)
 * `"requireReturnType": false` allows missing type in return tags
 * `"matchDescription"` specifies (as a string) a regular expression to match the description in each JSDoc comment (for example, `".+"` requires a description; this option does not apply to descriptions in parameter or return tags)
 * `"requireParamDescription": false` allows missing description in parameter tags
diff --git a/docs/user-guide/integrations.md b/docs/user-guide/integrations.md
index 1179fa960..159066348 100644
--- a/docs/user-guide/integrations.md
+++ b/docs/user-guide/integrations.md
@@ -5,7 +5,9 @@
 * Sublime Text 3:
     * [SublimeLinter-eslint](https://github.com/roadhump/SublimeLinter-eslint)
     * [Build Next](https://github.com/albertosantini/sublimetext-buildnext)
-* [Vim](https://github.com/vim-syntastic/syntastic/tree/master/syntax_checkers/javascript)
+* Vim:
+    * [ALE](https://github.com/w0rp/ale)
+    * [Syntastic](https://github.com/vim-syntastic/syntastic/tree/master/syntax_checkers/javascript)
 * Emacs: [Flycheck](http://www.flycheck.org/) supports ESLint with the [javascript-eslint](http://www.flycheck.org/en/latest/languages.html#javascript) checker.
 * Eclipse Orion: ESLint is the [default linter](https://dev.eclipse.org/mhonarc/lists/orion-dev/msg02718.html)
 * Eclipse IDE with [Tern ESLint linter](https://github.com/angelozerr/tern.java/wiki/Tern-Linter-ESLint)
diff --git a/docs/user-guide/migrating-to-5.0.0.md b/docs/user-guide/migrating-to-5.0.0.md
index 48288e60d..7d25105e6 100644
--- a/docs/user-guide/migrating-to-5.0.0.md
+++ b/docs/user-guide/migrating-to-5.0.0.md
@@ -7,16 +7,20 @@ The lists below are ordered roughly by the number of users each change is expect
 ### Breaking changes for users
 
 1. [Node.js 4 is no longer supported](#drop-node-4)
+1. [New rules have been added to `eslint:recommended`](#eslint-recommended-changes)
 1. [The `experimentalObjectRestSpread` option has been deprecated](#experimental-object-rest-spread)
 1. [Linting nonexistent files from the command line is now a fatal error](#nonexistent-files)
+1. [The default options for some rules have changed](#rule-default-changes)
 1. [Deprecated globals have been removed from the `node`, `browser`, and `jest` environments](#deprecated-globals)
 1. [Empty files are now linted](#empty-files)
 1. [Plugins in scoped packages are now resolvable in configs](#scoped-plugins)
+1. [Multi-line `eslint-disable-line` directives are now reported as problems](#multiline-directives)
 
 ### Breaking changes for plugin/custom rule developers
 
 1. [The `parent` property of AST nodes is now set before rules start running](#parent-before-rules)
 1. [When using the default parser, text nodes in JSX elements now have type `JSXText`](#jsx-text-nodes)
+1. [The `context.getScope()` method now returns more proper scopes](#context-get-scope)
 1. [The `_linter` property on rule context objects has been removed](#no-context-linter)
 1. [`RuleTester` now uses strict equality checks in its assertions](#rule-tester-equality)
 1. [Rules are now required to provide messages along with reports](#required-report-messages)
@@ -39,6 +43,26 @@ As of April 30th, 2018, Node.js 4 will be at EOL and will no longer be receiving
 
 **To address:** Make sure you upgrade to at least Node.js 6 when using ESLint v5. If you are unable to upgrade, we recommend continuing to use ESLint v4.x until you are able to upgrade Node.js.
 
+## <a name="eslint-recommended-changes"/> `eslint:recommended` changes
+
+Two new rules have been added to the [`eslint:recommended`](https://eslint.org/docs/user-guide/configuring#using-eslintrecommended) config:
+
+* [`for-direction`](/docs/rules/for-direction) enforces that a `for` loop update clause moves the counter in the right direction.
+* [`getter-return`](/docs/rules/getter-return) enforces that a `return` statement is present in property getters.
+
+**To address:** To mimic the `eslint:recommended` behavior from 4.x, you can disable these rules in a config file:
+
+```json
+{
+  "extends": "eslint:recommended",
+
+  "rules": {
+    "for-direction": "off",
+    "getter-return": "off"
+  }
+}
+```
+
 ## <a name="experimental-object-rest-spread"></a> The `experimentalObjectRestSpread` option has been deprecated
 
 Previously, when using the default parser it was possible to use the `experimentalObjectRestSpread` option to enable support for [rest/spread properties](https://developers.google.com/web/updates/2017/06/object-rest-spread), as follows:
@@ -69,8 +93,6 @@ For compatibility, ESLint v5 will treat `ecmaFeatures: { experimentalObjectRestS
 
 **To address:** If you use the `experimentalObjectRestSpread` option, you should be able to upgrade to ESLint v5 without any changes, but you will encounter a deprecation warning. To avoid the warning, use `ecmaVersion: 2018` in your config file rather than `ecmaFeatures: { experimentalObjectRestSpread: true }`. If you would like to disallow the use of other ES2018 features, consider using rules such as [`no-restricted-syntax`](/docs/rules/no-restricted-syntax).
 
-*Note: In the latest alpha release of ESLint v5, `experimentalObjectRestSpread` is not yet implemented as an alias for `ecmaVersion: 2018`, so configs that use `experimentalObjectRestSpread` may temporarily cause parsing errors. We plan to add this alias in a future prerelease.*
-
 ## <a name="nonexistent-files"></a> Linting nonexistent files from the command line is now a fatal error
 
 Previous versions of ESLint silently ignored any nonexistent files and globs provided on the command line:
@@ -92,7 +114,21 @@ Note that this also affects the [`CLIEngine.executeOnFiles()`](https://eslint.or
 
 If you use a boilerplate generator that relies on this behavior (e.g. to generate a script that runs `eslint tests/` in a new project before any test files are actually present), you can work around this issue by adding a dummy file that matches the given pattern (e.g. an empty `tests/index.js` file).
 
-*Note: This change has not yet appeared in the latest alpha release. We plan to add it in a future prerelease.*
+## <a name="rule-default-changes"></a> The default options for some rules have changed
+
+* The default options for the [`object-curly-newline`](/docs/rules/object-curly-newline) rule have changed from `{ multiline: true }` to `{ consistent: true }`.
+* The default options object for the [`no-self-assign`](/docs/rules/no-self-assign) rule has changed from `{ props: false }` to `{ props: true }`.
+
+**To address:** To restore the rule behavior from ESLint v4, you can update your config file to include the previous options:
+
+```json
+{
+  "rules": {
+    "object-curly-newline": ["error", { "multiline": true }],
+    "no-self-assign": ["error", { "props": false }]
+  }
+}
+```
 
 ## <a name="deprecated-globals"></a> Deprecated globals have been removed from the `node`, `browser`, and `jest` environments
 
@@ -123,10 +159,25 @@ If you have a custom rule, you should make sure it handles empty files appropria
 
 ## <a name="scoped-plugins"></a> Plugins in scoped packages are now resolvable in configs
 
-When it encounters a plugin name in a config starting with `@`, ESLint v5 will resolve it as a [scoped npm package](https://docs.npmjs.com/misc/scope). For example, if a config contains `"plugins": ["@foo"]`, ESLint v5 will attempt to load a package called `@foo/eslint-plugin`. (On the other hand, ESLint v4 would attempt to load a package called `eslint-plugin-@foo`.) This is a breaking change because users might have been relying on ESLint finding a package at `node_modules/eslint-plugin-@foo`. However, we think it is unlikely that many users were relying on this behavior, because packages published to npm cannot contain an `@` character in the middle.
+When ESLint v5 encounters a plugin name in a config starting with `@`, the plugin will be resolved as a [scoped npm package](https://docs.npmjs.com/misc/scope). For example, if a config contains `"plugins": ["@foo"]`, ESLint v5 will attempt to load a package called `@foo/eslint-plugin`. (On the other hand, ESLint v4 would attempt to load a package called `eslint-plugin-@foo`.) This is a breaking change because users might have been relying on ESLint finding a package at `node_modules/eslint-plugin-@foo`. However, we think it is unlikely that many users were relying on this behavior, because packages published to npm cannot contain an `@` character in the middle.
 
 **To address:** If you rely on ESLint loading a package like `eslint-config-@foo`, consider renaming the package to something else.
 
+## <a name="multiline-directives"></a> Multi-line `eslint-disable-line` directives are now reported as problems
+
+`eslint-disable-line` and `eslint-disable-next-line` directive comments are only allowed to span a single line. For example, the following directive comment is invalid:
+
+```js
+alert('foo'); /* eslint-disable-line
+   no-alert */ alert('bar');
+
+// (which line is the rule disabled on?)
+```
+
+Previously, ESLint would ignore these malformed directive comments. ESLint v5 will report an error when it sees a problem like this, so that the issue can be more easily corrected.
+
+**To address:** If you see new reported errors as a result of this change, ensure that your `eslint-disable-line` directives only span a single line. Note that "block comments" (delimited by `/* */`) are still allowed to be used for directives, provided that the block comments do not contain linebreaks.
+
 ---
 
 ## <a name="parent-before-rules"></a> The `parent` property of AST nodes is now set before rules start running
@@ -143,6 +194,16 @@ When parsing JSX code like `<a>foo</a>`, the default parser will now give the `f
 
 **To address:** If you have written a custom rule that relies on text nodes in JSX elements having the `Literal` type, you should update it to also work with nodes that have the `JSXText` type.
 
+## <a name="context-get-scope"></a> The `context.getScope()` method now returns more proper scopes
+
+Previously, the `context.getScope()` method changed its behavior based on the `parserOptions.ecmaVersion` property. However, this could cause confusing behavior when using a parser that doesn't respond to the `ecmaVersion` option, such as `babel-eslint`.
+
+Additionally, `context.getScope()` incorrectly returned the parent scope of the proper scope on `CatchClause` (in ES5), `ForStatement` (in ≧ES2015), `ForInStatement` (in ≧ES2015), `ForOfStatement`, and `WithStatement` nodes.
+
+In ESLint v5, the `context.getScope()` method has the same behavior regardless of `parserOptions.ecmaVersion` and returns the proper scope. See [the documentation](../developer-guide/working-with-rules#contextgetscope) for more details on which scopes are returned.
+
+**To address:** If you have written a custom rule that uses the `context.getScope()` method in node handlers, you may need to update it to account for the modified scope information.
+
 ## <a name="no-context-linter"></a> The `_linter` property on rule context objects has been removed
 
 Previously, rule context objects had an undocumented `_linter` property, which was used internally within ESLint to process reports from rules. Some rules used this property to achieve functionality that was not intended to be possible for rules. For example, several plugins used the `_linter` property in a rule to monitor reports from other rules, for the purpose of checking for unused `/* eslint-disable */` directive comments. Although this functionality was useful for users, it could also cause stability problems for projects using ESLint. For example, an upgrade to a rule in one plugin could unexpectedly cause a rule in another plugin to start reporting errors.
diff --git a/lib/cli-engine.js b/lib/cli-engine.js
index 8531d1c1d..9cab3b47b 100644
--- a/lib/cli-engine.js
+++ b/lib/cli-engine.js
@@ -381,6 +381,21 @@ class CLIEngine {
             providedOptions
         );
 
+        /*
+         * if an --ignore-path option is provided, ensure that the ignore
+         * file exists and is not a directory
+         */
+        if (options.ignore && options.ignorePath) {
+            try {
+                if (!fs.statSync(options.ignorePath).isFile()) {
+                    throw new Error(`${options.ignorePath} is not a file`);
+                }
+            } catch (e) {
+                e.message = `Error: Could not load file ${options.ignorePath}\nError: ${e.message}`;
+                throw e;
+            }
+        }
+
         /**
          * Stored options for this instance
          * @type {Object}
@@ -481,7 +496,7 @@ class CLIEngine {
      * @returns {string[]} The equivalent glob patterns.
      */
     resolveFileGlobPatterns(patterns) {
-        return globUtil.resolveFileGlobPatterns(patterns, this.options);
+        return globUtil.resolveFileGlobPatterns(patterns.filter(Boolean), this.options);
     }
 
     /**
@@ -515,7 +530,7 @@ class CLIEngine {
         }
 
         const startTime = Date.now();
-        const fileList = globUtil.listFilesToProcess(this.resolveFileGlobPatterns(patterns), options);
+        const fileList = globUtil.listFilesToProcess(patterns, options);
         const results = fileList.map(fileInfo => {
             if (fileInfo.ignored) {
                 return createIgnoreResult(fileInfo.filename, options.cwd);
diff --git a/lib/config/config-file.js b/lib/config/config-file.js
index 37ac84831..46d561516 100644
--- a/lib/config/config-file.js
+++ b/lib/config/config-file.js
@@ -467,7 +467,7 @@ function resolve(filePath, relativeTo) {
         debug(`Attempting to resolve ${normalizedPackageName}`);
 
         return {
-            filePath: resolver.resolve(normalizedPackageName, getLookupPath(relativeTo)),
+            filePath: require.resolve(normalizedPackageName),
             configName,
             configFullName
         };
diff --git a/lib/config/config-validator.js b/lib/config/config-validator.js
index 1a5b3ef13..ed9a34cb0 100644
--- a/lib/config/config-validator.js
+++ b/lib/config/config-validator.js
@@ -9,7 +9,8 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const ajv = require("../util/ajv"),
+const path = require("path"),
+    ajv = require("../util/ajv"),
     lodash = require("lodash"),
     configSchema = require("../../conf/config-schema.js"),
     util = require("util");
@@ -21,6 +22,12 @@ const ruleValidators = new WeakMap();
 //------------------------------------------------------------------------------
 let validateSchema;
 
+// Defitions for deprecation warnings.
+const deprecationWarningMessages = Object.freeze({
+    ESLINT_LEGACY_ECMAFEATURES: "The 'ecmaFeatures' config file property is deprecated, and has no effect.",
+    ESLINT_LEGACY_OBJECT_REST_SPREAD: "The 'parserOptions.ecmaFeatures.experimentalObjectRestSpread' option is deprecated. Use 'parserOptions.ecmaVersion' instead."
+});
+
 /**
  * Gets a complete options schema for a rule.
  * @param {{create: Function, schema: (Array|null)}} rule A new-style rule object
@@ -194,18 +201,18 @@ function formatErrors(errors) {
  * for each unique file path, but repeated invocations with the same file path have no effect.
  * No warnings are emitted if the `--no-deprecation` or `--no-warnings` Node runtime flags are active.
  * @param {string} source The name of the configuration source to report the warning for.
+ * @param {string} errorCode The warning message to show.
  * @returns {void}
  */
-const emitEcmaFeaturesWarning = lodash.memoize(source => {
-
-    /*
-     * util.deprecate seems to be the only way to emit a warning in Node 4.x while respecting the --no-warnings flag.
-     * (In Node 6+, process.emitWarning could be used instead.)
-     */
-    util.deprecate(
-        () => {},
-        `[eslint] The 'ecmaFeatures' config file property is deprecated, and has no effect. (found in ${source})`
-    )();
+const emitDeprecationWarning = lodash.memoize((source, errorCode) => {
+    const rel = path.relative(process.cwd(), source);
+    const message = deprecationWarningMessages[errorCode];
+
+    process.emitWarning(
+        `${message} (found in "${rel}")`,
+        "DeprecationWarning",
+        errorCode
+    );
 });
 
 /**
@@ -221,8 +228,17 @@ function validateConfigSchema(config, source) {
         throw new Error(`ESLint configuration in ${source} is invalid:\n${formatErrors(validateSchema.errors)}`);
     }
 
-    if (Object.prototype.hasOwnProperty.call(config, "ecmaFeatures")) {
-        emitEcmaFeaturesWarning(source);
+    if (Object.hasOwnProperty.call(config, "ecmaFeatures")) {
+        emitDeprecationWarning(source, "ESLINT_LEGACY_ECMAFEATURES");
+    }
+
+    if (
+        (config.parser || "espree") === "espree" &&
+        config.parserOptions &&
+        config.parserOptions.ecmaFeatures &&
+        config.parserOptions.ecmaFeatures.experimentalObjectRestSpread
+    ) {
+        emitDeprecationWarning(source, "ESLINT_LEGACY_OBJECT_REST_SPREAD");
     }
 }
 
diff --git a/lib/config/plugins.js b/lib/config/plugins.js
index a47322705..37c3be497 100644
--- a/lib/config/plugins.js
+++ b/lib/config/plugins.js
@@ -10,6 +10,7 @@
 
 const debug = require("debug")("eslint:plugins");
 const naming = require("../util/naming");
+const path = require("path");
 
 //------------------------------------------------------------------------------
 // Public Interface
@@ -100,7 +101,8 @@ class Plugins {
                     missingPluginErr.message = `Failed to load plugin ${pluginName}: ${missingPluginErr.message}`;
                     missingPluginErr.messageTemplate = "plugin-missing";
                     missingPluginErr.messageData = {
-                        pluginName: longName
+                        pluginName: longName,
+                        eslintPath: path.resolve(__dirname, "../..")
                     };
                     throw missingPluginErr;
                 }
diff --git a/lib/linter.js b/lib/linter.js
index 7ca835c15..e48c4d7a9 100644
--- a/lib/linter.js
+++ b/lib/linter.js
@@ -281,10 +281,23 @@ function getDirectiveComments(filename, ast, ruleMapper) {
 
         const directiveValue = trimmedCommentText.slice(match.index + match[1].length);
 
-        if (/^eslint-disable-(next-)?line$/.test(match[1]) && comment.loc.start.line === comment.loc.end.line) {
-            const directiveType = match[1].slice("eslint-".length);
-
-            disableDirectives.push(...createDisableDirectives(directiveType, comment.loc.start, directiveValue));
+        if (/^eslint-disable-(next-)?line$/.test(match[1])) {
+            if (comment.loc.start.line === comment.loc.end.line) {
+                const directiveType = match[1].slice("eslint-".length);
+
+                disableDirectives.push(...createDisableDirectives(directiveType, comment.loc.start, directiveValue));
+            } else {
+                problems.push({
+                    ruleId: null,
+                    severity: 2,
+                    message: `${match[1]} comment should not span multiple lines.`,
+                    line: comment.loc.start.line,
+                    column: comment.loc.start.column + 1,
+                    endLine: comment.loc.end.line,
+                    endColumn: comment.loc.end.column + 1,
+                    nodeType: null
+                });
+            }
         } else if (comment.type === "Block") {
             switch (match[1]) {
                 case "exported":
@@ -410,11 +423,12 @@ function normalizeVerifyOptions(providedOptions) {
 
 /**
  * Combines the provided parserOptions with the options from environments
+ * @param {string} parserName The parser name which uses this options.
  * @param {Object} providedOptions The provided 'parserOptions' key in a config
  * @param {Environment[]} enabledEnvironments The environments enabled in configuration and with inline comments
  * @returns {Object} Resulting parser options after merge
  */
-function resolveParserOptions(providedOptions, enabledEnvironments) {
+function resolveParserOptions(parserName, providedOptions, enabledEnvironments) {
     const parserOptionsFromEnv = enabledEnvironments
         .filter(env => env.parserOptions)
         .reduce((parserOptions, env) => ConfigOps.merge(parserOptions, env.parserOptions), {});
@@ -431,6 +445,16 @@ function resolveParserOptions(providedOptions, enabledEnvironments) {
 
     mergedParserOptions.ecmaVersion = normalizeEcmaVersion(mergedParserOptions.ecmaVersion, isModule);
 
+    // TODO: For backward compatibility. Will remove on v6.0.0.
+    if (
+        parserName === DEFAULT_PARSER_NAME &&
+        mergedParserOptions.ecmaFeatures &&
+        mergedParserOptions.ecmaFeatures.experimentalObjectRestSpread &&
+        (!mergedParserOptions.ecmaVersion || mergedParserOptions.ecmaVersion < 9)
+    ) {
+        mergedParserOptions.ecmaVersion = 9;
+    }
+
     return mergedParserOptions;
 }
 
@@ -604,27 +628,15 @@ function parse(text, providedParserOptions, parserName, parserMap, filePath) {
  * Gets the scope for the current node
  * @param {ScopeManager} scopeManager The scope manager for this AST
  * @param {ASTNode} currentNode The node to get the scope of
- * @param {number} ecmaVersion The `ecmaVersion` setting that this code was parsed with
  * @returns {eslint-scope.Scope} The scope information for this node
  */
-function getScope(scopeManager, currentNode, ecmaVersion) {
-    let initialNode;
+function getScope(scopeManager, currentNode) {
 
-    // if current node introduces a scope, add it to the list
-    if (
-        ["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"].indexOf(currentNode.type) >= 0 ||
-        ecmaVersion >= 6 && ["BlockStatement", "SwitchStatement", "CatchClause"].indexOf(currentNode.type) >= 0
-    ) {
-        initialNode = currentNode;
-    } else {
-        initialNode = currentNode.parent;
-    }
+    // On Program node, get the outermost scope to avoid return Node.js special function scope or ES modules scope.
+    const inner = currentNode.type !== "Program";
 
-    // Ascend the current node's parents
-    for (let node = initialNode; node; node = node.parent) {
-
-        // Get the innermost scope
-        const scope = scopeManager.acquire(node, true);
+    for (let node = currentNode; node; node = node.parent) {
+        const scope = scopeManager.acquire(node, inner);
 
         if (scope) {
             if (scope.type === "function-expression-name") {
@@ -648,7 +660,7 @@ function getScope(scopeManager, currentNode, ecmaVersion) {
 function markVariableAsUsed(scopeManager, currentNode, parserOptions, name) {
     const hasGlobalReturn = parserOptions.ecmaFeatures && parserOptions.ecmaFeatures.globalReturn;
     const specialScope = hasGlobalReturn || parserOptions.sourceType === "module";
-    const currentScope = getScope(scopeManager, currentNode, parserOptions.ecmaVersion);
+    const currentScope = getScope(scopeManager, currentNode);
 
     // Special Node.js scope means we need to start one level deeper
     const initialScope = currentScope.type === "global" && specialScope ? currentScope.childScopes[0] : currentScope;
@@ -771,7 +783,7 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parser
                 getAncestors: () => getAncestors(currentNode),
                 getDeclaredVariables: sourceCode.scopeManager.getDeclaredVariables.bind(sourceCode.scopeManager),
                 getFilename: () => filename,
-                getScope: () => getScope(sourceCode.scopeManager, currentNode, parserOptions.ecmaVersion),
+                getScope: () => getScope(sourceCode.scopeManager, currentNode),
                 getSourceCode: () => sourceCode,
                 markVariableAsUsed: name => markVariableAsUsed(sourceCode.scopeManager, currentNode, parserOptions, name),
                 parserOptions,
@@ -923,9 +935,9 @@ module.exports = class Linter {
             .map(envName => this.environments.get(envName))
             .filter(env => env);
 
-        const parserOptions = resolveParserOptions(config.parserOptions || {}, enabledEnvs);
-        const configuredGlobals = resolveGlobals(config.globals || {}, enabledEnvs);
         const parserName = config.parser || DEFAULT_PARSER_NAME;
+        const parserOptions = resolveParserOptions(parserName, config.parserOptions || {}, enabledEnvs);
+        const configuredGlobals = resolveGlobals(config.globals || {}, enabledEnvs);
         const settings = config.settings || {};
 
         if (!lastSourceCodes.get(this)) {
diff --git a/lib/rules/comma-style.js b/lib/rules/comma-style.js
index 5ba2dbb28..aac667f73 100644
--- a/lib/rules/comma-style.js
+++ b/lib/rules/comma-style.js
@@ -185,13 +185,7 @@ module.exports = {
                 items.forEach(item => {
                     const commaToken = item ? sourceCode.getTokenBefore(item) : previousItemToken,
                         currentItemToken = item ? sourceCode.getFirstToken(item) : sourceCode.getTokenAfter(commaToken),
-                        reportItem = item || currentItemToken,
-                        tokenBeforeComma = sourceCode.getTokenBefore(commaToken);
-
-                    // Check if previous token is wrapped in parentheses
-                    if (tokenBeforeComma && astUtils.isClosingParenToken(tokenBeforeComma)) {
-                        previousItemToken = tokenBeforeComma;
-                    }
+                        reportItem = item || currentItemToken;
 
                     /*
                      * This works by comparing three token locations:
diff --git a/lib/rules/for-direction.js b/lib/rules/for-direction.js
index c91888da2..817e2c111 100644
--- a/lib/rules/for-direction.js
+++ b/lib/rules/for-direction.js
@@ -14,7 +14,7 @@ module.exports = {
         docs: {
             description: "enforce \"for\" loop update clause moving the counter in the right direction.",
             category: "Possible Errors",
-            recommended: false,
+            recommended: true,
             url: "https://eslint.org/docs/rules/for-direction"
         },
         fixable: null,
diff --git a/lib/rules/getter-return.js b/lib/rules/getter-return.js
index 58f2a3978..fe40e5f09 100644
--- a/lib/rules/getter-return.js
+++ b/lib/rules/getter-return.js
@@ -47,7 +47,7 @@ module.exports = {
         docs: {
             description: "enforce `return` statements in getters",
             category: "Possible Errors",
-            recommended: false,
+            recommended: true,
             url: "https://eslint.org/docs/rules/getter-return"
         },
         fixable: null,
diff --git a/lib/rules/max-classes-per-file.js b/lib/rules/max-classes-per-file.js
new file mode 100644
index 000000000..bf6b4ba31
--- /dev/null
+++ b/lib/rules/max-classes-per-file.js
@@ -0,0 +1,60 @@
+/**
+ * @fileoverview Enforce a maximum number of classes per file
+ * @author James Garbutt <https://github.com/43081j>
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = {
+    meta: {
+        docs: {
+            description: "enforce a maximum number of classes per file",
+            category: "Best Practices",
+            recommended: false,
+            url: "https://eslint.org/docs/rules/max-classes-per-file"
+        },
+        schema: [
+            {
+                type: "integer",
+                minimum: 1
+            }
+        ],
+        messages: {
+            maximumExceeded: "Number of classes per file must not exceed {{ max }}"
+        }
+    },
+    create(context) {
+
+        const maxClasses = context.options[0] || 1;
+
+        let classCount = 0;
+
+        return {
+            Program() {
+                classCount = 0;
+            },
+            "Program:exit"(node) {
+                if (classCount > maxClasses) {
+                    context.report({
+                        node,
+                        messageId: "maximumExceeded",
+                        data: {
+                            max: maxClasses
+                        }
+                    });
+                }
+            },
+            "ClassDeclaration, ClassExpression"() {
+                classCount++;
+            }
+        };
+    }
+};
diff --git a/lib/rules/no-self-assign.js b/lib/rules/no-self-assign.js
index 8091d7d2e..5b65ea4f9 100644
--- a/lib/rules/no-self-assign.js
+++ b/lib/rules/no-self-assign.js
@@ -187,8 +187,7 @@ module.exports = {
 
     create(context) {
         const sourceCode = context.getSourceCode();
-        const options = context.options[0];
-        const props = Boolean(options && options.props);
+        const [{ props = true } = {}] = context.options;
 
         /**
          * Reports a given node as self assignments.
diff --git a/lib/rules/object-curly-newline.js b/lib/rules/object-curly-newline.js
index 39043a8b9..e979b5ffe 100644
--- a/lib/rules/object-curly-newline.js
+++ b/lib/rules/object-curly-newline.js
@@ -64,7 +64,7 @@ function normalizeOptionValue(value) {
             consistent = Boolean(value.consistent);
         }
     } else {
-        multiline = true;
+        consistent = true;
     }
 
     return { multiline, minProperties, consistent };
diff --git a/lib/rules/object-shorthand.js b/lib/rules/object-shorthand.js
index c5239a71d..71a320a0e 100644
--- a/lib/rules/object-shorthand.js
+++ b/lib/rules/object-shorthand.js
@@ -233,6 +233,10 @@ module.exports = {
             const keyText = sourceCode.text.slice(firstKeyToken.range[0], lastKeyToken.range[1]);
             let keyPrefix = "";
 
+            if (sourceCode.commentsExistBetween(lastKeyToken, node.value)) {
+                return null;
+            }
+
             if (node.value.async) {
                 keyPrefix += "async ";
             }
diff --git a/lib/rules/one-var.js b/lib/rules/one-var.js
index 40b5f0f0a..70223dd2c 100644
--- a/lib/rules/one-var.js
+++ b/lib/rules/one-var.js
@@ -18,6 +18,8 @@ module.exports = {
             url: "https://eslint.org/docs/rules/one-var"
         },
 
+        fixable: "code",
+
         schema: [
             {
                 oneOf: [
@@ -114,6 +116,8 @@ module.exports = {
             }
         }
 
+        const sourceCode = context.getSourceCode();
+
         //--------------------------------------------------------------------------
         // Helpers
         //--------------------------------------------------------------------------
@@ -272,6 +276,77 @@ module.exports = {
             return true;
         }
 
+        /**
+         * Fixer to join VariableDeclaration's into a single declaration
+         * @param   {VariableDeclarator[]} declarations The `VariableDeclaration` to join
+         * @returns {Function}                         The fixer function
+         */
+        function joinDeclarations(declarations) {
+            const declaration = declarations[0];
+            const body = Array.isArray(declaration.parent.parent.body) ? declaration.parent.parent.body : [];
+            const currentIndex = body.findIndex(node => node.range[0] === declaration.parent.range[0]);
+            const previousNode = body[currentIndex - 1];
+
+            return fixer => {
+                const type = sourceCode.getTokenBefore(declaration);
+                const prevSemi = sourceCode.getTokenBefore(type);
+                const res = [];
+
+                if (previousNode && previousNode.kind === sourceCode.getText(type)) {
+                    res.push(fixer.replaceText(prevSemi, ","));
+                    res.push(fixer.replaceText(type, ""));
+                }
+
+                return res;
+            };
+        }
+
+        /**
+         * 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) {
+            return fixer => declaration.declarations.map(declarator => {
+                const tokenAfterDeclarator = sourceCode.getTokenAfter(declarator);
+                const afterComma = sourceCode.getTokenAfter(tokenAfterDeclarator, { includeComments: true });
+
+                if (tokenAfterDeclarator.value !== ",") {
+                    return null;
+                }
+
+                /*
+                 * `var x,y`
+                 * tokenAfterDeclarator ^^ afterComma
+                 */
+                if (afterComma.range[0] === tokenAfterDeclarator.range[1]) {
+                    return fixer.replaceText(tokenAfterDeclarator, `; ${declaration.kind} `);
+                }
+
+                /*
+                 * `var x,
+                 * tokenAfterDeclarator ^
+                 *      y`
+                 *      ^ afterComma
+                 */
+                if (afterComma.loc.start.line > tokenAfterDeclarator.loc.end.line || afterComma.type === "Line" || afterComma.type === "Block") {
+                    let lastComment = afterComma;
+
+                    while (lastComment.type === "Line" || lastComment.type === "Block") {
+                        lastComment = sourceCode.getTokenAfter(lastComment, { includeComments: true });
+                    }
+
+                    return fixer.replaceTextRange(
+                        [tokenAfterDeclarator.range[0], lastComment.range[0]],
+                        `;\n${sourceCode.text.slice(tokenAfterDeclarator.range[1], lastComment.range[0])}\n${declaration.kind} `
+                    );
+                }
+
+                return fixer.replaceText(tokenAfterDeclarator, `; ${declaration.kind}`);
+            }).filter(x => x);
+        }
+
         /**
          * Checks a given VariableDeclaration node for errors.
          * @param {ASTNode} node The VariableDeclaration node to check
@@ -315,7 +390,8 @@ module.exports = {
                             message: "Combine this with the previous '{{type}}' statement.",
                             data: {
                                 type
-                            }
+                            },
+                            fix: joinDeclarations(declarations)
                         });
                     } else if (options[type].initialized === MODE_CONSECUTIVE && declarationCounts.initialized > 0 && previousDeclCounts.initialized > 0) {
                         context.report({
@@ -323,7 +399,8 @@ module.exports = {
                             message: "Combine this with the previous '{{type}}' statement with initialized variables.",
                             data: {
                                 type
-                            }
+                            },
+                            fix: joinDeclarations(declarations)
                         });
                     } else if (options[type].uninitialized === MODE_CONSECUTIVE &&
                             declarationCounts.uninitialized > 0 &&
@@ -333,7 +410,8 @@ module.exports = {
                             message: "Combine this with the previous '{{type}}' statement with uninitialized variables.",
                             data: {
                                 type
-                            }
+                            },
+                            fix: joinDeclarations(declarations)
                         });
                     }
                 }
@@ -347,7 +425,8 @@ module.exports = {
                         message: "Combine this with the previous '{{type}}' statement.",
                         data: {
                             type
-                        }
+                        },
+                        fix: joinDeclarations(declarations)
                     });
                 } else {
                     if (options[type].initialized === MODE_ALWAYS && declarationCounts.initialized > 0) {
@@ -356,7 +435,8 @@ module.exports = {
                             message: "Combine this with the previous '{{type}}' statement with initialized variables.",
                             data: {
                                 type
-                            }
+                            },
+                            fix: joinDeclarations(declarations)
                         });
                     }
                     if (options[type].uninitialized === MODE_ALWAYS && declarationCounts.uninitialized > 0) {
@@ -368,7 +448,8 @@ module.exports = {
                             message: "Combine this with the previous '{{type}}' statement with uninitialized variables.",
                             data: {
                                 type
-                            }
+                            },
+                            fix: joinDeclarations(declarations)
                         });
                     }
                 }
@@ -387,7 +468,8 @@ module.exports = {
                             message: "Split '{{type}}' declarations into multiple statements.",
                             data: {
                                 type
-                            }
+                            },
+                            fix: splitDeclarations(node)
                         });
                     } else if (options[type].initialized === MODE_NEVER && declarationCounts.initialized > 0) {
 
@@ -397,7 +479,8 @@ module.exports = {
                             message: "Split initialized '{{type}}' declarations into multiple statements.",
                             data: {
                                 type
-                            }
+                            },
+                            fix: splitDeclarations(node)
                         });
                     } else if (options[type].uninitialized === MODE_NEVER && declarationCounts.uninitialized > 0) {
 
@@ -407,7 +490,8 @@ module.exports = {
                             message: "Split uninitialized '{{type}}' declarations into multiple statements.",
                             data: {
                                 type
-                            }
+                            },
+                            fix: splitDeclarations(node)
                         });
                     }
                 }
diff --git a/lib/rules/prefer-template.js b/lib/rules/prefer-template.js
index 2b893fd37..14c419942 100644
--- a/lib/rules/prefer-template.js
+++ b/lib/rules/prefer-template.js
@@ -38,6 +38,45 @@ function getTopConcatBinaryExpression(node) {
     return currentNode;
 }
 
+/**
+ * Determines whether a given node is a octal escape sequence
+ * @param {ASTNode} node A node to check
+ * @returns {boolean} `true` if the node is an octal escape sequence
+ */
+function isOctalEscapeSequence(node) {
+
+    // No need to check TemplateLiterals – would throw error with octal escape
+    const isStringLiteral = node.type === "Literal" && typeof node.value === "string";
+
+    if (!isStringLiteral) {
+        return false;
+    }
+
+    const match = node.raw.match(/^([^\\]|\\[^0-7])*\\([0-7]{1,3})/);
+
+    if (match) {
+
+        // \0 is actually not considered an octal
+        if (match[2] !== "0" || typeof match[3] !== "undefined") {
+            return true;
+        }
+    }
+    return false;
+}
+
+/**
+ * Checks whether or not a node contains a octal escape sequence
+ * @param {ASTNode} node A node to check
+ * @returns {boolean} `true` if the node contains an octal escape sequence
+ */
+function hasOctalEscapeSequence(node) {
+    if (isConcatenation(node)) {
+        return hasOctalEscapeSequence(node.left) || hasOctalEscapeSequence(node.right);
+    }
+
+    return isOctalEscapeSequence(node);
+}
+
 /**
  * Checks whether or not a given binary expression has string literals.
  * @param {ASTNode} node - A node to check.
@@ -193,6 +232,22 @@ module.exports = {
             return `\`\${${textBeforeNode || ""}${sourceCode.getText(currentNode)}${textAfterNode || ""}}\``;
         }
 
+        /**
+         * Returns a fixer object that converts a non-string binary expression to a template literal
+         * @param {SourceCodeFixer} fixer The fixer object
+         * @param {ASTNode} node A node that should be converted to a template literal
+         * @returns {Object} A fix for this binary expression
+         */
+        function fixNonStringBinaryExpression(fixer, node) {
+            const topBinaryExpr = getTopConcatBinaryExpression(node.parent);
+
+            if (hasOctalEscapeSequence(topBinaryExpr)) {
+                return null;
+            }
+
+            return fixer.replaceText(topBinaryExpr, getTemplateLiteral(topBinaryExpr, null, null));
+        }
+
         /**
          * Reports if a given node is string concatenation with non string literals.
          *
@@ -216,9 +271,7 @@ module.exports = {
                 context.report({
                     node: topBinaryExpr,
                     message: "Unexpected string concatenation.",
-                    fix(fixer) {
-                        return fixer.replaceText(topBinaryExpr, getTemplateLiteral(topBinaryExpr, null, null));
-                    }
+                    fix: fixer => fixNonStringBinaryExpression(fixer, node)
                 });
             }
         }
diff --git a/lib/rules/valid-jsdoc.js b/lib/rules/valid-jsdoc.js
index 4038f70e5..971e755c4 100644
--- a/lib/rules/valid-jsdoc.js
+++ b/lib/rules/valid-jsdoc.js
@@ -102,7 +102,7 @@ module.exports = {
         function startFunction(node) {
             fns.push({
                 returnPresent: (node.type === "ArrowFunctionExpression" && node.body.type !== "BlockStatement") ||
-                    isTypeClass(node)
+                    isTypeClass(node) || node.async
             });
         }
 
diff --git a/lib/util/glob-util.js b/lib/util/glob-util.js
index b91ec53e6..9d5d7e5aa 100644
--- a/lib/util/glob-util.js
+++ b/lib/util/glob-util.js
@@ -22,6 +22,15 @@ const debug = require("debug")("eslint:glob-util");
 // Helpers
 //------------------------------------------------------------------------------
 
+/**
+ * Checks whether a directory exists at the given location
+ * @param {string} resolvedPath A path from the CWD
+ * @returns {boolean} `true` if a directory exists
+ */
+function directoryExists(resolvedPath) {
+    return fs.existsSync(resolvedPath) && fs.statSync(resolvedPath).isDirectory();
+}
+
 /**
  * Checks if a provided path is a directory and returns a glob string matching
  * all files under that directory if so, the path itself otherwise.
@@ -64,7 +73,7 @@ function processPath(options) {
         let newPath = pathname;
         const resolvedPath = path.resolve(cwd, pathname);
 
-        if (fs.existsSync(resolvedPath) && fs.statSync(resolvedPath).isDirectory()) {
+        if (directoryExists(resolvedPath)) {
             newPath = pathname.replace(/[/\\]$/, "") + suffix;
         }
 
@@ -72,21 +81,92 @@ function processPath(options) {
     };
 }
 
+/**
+ * The error type when no files match a glob.
+ */
+class NoFilesFoundError extends Error {
+
+    /**
+     * @param {string} pattern - The glob pattern which was not found.
+     */
+    constructor(pattern) {
+        super(`No files matching '${pattern}' were found.`);
+
+        this.messageTemplate = "file-not-found";
+        this.messageData = { pattern };
+    }
+
+}
+
+/**
+ * The error type when there are files matched by a glob, but all of them have been ignored.
+ */
+class AllFilesIgnoredError extends Error {
+
+    /**
+     * @param {string} pattern - The glob pattern which was not found.
+     */
+    constructor(pattern) {
+        super(`All files matched by '${pattern}' are ignored.`);
+        this.messageTemplate = "all-files-ignored";
+        this.messageData = { pattern };
+    }
+}
+
+const NORMAL_LINT = {};
+const SILENTLY_IGNORE = {};
+const IGNORE_AND_WARN = {};
+
+/**
+ * Tests whether a file should be linted or ignored
+ * @param {string} filename The file to be processed
+ * @param {{ignore: (boolean|null)}} options If `ignore` is false, updates the behavior to
+ * not process custom ignore paths, and lint files specified by direct path even if they
+ * match the default ignore path
+ * @param {boolean} isDirectPath True if the file was provided as a direct path
+ * (as opposed to being resolved from a glob)
+ * @param {IgnoredPaths} ignoredPaths An instance of IgnoredPaths to check whether a given
+ * file is ignored.
+ * @returns {(NORMAL_LINT|SILENTLY_IGNORE|IGNORE_AND_WARN)} A directive for how the
+ * file should be processed (either linted normally, or silently ignored, or ignored
+ * with a warning that it is being ignored)
+ */
+function testFileAgainstIgnorePatterns(filename, options, isDirectPath, ignoredPaths) {
+    const shouldProcessCustomIgnores = options.ignore !== false;
+    const shouldLintIgnoredDirectPaths = options.ignore === false;
+    const fileMatchesIgnorePatterns = ignoredPaths.contains(filename, "default") ||
+        (shouldProcessCustomIgnores && ignoredPaths.contains(filename, "custom"));
+
+    if (fileMatchesIgnorePatterns && isDirectPath && !shouldLintIgnoredDirectPaths) {
+        return IGNORE_AND_WARN;
+    }
+
+    if (!fileMatchesIgnorePatterns || (isDirectPath && shouldLintIgnoredDirectPaths)) {
+        return NORMAL_LINT;
+    }
+
+    return SILENTLY_IGNORE;
+}
+
 //------------------------------------------------------------------------------
 // Public Interface
 //------------------------------------------------------------------------------
 
 /**
  * Resolves any directory patterns into glob-based patterns for easier handling.
- * @param   {string[]} patterns    File patterns (such as passed on the command line).
- * @param   {Object} options       An options object.
+ * @param   {string[]} patterns               File patterns (such as passed on the command line).
+ * @param   {Object} options                  An options object.
+ * @param   {string} [options.globInputPaths] False disables glob resolution.
  * @returns {string[]} The equivalent glob patterns and filepath strings.
  */
 function resolveFileGlobPatterns(patterns, options) {
+    if (options.globInputPaths === false) {
+        return patterns;
+    }
 
     const processPathExtensions = processPath(options);
 
-    return patterns.filter(p => p.length).map(processPathExtensions);
+    return patterns.map(processPathExtensions);
 }
 
 const dotfilesPattern = /(?:(?:^\.)|(?:[/\\]\.))[^/\\.].*/;
@@ -95,19 +175,17 @@ const dotfilesPattern = /(?:(?:^\.)|(?:[/\\]\.))[^/\\.].*/;
  * Build a list of absolute filesnames on which ESLint will act.
  * Ignored files are excluded from the results, as are duplicates.
  *
- * @param   {string[]} globPatterns                    Glob patterns.
- * @param   {Object}   [providedOptions]               An options object.
- * @param   {string}   [providedOptions.cwd]           CWD (considered for relative filenames)
- * @param   {boolean}  [providedOptions.ignore]        False disables use of .eslintignore.
- * @param   {string}   [providedOptions.ignorePath]    The ignore file to use instead of .eslintignore.
- * @param   {string}   [providedOptions.ignorePattern] A pattern of files to ignore.
+ * @param   {string[]} globPatterns                     Glob patterns.
+ * @param   {Object}   [providedOptions]                An options object.
+ * @param   {string}   [providedOptions.cwd]            CWD (considered for relative filenames)
+ * @param   {boolean}  [providedOptions.ignore]         False disables use of .eslintignore.
+ * @param   {string}   [providedOptions.ignorePath]     The ignore file to use instead of .eslintignore.
+ * @param   {string}   [providedOptions.ignorePattern]  A pattern of files to ignore.
+ * @param   {string}   [providedOptions.globInputPaths] False disables glob resolution.
  * @returns {string[]} Resolved absolute filenames.
  */
 function listFilesToProcess(globPatterns, providedOptions) {
     const options = providedOptions || { ignore: true };
-    const files = [];
-    const addedFilenames = new Set();
-
     const cwd = options.cwd || process.cwd();
 
     const getIgnorePaths = lodash.memoize(
@@ -115,69 +193,79 @@ function listFilesToProcess(globPatterns, providedOptions) {
             new IgnoredPaths(optionsObj)
     );
 
-    /**
-     * Executes the linter on a file defined by the `filename`. Skips
-     * any files that are already linted.
-     * @param {string} filename The file to be processed
-     * @param {boolean} isDirectPath True if the file
-     * was provided as a direct path (as opposed to being resolved from a glob)
-     * @param {IgnoredPaths} ignoredPaths An instance of IgnoredPaths
-     * @returns {void}
+    /*
+     * The test "should use default options if none are provided" (source-code-util.js) checks that 'module.exports.resolveFileGlobPatterns' was called.
+     * So it cannot use the local function "resolveFileGlobPatterns".
      */
-    function addFile(filename, isDirectPath, ignoredPaths) {
-        if (addedFilenames.has(filename)) {
-            return;
-        }
-
-        const shouldProcessCustomIgnores = options.ignore !== false;
-        const shouldLintIgnoredDirectPaths = options.ignore === false;
-        const fileMatchesIgnorePatterns = ignoredPaths.contains(filename, "default") ||
-            (shouldProcessCustomIgnores && ignoredPaths.contains(filename, "custom"));
-
-        if (fileMatchesIgnorePatterns && isDirectPath && !shouldLintIgnoredDirectPaths) {
-            files.push({ filename, ignored: true });
-            addedFilenames.add(filename);
-        }
-
-        if (!fileMatchesIgnorePatterns || (isDirectPath && shouldLintIgnoredDirectPaths)) {
-            files.push({ filename, ignored: false });
-            addedFilenames.add(filename);
-        }
-    }
+    const resolvedGlobPatterns = module.exports.resolveFileGlobPatterns(globPatterns, options);
 
     debug("Creating list of files to process.");
-    globPatterns.forEach(pattern => {
+    const resolvedPathsByGlobPattern = resolvedGlobPatterns.map(pattern => {
         const file = path.resolve(cwd, pattern);
 
-        if (fs.existsSync(file) && fs.statSync(file).isFile()) {
+        if (options.globInputPaths === false || (fs.existsSync(file) && fs.statSync(file).isFile())) {
             const ignoredPaths = getIgnorePaths(options);
+            const fullPath = options.globInputPaths === false ? file : fs.realpathSync(file);
+
+            return [{
+                filename: fullPath,
+                behavior: testFileAgainstIgnorePatterns(fullPath, options, true, ignoredPaths)
+            }];
+        }
 
-            addFile(fs.realpathSync(file), true, ignoredPaths);
-        } else {
+        // regex to find .hidden or /.hidden patterns, but not ./relative or ../relative
+        const globIncludesDotfiles = dotfilesPattern.test(pattern);
+        let newOptions = options;
 
-            // regex to find .hidden or /.hidden patterns, but not ./relative or ../relative
-            const globIncludesDotfiles = dotfilesPattern.test(pattern);
-            let newOptions = options;
+        if (!options.dotfiles) {
+            newOptions = Object.assign({}, options, { dotfiles: globIncludesDotfiles });
+        }
 
-            if (!options.dotfiles) {
-                newOptions = Object.assign({}, options, { dotfiles: globIncludesDotfiles });
-            }
+        const ignoredPaths = getIgnorePaths(newOptions);
+        const shouldIgnore = ignoredPaths.getIgnoredFoldersGlobChecker();
+        const globOptions = {
+            nodir: true,
+            dot: true,
+            cwd
+        };
 
-            const ignoredPaths = getIgnorePaths(newOptions);
-            const shouldIgnore = ignoredPaths.getIgnoredFoldersGlobChecker();
-            const globOptions = {
-                nodir: true,
-                dot: true,
-                cwd
+        return new GlobSync(pattern, globOptions, shouldIgnore).found.map(globMatch => {
+            const relativePath = path.resolve(cwd, globMatch);
+
+            return {
+                filename: relativePath,
+                behavior: testFileAgainstIgnorePatterns(relativePath, options, false, ignoredPaths)
             };
+        });
+    });
 
-            new GlobSync(pattern, globOptions, shouldIgnore).found.forEach(globMatch => {
-                addFile(path.resolve(cwd, globMatch), false, ignoredPaths);
-            });
+    const allPathDescriptors = resolvedPathsByGlobPattern.reduce((pathsForAllGlobs, pathsForCurrentGlob, index) => {
+        if (pathsForCurrentGlob.every(pathDescriptor => pathDescriptor.behavior === SILENTLY_IGNORE)) {
+            throw new (pathsForCurrentGlob.length ? AllFilesIgnoredError : NoFilesFoundError)(globPatterns[index]);
         }
-    });
 
-    return files;
+        pathsForCurrentGlob.forEach(pathDescriptor => {
+            switch (pathDescriptor.behavior) {
+                case NORMAL_LINT:
+                    pathsForAllGlobs.push({ filename: pathDescriptor.filename, ignored: false });
+                    break;
+                case IGNORE_AND_WARN:
+                    pathsForAllGlobs.push({ filename: pathDescriptor.filename, ignored: true });
+                    break;
+                case SILENTLY_IGNORE:
+
+                    // do nothing
+                    break;
+
+                default:
+                    throw new Error(`Unexpected file behavior for ${pathDescriptor.filename}`);
+            }
+        });
+
+        return pathsForAllGlobs;
+    }, []);
+
+    return lodash.uniqBy(allPathDescriptors, pathDescriptor => pathDescriptor.filename);
 }
 
 module.exports = {
diff --git a/lib/util/source-code-util.js b/lib/util/source-code-util.js
index 815fad911..66d91cd21 100644
--- a/lib/util/source-code-util.js
+++ b/lib/util/source-code-util.js
@@ -78,14 +78,13 @@ function getSourceCodeOfFiles(patterns, providedOptions, providedCallback) {
         callback = providedCallback;
     }
     debug("constructed options:", options);
-    const resolvedPatterns = globUtil.resolveFileGlobPatterns(globPatternsList, options);
 
-    const filenames = globUtil.listFilesToProcess(resolvedPatterns, options)
+    const filenames = globUtil.listFilesToProcess(globPatternsList, options)
         .filter(fileInfo => !fileInfo.ignored)
         .reduce((files, fileInfo) => files.concat(fileInfo.filename), []);
 
     if (filenames.length === 0) {
-        debug(`Did not find any files matching pattern(s): ${resolvedPatterns}`);
+        debug(`Did not find any files matching pattern(s): ${globPatternsList}`);
     }
     filenames.forEach(filename => {
         const sourceCode = getSourceCodeOfFile(filename, options);
diff --git a/messages/all-files-ignored.txt b/messages/all-files-ignored.txt
new file mode 100644
index 000000000..3b741a03e
--- /dev/null
+++ b/messages/all-files-ignored.txt
@@ -0,0 +1,8 @@
+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.
+
+If you do want to lint these files, try the following solutions:
+
+* Check your .eslintignore file, or the eslintIgnore property in package.json, to ensure that the files are not configured to be ignored.
+* Explicitly list the files from this glob that you'd like to lint on the command-line, rather than providing a glob as an argument.
diff --git a/messages/file-not-found.txt b/messages/file-not-found.txt
new file mode 100644
index 000000000..97e2d37fa
--- /dev/null
+++ b/messages/file-not-found.txt
@@ -0,0 +1,2 @@
+No files matching the pattern "<%= pattern %>" were found.
+Please check for typing mistakes in the pattern.
diff --git a/messages/plugin-missing.txt b/messages/plugin-missing.txt
index 00c7fe78b..766020b2b 100644
--- a/messages/plugin-missing.txt
+++ b/messages/plugin-missing.txt
@@ -6,4 +6,6 @@ ESLint couldn't find the plugin "<%- pluginName %>". This can happen for a coupl
 
     npm i <%- pluginName %>@latest --save-dev
 
+Path to ESLint package: <%- eslintPath %>
+
 If you still can't figure out the problem, please stop by https://gitter.im/eslint/eslint to chat with the team.
diff --git a/package.json b/package.json
index e1199bb32..9cc8b83da 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "eslint",
-  "version": "5.0.0-alpha.1",
+  "version": "5.0.0-alpha.2",
   "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
   "description": "An AST-based pattern checker for JavaScript.",
   "bin": {
@@ -34,13 +34,13 @@
   "homepage": "https://eslint.org",
   "bugs": "https://github.com/eslint/eslint/issues/",
   "dependencies": {
-    "ajv": "^6.0.1",
+    "ajv": "^6.5.0",
     "babel-code-frame": "^6.26.0",
     "chalk": "^2.1.0",
     "cross-spawn": "^6.0.5",
     "debug": "^3.1.0",
     "doctrine": "^2.1.0",
-    "eslint-scope": "^3.7.1",
+    "eslint-scope": "^4.0.0-alpha.0",
     "eslint-visitor-keys": "^1.0.0",
     "espree": "^4.0.0-alpha.0",
     "esquery": "^1.0.1",
@@ -48,7 +48,7 @@
     "file-entry-cache": "^2.0.0",
     "functional-red-black-tree": "^1.0.1",
     "glob": "^7.1.2",
-    "globals": "^11.4.0",
+    "globals": "^11.5.0",
     "ignore": "^3.3.3",
     "imurmurhash": "^0.1.4",
     "inquirer": "^5.2.0",
@@ -73,24 +73,24 @@
     "text-table": "^0.2.0"
   },
   "devDependencies": {
-    "babel-core": "^6.26.0",
+    "babel-core": "^6.26.3",
     "babel-polyfill": "^6.26.0",
     "babel-preset-es2015": "^6.24.1",
     "babelify": "^8.0.0",
     "beefy": "^2.1.8",
     "brfs": "^1.5.0",
-    "browserify": "^16.1.1",
+    "browserify": "^16.2.2",
     "chai": "^4.0.1",
     "cheerio": "^0.22.0",
-    "coveralls": "^3.0.0",
+    "coveralls": "^3.0.1",
     "dateformat": "^3.0.3",
-    "ejs": "^2.5.8",
+    "ejs": "^2.6.1",
     "eslint-plugin-eslint-plugin": "^1.2.0",
     "eslint-plugin-node": "^6.0.1",
     "eslint-plugin-rulesdir": "^0.1.0",
     "eslint-release": "^0.11.1",
-    "eslint-rule-composer": "^0.1.1",
-    "eslump": "^1.6.1",
+    "eslint-rule-composer": "^0.3.0",
+    "eslump": "^1.6.2",
     "esprima": "^4.0.0",
     "istanbul": "^0.4.5",
     "jsdoc": "^3.5.5",
@@ -103,11 +103,11 @@
     "load-perf": "^0.2.0",
     "markdownlint": "^0.8.1",
     "mocha": "^5.0.5",
-    "mock-fs": "^4.3.0",
+    "mock-fs": "^4.5.0",
     "npm-license": "^0.3.3",
     "phantomjs-prebuilt": "^2.1.16",
     "proxyquire": "^2.0.1",
-    "shelljs": "^0.8.1",
+    "shelljs": "^0.8.2",
     "sinon": "^3.3.0",
     "temp": "^0.8.3",
     "through": "^2.3.8"
diff --git a/packages/eslint-config-eslint/default.yml b/packages/eslint-config-eslint/default.yml
index 8c5ac071c..713042f13 100644
--- a/packages/eslint-config-eslint/default.yml
+++ b/packages/eslint-config-eslint/default.yml
@@ -1,5 +1,9 @@
 extends:
-    "eslint:recommended"
+    - "eslint:recommended"
+    - "plugin:node/recommended"
+
+plugins:
+    - "node"
 
 rules:
     array-bracket-spacing: "error"
@@ -24,12 +28,10 @@ rules:
     dot-notation: ["error", { allowKeywords: true }]
     eol-last: "error"
     eqeqeq: "error"
-    for-direction: "error"
     func-call-spacing: "error"
     func-style: ["error", "declaration"]
     function-paren-newline: ["error", "consistent"]
     generator-star-spacing: "error"
-    getter-return: "error"
     guard-for-in: "error"
     handle-callback-err: ["error", "err"]
     key-spacing: ["error", { beforeColon: false, afterColon: true }]
diff --git a/packages/eslint-config-eslint/package.json b/packages/eslint-config-eslint/package.json
index 9098c1e19..3d8859b05 100644
--- a/packages/eslint-config-eslint/package.json
+++ b/packages/eslint-config-eslint/package.json
@@ -22,6 +22,9 @@
   "dependencies": {
     "js-yaml": "^3.5.1"
   },
+  "peerDependencies": {
+    "eslint-plugin-node": "^6.0.1"
+  },
   "keywords": [
     "eslintconfig",
     "eslint-config",
diff --git a/templates/blogpost.md.ejs b/templates/blogpost.md.ejs
index 05261a58f..4a4ad4091 100644
--- a/templates/blogpost.md.ejs
+++ b/templates/blogpost.md.ejs
@@ -7,7 +7,7 @@ tags:
 ---
 # ESLint v<%= version %> released
 
-We just pushed ESLint v<%- version %>, which is a <%- type %> release upgrade of ESLint. This release <% if (type !== "patch") { %>adds some new features and <% } %>fixes several bugs found in the previous release. <% if (type === "major") { %>This release also has some breaking changes, so please read the following closely. <% } %>
+We just pushed ESLint v<%- version %>, which is a <%- type %> release upgrade of ESLint. This release <% if (type !== "patch") { %>adds some new features and <% } %>fixes several bugs found in the previous release.<% if (type === "major") { %>This release also has some breaking changes, so please read the following closely.<% } %>
 
 <%
 const RULE_REGEX = new RegExp(`\`?\\b(${ruleList.join("|")})\\b\`?`, "g");
diff --git a/tools/eslint-fuzzer.js b/tools/eslint-fuzzer.js
index ea84e994b..342dee3e4 100644
--- a/tools/eslint-fuzzer.js
+++ b/tools/eslint-fuzzer.js
@@ -110,7 +110,7 @@ function fuzz(options) {
         const text = codeGenerator({ sourceType });
         const config = {
             rules: lodash.mapValues(ruleConfigs, lodash.sample),
-            parserOptions: { sourceType, ecmaVersion: 2017 }
+            parserOptions: { sourceType, ecmaVersion: 2018 }
         };
 
         let autofixResult;


Test patch:
diff --git a/lib/testers/rule-tester.js b/lib/testers/rule-tester.js
index 3650acf91..318fafe1b 100644
--- a/lib/testers/rule-tester.js
+++ b/lib/testers/rule-tester.js
@@ -396,10 +396,10 @@ class RuleTester {
          * @private
          */
         function assertASTDidntChange(beforeAST, afterAST) {
-            if (!lodash.isEqual(beforeAST, afterAST)) {
 
-                // Not using directly to avoid performance problem in node 6.1.0. See #6111
-                assert.deepStrictEqual(beforeAST, afterAST, "Rule should not modify AST.");
+            // Feature detect the Node.js implementation and use that if available.
+            if ((util.isDeepStrictEqual && !util.isDeepStrictEqual(beforeAST, afterAST)) || !lodash.isEqual(beforeAST, afterAST)) {
+                assert.fail(null, null, "Rule should not modify AST.");
             }
         }
 
diff --git a/tests/fixtures/cli-engine/empty/.keep b/tests/fixtures/cli-engine/empty/.keep
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/fixtures/config-file/experimental-object-rest-spread/another-parser/.eslintrc.yml b/tests/fixtures/config-file/experimental-object-rest-spread/another-parser/.eslintrc.yml
new file mode 100644
index 000000000..c64b2c309
--- /dev/null
+++ b/tests/fixtures/config-file/experimental-object-rest-spread/another-parser/.eslintrc.yml
@@ -0,0 +1,6 @@
+root: true
+
+parser: ./parser.js
+parserOptions:
+  ecmaFeatures:
+    experimentalObjectRestSpread: true
diff --git a/tests/fixtures/config-file/experimental-object-rest-spread/another-parser/parser.js b/tests/fixtures/config-file/experimental-object-rest-spread/another-parser/parser.js
new file mode 100644
index 000000000..f193589ef
--- /dev/null
+++ b/tests/fixtures/config-file/experimental-object-rest-spread/another-parser/parser.js
@@ -0,0 +1,1 @@
+module.exports.parse = () => ({ type: "Program", body: [] })
diff --git a/tests/fixtures/config-file/experimental-object-rest-spread/basic/.eslintrc.yml b/tests/fixtures/config-file/experimental-object-rest-spread/basic/.eslintrc.yml
new file mode 100644
index 000000000..a5c9e4ebf
--- /dev/null
+++ b/tests/fixtures/config-file/experimental-object-rest-spread/basic/.eslintrc.yml
@@ -0,0 +1,5 @@
+root: true
+
+parserOptions:
+  ecmaFeatures:
+    experimentalObjectRestSpread: true
diff --git a/tests/fixtures/config-file/experimental-object-rest-spread/extends/.eslintrc.yml b/tests/fixtures/config-file/experimental-object-rest-spread/extends/.eslintrc.yml
new file mode 100644
index 000000000..2daef0dea
--- /dev/null
+++ b/tests/fixtures/config-file/experimental-object-rest-spread/extends/.eslintrc.yml
@@ -0,0 +1,4 @@
+root: true
+
+extends:
+  - ./common.yml
diff --git a/tests/fixtures/config-file/experimental-object-rest-spread/extends/common.yml b/tests/fixtures/config-file/experimental-object-rest-spread/extends/common.yml
new file mode 100644
index 000000000..99975a7bd
--- /dev/null
+++ b/tests/fixtures/config-file/experimental-object-rest-spread/extends/common.yml
@@ -0,0 +1,3 @@
+parserOptions:
+  ecmaFeatures:
+    experimentalObjectRestSpread: true
diff --git a/tests/fixtures/config-file/experimental-object-rest-spread/subdir/.eslintrc.yml b/tests/fixtures/config-file/experimental-object-rest-spread/subdir/.eslintrc.yml
new file mode 100644
index 000000000..a5c9e4ebf
--- /dev/null
+++ b/tests/fixtures/config-file/experimental-object-rest-spread/subdir/.eslintrc.yml
@@ -0,0 +1,5 @@
+root: true
+
+parserOptions:
+  ecmaFeatures:
+    experimentalObjectRestSpread: true
diff --git a/tests/fixtures/config-file/experimental-object-rest-spread/subdir/lib/.eslintrc.yml b/tests/fixtures/config-file/experimental-object-rest-spread/subdir/lib/.eslintrc.yml
new file mode 100644
index 000000000..78dc43786
--- /dev/null
+++ b/tests/fixtures/config-file/experimental-object-rest-spread/subdir/lib/.eslintrc.yml
@@ -0,0 +1,2 @@
+rules:
+  no-undef: off
diff --git a/tests/fixtures/glob-util/empty/.gitkeep b/tests/fixtures/glob-util/empty/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/lib/cli-engine.js b/tests/lib/cli-engine.js
index acbdba72d..c4e0ab054 100644
--- a/tests/lib/cli-engine.js
+++ b/tests/lib/cli-engine.js
@@ -103,6 +103,13 @@ describe("CLIEngine", () => {
                 process.chdir(originalDir);
             }
         });
+
+        it("should report one fatal message when given a path by --ignore-path that is not a file when ignore is true.", () => {
+            assert.throws(() => {
+                // eslint-disable-next-line no-new
+                new CLIEngine({ ignorePath: fixtureDir });
+            }, `Error: Could not load file ${fixtureDir}\nError: ${fixtureDir} is not a file`);
+        });
     });
 
     describe("executeOnText()", () => {
@@ -726,6 +733,33 @@ describe("CLIEngine", () => {
             assert.strictEqual(report.results[1].messages.length, 0);
         });
 
+        it("should resolve globs when 'globInputPaths' option is true", () => {
+            engine = new CLIEngine({
+                extensions: [".js", ".js2"],
+                ignore: false,
+                cwd: getFixturePath("..")
+            });
+
+            const report = engine.executeOnFiles(["fixtures/files/*"]);
+
+            assert.strictEqual(report.results.length, 2);
+            assert.strictEqual(report.results[0].messages.length, 0);
+            assert.strictEqual(report.results[1].messages.length, 0);
+        });
+
+        it("should not resolve globs when 'globInputPaths' option is false", () => {
+            engine = new CLIEngine({
+                extensions: [".js", ".js2"],
+                ignore: false,
+                cwd: getFixturePath(".."),
+                globInputPaths: false
+            });
+
+            assert.throws(() => {
+                engine.executeOnFiles(["fixtures/files/*"]);
+            }, `ENOENT: no such file or directory, open '${getFixturePath("..", "fixtures", "files", "*")}`);
+        });
+
         it("should report on all files passed explicitly, even if ignored by default", () => {
 
             engine = new CLIEngine({
@@ -767,9 +801,9 @@ describe("CLIEngine", () => {
                 cwd: getFixturePath("cli-engine")
             });
 
-            const report = engine.executeOnFiles(["node_modules"]);
-
-            assert.strictEqual(report.results.length, 0);
+            assert.throws(() => {
+                engine.executeOnFiles(["node_modules"]);
+            }, "All files matched by 'node_modules' are ignored.");
         });
 
         // https://github.com/eslint/eslint/issues/5547
@@ -780,9 +814,9 @@ describe("CLIEngine", () => {
                 ignore: false
             });
 
-            const report = engine.executeOnFiles(["node_modules"]);
-
-            assert.strictEqual(report.results.length, 0);
+            assert.throws(() => {
+                engine.executeOnFiles(["node_modules"]);
+            }, "All files matched by 'node_modules' are ignored.");
         });
 
         it("should not check .hidden files if they are passed explicitly without --no-ignore flag", () => {
@@ -1029,35 +1063,32 @@ describe("CLIEngine", () => {
 
         });
 
-        it("should return zero messages when given a directory with eslint excluded files in the directory", () => {
+        it("should throw an error when given a directory with all eslint excluded files in the directory", () => {
 
             engine = new CLIEngine({
                 ignorePath: getFixturePath(".eslintignore")
             });
 
-            const report = engine.executeOnFiles([getFixturePath("./")]);
-
-            assert.strictEqual(report.results.length, 0);
+            assert.throws(() => {
+                engine.executeOnFiles([getFixturePath("./")]);
+            }, `All files matched by '${getFixturePath("./")}' are ignored.`);
         });
 
-        it("should return zero messages when all given files are ignored", () => {
-            engine = new CLIEngine({
-                ignorePath: getFixturePath(".eslintignore")
-            });
-
-            const report = engine.executeOnFiles(["tests/fixtures/"]);
+        it("should throw an error when all given files are ignored", () => {
 
-            assert.strictEqual(report.results.length, 0);
+            assert.throws(() => {
+                engine.executeOnFiles(["tests/fixtures/"]);
+            }, "All files matched by 'tests/fixtures/' are ignored.");
         });
 
-        it("should return zero messages when all given files are ignored event with a `./` prefix", () => {
+        it("should throw an error when all given files are ignored even with a `./` prefix", () => {
             engine = new CLIEngine({
                 ignorePath: getFixturePath(".eslintignore")
             });
 
-            const report = engine.executeOnFiles(["./tests/fixtures/"]);
-
-            assert.strictEqual(report.results.length, 0);
+            assert.throws(() => {
+                engine.executeOnFiles(["./tests/fixtures/"]);
+            }, "All files matched by './tests/fixtures/' are ignored.");
         });
 
         // https://github.com/eslint/eslint/issues/3788
@@ -1081,7 +1112,7 @@ describe("CLIEngine", () => {
         });
 
         // https://github.com/eslint/eslint/issues/3812
-        it("should ignore all files when tests/fixtures/ is in ignore file", () => {
+        it("should ignore all files and throw an error when tests/fixtures/ is in ignore file", () => {
             engine = new CLIEngine({
                 ignorePath: getFixturePath("cli-engine/.eslintignore2"),
                 useEslintrc: false,
@@ -1090,19 +1121,19 @@ describe("CLIEngine", () => {
                 }
             });
 
-            const report = engine.executeOnFiles(["./tests/fixtures/cli-engine/"]);
-
-            assert.strictEqual(report.results.length, 0);
+            assert.throws(() => {
+                engine.executeOnFiles(["./tests/fixtures/cli-engine/"]);
+            }, "No files matching './tests/fixtures/cli-engine/' were found.");
         });
 
-        it("should return zero messages when all given files are ignored via ignore-pattern", () => {
+        it("should throw an error when all given files are ignored via ignore-pattern", () => {
             engine = new CLIEngine({
                 ignorePattern: "tests/fixtures/single-quoted.js"
             });
 
-            const report = engine.executeOnFiles(["tests/fixtures/*-quoted.js"]);
-
-            assert.strictEqual(report.results.length, 0);
+            assert.throws(() => {
+                engine.executeOnFiles(["tests/fixtures/*-quoted.js"]);
+            }, "All files matched by 'tests/fixtures/*-quoted.js' are ignored.");
         });
 
         it("should return a warning when an explicitly given file is ignored", () => {
@@ -1344,29 +1375,6 @@ describe("CLIEngine", () => {
             assert.strictEqual(report.results[0].messages.length, 0);
         });
 
-        it("should not fail if an ignored file cannot be resolved", () => {
-
-            const fakeFS = leche.fake(fs),
-                LocalCLIEngine = proxyquire("../../lib/cli-engine", {
-                    fs: fakeFS
-                });
-
-            fakeFS.realpathSync = function() {
-                throw new Error("this error should not happen");
-            };
-            fakeFS.existsSync = fs.existsSync;
-            fakeFS.unlinkSync = fs.unlinkSync;
-
-            engine = new LocalCLIEngine({
-                ignorePattern: "tests"
-            });
-
-            assert.doesNotThrow(() => {
-                engine.executeOnFiles(["tests/fixtures/file-not-found.js"]);
-            });
-
-        });
-
         describe("Fix Mode", () => {
 
             it("should return fixed text on multiple files when in fix mode", () => {
@@ -2600,6 +2608,45 @@ describe("CLIEngine", () => {
                 });
             });
         });
+
+        describe("Patterns which match no file should throw errors.", () => {
+            beforeEach(() => {
+                engine = new CLIEngine({
+                    cwd: getFixturePath("cli-engine"),
+                    useEslintrc: false
+                });
+            });
+
+            it("one file", () => {
+                assert.throws(() => {
+                    engine.executeOnFiles(["non-exist.js"]);
+                }, "No files matching 'non-exist.js' were found.");
+            });
+
+            it("should throw if the directory exists and is empty", () => {
+                assert.throws(() => {
+                    engine.executeOnFiles(["empty"]);
+                }, "No files matching 'empty' were found.");
+            });
+
+            it("one glob pattern", () => {
+                assert.throws(() => {
+                    engine.executeOnFiles(["non-exist/**/*.js"]);
+                }, "No files matching 'non-exist/**/*.js' were found.");
+            });
+
+            it("two files", () => {
+                assert.throws(() => {
+                    engine.executeOnFiles(["aaa.js", "bbb.js"]);
+                }, "No files matching 'aaa.js' were found.");
+            });
+
+            it("a mix of an existing file and a non-existing file", () => {
+                assert.throws(() => {
+                    engine.executeOnFiles(["console.js", "non-exist.js"]);
+                }, "No files matching 'non-exist.js' were found.");
+            });
+        });
     });
 
     describe("getConfigForFile", () => {
@@ -2976,9 +3023,10 @@ describe("CLIEngine", () => {
     describe("resolveFileGlobPatterns", () => {
 
         leche.withData([
-            [".", "**/*.js"],
-            ["./", "**/*.js"],
-            ["../", "../**/*.js"]
+            [".", ["**/*.js"]],
+            ["./", ["**/*.js"]],
+            ["../", ["../**/*.js"]],
+            ["", []]
         ], (input, expected) => {
 
             it(`should correctly resolve ${input} to ${expected}`, () => {
@@ -2986,7 +3034,7 @@ describe("CLIEngine", () => {
 
                 const result = engine.resolveFileGlobPatterns([input]);
 
-                assert.strictEqual(result[0], expected);
+                assert.deepStrictEqual(result, expected);
 
             });
         });
diff --git a/tests/lib/cli.js b/tests/lib/cli.js
index 04a966c81..2abf0d0ef 100644
--- a/tests/lib/cli.js
+++ b/tests/lib/cli.js
@@ -320,13 +320,13 @@ describe("cli", () => {
     });
 
     describe("when given a directory with eslint excluded files in the directory", () => {
-        it("should not process any files", () => {
+        it("should throw an error and not process any files", () => {
             const ignorePath = getFixturePath(".eslintignore");
             const filePath = getFixturePath(".");
-            const exit = cli.execute(`--ignore-path ${ignorePath} ${filePath}`);
 
-            assert.isTrue(log.info.notCalled);
-            assert.strictEqual(exit, 0);
+            assert.throws(() => {
+                cli.execute(`--ignore-path ${ignorePath} ${filePath}`);
+            }, `All files matched by '${filePath}' are ignored.`);
         });
     });
 
diff --git a/tests/lib/config.js b/tests/lib/config.js
index 1f9690339..6baae0e05 100644
--- a/tests/lib/config.js
+++ b/tests/lib/config.js
@@ -83,6 +83,14 @@ function assertConfigsEqual(actual, expected) {
     }
 }
 
+/**
+ * Wait for the next tick.
+ * @returns {Promise<void>} -
+ */
+function nextTick() {
+    return new Promise(resolve => process.nextTick(resolve));
+}
+
 //------------------------------------------------------------------------------
 // Tests
 //------------------------------------------------------------------------------
@@ -1086,7 +1094,6 @@ describe("Config", () => {
             });
         });
 
-
         describe("with overrides", () => {
 
             /**
@@ -1359,6 +1366,112 @@ describe("Config", () => {
                 assertConfigsEqual(actual, expected);
             });
         });
+
+        describe("deprecation warnings", () => {
+            let warning = null;
+
+            function onWarning(w) { // eslint-disable-line require-jsdoc
+
+                // Node.js 6.x does not have 'w.code' property.
+                if (!w.hasOwnProperty("code") || typeof w.code === "string" && w.code.startsWith("ESLINT_")) {
+                    warning = w;
+                }
+            }
+
+            beforeEach(() => {
+                warning = null;
+                process.on("warning", onWarning);
+            });
+            afterEach(() => {
+                process.removeListener("warning", onWarning);
+            });
+
+            it("should emit a deprecation warning if 'ecmaFeatures' is given.", () => Promise.resolve()
+                .then(() => {
+                    const cwd = path.resolve(__dirname, "../fixtures/config-file/ecma-features/");
+                    const config = new Config({ cwd }, linter);
+
+                    config.getConfig("test.js");
+
+                    // Wait for "warning" event.
+                    return nextTick();
+                })
+                .then(() => {
+                    assert.notStrictEqual(warning, null);
+                    assert.strictEqual(
+                        warning.message,
+                        `The 'ecmaFeatures' config file property is deprecated, and has no effect. (found in "tests${path.sep}fixtures${path.sep}config-file${path.sep}ecma-features${path.sep}.eslintrc.yml")`
+                    );
+                }));
+
+            it("should emit a deprecation warning if 'parserOptions.ecmaFeatures.experimentalObjectRestSpread' is given.", () => Promise.resolve()
+                .then(() => {
+                    const cwd = path.resolve(__dirname, "../fixtures/config-file/experimental-object-rest-spread/basic/");
+                    const config = new Config({ cwd }, linter);
+
+                    config.getConfig("test.js");
+
+                    // Wait for "warning" event.
+                    return nextTick();
+                })
+                .then(() => {
+                    assert.notStrictEqual(warning, null);
+                    assert.strictEqual(
+                        warning.message,
+                        `The 'parserOptions.ecmaFeatures.experimentalObjectRestSpread' option is deprecated. Use 'parserOptions.ecmaVersion' instead. (found in "tests${path.sep}fixtures${path.sep}config-file${path.sep}experimental-object-rest-spread${path.sep}basic${path.sep}.eslintrc.yml")`
+                    );
+                }));
+
+            it("should emit a deprecation warning if 'parserOptions.ecmaFeatures.experimentalObjectRestSpread' is given in a parent config.", () => Promise.resolve()
+                .then(() => {
+                    const cwd = path.resolve(__dirname, "../fixtures/config-file/experimental-object-rest-spread/subdir/");
+                    const config = new Config({ cwd }, linter);
+
+                    config.getConfig("lib/test.js");
+
+                    // Wait for "warning" event.
+                    return nextTick();
+                })
+                .then(() => {
+                    assert.notStrictEqual(warning, null);
+                    assert.strictEqual(
+                        warning.message,
+                        `The 'parserOptions.ecmaFeatures.experimentalObjectRestSpread' option is deprecated. Use 'parserOptions.ecmaVersion' instead. (found in "tests${path.sep}fixtures${path.sep}config-file${path.sep}experimental-object-rest-spread${path.sep}subdir${path.sep}.eslintrc.yml")`
+                    );
+                }));
+
+            it("should emit a deprecation warning if 'parserOptions.ecmaFeatures.experimentalObjectRestSpread' is given in a shareable config.", () => Promise.resolve()
+                .then(() => {
+                    const cwd = path.resolve(__dirname, "../fixtures/config-file/experimental-object-rest-spread/extends/");
+                    const config = new Config({ cwd }, linter);
+
+                    config.getConfig("test.js");
+
+                    // Wait for "warning" event.
+                    return nextTick();
+                })
+                .then(() => {
+                    assert.notStrictEqual(warning, null);
+                    assert.strictEqual(
+                        warning.message,
+                        `The 'parserOptions.ecmaFeatures.experimentalObjectRestSpread' option is deprecated. Use 'parserOptions.ecmaVersion' instead. (found in "tests${path.sep}fixtures${path.sep}config-file${path.sep}experimental-object-rest-spread${path.sep}extends${path.sep}common.yml")`
+                    );
+                }));
+
+            it("should NOT emit a deprecation warning even if 'parserOptions.ecmaFeatures.experimentalObjectRestSpread' is given, if parser is not espree.", () => Promise.resolve()
+                .then(() => {
+                    const cwd = path.resolve(__dirname, "../fixtures/config-file/experimental-object-rest-spread/another-parser/");
+                    const config = new Config({ cwd }, linter);
+
+                    config.getConfig("test.js");
+
+                    // Wait for "warning" event.
+                    return nextTick();
+                })
+                .then(() => {
+                    assert.strictEqual(warning, null);
+                }));
+        });
     });
 
     describe("Plugin Environments", () => {
diff --git a/tests/lib/config/config-file.js b/tests/lib/config/config-file.js
index 91c6508d4..287a7d67d 100644
--- a/tests/lib/config/config-file.js
+++ b/tests/lib/config/config-file.js
@@ -8,7 +8,8 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const assert = require("chai").assert,
+const Module = require("module"),
+    assert = require("chai").assert,
     leche = require("leche"),
     sinon = require("sinon"),
     path = require("path"),
@@ -127,6 +128,29 @@ function createStubModuleResolver(mapping) {
     };
 }
 
+/**
+ * Overrides the native module resolver to resolve with the given mappings.
+ * @param {Object<string,string>} mapping A mapping of module name to path.
+ * @returns {void}
+ * @private
+ */
+function overrideNativeResolve(mapping) {
+    let originalFindPath;
+
+    beforeEach(() => {
+        originalFindPath = Module._findPath; // eslint-disable-line no-underscore-dangle
+        Module._findPath = function(request, paths, isMain) { // eslint-disable-line no-underscore-dangle
+            if (mapping.hasOwnProperty(request)) {
+                return mapping[request];
+            }
+            return originalFindPath.call(this, request, paths, isMain);
+        };
+    });
+    afterEach(() => {
+        Module._findPath = originalFindPath; // eslint-disable-line no-underscore-dangle
+    });
+}
+
 //------------------------------------------------------------------------------
 // Tests
 //------------------------------------------------------------------------------
@@ -145,6 +169,10 @@ describe("ConfigFile", () => {
 
     describe("applyExtends()", () => {
 
+        overrideNativeResolve({
+            "eslint-plugin-test": getProjectModulePath("eslint-plugin-test")
+        });
+
         it("should apply extension 'foo' when specified from root directory config", () => {
 
             const resolvedPath = path.resolve(PROJECT_PATH, "./node_modules/eslint-config-foo/index.js");
@@ -864,6 +892,10 @@ describe("ConfigFile", () => {
 
         describe("Plugins", () => {
 
+            overrideNativeResolve({
+                "eslint-plugin-test": getProjectModulePath("eslint-plugin-test")
+            });
+
             it("should load information from a YML file and load plugins", () => {
 
                 const stubConfig = new Config({}, new Linter());
@@ -895,9 +927,6 @@ describe("ConfigFile", () => {
                 const resolvedPath = path.resolve(PROJECT_PATH, "./node_modules/eslint-plugin-test/index.js");
 
                 const configDeps = {
-                    "../util/module-resolver": createStubModuleResolver({
-                        "eslint-plugin-test": resolvedPath
-                    }),
                     "require-uncached"(filename) {
                         return configDeps[filename];
                     }
@@ -1000,6 +1029,9 @@ describe("ConfigFile", () => {
     describe("resolve()", () => {
 
         describe("Relative to CWD", () => {
+            overrideNativeResolve({
+                "eslint-plugin-foo": getProjectModulePath("eslint-plugin-foo")
+            });
 
             leche.withData([
                 [".eslintrc", path.resolve(".eslintrc")],
@@ -1035,6 +1067,10 @@ describe("ConfigFile", () => {
 
             const relativePath = path.resolve("./foo/bar");
 
+            overrideNativeResolve({
+                "@foo/eslint-plugin-bar": getProjectModulePath("@foo/eslint-plugin-bar")
+            });
+
             leche.withData([
                 [".eslintrc", path.resolve("./foo/bar", ".eslintrc"), relativePath],
                 ["eslint-config-foo", getRelativeModulePath("eslint-config-foo", relativePath), relativePath],
@@ -1042,7 +1078,7 @@ describe("ConfigFile", () => {
                 ["eslint-configfoo", getRelativeModulePath("eslint-config-eslint-configfoo", relativePath), relativePath],
                 ["@foo/eslint-config", getRelativeModulePath("@foo/eslint-config", relativePath), relativePath],
                 ["@foo/bar", getRelativeModulePath("@foo/eslint-config-bar", relativePath), relativePath],
-                ["plugin:@foo/bar/baz", getRelativeModulePath("@foo/eslint-plugin-bar", relativePath), relativePath]
+                ["plugin:@foo/bar/baz", getProjectModulePath("@foo/eslint-plugin-bar"), relativePath]
             ], (input, expected, relativeTo) => {
                 it(`should return ${expected} when passed ${input}`, () => {
 
@@ -1050,9 +1086,7 @@ describe("ConfigFile", () => {
                         "eslint-config-foo": getRelativeModulePath("eslint-config-foo", relativePath),
                         "eslint-config-eslint-configfoo": getRelativeModulePath("eslint-config-eslint-configfoo", relativePath),
                         "@foo/eslint-config": getRelativeModulePath("@foo/eslint-config", relativePath),
-                        "@foo/eslint-config-bar": getRelativeModulePath("@foo/eslint-config-bar", relativePath),
-                        "eslint-plugin-foo": getRelativeModulePath("eslint-plugin-foo", relativePath),
-                        "@foo/eslint-plugin-bar": getRelativeModulePath("@foo/eslint-plugin-bar", relativePath)
+                        "@foo/eslint-config-bar": getRelativeModulePath("@foo/eslint-config-bar", relativePath)
                     };
 
                     const StubbedConfigFile = proxyquire("../../../lib/config/config-file", {
diff --git a/tests/lib/config/config-initializer.js b/tests/lib/config/config-initializer.js
index ceeed0cb3..72c7d2e99 100644
--- a/tests/lib/config/config-initializer.js
+++ b/tests/lib/config/config-initializer.js
@@ -380,7 +380,7 @@ describe("configInitializer", () => {
                 process.chdir(fixtureDir);
                 assert.throws(() => {
                     config = init.processAnswers(answers);
-                }, "Automatic Configuration failed.  No files were able to be parsed.");
+                }, "No files matching 'not-a-real-filename' were found.");
             });
         });
     });
diff --git a/tests/lib/linter.js b/tests/lib/linter.js
index 53290c1ed..d47f016c8 100644
--- a/tests/lib/linter.js
+++ b/tests/lib/linter.js
@@ -1913,30 +1913,47 @@ describe("Linter", () => {
 
                 const messages = linter.verify(code, config, filename);
 
-                assert.strictEqual(messages.length, 1);
+                assert.strictEqual(messages.length, 2);
 
-                assert.strictEqual(messages[0].ruleId, "no-console");
+                assert.strictEqual(messages[1].ruleId, "no-console");
             });
 
-            it("should report a violation if eslint-disable-line in a block comment is not on a single line", () => {
+            it("should not disable rule and add an extra report if eslint-disable-line in a block comment is not on a single line", () => {
                 const code = [
                     "alert('test'); /* eslint-disable-line ",
                     "no-alert */"
                 ].join("\n");
                 const config = {
                     rules: {
-                        "no-alert": 1,
-                        quotes: [1, "double"],
-                        semi: [1, "always"]
+                        "no-alert": 1
                     }
                 };
 
-                const messages = linter.verify(code, config, filename);
-
-                assert.strictEqual(messages.length, 2);
+                const messages = linter.verify(code, config);
 
-                assert.strictEqual(messages[0].ruleId, "no-alert");
-                assert.strictEqual(messages[1].ruleId, "quotes");
+                assert.deepStrictEqual(messages, [
+                    {
+                        ruleId: "no-alert",
+                        severity: 1,
+                        line: 1,
+                        column: 1,
+                        endLine: 1,
+                        endColumn: 14,
+                        message: "Unexpected alert.",
+                        messageId: "unexpected",
+                        nodeType: "CallExpression"
+                    },
+                    {
+                        ruleId: null,
+                        severity: 2,
+                        message: "eslint-disable-line comment should not span multiple lines.",
+                        line: 1,
+                        column: 16,
+                        endLine: 2,
+                        endColumn: 12,
+                        nodeType: null
+                    }
+                ]);
             });
 
             it("should not report a violation for eslint-disable-line in block comment", () => {
@@ -2089,8 +2106,8 @@ describe("Linter", () => {
                 };
                 const messages = linter.verify(code, config, filename);
 
-                assert.strictEqual(messages.length, 1);
-                assert.strictEqual(messages[0].ruleId, "no-alert");
+                assert.strictEqual(messages.length, 2);
+                assert.strictEqual(messages[1].ruleId, "no-alert");
             });
 
             it("should ignore violations only of specified rule", () => {
@@ -2243,9 +2260,9 @@ describe("Linter", () => {
 
                 const messages = linter.verify(code, config, filename);
 
-                assert.strictEqual(messages.length, 1);
+                assert.strictEqual(messages.length, 2);
 
-                assert.strictEqual(messages[0].ruleId, "no-console");
+                assert.strictEqual(messages[1].ruleId, "no-console");
             });
 
             it("should not ignore violations if comment is of the type Shebang", () => {
@@ -3492,6 +3509,265 @@ describe("Linter", () => {
             linter.verify("x", { rules: { "foo-bar-baz": "error" } });
             assert(spy.calledOnce);
         });
+
+        it("should parse ES2018 code for backward compatibility if 'parserOptions.ecmaFeatures.experimentalObjectRestSpread' is given.", () => {
+            const messages = linter.verify(
+                "async function* f() { let {a, ...rest} = { a, ...obj }; }",
+                { parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } } }
+            );
+
+            assert(messages.length === 0);
+        });
+    });
+
+    describe("context.getScope()", () => {
+
+        /**
+         * Get the scope on the node `astSelector` specified.
+         * @param {string} code The source code to verify.
+         * @param {string} astSelector The AST selector to get scope.
+         * @param {number} [ecmaVersion=5] The ECMAScript version.
+         * @returns {{node: ASTNode, scope: escope.Scope}} Gotten scope.
+         */
+        function getScope(code, astSelector, ecmaVersion = 5) {
+            let node, scope;
+
+            linter.defineRule("get-scope", context => ({
+                [astSelector](node0) {
+                    node = node0;
+                    scope = context.getScope();
+                }
+            }));
+            linter.verify(
+                code,
+                {
+                    parserOptions: { ecmaVersion },
+                    rules: { "get-scope": 2 }
+                }
+            );
+
+            return { node, scope };
+        }
+
+        it("should return 'function' scope on FunctionDeclaration (ES5)", () => {
+            const { node, scope } = getScope("function f() {}", "FunctionDeclaration");
+
+            assert.strictEqual(scope.type, "function");
+            assert.strictEqual(scope.block, node);
+        });
+
+        it("should return 'function' scope on FunctionExpression (ES5)", () => {
+            const { node, scope } = getScope("!function f() {}", "FunctionExpression");
+
+            assert.strictEqual(scope.type, "function");
+            assert.strictEqual(scope.block, node);
+        });
+
+        it("should return 'function' scope on the body of FunctionDeclaration (ES5)", () => {
+            const { node, scope } = getScope("function f() {}", "BlockStatement");
+
+            assert.strictEqual(scope.type, "function");
+            assert.strictEqual(scope.block, node.parent);
+        });
+
+        it("should return 'function' scope on the body of FunctionDeclaration (ES2015)", () => {
+            const { node, scope } = getScope("function f() {}", "BlockStatement", 2015);
+
+            assert.strictEqual(scope.type, "function");
+            assert.strictEqual(scope.block, node.parent);
+        });
+
+        it("should return 'function' scope on BlockStatement in functions (ES5)", () => {
+            const { node, scope } = getScope("function f() { { var b; } }", "BlockStatement > BlockStatement");
+
+            assert.strictEqual(scope.type, "function");
+            assert.strictEqual(scope.block, node.parent.parent);
+            assert.deepStrictEqual(scope.variables.map(v => v.name), ["arguments", "b"]);
+        });
+
+        it("should return 'block' scope on BlockStatement in functions (ES2015)", () => {
+            const { node, scope } = getScope("function f() { { let a; var b; } }", "BlockStatement > BlockStatement", 2015);
+
+            assert.strictEqual(scope.type, "block");
+            assert.strictEqual(scope.upper.type, "function");
+            assert.strictEqual(scope.block, node);
+            assert.deepStrictEqual(scope.variables.map(v => v.name), ["a"]);
+            assert.deepStrictEqual(scope.variableScope.variables.map(v => v.name), ["arguments", "b"]);
+        });
+
+        it("should return 'block' scope on nested BlockStatement in functions (ES2015)", () => {
+            const { node, scope } = getScope("function f() { { let a; { let b; var c; } } }", "BlockStatement > BlockStatement > BlockStatement", 2015);
+
+            assert.strictEqual(scope.type, "block");
+            assert.strictEqual(scope.upper.type, "block");
+            assert.strictEqual(scope.upper.upper.type, "function");
+            assert.strictEqual(scope.block, node);
+            assert.deepStrictEqual(scope.variables.map(v => v.name), ["b"]);
+            assert.deepStrictEqual(scope.upper.variables.map(v => v.name), ["a"]);
+            assert.deepStrictEqual(scope.variableScope.variables.map(v => v.name), ["arguments", "c"]);
+        });
+
+        it("should return 'function' scope on SwitchStatement in functions (ES5)", () => {
+            const { node, scope } = getScope("function f() { switch (a) { case 0: var b; } }", "SwitchStatement");
+
+            assert.strictEqual(scope.type, "function");
+            assert.strictEqual(scope.block, node.parent.parent);
+            assert.deepStrictEqual(scope.variables.map(v => v.name), ["arguments", "b"]);
+        });
+
+        it("should return 'switch' scope on SwitchStatement in functions (ES2015)", () => {
+            const { node, scope } = getScope("function f() { switch (a) { case 0: let b; } }", "SwitchStatement", 2015);
+
+            assert.strictEqual(scope.type, "switch");
+            assert.strictEqual(scope.block, node);
+            assert.deepStrictEqual(scope.variables.map(v => v.name), ["b"]);
+        });
+
+        it("should return 'function' scope on SwitchCase in functions (ES5)", () => {
+            const { node, scope } = getScope("function f() { switch (a) { case 0: var b; } }", "SwitchCase");
+
+            assert.strictEqual(scope.type, "function");
+            assert.strictEqual(scope.block, node.parent.parent.parent);
+            assert.deepStrictEqual(scope.variables.map(v => v.name), ["arguments", "b"]);
+        });
+
+        it("should return 'switch' scope on SwitchCase in functions (ES2015)", () => {
+            const { node, scope } = getScope("function f() { switch (a) { case 0: let b; } }", "SwitchCase", 2015);
+
+            assert.strictEqual(scope.type, "switch");
+            assert.strictEqual(scope.block, node.parent);
+            assert.deepStrictEqual(scope.variables.map(v => v.name), ["b"]);
+        });
+
+        it("should return 'catch' scope on CatchClause in functions (ES5)", () => {
+            const { node, scope } = getScope("function f() { try {} catch (e) { var a; } }", "CatchClause");
+
+            assert.strictEqual(scope.type, "catch");
+            assert.strictEqual(scope.block, node);
+            assert.deepStrictEqual(scope.variables.map(v => v.name), ["e"]);
+        });
+
+        it("should return 'catch' scope on CatchClause in functions (ES2015)", () => {
+            const { node, scope } = getScope("function f() { try {} catch (e) { let a; } }", "CatchClause", 2015);
+
+            assert.strictEqual(scope.type, "catch");
+            assert.strictEqual(scope.block, node);
+            assert.deepStrictEqual(scope.variables.map(v => v.name), ["e"]);
+        });
+
+        it("should return 'catch' scope on the block of CatchClause in functions (ES5)", () => {
+            const { node, scope } = getScope("function f() { try {} catch (e) { var a; } }", "CatchClause > BlockStatement");
+
+            assert.strictEqual(scope.type, "catch");
+            assert.strictEqual(scope.block, node.parent);
+            assert.deepStrictEqual(scope.variables.map(v => v.name), ["e"]);
+        });
+
+        it("should return 'block' scope on the block of CatchClause in functions (ES2015)", () => {
+            const { node, scope } = getScope("function f() { try {} catch (e) { let a; } }", "CatchClause > BlockStatement", 2015);
+
+            assert.strictEqual(scope.type, "block");
+            assert.strictEqual(scope.block, node);
+            assert.deepStrictEqual(scope.variables.map(v => v.name), ["a"]);
+        });
+
+        it("should return 'function' scope on ForStatement in functions (ES5)", () => {
+            const { node, scope } = getScope("function f() { for (var i = 0; i < 10; ++i) {} }", "ForStatement");
+
+            assert.strictEqual(scope.type, "function");
+            assert.strictEqual(scope.block, node.parent.parent);
+            assert.deepStrictEqual(scope.variables.map(v => v.name), ["arguments", "i"]);
+        });
+
+        it("should return 'for' scope on ForStatement in functions (ES2015)", () => {
+            const { node, scope } = getScope("function f() { for (let i = 0; i < 10; ++i) {} }", "ForStatement", 2015);
+
+            assert.strictEqual(scope.type, "for");
+            assert.strictEqual(scope.block, node);
+            assert.deepStrictEqual(scope.variables.map(v => v.name), ["i"]);
+        });
+
+        it("should return 'function' scope on the block body of ForStatement in functions (ES5)", () => {
+            const { node, scope } = getScope("function f() { for (var i = 0; i < 10; ++i) {} }", "ForStatement > BlockStatement");
+
+            assert.strictEqual(scope.type, "function");
+            assert.strictEqual(scope.block, node.parent.parent.parent);
+            assert.deepStrictEqual(scope.variables.map(v => v.name), ["arguments", "i"]);
+        });
+
+        it("should return 'block' scope on the block body of ForStatement in functions (ES2015)", () => {
+            const { node, scope } = getScope("function f() { for (let i = 0; i < 10; ++i) {} }", "ForStatement > BlockStatement", 2015);
+
+            assert.strictEqual(scope.type, "block");
+            assert.strictEqual(scope.upper.type, "for");
+            assert.strictEqual(scope.block, node);
+            assert.deepStrictEqual(scope.variables.map(v => v.name), []);
+            assert.deepStrictEqual(scope.upper.variables.map(v => v.name), ["i"]);
+        });
+
+        it("should return 'function' scope on ForInStatement in functions (ES5)", () => {
+            const { node, scope } = getScope("function f() { for (var key in obj) {} }", "ForInStatement");
+
+            assert.strictEqual(scope.type, "function");
+            assert.strictEqual(scope.block, node.parent.parent);
+            assert.deepStrictEqual(scope.variables.map(v => v.name), ["arguments", "key"]);
+        });
+
+        it("should return 'for' scope on ForInStatement in functions (ES2015)", () => {
+            const { node, scope } = getScope("function f() { for (let key in obj) {} }", "ForInStatement", 2015);
+
+            assert.strictEqual(scope.type, "for");
+            assert.strictEqual(scope.block, node);
+            assert.deepStrictEqual(scope.variables.map(v => v.name), ["key"]);
+        });
+
+        it("should return 'function' scope on the block body of ForInStatement in functions (ES5)", () => {
+            const { node, scope } = getScope("function f() { for (var key in obj) {} }", "ForInStatement > BlockStatement");
+
+            assert.strictEqual(scope.type, "function");
+            assert.strictEqual(scope.block, node.parent.parent.parent);
+            assert.deepStrictEqual(scope.variables.map(v => v.name), ["arguments", "key"]);
+        });
+
+        it("should return 'block' scope on the block body of ForInStatement in functions (ES2015)", () => {
+            const { node, scope } = getScope("function f() { for (let key in obj) {} }", "ForInStatement > BlockStatement", 2015);
+
+            assert.strictEqual(scope.type, "block");
+            assert.strictEqual(scope.upper.type, "for");
+            assert.strictEqual(scope.block, node);
+            assert.deepStrictEqual(scope.variables.map(v => v.name), []);
+            assert.deepStrictEqual(scope.upper.variables.map(v => v.name), ["key"]);
+        });
+
+        it("should return 'for' scope on ForOfStatement in functions (ES2015)", () => {
+            const { node, scope } = getScope("function f() { for (let x of xs) {} }", "ForOfStatement", 2015);
+
+            assert.strictEqual(scope.type, "for");
+            assert.strictEqual(scope.block, node);
+            assert.deepStrictEqual(scope.variables.map(v => v.name), ["x"]);
+        });
+
+        it("should return 'block' scope on the block body of ForOfStatement in functions (ES2015)", () => {
+            const { node, scope } = getScope("function f() { for (let x of xs) {} }", "ForOfStatement > BlockStatement", 2015);
+
+            assert.strictEqual(scope.type, "block");
+            assert.strictEqual(scope.upper.type, "for");
+            assert.strictEqual(scope.block, node);
+            assert.deepStrictEqual(scope.variables.map(v => v.name), []);
+            assert.deepStrictEqual(scope.upper.variables.map(v => v.name), ["x"]);
+        });
+
+        it("should shadow the same name variable by the iteration variable.", () => {
+            const { node, scope } = getScope("let x; for (let x of x) {}", "ForOfStatement", 2015);
+
+            assert.strictEqual(scope.type, "for");
+            assert.strictEqual(scope.upper.type, "global");
+            assert.strictEqual(scope.block, node);
+            assert.strictEqual(scope.upper.variables[0].references.length, 0);
+            assert.strictEqual(scope.references[0].identifier, node.left.declarations[0].id);
+            assert.strictEqual(scope.references[1].identifier, node.right);
+            assert.strictEqual(scope.references[1].resolved, scope.variables[0]);
+        });
     });
 
     describe("Variables and references", () => {
diff --git a/tests/lib/rules/comma-style.js b/tests/lib/rules/comma-style.js
index 2bed575bf..83a1ca2c9 100644
--- a/tests/lib/rules/comma-style.js
+++ b/tests/lib/rules/comma-style.js
@@ -607,6 +607,11 @@ ruleTester.run("comma-style", rule, {
                 }
             }],
             errors: [{ messageId: "expectedCommaLast" }]
+        },
+        {
+            code: "[\n[foo(3)],\n,\nbar\n];",
+            output: "[\n[foo(3)],,\nbar\n];",
+            errors: [{ messageId: "unexpectedLineBeforeAndAfterComma" }]
         }
     ]
 });
diff --git a/tests/lib/rules/max-classes-per-file.js b/tests/lib/rules/max-classes-per-file.js
new file mode 100644
index 000000000..ecc92d1c1
--- /dev/null
+++ b/tests/lib/rules/max-classes-per-file.js
@@ -0,0 +1,59 @@
+/**
+ * @fileoverview Tests for max-classes-per-file rule.
+ * @author James Garbutt <https://github.com/43081j>
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const rule = require("../../../lib/rules/max-classes-per-file"),
+    RuleTester = require("../../../lib/testers/rule-tester");
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+
+const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
+
+ruleTester.run("max-classes-per-file", rule, {
+    valid: [
+        "class Foo {}",
+        "var x = class {};",
+        "var x = 5;",
+        {
+            code: "class Foo {}",
+            options: [1]
+        },
+        {
+            code: "class Foo {}\nclass Bar {}",
+            options: [2]
+        }
+    ],
+
+    invalid: [
+        {
+            code: "class Foo {}\nclass Bar {}",
+            errors: [{ messageId: "maximumExceeded", type: "Program" }]
+        },
+        {
+            code: "var x = class {};\nvar y = class {};",
+            errors: [{ messageId: "maximumExceeded", type: "Program" }]
+        },
+        {
+            code: "class Foo {}\nvar x = class {};",
+            errors: [{ messageId: "maximumExceeded", type: "Program" }]
+        },
+        {
+            code: "class Foo {} class Bar {}",
+            options: [1],
+            errors: [{ messageId: "maximumExceeded", type: "Program" }]
+        },
+        {
+            code: "class Foo {} class Bar {} class Baz {}",
+            options: [2],
+            errors: [{ messageId: "maximumExceeded", type: "Program" }]
+        }
+    ]
+});
diff --git a/tests/lib/rules/no-self-assign.js b/tests/lib/rules/no-self-assign.js
index 6623f4c9d..f15a75723 100644
--- a/tests/lib/rules/no-self-assign.js
+++ b/tests/lib/rules/no-self-assign.js
@@ -47,11 +47,26 @@ ruleTester.run("no-self-assign", rule, {
         { code: "a.b().c = a.b().c", options: [{ props: true }] },
         { code: "b().c = b().c", options: [{ props: true }] },
         { code: "a[b + 1] = a[b + 1]", options: [{ props: true }] }, // it ignores non-simple computed properties.
-        "a.b = a.b",
-        "a.b.c = a.b.c",
-        "a[b] = a[b]",
-        "a['b'] = a['b']",
-        "a[\n    'b'\n] = a[\n    'b'\n]"
+        {
+            code: "a.b = a.b",
+            options: [{ props: false }]
+        },
+        {
+            code: "a.b.c = a.b.c",
+            options: [{ props: false }]
+        },
+        {
+            code: "a[b] = a[b]",
+            options: [{ props: false }]
+        },
+        {
+            code: "a['b'] = a['b']",
+            options: [{ props: false }]
+        },
+        {
+            code: "a[\n    'b'\n] = a[\n    'b'\n]",
+            options: [{ props: false }]
+        }
     ],
     invalid: [
         { code: "a = a", errors: ["'a' is assigned to itself."] },
@@ -68,6 +83,26 @@ ruleTester.run("no-self-assign", rule, {
         { code: "({a, b} = {c, a})", parserOptions: { ecmaVersion: 6 }, errors: ["'a' is assigned to itself."] },
         { code: "({a: {b}, c: [d]} = {a: {b}, c: [d]})", parserOptions: { ecmaVersion: 6 }, errors: ["'b' is assigned to itself.", "'d' is assigned to itself."] },
         { code: "({a, b} = {a, ...x, b})", parserOptions: { ecmaVersion: 2018 }, errors: ["'b' is assigned to itself."] },
+        {
+            code: "a.b = a.b",
+            errors: ["'a.b' is assigned to itself."]
+        },
+        {
+            code: "a.b.c = a.b.c",
+            errors: ["'a.b.c' is assigned to itself."]
+        },
+        {
+            code: "a[b] = a[b]",
+            errors: ["'a[b]' is assigned to itself."]
+        },
+        {
+            code: "a['b'] = a['b']",
+            errors: ["'a['b']' is assigned to itself."]
+        },
+        {
+            code: "a[\n    'b'\n] = a[\n    'b'\n]",
+            errors: ["'a['b']' is assigned to itself."]
+        },
         { code: "a.b = a.b", options: [{ props: true }], errors: ["'a.b' is assigned to itself."] },
         { code: "a.b.c = a.b.c", options: [{ props: true }], errors: ["'a.b.c' is assigned to itself."] },
         { code: "a[b] = a[b]", options: [{ props: true }], errors: ["'a[b]' is assigned to itself."] },
diff --git a/tests/lib/rules/object-curly-newline.js b/tests/lib/rules/object-curly-newline.js
index a3235a91a..ac74c7a5e 100644
--- a/tests/lib/rules/object-curly-newline.js
+++ b/tests/lib/rules/object-curly-newline.js
@@ -22,6 +22,20 @@ const ruleTester = new RuleTester({ parserOptions: { sourceType: "module" } });
 ruleTester.run("object-curly-newline", rule, {
     valid: [
 
+        // default ------------------------------------------------------------
+        [
+            "var a = {",
+            "};"
+        ].join("\n"),
+
+        [
+            "var a = {",
+            "   foo",
+            "};"
+        ].join("\n"),
+
+        "var a = { foo }",
+
         // "always" ------------------------------------------------------------
         {
             code: [
@@ -553,6 +567,18 @@ ruleTester.run("object-curly-newline", rule, {
     ],
     invalid: [
 
+        // default ------------------------------------------------------------
+        {
+            code: [
+                "var a = { a",
+                "};"
+            ].join("\n"),
+            output: "var a = { a};",
+            errors: [
+                { line: 2, column: 1, message: "Unexpected line break before this closing brace." }
+            ]
+        },
+
         // "always" ------------------------------------------------------------
         {
             code: [
diff --git a/tests/lib/rules/object-shorthand.js b/tests/lib/rules/object-shorthand.js
index 31abe8faa..c52f43af0 100644
--- a/tests/lib/rules/object-shorthand.js
+++ b/tests/lib/rules/object-shorthand.js
@@ -427,6 +427,16 @@ ruleTester.run("object-shorthand", rule, {
             output: "var x = {\n  *f() {\n    /* comment */\n    a(b);\n    }\n  }",
             errors: [METHOD_ERROR]
         },
+        {
+            code: "var x = {\n  f: /* comment */ function() {\n  }\n  }",
+            output: null,
+            errors: [METHOD_ERROR]
+        },
+        {
+            code: "var x = {\n f /* comment */: function() {\n  }\n  }",
+            output: null,
+            errors: [METHOD_ERROR]
+        },
         {
             code: "var x = {y: function() {}}",
             output: "var x = {y() {}}",
diff --git a/tests/lib/rules/one-var.js b/tests/lib/rules/one-var.js
index b8f3a913f..50a2ecf1d 100644
--- a/tests/lib/rules/one-var.js
+++ b/tests/lib/rules/one-var.js
@@ -473,12 +473,24 @@ ruleTester.run("one-var", rule, {
         {
             code: "var a = 1, b = 2; var c; var d; var e = 3, f = 4;",
             options: [{ initialized: "consecutive", uninitialized: "never" }]
+        },
+        {
+            code: "var a; somethingElse(); var b;",
+            output: null,
+            options: [{ var: "never" }],
+            errors: null
+        },
+        {
+            code: "var foo = 1;\nlet bar = function() { var x; };\nvar baz = 2;",
+            output: null,
+            options: [{ var: "never" }],
+            errors: null
         }
-
     ],
     invalid: [
         {
             code: "function foo() { var bar = true, baz = false; }",
+            output: "function foo() { var bar = true; var baz = false; }",
             options: ["never"],
             errors: [{
                 message: "Split 'var' declarations into multiple statements.",
@@ -487,6 +499,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "function foo() { var bar = true; var baz = false; }",
+            output: "function foo() { var bar = true,  baz = false; }",
             options: ["always"],
             errors: [{
                 message: "Combine this with the previous 'var' statement.",
@@ -495,6 +508,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var a = 1; for (var b = 2;;) {}",
+            output: null,
             options: ["always"],
             errors: [{
                 message: "Combine this with the previous 'var' statement.",
@@ -503,6 +517,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "function foo() { var foo = true, bar = false; }",
+            output: "function foo() { var foo = true; var bar = false; }",
             options: [{ initialized: "never" }],
             errors: [
                 {
@@ -513,6 +528,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "function foo() { var foo, bar; }",
+            output: "function foo() { var foo; var bar; }",
             options: [{ uninitialized: "never" }],
             errors: [
                 {
@@ -523,6 +539,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "function foo() { var bar, baz; var a = true; var b = false; var c, d;}",
+            output: "function foo() { var bar, baz; var a = true; var b = false,  c, d;}",
             options: [{ uninitialized: "always", initialized: "never" }],
             errors: [
                 {
@@ -533,6 +550,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "function foo() { var bar = true, baz = false; var a; var b; var c = true, d = false; }",
+            output: "function foo() { var bar = true, baz = false; var a; var b,  c = true, d = false; }",
             options: [{ uninitialized: "never", initialized: "always" }],
             errors: [
                 {
@@ -543,6 +561,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "function foo() { var bar = true, baz = false; var a, b;}",
+            output: "function foo() { var bar = true; var baz = false; var a; var b;}",
             options: [{ uninitialized: "never", initialized: "never" }],
             errors: [
                 {
@@ -557,6 +576,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "function foo() { var bar = true; var baz = false; var a; var b;}",
+            output: "function foo() { var bar = true,  baz = false,  a,  b;}",
             options: [{ uninitialized: "always", initialized: "always" }],
             errors: [
                 {
@@ -575,6 +595,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "function foo() { var a = [1, 2, 3]; var [b, c, d] = a; }",
+            output: "function foo() { var a = [1, 2, 3],  [b, c, d] = a; }",
             options: ["always"],
             errors: [{
                 message: "Combine this with the previous 'var' statement.",
@@ -583,6 +604,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "function foo() { let a = 1; let b = 2; }",
+            output: "function foo() { let a = 1,  b = 2; }",
             options: ["always"],
             errors: [{
                 message: "Combine this with the previous 'let' statement.",
@@ -591,6 +613,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "function foo() { const a = 1; const b = 2; }",
+            output: "function foo() { const a = 1,  b = 2; }",
             options: ["always"],
             errors: [{
                 message: "Combine this with the previous 'const' statement.",
@@ -599,6 +622,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "function foo() { let a = 1; let b = 2; }",
+            output: "function foo() { let a = 1,  b = 2; }",
             options: [{ let: "always" }],
             errors: [{
                 message: "Combine this with the previous 'let' statement.",
@@ -607,6 +631,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "function foo() { const a = 1; const b = 2; }",
+            output: "function foo() { const a = 1,  b = 2; }",
             options: [{ const: "always" }],
             errors: [{
                 message: "Combine this with the previous 'const' statement.",
@@ -615,6 +640,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "function foo() { let a = 1, b = 2; }",
+            output: "function foo() { let a = 1; let b = 2; }",
             options: [{ let: "never" }],
             errors: [{
                 message: "Split 'let' declarations into multiple statements.",
@@ -623,6 +649,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "function foo() { let a = 1, b = 2; }",
+            output: "function foo() { let a = 1; let b = 2; }",
             options: [{ initialized: "never" }],
             errors: [{
                 message: "Split initialized 'let' declarations into multiple statements.",
@@ -631,6 +658,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "function foo() { let a, b; }",
+            output: "function foo() { let a; let b; }",
             options: [{ uninitialized: "never" }],
             errors: [{
                 message: "Split uninitialized 'let' declarations into multiple statements.",
@@ -639,6 +667,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "function foo() { const a = 1, b = 2; }",
+            output: "function foo() { const a = 1; const b = 2; }",
             options: [{ initialized: "never" }],
             errors: [{
                 message: "Split initialized 'const' declarations into multiple statements.",
@@ -647,6 +676,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "function foo() { const a = 1, b = 2; }",
+            output: "function foo() { const a = 1; const b = 2; }",
             options: [{ const: "never" }],
             errors: [{
                 message: "Split 'const' declarations into multiple statements.",
@@ -655,6 +685,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let foo = true; switch(foo) { case true: let bar = 2; break; case false: let baz = 3; break; }",
+            output: null,
             options: [{ var: "always", let: "always", const: "never" }],
             errors: [{
                 message: "Combine this with the previous 'let' statement.",
@@ -665,6 +696,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var one = 1, two = 2;\nvar three;",
+            output: "var one = 1, two = 2,\n three;",
             options: ["always"],
             errors: [{
                 message: "Combine this with the previous 'var' statement.",
@@ -675,6 +707,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var i = [0], j;",
+            output: "var i = [0]; var j;",
             options: [{ initialized: "never" }],
             errors: [{
                 message: "Split initialized 'var' declarations into multiple statements.",
@@ -683,6 +716,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var i = [0], j;",
+            output: "var i = [0]; var j;",
             options: [{ uninitialized: "never" }],
             errors: [{
                 message: "Split uninitialized 'var' declarations into multiple statements.",
@@ -691,6 +725,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "for (var x of foo) {}; for (var y of foo) {}",
+            output: null,
             options: ["always"],
             errors: [{
                 message: "Combine this with the previous 'var' statement.",
@@ -699,6 +734,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "for (var x in foo) {}; for (var y in foo) {}",
+            output: null,
             options: ["always"],
             errors: [{
                 message: "Combine this with the previous 'var' statement.",
@@ -707,6 +743,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var foo = function() { var bar = true; var baz = false; }",
+            output: "var foo = function() { var bar = true,  baz = false; }",
             errors: [{
                 message: "Combine this with the previous 'var' statement.",
                 type: "VariableDeclaration",
@@ -716,6 +753,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "function foo() { var bar = true; if (qux) { var baz = false; } else { var quxx = 42; } }",
+            output: null,
             errors: [{
                 message: "Combine this with the previous 'var' statement.",
                 type: "VariableDeclaration",
@@ -730,6 +768,8 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var foo = () => { var bar = true; var baz = false; }",
+            output: "var foo = () => { var bar = true,  baz = false; }",
+            parserOptions: { ecmaVersion: 6 },
             errors: [{
                 message: "Combine this with the previous 'var' statement.",
                 type: "VariableDeclaration",
@@ -739,6 +779,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var foo = function() { var bar = true; if (qux) { var baz = false; } }",
+            output: null,
             errors: [{
                 message: "Combine this with the previous 'var' statement.",
                 type: "VariableDeclaration",
@@ -748,6 +789,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var foo; var bar;",
+            output: "var foo,  bar;",
             errors: [{
                 message: "Combine this with the previous 'var' statement.",
                 type: "VariableDeclaration",
@@ -757,6 +799,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var x = 1, y = 2; for (var z in foo) {}",
+            output: "var x = 1; var y = 2; for (var z in foo) {}",
             options: [{ initialized: "never", uninitialized: "always" }],
             errors: [{
                 message: "Split initialized 'var' declarations into multiple statements.",
@@ -767,6 +810,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var x = 1, y = 2; for (var z of foo) {}",
+            output: "var x = 1; var y = 2; for (var z of foo) {}",
             options: [{ initialized: "never", uninitialized: "always" }],
             errors: [{
                 message: "Split initialized 'var' declarations into multiple statements.",
@@ -777,6 +821,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var x; var y; for (var z in foo) {}",
+            output: "var x,  y; for (var z in foo) {}",
             options: [{ initialized: "never", uninitialized: "always" }],
             errors: [{
                 message: "Combine this with the previous 'var' statement with uninitialized variables.",
@@ -787,6 +832,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var x; var y; for (var z of foo) {}",
+            output: "var x,  y; for (var z of foo) {}",
             options: [{ initialized: "never", uninitialized: "always" }],
             errors: [{
                 message: "Combine this with the previous 'var' statement with uninitialized variables.",
@@ -797,6 +843,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var x; for (var y in foo) {var bar = y; var a; for (var z of bar) {}}",
+            output: "var x; for (var y in foo) {var bar = y,  a; for (var z of bar) {}}",
             options: [{ initialized: "never", uninitialized: "always" }],
             errors: [{
                 message: "Combine this with the previous 'var' statement with uninitialized variables.",
@@ -807,6 +854,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var a = 1; var b = 2; var x, y; for (var z of foo) {var c = 3, baz = z; for (var d in baz) {}}",
+            output: "var a = 1; var b = 2; var x, y; for (var z of foo) {var c = 3; var baz = z; for (var d in baz) {}}",
             options: [{ initialized: "never", uninitialized: "always" }],
             errors: [{
                 message: "Split initialized 'var' declarations into multiple statements.",
@@ -815,8 +863,88 @@ ruleTester.run("one-var", rule, {
                 column: 53
             }]
         },
+        {
+            code: "var {foo} = 1, [bar] = 2;",
+            output: "var {foo} = 1; var [bar] = 2;",
+            options: [{ initialized: "never" }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{
+                message: "Split initialized 'var' declarations into multiple statements.",
+                type: "VariableDeclaration",
+                line: 1,
+                column: 1
+            }]
+        },
+        {
+            code: "const foo = 1,\n    bar = 2;",
+            output: "const foo = 1;\n\n    \nconst bar = 2;",
+            options: [{ initialized: "never" }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{
+                message: "Split initialized 'const' declarations into multiple statements.",
+                type: "VariableDeclaration",
+                line: 1,
+                column: 1
+            }]
+        },
+        {
+            code: "var foo = 1,\n    bar = 2;",
+            output: "var foo = 1;\n\n    \nvar bar = 2;",
+            options: [{ initialized: "never" }],
+            errors: [{
+                message: "Split initialized 'var' declarations into multiple statements.",
+                type: "VariableDeclaration",
+                line: 1,
+                column: 1
+            }]
+        },
+        {
+            code: "var foo = 1, // comment\n    bar = 2;",
+            output: "var foo = 1;\n // comment\n    \nvar bar = 2;",
+            options: [{ initialized: "never" }],
+            errors: [{
+                message: "Split initialized 'var' declarations into multiple statements.",
+                type: "VariableDeclaration",
+                line: 1,
+                column: 1
+            }]
+        },
+        {
+            code: "var f, k /* test */, l;",
+            output: "var f; var k /* test */; var l;",
+            options: ["never"],
+            errors: [{
+                message: "Split 'var' declarations into multiple statements.",
+                type: "VariableDeclaration",
+                line: 1,
+                column: 1
+            }]
+        },
+        {
+            code: "var f,          /* test */ l;",
+            output: "var f;\n          /* test */ \nvar l;",
+            options: ["never"],
+            errors: [{
+                message: "Split 'var' declarations into multiple statements.",
+                type: "VariableDeclaration",
+                line: 1,
+                column: 1
+            }]
+        },
+        {
+            code: "var f, k /* test \n some more comment \n even more */, l = 1, P;",
+            output: "var f; var k /* test \n some more comment \n even more */; var l = 1; var P;",
+            options: ["never"],
+            errors: [{
+                message: "Split 'var' declarations into multiple statements.",
+                type: "VariableDeclaration",
+                line: 1,
+                column: 1
+            }]
+        },
         {
             code: "var foo = require('foo'), bar;",
+            output: null,
             options: [{ separateRequires: true, var: "always" }],
             parserOptions: { env: { node: true } },
             errors: [{
@@ -828,6 +956,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var foo, bar = require('bar');",
+            output: null,
             options: [{ separateRequires: true, var: "always" }],
             parserOptions: { env: { node: true } },
             errors: [{
@@ -839,6 +968,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let foo, bar = require('bar');",
+            output: null,
             options: [{ separateRequires: true, let: "always" }],
             parserOptions: { env: { node: true } },
             errors: [{
@@ -850,6 +980,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "const foo = 0, bar = require('bar');",
+            output: null,
             options: [{ separateRequires: true, const: "always" }],
             parserOptions: { env: { node: true } },
             errors: [{
@@ -861,6 +992,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "const foo = require('foo'); const bar = require('bar');",
+            output: "const foo = require('foo'),  bar = require('bar');",
             options: [{ separateRequires: true, const: "always" }],
             parserOptions: { env: { node: true } },
             errors: [{
@@ -874,6 +1006,7 @@ ruleTester.run("one-var", rule, {
         // https://github.com/eslint/eslint/issues/4680
         {
             code: "var a = 1, b; var c;",
+            output: "var a = 1, b,  c;",
             options: ["consecutive"],
             errors: [{
                 message: "Combine this with the previous 'var' statement.",
@@ -884,6 +1017,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var a = 0, b = 1; var c = 2;",
+            output: "var a = 0, b = 1,  c = 2;",
             options: ["consecutive"],
             errors: [{
                 message: "Combine this with the previous 'var' statement.",
@@ -894,6 +1028,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let a = 1, b; let c;",
+            output: "let a = 1, b,  c;",
             options: ["consecutive"],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -905,6 +1040,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let a = 0, b = 1; let c = 2;",
+            output: "let a = 0, b = 1,  c = 2;",
             options: ["consecutive"],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -916,6 +1052,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "const a = 0, b = 1; const c = 2;",
+            output: "const a = 0, b = 1,  c = 2;",
             options: ["consecutive"],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -927,6 +1064,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "const a = 0; var b = 1; var c = 2; const d = 3;",
+            output: "const a = 0; var b = 1,  c = 2; const d = 3;",
             options: ["consecutive"],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -938,6 +1076,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "const a = 0; let b = 1; let c = 2; const d = 3;",
+            output: "const a = 0; let b = 1,  c = 2; const d = 3;",
             options: ["consecutive"],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -949,6 +1088,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let a = 0; const b = 1; const c = 1; var d = 2;",
+            output: "let a = 0; const b = 1,  c = 1; var d = 2;",
             options: ["consecutive"],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -960,6 +1100,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var a = 0; var b; var c; var d = 1",
+            output: "var a = 0; var b,  c; var d = 1",
             options: [{ initialized: "consecutive", uninitialized: "always" }],
             errors: [{
                 message: "Combine this with the previous 'var' statement with uninitialized variables.",
@@ -970,6 +1111,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var a = 0; var b = 1; var c; var d;",
+            output: "var a = 0,  b = 1; var c,  d;",
             options: [{ initialized: "consecutive", uninitialized: "always" }],
             errors: [{
                 message: "Combine this with the previous 'var' statement with initialized variables.",
@@ -986,6 +1128,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let a = 0; let b; let c; let d = 1;",
+            output: "let a = 0; let b,  c; let d = 1;",
             options: [{ initialized: "consecutive", uninitialized: "always" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -997,6 +1140,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let a = 0; let b = 1; let c; let d;",
+            output: "let a = 0,  b = 1; let c,  d;",
             options: [{ initialized: "consecutive", uninitialized: "always" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1014,6 +1158,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "const a = 0; let b; let c; const d = 1;",
+            output: "const a = 0; let b,  c; const d = 1;",
             options: [{ initialized: "consecutive", uninitialized: "always" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1025,6 +1170,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "const a = 0; const b = 1; let c; let d;",
+            output: "const a = 0,  b = 1; let c,  d;",
             options: [{ initialized: "consecutive", uninitialized: "always" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1042,6 +1188,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var a = 0; var b = 1; var c, d;",
+            output: "var a = 0,  b = 1; var c; var d;",
             options: [{ initialized: "consecutive", uninitialized: "never" }],
             errors: [{
                 message: "Combine this with the previous 'var' statement with initialized variables.",
@@ -1058,6 +1205,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var a = 0; var b, c; var d = 1;",
+            output: "var a = 0; var b; var c; var d = 1;",
             options: [{ initialized: "consecutive", uninitialized: "never" }],
             errors: [{
                 message: "Split uninitialized 'var' declarations into multiple statements.",
@@ -1068,6 +1216,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let a = 0; let b = 1; let c, d;",
+            output: "let a = 0,  b = 1; let c; let d;",
             options: [{ initialized: "consecutive", uninitialized: "never" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1085,6 +1234,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let a = 0; let b, c; let d = 1;",
+            output: "let a = 0; let b; let c; let d = 1;",
             options: [{ initialized: "consecutive", uninitialized: "never" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1096,6 +1246,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "const a = 0; const b = 1; let c, d;",
+            output: "const a = 0,  b = 1; let c; let d;",
             options: [{ initialized: "consecutive", uninitialized: "never" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1113,6 +1264,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "const a = 0; let b, c; const d = 1;",
+            output: "const a = 0; let b; let c; const d = 1;",
             options: [{ initialized: "consecutive", uninitialized: "never" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1124,6 +1276,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var a; var b; var c = 0; var d = 1;",
+            output: "var a,  b; var c = 0,  d = 1;",
             options: [{ uninitialized: "consecutive", initialized: "always" }],
             errors: [{
                 message: "Combine this with the previous 'var' statement with uninitialized variables.",
@@ -1140,6 +1293,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var a; var b = 0; var c = 1; var d;",
+            output: "var a; var b = 0,  c = 1; var d;",
             options: [{ uninitialized: "consecutive", initialized: "always" }],
             errors: [{
                 message: "Combine this with the previous 'var' statement with initialized variables.",
@@ -1150,6 +1304,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let a; let b; let c = 0; let d = 1;",
+            output: "let a,  b; let c = 0,  d = 1;",
             options: [{ uninitialized: "consecutive", initialized: "always" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1167,6 +1322,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let a; let b = 0; let c = 1; let d;",
+            output: "let a; let b = 0,  c = 1; let d;",
             options: [{ uninitialized: "consecutive", initialized: "always" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1178,6 +1334,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let a; let b; const c = 0; const d = 1;",
+            output: "let a,  b; const c = 0,  d = 1;",
             options: [{ uninitialized: "consecutive", initialized: "always" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1195,6 +1352,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let a; const b = 0; const c = 1; let d;",
+            output: "let a; const b = 0,  c = 1; let d;",
             options: [{ uninitialized: "consecutive", initialized: "always" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1206,6 +1364,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var a; var b; var c = 0, d = 1;",
+            output: "var a,  b; var c = 0; var d = 1;",
             options: [{ uninitialized: "consecutive", initialized: "never" }],
             errors: [{
                 message: "Combine this with the previous 'var' statement with uninitialized variables.",
@@ -1222,6 +1381,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var a; var b = 0, c = 1; var d;",
+            output: "var a; var b = 0; var c = 1; var d;",
             options: [{ uninitialized: "consecutive", initialized: "never" }],
             errors: [{
                 message: "Split initialized 'var' declarations into multiple statements.",
@@ -1232,6 +1392,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let a; let b; let c = 0, d = 1;",
+            output: "let a,  b; let c = 0; let d = 1;",
             options: [{ uninitialized: "consecutive", initialized: "never" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1249,6 +1410,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let a; let b = 0, c = 1; let d;",
+            output: "let a; let b = 0; let c = 1; let d;",
             options: [{ uninitialized: "consecutive", initialized: "never" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1260,6 +1422,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let a; let b; const c = 0, d = 1;",
+            output: "let a,  b; const c = 0; const d = 1;",
             options: [{ uninitialized: "consecutive", initialized: "never" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1277,6 +1440,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let a; const b = 0, c = 1; let d;",
+            output: "let a; const b = 0; const c = 1; let d;",
             options: [{ uninitialized: "consecutive", initialized: "never" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1288,6 +1452,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var a = 0; var b = 1;",
+            output: "var a = 0,  b = 1;",
             options: [{ var: "consecutive" }],
             errors: [{
                 message: "Combine this with the previous 'var' statement.",
@@ -1298,6 +1463,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let a = 0; let b = 1;",
+            output: "let a = 0,  b = 1;",
             options: [{ let: "consecutive" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1309,6 +1475,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "const a = 0; const b = 1;",
+            output: "const a = 0,  b = 1;",
             options: [{ const: "consecutive" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1320,6 +1487,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let a; let b; const c = 0; const d = 1;",
+            output: "let a,  b; const c = 0,  d = 1;",
             options: [{ let: "consecutive", const: "always" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1337,6 +1505,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let a; const b = 0; const c = 1; let d;",
+            output: "let a; const b = 0,  c = 1; let d;",
             options: [{ let: "consecutive", const: "always" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1348,6 +1517,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let a; let b; const c = 0, d = 1;",
+            output: "let a,  b; const c = 0; const d = 1;",
             options: [{ let: "consecutive", const: "never" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1365,6 +1535,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let a; const b = 0, c = 1; let d;",
+            output: "let a; const b = 0; const c = 1; let d;",
             options: [{ let: "consecutive", const: "never" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1376,6 +1547,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "const a = 0; const b = 1; let c; let d;",
+            output: "const a = 0,  b = 1; let c,  d;",
             options: [{ const: "consecutive", let: "always" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1393,6 +1565,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "const a = 0; let b; let c; const d = 1;",
+            output: "const a = 0; let b,  c; const d = 1;",
             options: [{ const: "consecutive", let: "always" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1404,6 +1577,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "const a = 0; const b = 1; let c, d;",
+            output: "const a = 0,  b = 1; let c; let d;",
             options: [{ const: "consecutive", let: "never" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1421,6 +1595,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "const a = 0; let b, c; const d = 1;",
+            output: "const a = 0; let b; let c; const d = 1;",
             options: [{ const: "consecutive", let: "never" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1432,6 +1607,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var bar; var baz;",
+            output: "var bar,  baz;",
             options: ["consecutive"],
             errors: [{
                 message: "Combine this with the previous 'var' statement.",
@@ -1442,6 +1618,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var bar = 1; var baz = 2; qux(); var qux = 3; var quux;",
+            output: "var bar = 1,  baz = 2; qux(); var qux = 3,  quux;",
             options: ["consecutive"],
             errors: [{
                 message: "Combine this with the previous 'var' statement.",
@@ -1458,6 +1635,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "let a, b; let c; var d, e;",
+            output: "let a, b,  c; var d; var e;",
             options: [{ var: "never", let: "consecutive", const: "consecutive" }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{
@@ -1475,6 +1653,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var a; var b;",
+            output: "var a,  b;",
             options: [{ var: "consecutive" }],
             errors: [{
                 message: "Combine this with the previous 'var' statement.",
@@ -1485,6 +1664,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var a = 1; var b = 2; var c, d; var e = 3; var f = 4;",
+            output: "var a = 1,  b = 2; var c; var d; var e = 3,  f = 4;",
             options: [{ initialized: "consecutive", uninitialized: "never" }],
             errors: [{
                 message: "Combine this with the previous 'var' statement with initialized variables.",
@@ -1507,6 +1687,7 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var a = 1; var b = 2; foo(); var c = 3; var d = 4;",
+            output: "var a = 1,  b = 2; foo(); var c = 3,  d = 4;",
             options: [{ initialized: "consecutive" }],
             errors: [{
                 message: "Combine this with the previous 'var' statement with initialized variables.",
diff --git a/tests/lib/rules/prefer-template.js b/tests/lib/rules/prefer-template.js
index d7fa457ab..bab21ebb5 100644
--- a/tests/lib/rules/prefer-template.js
+++ b/tests/lib/rules/prefer-template.js
@@ -26,6 +26,7 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
 ruleTester.run("prefer-template", rule, {
     valid: [
         "'use strict';",
+        "var foo = 'foo' + '\\0';",
         "var foo = 'bar';",
         "var foo = 'bar' + 'baz';",
         "var foo = foo + +'100';",
@@ -187,6 +188,26 @@ ruleTester.run("prefer-template", rule, {
             code: "foo + 'handles unicode escapes correctly: \\x27'", // "\x27" === "'"
             output: "`${foo  }handles unicode escapes correctly: \\x27`",
             errors
+        },
+        {
+            code: "foo + 'does not autofix octal escape sequence' + '\\033'",
+            output: null,
+            errors
+        },
+        {
+            code: "foo + '\\n other text \\033'",
+            output: null,
+            errors
+        },
+        {
+            code: "foo + '\\\\033'",
+            output: "`${foo  }\\\\033`",
+            errors
+        },
+        {
+            code: "foo + '\\0'",
+            output: "`${foo  }\\0`",
+            errors
         }
     ]
 });
diff --git a/tests/lib/rules/valid-jsdoc.js b/tests/lib/rules/valid-jsdoc.js
index d6e0219c5..7304192be 100644
--- a/tests/lib/rules/valid-jsdoc.js
+++ b/tests/lib/rules/valid-jsdoc.js
@@ -267,6 +267,32 @@ ruleTester.run("valid-jsdoc", rule, {
             options: [{ requireReturn: false }]
         },
 
+        // async function
+        {
+            code:
+              "/**\n" +
+              " * An async function. Options requires return.\n" +
+              " * @returns {Promise} that is empty\n" +
+              " */\n" +
+              "async function a() {}",
+            options: [{ requireReturn: true }],
+            parserOptions: {
+                ecmaVersion: 2017
+            }
+        },
+        {
+            code:
+              "/**\n" +
+              " * An async function. Options do not require return.\n" +
+              " * @returns {Promise} that is empty\n" +
+              " */\n" +
+              "async function a() {}",
+            options: [{ requireReturn: false }],
+            parserOptions: {
+                ecmaVersion: 2017
+            }
+        },
+
         // type validations
         {
             code:
diff --git a/tests/lib/testers/rule-tester.js b/tests/lib/testers/rule-tester.js
index 6456359a7..a3f8073c2 100644
--- a/tests/lib/testers/rule-tester.js
+++ b/tests/lib/testers/rule-tester.js
@@ -9,11 +9,20 @@
 //------------------------------------------------------------------------------
 // Requirements
 //------------------------------------------------------------------------------
-
 const sinon = require("sinon"),
     EventEmitter = require("events"),
     RuleTester = require("../../../lib/testers/rule-tester"),
-    assert = require("chai").assert;
+    assert = require("chai").assert,
+    nodeAssert = require("assert");
+
+const NODE_ASSERT_STRICT_EQUAL_OPERATOR = (() => {
+    try {
+        nodeAssert.strictEqual(1, 2);
+    } catch (err) {
+        return err.operator;
+    }
+    throw new Error("unexpected successful assertion");
+})();
 
 //------------------------------------------------------------------------------
 // Rewire Things
@@ -53,6 +62,23 @@ describe("RuleTester", () => {
 
     let ruleTester;
 
+    /**
+     * @description A helper function to verify Node.js core error messages.
+     * @param {string} actual The actual input
+     * @param {string} expected The expected input
+     * @returns {Function} Error callback to verify that the message is correct
+     *                     for the actual and expected input.
+     */
+    function assertErrorMatches(actual, expected) {
+        const err = new nodeAssert.AssertionError({
+            actual,
+            expected,
+            operator: NODE_ASSERT_STRICT_EQUAL_OPERATOR
+        });
+
+        return err.message;
+    }
+
     beforeEach(() => {
         RuleTester.resetDefaultConfig();
         ruleTester = new RuleTester();
@@ -126,7 +152,7 @@ describe("RuleTester", () => {
                     { code: "var foo = bar;", errors: [{ message: "Bad error message." }] }
                 ]
             });
-        }, /Bad var\.((.*==)|(.*strictEqual)).*Bad error message/);
+        }, assertErrorMatches("Bad var.", "Bad error message."));
     });
 
     it("should throw an error when the error message regex does not match", () => {
@@ -167,7 +193,7 @@ describe("RuleTester", () => {
                     { code: "var foo = bar;", errors: ["Bad error message."] }
                 ]
             });
-        }, /Bad var\.((.*==)|(.*strictEqual)).*Bad error message/);
+        }, assertErrorMatches("Bad var.", "Bad error message."));
     });
 
     it("should throw an error when the error is a string and it does not match error message", () => {
diff --git a/tests/lib/util/glob-util.js b/tests/lib/util/glob-util.js
index 47c601d26..afa7d3f70 100644
--- a/tests/lib/util/glob-util.js
+++ b/tests/lib/util/glob-util.js
@@ -58,6 +58,17 @@ describe("globUtil", () => {
             assert.deepStrictEqual(result, ["one-js-file/**/*.js"]);
         });
 
+        it("should not convert path with globInputPaths option false", () => {
+            const patterns = ["one-js-file"];
+            const opts = {
+                cwd: getFixturePath("glob-util"),
+                globInputPaths: false
+            };
+            const result = globUtil.resolveFileGlobPatterns(patterns, opts);
+
+            assert.deepStrictEqual(result, ["one-js-file"]);
+        });
+
         it("should convert an absolute directory name with no provided extensions into a posix glob pattern", () => {
             const patterns = [getFixturePath("glob-util", "one-js-file")];
             const opts = {
@@ -140,17 +151,6 @@ describe("globUtil", () => {
 
             assert.deepStrictEqual(result, ["one-js-file/example.js"]);
         });
-
-        it("should ignore empty patterns", () => {
-            const patterns = [""];
-            const opts = {
-                cwd: getFixturePath()
-            };
-            const result = globUtil.resolveFileGlobPatterns(patterns, opts);
-
-            assert.deepStrictEqual(result, []);
-        });
-
     });
 
     describe("listFilesToProcess()", () => {
@@ -167,6 +167,19 @@ describe("globUtil", () => {
             assert.deepStrictEqual(result, [{ filename: file1, ignored: false }]);
         });
 
+        it("should return an array with a unmodified filename", () => {
+            const patterns = [getFixturePath("glob-util", "one-js-file", "**/*.js")];
+            const result = globUtil.listFilesToProcess(patterns, {
+                cwd: getFixturePath(),
+                globInputPaths: false
+            });
+
+            const file1 = getFixturePath("glob-util", "one-js-file", "**/*.js");
+
+            assert.isArray(result);
+            assert.deepStrictEqual(result, [{ filename: file1, ignored: false }]);
+        });
+
         it("should return all files matching a glob pattern", () => {
             const patterns = [getFixturePath("glob-util", "two-js-files", "**/*.js")];
             const result = globUtil.listFilesToProcess(patterns, {
@@ -204,13 +217,14 @@ describe("globUtil", () => {
             ]);
         });
 
-        it("should not return hidden files for standard glob patterns", () => {
+        it("should ignore hidden files for standard glob patterns", () => {
             const patterns = [getFixturePath("glob-util", "hidden", "**/*.js")];
-            const result = globUtil.listFilesToProcess(patterns, {
-                cwd: getFixturePath()
-            });
 
-            assert.strictEqual(result.length, 0);
+            assert.throws(() => {
+                globUtil.listFilesToProcess(patterns, {
+                    cwd: getFixturePath()
+                });
+            }, `All files matched by '${patterns[0]}' are ignored.`);
         });
 
         it("should return hidden files if included in glob pattern", () => {
@@ -227,14 +241,15 @@ describe("globUtil", () => {
             ]);
         });
 
-        it("should silently ignore default ignored files if not passed explicitly", () => {
+        it("should ignore default ignored files if not passed explicitly", () => {
             const directory = getFixturePath("glob-util", "hidden");
             const patterns = [directory];
-            const result = globUtil.listFilesToProcess(patterns, {
-                cwd: getFixturePath()
-            });
 
-            assert.strictEqual(result.length, 0);
+            assert.throws(() => {
+                globUtil.listFilesToProcess(patterns, {
+                    cwd: getFixturePath()
+                });
+            }, `All files matched by '${directory}' are ignored.`);
         });
 
         it("should ignore and warn for default ignored files when passed explicitly", () => {
@@ -248,15 +263,16 @@ describe("globUtil", () => {
             assert.deepStrictEqual(result[0], { filename, ignored: true });
         });
 
-        it("should silently ignore default ignored files if not passed explicitly even if ignore is false", () => {
+        it("should ignore default ignored files if not passed explicitly even if ignore is false", () => {
             const directory = getFixturePath("glob-util", "hidden");
             const patterns = [directory];
-            const result = globUtil.listFilesToProcess(patterns, {
-                cwd: getFixturePath(),
-                ignore: false
-            });
 
-            assert.strictEqual(result.length, 0);
+            assert.throws(() => {
+                globUtil.listFilesToProcess(patterns, {
+                    cwd: getFixturePath(),
+                    ignore: false
+                });
+            }, `All files matched by '${directory}' are ignored.`);
         });
 
         it("should not ignore default ignored files when passed explicitly if ignore is false", () => {
@@ -271,20 +287,46 @@ describe("globUtil", () => {
             assert.deepStrictEqual(result[0], { filename, ignored: false });
         });
 
-        it("should not return a file which does not exist", () => {
-            const patterns = ["tests/fixtures/glob-util/hidden/bar.js"];
-            const result = globUtil.listFilesToProcess(patterns);
+        it("should throw an error for a file which does not exist", () => {
+            const filename = getFixturePath("glob-util", "hidden", "bar.js");
+            const patterns = [filename];
+
+            assert.throws(() => {
+                globUtil.listFilesToProcess(patterns, {
+                    cwd: getFixturePath(),
+                    allowMissingGlobs: true
+                });
+            }, `No files matching '${filename}' were found.`);
+        });
 
-            assert.strictEqual(result.length, 0);
+        it("should throw if a folder that does not have any applicable files is linted", () => {
+            const filename = getFixturePath("glob-util", "empty");
+            const patterns = [filename];
+
+            assert.throws(() => {
+                globUtil.listFilesToProcess(patterns, {
+                    cwd: getFixturePath()
+                });
+            }, `No files matching '${filename}' were found.`);
         });
 
-        it("should not return an ignored file", () => {
+        it("should throw if only ignored files match a glob", () => {
+            const pattern = getFixturePath("glob-util", "ignored");
+            const options = { ignore: true, ignorePath: getFixturePath("glob-util", "ignored", ".eslintignore") };
+
+            assert.throws(() => {
+                globUtil.listFilesToProcess([pattern], options);
+            }, `All files matched by '${pattern}' are ignored.`);
+        });
+
+        it("should throw an error if no files match a glob", () => {
 
             // Relying here on the .eslintignore from the repo root
             const patterns = ["tests/fixtures/glob-util/ignored/**/*.js"];
-            const result = globUtil.listFilesToProcess(patterns);
 
-            assert.strictEqual(result.length, 0);
+            assert.throws(() => {
+                globUtil.listFilesToProcess(patterns);
+            }, `No files matching '${patterns[0]}' were found.`);
         });
 
         it("should return an ignored file, if ignore option is turned off", () => {
@@ -295,20 +337,22 @@ describe("globUtil", () => {
             assert.strictEqual(result.length, 1);
         });
 
-        it("should not return a file from a glob if it matches a pattern in an ignore file", () => {
+        it("should ignore a file from a glob if it matches a pattern in an ignore file", () => {
             const options = { ignore: true, ignorePath: getFixturePath("glob-util", "ignored", ".eslintignore") };
             const patterns = [getFixturePath("glob-util", "ignored", "**/*.js")];
-            const result = globUtil.listFilesToProcess(patterns, options);
 
-            assert.strictEqual(result.length, 0);
+            assert.throws(() => {
+                globUtil.listFilesToProcess(patterns, options);
+            }, `All files matched by '${patterns[0]}' are ignored.`);
         });
 
-        it("should not return a file from a glob if matching a specified ignore pattern", () => {
+        it("should ignore a file from a glob if matching a specified ignore pattern", () => {
             const options = { ignore: true, ignorePattern: "foo.js", cwd: getFixturePath() };
             const patterns = [getFixturePath("glob-util", "ignored", "**/*.js")];
-            const result = globUtil.listFilesToProcess(patterns, options);
 
-            assert.strictEqual(result.length, 0);
+            assert.throws(() => {
+                globUtil.listFilesToProcess(patterns, options);
+            }, `All files matched by '${patterns[0]}' are ignored.`);
         });
 
         it("should return a file only once if listed in more than 1 pattern", () => {
diff --git a/tests/lib/util/source-code-util.js b/tests/lib/util/source-code-util.js
index 374443321..1a406e5d3 100644
--- a/tests/lib/util/source-code-util.js
+++ b/tests/lib/util/source-code-util.js
@@ -155,11 +155,12 @@ describe("SourceCodeUtil", () => {
             assert.property(sourceCode, barFilename);
         });
 
-        it("should should not include non-existent filesnames in results", () => {
+        it("should should not include non-existent filenames in results", () => {
             const filename = getFixturePath("missing.js");
-            const sourceCode = getSourceCodeOfFiles(filename, { cwd: fixtureDir });
 
-            assert.notProperty(sourceCode, filename);
+            assert.throws(() => {
+                getSourceCodeOfFiles(filename, { cwd: fixtureDir });
+            }, `No files matching '${filename}' were found.`);
         });
 
         it("should throw for files with parsing errors", () => {
@@ -248,9 +249,8 @@ describe("SourceCodeUtil", () => {
             const firstFn = getFixturePath("foo.js");
             const secondFn = getFixturePath("bar.js");
             const thirdFn = getFixturePath("nested/foo.js");
-            const missingFn = getFixturePath("missing.js");
 
-            getSourceCodeOfFiles([firstFn, secondFn, thirdFn, missingFn], { cwd: fixtureDir }, callback);
+            getSourceCodeOfFiles([firstFn, secondFn, thirdFn], { cwd: fixtureDir }, callback);
             assert(callback.calledWith(3));
         });