Repository: eslint/eslint (js)

Issue:
crash on malformed package.json
If `package.json` is malformed, eslint fails by crashing. This is relevant because then in Atom, every file that is to be checked by eslint is marked as invalid.

**Tell us about your environment**

* **ESLint Version:** 4.19.1
* **Node Version:** 9.8.0
* **npm Version:** 6.0.1

**What parser (default, Babel-ESLint, etc.) are you using?**

default

**Please show your full configuration:**

<details>
<summary>Configuration</summary>

<!-- Paste your configuration below: -->
original `package.json` so I can `npm i` eslint:

```json
{
  "name": "test",
  "version": "0.1.0",
  "description": "test eslint",
  "main": "app.js",
  "scripts": {
    "lint": "eslint ."
  },
  "author": "Jacek Kopecky <jacek@jacek.cz>",
  "engines": {
    "node": ">=8.7.0"
  },
  "devDependencies": {
    "eslint": "^4.19.1"
  }
}
```

No `.eslintrc` or anything like that.

</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.**

I was editing package.json and introduced a syntax error - the usual extra comma (near the end of the file below).

```json
{
  "name": "test",
  "version": "0.1.0",
  "description": "test eslint",
  "main": "app.js",
  "scripts": {
    "lint": "eslint ."
  },
  "author": "Jacek Kopecky <jacek@jacek.cz>",
  "engines": {
    "node": ">=8.7.0"
  },
  "devDependencies": {
    "eslint": "^4.19.1",
  }
}
```

Then I want to lint the project:

```bash
eslint .
```

**What did you expect to happen?**

Eslint should either fail gracefully with a warning because it can't parse `package.json`, or it assumes there's nothing in `package.json` of interest to eslint (which is correct) and proceeds to check the directory, which is otherwise empty so eslint succeeds quietly. If eslint fails, its output should clearly blame `package.json` in the normal »this file has a linting error« format.

**What actually happened? Please include the actual, raw output from ESLint.**

Crash.

```
Unexpected token } in JSON at position 275
SyntaxError: Unexpected token } in JSON at position 275
    at JSON.parse (<anonymous>)
    at new IgnoredPaths (/Users/kopeckyj/tmp/eslint/node_modules/eslint/lib/ignored-paths.js:176:55)
    at lodash.memoize.optionsObj (/Users/kopeckyj/tmp/eslint/node_modules/eslint/lib/util/glob-util.js:115:13)
    at memoized (/Users/kopeckyj/tmp/eslint/node_modules/lodash/lodash.js:10551:27)
    at globPatterns.forEach.pattern (/Users/kopeckyj/tmp/eslint/node_modules/eslint/lib/util/glob-util.js:175:34)
    at Array.forEach (<anonymous>)
    at Object.listFilesToProcess (/Users/kopeckyj/tmp/eslint/node_modules/eslint/lib/util/glob-util.js:158:18)
    at CLIEngine.executeOnFiles (/Users/kopeckyj/tmp/eslint/node_modules/eslint/lib/cli-engine.js:518:35)
    at Object.execute (/Users/kopeckyj/tmp/eslint/node_modules/eslint/lib/cli.js:189:111)
    at Object.<anonymous> (/Users/kopeckyj/tmp/eslint/node_modules/eslint/bin/eslint.js:74:28)
```

Pull request:
Fix: prevent crashing from JSON parsing error (fixes #10364)
<!--
    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).
-->

**What is the purpose of this pull request? (put an "X" next to item)**

[ ] Documentation update
[x] Bug fix ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/bug-report.md))
[ ] New rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-proposal.md))
[ ] Changes an existing rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-change-proposal.md))
[ ] Add autofixing to a rule
[ ] Add a CLI option
[ ] Add something to the core
[ ] Other, please explain:

<!--
    If the item you've checked above has a template, please paste the template questions below and answer them. (If this pull request is addressing an issue, you can just paste a link to the issue here instead.)
-->
close #10364 

<!--
    Please ensure your pull request is ready:

    - Read the pull request guide (https://eslint.org/docs/developer-guide/contributing/pull-requests)
    - Include tests for this change
    - Update documentation for this change (if appropriate)
-->

<!--
    The following is required for all pull requests:
-->

**What changes did you make? (Give an overview)**
Display better error message when failed to parse JSON.


Patch:
diff --git a/.travis.yml b/.travis.yml
index 5763f04af..ff3e956a7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,6 +3,7 @@ node_js:
     - "6"
     - "8"
     - "9"
+    - "10"
 sudo: false
 branches:
     only:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a57981723..2b513d8df 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,24 @@
+v5.0.0-alpha.4 - May 28, 2018
+
+* ce3e62a Docs: remove test coverage badge (#10407) (薛定谔的猫)
+* 240c1a4 Fix: prefer-const object destructuring false positive (fixes #9108) (#10368) (Pig Fang)
+* 93c9a52 Update: config-validator should validate overrides (#10357) (Toru Nagashima)
+* c2e0398 Update: Improves the prefer-object-spread rule by removing extraneous visitors (#10351) (Sharmila Jesupaul)
+* d848949 Update: Support JSXFragment node (fixes #9662) (#9664) (Clement Hoang)
+* f268128 Build: add Node v10 to travis (#10262) (alberto)
+* 9c922ce Update: Add "consistent" option to array-element-newline (fixes #9457) (#10355) (Pig Fang)
+* 65bce3a Fix: ensure --stdin flag works when stdin is piped asynchronously (#10393) (Teddy Katz)
+* b9b23a9 Chore: rm unused argument (#10400) (薛定谔的猫)
+* 8b7a70c Fix: handle one-var with no semicolon (fixes #10330) (#10371) (Malcolm Groves)
+* 465e615 New: prompt users before installing dependencies (#10353) (Pig Fang)
+* e25fc22 Chore: remove assert.doesNotThrow in tests (#10199) (Ruben Bridgewater)
+* fb148aa Fix: allow no tokens after `return` keyword (fixes #10372) (#10379) (Pig Fang)
+* 074bc1c Docs: polish for max-classes-per-file rule (#10377) (Pig Fang)
+* a812845 Fix: allow array spread for prefer-object-spread rule (fixes #10344) (#10347) (Pig Fang)
+* 448fc52 Docs: Update link to Integrations / Build tools / Start (#10354) (Kir Belevich)
+* 4e5e9be Chore: avoid unnecessary filesystem accesses during config search (#10359) (Teddy Katz)
+* 363da01 Chore: avoid code duplication in rule severity checking (#10358) (Teddy Katz)
+
 v5.0.0-alpha.3 - May 11, 2018
 
 * 1a6b399 New: Adds prefer-object-spread rule (refs: #7230) (#9955) (Sharmila Jesupaul)
diff --git a/README.md b/README.md
index cb8c0277d..95c272094 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,6 @@
 [![NPM version][npm-image]][npm-url]
 [![build status][travis-image]][travis-url]
 [![Build status][appveyor-image]][appveyor-url]
-[![Test coverage][coveralls-image]][coveralls-url]
 [![Downloads][downloads-image]][downloads-url]
 [![Bountysource](https://www.bountysource.com/badge/tracker?tracker_id=282608)](https://www.bountysource.com/trackers/282608-eslint?utm_source=282608&utm_medium=shield&utm_campaign=TRACKER_BADGE)
 [![Join the chat at https://gitter.im/eslint/eslint](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/eslint/eslint?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
diff --git a/bin/eslint.js b/bin/eslint.js
index 1255e3d8b..adc07c2e7 100755
--- a/bin/eslint.js
+++ b/bin/eslint.js
@@ -56,7 +56,15 @@ process.once("uncaughtException", err => {
 });
 
 if (useStdIn) {
-    process.exitCode = cli.execute(process.argv, fs.readFileSync(process.stdin.fd, "utf8"));
+
+    /*
+     * Note: `process.stdin.fd` is not used here due to https://github.com/nodejs/node/issues/7439.
+     * Accessing the `process.stdin` property seems to modify the behavior of file descriptor 0, resulting
+     * in an error when stdin is piped in asynchronously.
+     */
+    const STDIN_FILE_DESCRIPTOR = 0;
+
+    process.exitCode = cli.execute(process.argv, fs.readFileSync(STDIN_FILE_DESCRIPTOR, "utf8"));
 } else if (init) {
     const configInit = require("../lib/config/config-initializer");
 
diff --git a/docs/rules/array-element-newline.md b/docs/rules/array-element-newline.md
index 21d957101..6a3a66e1d 100644
--- a/docs/rules/array-element-newline.md
+++ b/docs/rules/array-element-newline.md
@@ -12,6 +12,7 @@ This rule has either a string option:
 
 * `"always"` (default) requires line breaks between array elements
 * `"never"` disallows line breaks between array elements
+* `"consistent"` requires consistent usage of linebreaks between array elements
 
 Or an object option (Requires line breaks if any of properties is satisfied. Otherwise, disallows line breaks):
 
@@ -102,6 +103,69 @@ var e = [
 ];
 ```
 
+### consistent
+
+Examples of **incorrect** code for this rule with the `"consistent"` option:
+
+```js
+/*eslint array-element-newline: ["error", "consistent"]*/
+
+var a = [
+    1, 2,
+    3
+];
+var b = [
+    function foo() {
+        dosomething();
+    }, function bar() {
+        dosomething();
+    },
+    function baz() {
+        dosomething();
+    }
+];
+```
+
+Examples of **correct** code for this rule with the `"consistent"` option:
+
+```js
+/*eslint array-element-newline: ["error", "consistent"]*/
+
+var a = [];
+var b = [1];
+var c = [1, 2];
+var d = [1, 2, 3];
+var e = [
+    1,
+    2
+];
+var f = [
+    1,
+    2,
+    3
+];
+var g = [
+    function foo() {
+        dosomething();
+    }, function bar() {
+        dosomething();
+    }, function baz() {
+        dosomething();
+    }
+];
+var h = [
+    function foo() {
+        dosomething();
+    },
+    function bar() {
+        dosomething();
+    },
+    function baz() {
+        dosomething();
+    }
+];
+```
+
 ### multiline
 
 Examples of **incorrect** code for this rule with the `{ "multiline": true }` option:
diff --git a/lib/config/config-file.js b/lib/config/config-file.js
index 87f60f91c..d09b36688 100644
--- a/lib/config/config-file.js
+++ b/lib/config/config-file.js
@@ -115,6 +115,11 @@ function loadJSONConfigFile(filePath) {
     } catch (e) {
         debug(`Error reading JSON file: ${filePath}`);
         e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
+        e.messageTemplate = "failed-to-read-json";
+        e.messageData = {
+            path: filePath,
+            message: e.message
+        };
         throw e;
     }
 }
diff --git a/lib/config/config-initializer.js b/lib/config/config-initializer.js
index fe42880b4..5fd9f9c51 100644
--- a/lib/config/config-initializer.js
+++ b/lib/config/config-initializer.js
@@ -239,15 +239,16 @@ function configureRules(answers, config) {
  * @returns {Object} config object
  */
 function processAnswers(answers) {
-    let config = { rules: {}, env: {} };
+    let config = { rules: {}, env: {}, parserOptions: {} };
 
-    if (answers.es6) {
-        config.env.es6 = true;
+    config.parserOptions.ecmaVersion = answers.ecmaVersion;
+    if (answers.ecmaVersion >= 2015) {
         if (answers.modules) {
-            config.parserOptions = config.parserOptions || {};
             config.parserOptions.sourceType = "module";
         }
+        config.env.es6 = true;
     }
+
     if (answers.commonjs) {
         config.env.commonjs = true;
     }
@@ -504,7 +505,7 @@ function promptUser() {
                 earlyAnswers.styleguide = "airbnb-base";
             }
 
-            const config = getConfigForStyleGuide(earlyAnswers.styleguide, earlyAnswers.installESLint);
+            const config = getConfigForStyleGuide(earlyAnswers.styleguide);
             const modules = getModulesList(config);
 
             return askInstallModules(modules, earlyAnswers.packageJsonExists)
@@ -514,10 +515,18 @@ function promptUser() {
         // continue with the questions otherwise...
         return inquirer.prompt([
             {
-                type: "confirm",
-                name: "es6",
-                message: "Are you using ECMAScript 6 features?",
-                default: false
+                type: "list",
+                name: "ecmaVersion",
+                message: "Which version of ECMAScript do you use?",
+                choices: [
+                    { name: "ES3", value: 3 },
+                    { name: "ES5", value: 5 },
+                    { name: "ES2015", value: 2015 },
+                    { name: "ES2016", value: 2016 },
+                    { name: "ES2017", value: 2017 },
+                    { name: "ES2018", value: 2018 }
+                ],
+                default: 1 // This is the index in the choices list
             },
             {
                 type: "confirm",
@@ -525,7 +534,7 @@ function promptUser() {
                 message: "Are you using ES6 modules?",
                 default: false,
                 when(answers) {
-                    return answers.es6 === true;
+                    return answers.ecmaVersion >= 2015;
                 }
             },
             {
diff --git a/lib/config/config-validator.js b/lib/config/config-validator.js
index ed9a34cb0..185d4650d 100644
--- a/lib/config/config-validator.js
+++ b/lib/config/config-validator.js
@@ -254,6 +254,11 @@ function validate(config, source, ruleMapper, envContext) {
     validateConfigSchema(config, source);
     validateRules(config.rules, source, ruleMapper);
     validateEnvironment(config.env, source, envContext);
+
+    for (const override of config.overrides || []) {
+        validateRules(override.rules, source, ruleMapper);
+        validateEnvironment(override.env, source, envContext);
+    }
 }
 
 //------------------------------------------------------------------------------
diff --git a/lib/ignored-paths.js b/lib/ignored-paths.js
index 8fff260d0..0371e5e10 100644
--- a/lib/ignored-paths.js
+++ b/lib/ignored-paths.js
@@ -176,6 +176,11 @@ class IgnoredPaths {
                             packageJSONOptions = JSON.parse(fs.readFileSync(packageJSONPath, "utf8"));
                         } catch (e) {
                             debug("Could not read package.json file to check eslintIgnore property");
+                            e.messageTemplate = "failed-to-read-json";
+                            e.messageData = {
+                                path: packageJSONPath,
+                                message: e.message
+                            };
                             throw e;
                         }
 
diff --git a/lib/rules/array-element-newline.js b/lib/rules/array-element-newline.js
index 359b8d436..b437c6932 100644
--- a/lib/rules/array-element-newline.js
+++ b/lib/rules/array-element-newline.js
@@ -24,7 +24,7 @@ module.exports = {
             {
                 oneOf: [
                     {
-                        enum: ["always", "never"]
+                        enum: ["always", "never", "consistent"]
                     },
                     {
                         type: "object",
@@ -63,6 +63,7 @@ module.exports = {
          * @returns {{multiline: boolean, minItems: number}} Normalized option object.
          */
         function normalizeOptionValue(providedOption) {
+            let consistent = false;
             let multiline = false;
             let minItems;
 
@@ -72,12 +73,15 @@ module.exports = {
                 minItems = 0;
             } else if (option === "never") {
                 minItems = Number.POSITIVE_INFINITY;
+            } else if (option === "consistent") {
+                consistent = true;
+                minItems = Number.POSITIVE_INFINITY;
             } else {
                 multiline = Boolean(option.multiline);
                 minItems = option.minItems || Number.POSITIVE_INFINITY;
             }
 
-            return { multiline, minItems };
+            return { consistent, multiline, minItems };
         }
 
         /**
@@ -193,11 +197,30 @@ module.exports = {
                     .some(element => element.loc.start.line !== element.loc.end.line);
             }
 
+            const linebreaksCount = node.elements.map((element, i) => {
+                const previousElement = elements[i - 1];
+
+                if (i === 0 || element === null || previousElement === null) {
+                    return false;
+                }
+
+                const commaToken = sourceCode.getFirstTokenBetween(previousElement, element, astUtils.isCommaToken);
+                const lastTokenOfPreviousElement = sourceCode.getTokenBefore(commaToken);
+                const firstTokenOfCurrentElement = sourceCode.getTokenAfter(commaToken);
+
+                return !astUtils.isTokenOnSameLine(lastTokenOfPreviousElement, firstTokenOfCurrentElement);
+            }).filter(isBreak => isBreak === true).length;
+
             const needsLinebreaks = (
                 elements.length >= options.minItems ||
                 (
                     options.multiline &&
                     elementBreak
+                ) ||
+                (
+                    options.consistent &&
+                    linebreaksCount > 0 &&
+                    linebreaksCount < node.elements.length
                 )
             );
 
diff --git a/lib/rules/no-extra-parens.js b/lib/rules/no-extra-parens.js
index 9765dfa77..3d4ee19e8 100644
--- a/lib/rules/no-extra-parens.js
+++ b/lib/rules/no-extra-parens.js
@@ -86,7 +86,7 @@ module.exports = {
          * @private
          */
         function ruleApplies(node) {
-            if (node.type === "JSXElement") {
+            if (node.type === "JSXElement" || node.type === "JSXFragment") {
                 const isSingleLine = node.loc.start.line === node.loc.end.line;
 
                 switch (IGNORE_JSX) {
diff --git a/lib/rules/no-useless-escape.js b/lib/rules/no-useless-escape.js
index efc9706f4..2ddab7854 100644
--- a/lib/rules/no-useless-escape.js
+++ b/lib/rules/no-useless-escape.js
@@ -174,7 +174,7 @@ module.exports = {
                  * JSXAttribute doesn't have any escape sequence: https://facebook.github.io/jsx/.
                  * In addition, backticks are not supported by JSX yet: https://github.com/facebook/jsx/issues/25.
                  */
-                if (node.parent.type === "JSXAttribute" || node.parent.type === "JSXElement") {
+                if (node.parent.type === "JSXAttribute" || node.parent.type === "JSXElement" || node.parent.type === "JSXFragment") {
                     return;
                 }
 
diff --git a/lib/rules/prefer-const.js b/lib/rules/prefer-const.js
index a24a00284..a7c46b34d 100644
--- a/lib/rules/prefer-const.js
+++ b/lib/rules/prefer-const.js
@@ -5,6 +5,8 @@
 
 "use strict";
 
+const astUtils = require("../ast-utils");
+
 //------------------------------------------------------------------------------
 // Helpers
 //------------------------------------------------------------------------------
@@ -55,6 +57,54 @@ function canBecomeVariableDeclaration(identifier) {
     );
 }
 
+/**
+ * Checks if an property or element is from outer scope or function parameters
+ * in destructing pattern.
+ *
+ * @param {string} name - A variable name to be checked.
+ * @param {eslint-scope.Scope} initScope - A scope to start find.
+ * @returns {boolean} Indicates if the variable is from outer scope or function parameters.
+ */
+function isOuterVariableInDestructing(name, initScope) {
+    if (initScope.through.find(ref => ref.resolved && ref.resolved.name === name)) {
+        return true;
+    }
+
+    const variable = astUtils.getVariableByName(initScope, name);
+
+    if (variable !== null) {
+        return variable.defs.some(def => def.type === "Parameter");
+    }
+
+    return false;
+}
+
+/**
+ * Gets the VariableDeclarator/AssignmentExpression node that a given reference
+ * belongs to.
+ * This is used to detect a mix of reassigned and never reassigned in a
+ * destructuring.
+ *
+ * @param {eslint-scope.Reference} reference - A reference to get.
+ * @returns {ASTNode|null} A VariableDeclarator/AssignmentExpression node or
+ *      null.
+ */
+function getDestructuringHost(reference) {
+    if (!reference.isWrite()) {
+        return null;
+    }
+    let node = reference.identifier.parent;
+
+    while (PATTERN_TYPE.test(node.type)) {
+        node = node.parent;
+    }
+
+    if (!DESTRUCTURING_HOST_TYPE.test(node.type)) {
+        return null;
+    }
+    return node;
+}
+
 /**
  * Gets an identifier node of a given variable.
  *
@@ -102,6 +152,32 @@ function getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign) {
             if (isReassigned) {
                 return null;
             }
+
+            const destructuringHost = getDestructuringHost(reference);
+
+            if (destructuringHost !== null && destructuringHost.left !== void 0) {
+                const leftNode = destructuringHost.left;
+                let hasOuterVariables = false;
+
+                if (leftNode.type === "ObjectPattern") {
+                    const properties = leftNode.properties;
+
+                    hasOuterVariables = properties
+                        .filter(prop => prop.value)
+                        .map(prop => prop.value.name)
+                        .some(name => isOuterVariableInDestructing(name, variable.scope));
+                } else if (leftNode.type === "ArrayPattern") {
+                    const elements = leftNode.elements;
+
+                    hasOuterVariables = elements
+                        .map(element => element.name)
+                        .some(name => isOuterVariableInDestructing(name, variable.scope));
+                }
+                if (hasOuterVariables) {
+                    return null;
+                }
+            }
+
             writer = reference;
 
         } else if (reference.isRead() && writer === null) {
@@ -131,32 +207,6 @@ function getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign) {
     return writer.identifier;
 }
 
-/**
- * Gets the VariableDeclarator/AssignmentExpression node that a given reference
- * belongs to.
- * This is used to detect a mix of reassigned and never reassigned in a
- * destructuring.
- *
- * @param {eslint-scope.Reference} reference - A reference to get.
- * @returns {ASTNode|null} A VariableDeclarator/AssignmentExpression node or
- *      null.
- */
-function getDestructuringHost(reference) {
-    if (!reference.isWrite()) {
-        return null;
-    }
-    let node = reference.identifier.parent;
-
-    while (PATTERN_TYPE.test(node.type)) {
-        node = node.parent;
-    }
-
-    if (!DESTRUCTURING_HOST_TYPE.test(node.type)) {
-        return null;
-    }
-    return node;
-}
-
 /**
  * Groups by the VariableDeclarator/AssignmentExpression node that each
  * reference of given variables belongs to.
@@ -290,7 +340,7 @@ module.exports = {
                     (varDeclParent.parent.type === "ForInStatement" || varDeclParent.parent.type === "ForOfStatement" || varDeclParent.declarations[0].init) &&
 
                     /*
-                     * If options.destucturing is "all", then this warning will not occur unless
+                     * If options.destructuring is "all", then this warning will not occur unless
                      * every assignment in the destructuring should be const. In that case, it's safe
                      * to apply the fix.
                      */
diff --git a/lib/rules/prefer-object-spread.js b/lib/rules/prefer-object-spread.js
index aa69824a5..d6577df7d 100644
--- a/lib/rules/prefer-object-spread.js
+++ b/lib/rules/prefer-object-spread.js
@@ -196,6 +196,34 @@ function autofixObjectLiteral(node, sourceCode) {
     };
 }
 
+/**
+ * Check if the node has modified a given variable
+ * @param {ASTNode|null} node - The node that the rule warns on, i.e. the Object.assign call
+ * @returns {boolean} - true if node is an assignment, variable declaration, or import statement
+ */
+function isModifier(node) {
+    if (!node.type) {
+        return false;
+    }
+
+    return node.type === "AssignmentExpression" ||
+        node.type === "VariableDeclarator" ||
+        node.type === "ImportDeclaration";
+}
+
+/**
+ * Check if the node has modified a given variable
+ * @param {array} references - list of reference nodes
+ * @returns {boolean} - true if node is has been overwritten by an assignment or import
+ */
+function modifyingObjectReference(references) {
+    return references.some(ref => (
+        ref.identifier &&
+        ref.identifier.parent &&
+        isModifier(ref.identifier.parent)
+    ));
+}
+
 
 module.exports = {
     meta: {
@@ -216,35 +244,25 @@ module.exports = {
 
     create: function rule(context) {
         const sourceCode = context.getSourceCode();
-        let overWritingNativeObject = false;
-
-        return {
-            VariableDeclaration(node) {
+        const scope = context.getScope();
+        const objectVariable = scope.variables.filter(variable => variable.name === "Object");
+        const moduleReferences = scope.childScopes.filter(childScope => {
+            const varNamedObject = childScope.variables.filter(variable => variable.name === "Object");
 
-                /*
-                 * If a declared variable is overwriting the native `Object`, eg. `const Object = 'something'`
-                 * we want to skip warning on them since the behavior might be different.
-                 */
-                if (node.declarations.length) {
-                    const declarationNames = node.declarations.map(dec => dec.id);
-                    const nativeObjectOverride = declarationNames.filter(identifier => identifier.name === "Object");
+            return childScope.type === "module" && varNamedObject.length;
+        });
+        const references = [].concat(...objectVariable.map(variable => variable.references || []));
 
-                    if (nativeObjectOverride.length) {
-                        overWritingNativeObject = true;
-                    }
-                }
-            },
-            AssignmentExpression(node) {
+        return {
+            CallExpression(node) {
 
                 /*
-                 * If an assignment is reassigning the native `Object`, eg. `Object = 'something'`
-                 * we want to skip warning on them since the behavior might be different.
+                 * If current file is either importing Object or redefining it,
+                 * we skip warning on this rule.
                  */
-                if (node.left.name === "Object") {
-                    overWritingNativeObject = true;
+                if (moduleReferences.length || (references.length && modifyingObjectReference(references))) {
+                    return;
                 }
-            },
-            CallExpression(node) {
 
                 /*
                  * The condition below is cases where Object.assign has a single argument and
@@ -252,7 +270,6 @@ module.exports = {
                  * For now, we will warn on this case and autofix it.
                  */
                 if (
-                    !overWritingNativeObject &&
                     node.arguments.length === 1 &&
                     node.arguments[0].type === "ObjectExpression" &&
                     isObjectAssign(node)
@@ -270,7 +287,6 @@ module.exports = {
                  * that can be spread. e.g `Object.assign({ foo: bar }, baz)`
                  */
                 if (
-                    !overWritingNativeObject &&
                     node.arguments.length > 1 &&
                     node.arguments[0].type === "ObjectExpression" &&
                     isObjectAssign(node) &&
diff --git a/lib/rules/quotes.js b/lib/rules/quotes.js
index fa8bbae5f..78794e72b 100644
--- a/lib/rules/quotes.js
+++ b/lib/rules/quotes.js
@@ -132,6 +132,7 @@ module.exports = {
          *
          * - `<div className="foo"></div>` ... If the literal is an attribute value, the parent of the literal is `JSXAttribute`.
          * - `<div>foo</div>` ... If the literal is a text content, the parent of the literal is `JSXElement`.
+         * - `<>foo</>` ... If the literal is a text content, the parent of the literal is `JSXFragment`.
          *
          * In particular, this function returns `false` in the following cases:
          *
@@ -146,7 +147,7 @@ module.exports = {
          * @private
          */
         function isJSXLiteral(node) {
-            return node.parent.type === "JSXAttribute" || node.parent.type === "JSXElement";
+            return node.parent.type === "JSXAttribute" || node.parent.type === "JSXElement" || node.parent.type === "JSXFragment";
         }
 
         /**
diff --git a/lib/util/npm-util.js b/lib/util/npm-util.js
index 0b21f6261..97aabde7b 100644
--- a/lib/util/npm-util.js
+++ b/lib/util/npm-util.js
@@ -109,8 +109,14 @@ function check(packages, opt) {
     try {
         fileJson = JSON.parse(fs.readFileSync(pkgJson, "utf8"));
     } catch (e) {
-        log.info("Could not read package.json file. Please check that the file contains valid JSON.");
-        throw new Error(e);
+        const error = new Error(e);
+
+        error.messageTemplate = "failed-to-read-json";
+        error.messageData = {
+            path: pkgJson,
+            message: e.message
+        };
+        throw error;
     }
 
     if (opt.devDependencies && typeof fileJson.devDependencies === "object") {
diff --git a/messages/failed-to-read-json.txt b/messages/failed-to-read-json.txt
new file mode 100644
index 000000000..b5e2b861c
--- /dev/null
+++ b/messages/failed-to-read-json.txt
@@ -0,0 +1,3 @@
+Failed to read JSON file at <%= path %>:
+
+<%= message %>
diff --git a/package.json b/package.json
index 44663d32c..e3bf2344b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "eslint",
-  "version": "5.0.0-alpha.3",
+  "version": "5.0.0-alpha.4",
   "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
   "description": "An AST-based pattern checker for JavaScript.",
   "bin": {


Test patch:
diff --git a/tests/bin/eslint.js b/tests/bin/eslint.js
index 5fc818f28..75e7c2c4b 100644
--- a/tests/bin/eslint.js
+++ b/tests/bin/eslint.js
@@ -152,6 +152,17 @@ describe("bin/eslint.js", () => {
             }
         );
 
+        it("successfully reads from an asynchronous pipe", () => {
+            const child = runESLint(["--stdin", "--no-eslintrc"]);
+
+            child.stdin.write("var foo = bar;\n");
+            return new Promise(resolve => setTimeout(resolve, 300)).then(() => {
+                child.stdin.write("var baz = qux;\n");
+                child.stdin.end();
+
+                return assertExitCode(child, 0);
+            });
+        });
     });
 
     describe("running on files", () => {
diff --git a/tests/fixtures/config-initializer/new-es-features/new-es-features.js b/tests/fixtures/config-initializer/new-es-features/new-es-features.js
new file mode 100644
index 000000000..c3e03fc32
--- /dev/null
+++ b/tests/fixtures/config-initializer/new-es-features/new-es-features.js
@@ -0,0 +1,3 @@
+async function fn() {
+    await Promise.resolve();
+}
diff --git a/tests/fixtures/ignored-paths/broken-package-json/package.json b/tests/fixtures/ignored-paths/broken-package-json/package.json
new file mode 100644
index 000000000..7c1fe4aff
--- /dev/null
+++ b/tests/fixtures/ignored-paths/broken-package-json/package.json
@@ -0,0 +1,11 @@
+{
+    "name": "mypackage",
+    "version": "0.0.1",
+    "eslintConfig": {
+        "env": {
+            "browser": true,
+            "node": true
+        }
+    }
+    "eslintIgnore": "hello.js"
+}
diff --git a/tests/lib/config/config-file.js b/tests/lib/config/config-file.js
index 287a7d67d..4b74d0475 100644
--- a/tests/lib/config/config-file.js
+++ b/tests/lib/config/config-file.js
@@ -636,7 +636,12 @@ describe("ConfigFile", () => {
 
         it("should throw error when loading invalid package.json file", () => {
             assert.throws(() => {
-                ConfigFile.load(getFixturePath("broken-package-json/package.json"), configContext);
+                try {
+                    ConfigFile.load(getFixturePath("broken-package-json/package.json"), configContext);
+                } catch (error) {
+                    assert.strictEqual(error.messageTemplate, "failed-to-read-json");
+                    throw error;
+                }
             }, /Cannot read config file/);
         });
 
diff --git a/tests/lib/config/config-initializer.js b/tests/lib/config/config-initializer.js
index 579c9a526..ac8a7dd6f 100644
--- a/tests/lib/config/config-initializer.js
+++ b/tests/lib/config/config-initializer.js
@@ -123,8 +123,9 @@ describe("configInitializer", () => {
                     quotes: "single",
                     linebreak: "unix",
                     semi: true,
-                    es6: true,
+                    ecmaVersion: 2015,
                     modules: true,
+                    es6Globals: true,
                     env: ["browser"],
                     jsx: false,
                     react: false,
@@ -141,6 +142,7 @@ describe("configInitializer", () => {
                 assert.deepStrictEqual(config.rules["linebreak-style"], ["error", "unix"]);
                 assert.deepStrictEqual(config.rules.semi, ["error", "always"]);
                 assert.strictEqual(config.env.es6, true);
+                assert.strictEqual(config.parserOptions.ecmaVersion, 2015);
                 assert.strictEqual(config.parserOptions.sourceType, "module");
                 assert.strictEqual(config.env.browser, true);
                 assert.strictEqual(config.extends, "eslint:recommended");
@@ -171,9 +173,10 @@ describe("configInitializer", () => {
             });
 
             it("should not enable es6", () => {
-                answers.es6 = false;
+                answers.ecmaVersion = 5;
                 const config = init.processAnswers(answers);
 
+                assert.strictEqual(config.parserOptions.ecmaVersion, 5);
                 assert.isUndefined(config.env.es6);
             });
 
@@ -337,7 +340,7 @@ describe("configInitializer", () => {
                 answers = {
                     source: "auto",
                     patterns,
-                    es6: false,
+                    ecmaVersion: 5,
                     env: ["browser"],
                     jsx: false,
                     react: false,
@@ -377,6 +380,15 @@ describe("configInitializer", () => {
                 assert.notProperty(config.rules, "no-console");
             });
 
+            it("should support new ES features if using later ES version", () => {
+                const filename = getFixturePath("new-es-features");
+
+                answers.patterns = filename;
+                answers.ecmaVersion = 2017;
+                process.chdir(fixtureDir);
+                config = init.processAnswers(answers);
+            });
+
             it("should throw on fatal parsing error", () => {
                 const filename = getFixturePath("parse-error");
 
diff --git a/tests/lib/config/config-validator.js b/tests/lib/config/config-validator.js
index 76e573472..456b15183 100644
--- a/tests/lib/config/config-validator.js
+++ b/tests/lib/config/config-validator.js
@@ -362,6 +362,40 @@ describe("Validator", () => {
 
                 assert.throws(fn, "ESLint configuration in tests is invalid:\n\t- Unexpected top-level property \"overrides[0].root\".\n");
             });
+
+            describe("env", () => {
+
+                it("should catch invalid environments", () => {
+                    const fn = validator.validate.bind(null, { overrides: [{ files: "*", env: { browser: true, invalid: true } }] }, null, ruleMapper, linter.environments);
+
+                    assert.throws(fn, "Environment key \"invalid\" is unknown\n");
+                });
+
+                it("should catch disabled invalid environments", () => {
+                    const fn = validator.validate.bind(null, { overrides: [{ files: "*", env: { browser: true, invalid: false } }] }, null, ruleMapper, linter.environments);
+
+                    assert.throws(fn, "Environment key \"invalid\" is unknown\n");
+                });
+
+            });
+
+            describe("rules", () => {
+
+                it("should catch invalid rule options", () => {
+                    const fn = validator.validate.bind(null, { overrides: [{ files: "*", rules: { "mock-rule": [3, "third"] } }] }, "tests", ruleMapper, linter.environments);
+
+                    assert.throws(fn, "tests:\n\tConfiguration for rule \"mock-rule\" is invalid:\n\tSeverity should be one of the following: 0 = off, 1 = warn, 2 = error (you passed '3').\n");
+                });
+
+                it("should not allow options for rules with no options", () => {
+                    linter.defineRule("mock-no-options-rule", mockNoOptionsRule);
+
+                    const fn = validator.validate.bind(null, { overrides: [{ files: "*", rules: { "mock-no-options-rule": [2, "extra"] } }] }, "tests", ruleMapper, linter.environments);
+
+                    assert.throws(fn, "tests:\n\tConfiguration for rule \"mock-no-options-rule\" is invalid:\n\tValue [\"extra\"] should NOT have more than 0 items.\n");
+                });
+            });
+
         });
 
     });
diff --git a/tests/lib/ignored-paths.js b/tests/lib/ignored-paths.js
index bda83c2bd..010488931 100644
--- a/tests/lib/ignored-paths.js
+++ b/tests/lib/ignored-paths.js
@@ -169,6 +169,18 @@ describe("IgnoredPaths", () => {
             assert.isTrue(ignoredPaths.contains("world.js"));
         });
 
+        it("should use correct message template if failed to parse package.json", () => {
+            assert.throw(() => {
+                try {
+                    // eslint-disable-next-line no-new
+                    new IgnoredPaths({ ignore: true, cwd: getFixturePath("broken-package-json") });
+                } catch (error) {
+                    assert.strictEqual(error.messageTemplate, "failed-to-read-json");
+                    throw error;
+                }
+            });
+        });
+
         it("should not use package.json's eslintIgnore files if specified .eslintignore file", () => {
             const ignoredPaths = new IgnoredPaths({ ignore: true, cwd: getFixturePath() });
 
diff --git a/tests/lib/rules/array-element-newline.js b/tests/lib/rules/array-element-newline.js
index f652105fc..c9ddd1605 100644
--- a/tests/lib/rules/array-element-newline.js
+++ b/tests/lib/rules/array-element-newline.js
@@ -53,7 +53,7 @@ ruleTester.run("array-element-newline", rule, {
         { code: "var foo = [// any comment \n1,\n2];", options: ["always"] },
         { code: "var foo = [1,\n2 // any comment\n];", options: ["always"] },
         { code: "var foo = [1,\n2,\n3];", options: ["always"] },
-        { code: "var foo = [\nfunction foo() {\ndosomething();\n},\nfunction bar() {\nosomething();\n}\n];", options: ["always"] },
+        { code: "var foo = [\nfunction foo() {\ndosomething();\n},\nfunction bar() {\ndosomething();\n}\n];", options: ["always"] },
 
         // "never"
         { code: "var foo = [];", options: ["never"] },
@@ -66,6 +66,23 @@ ruleTester.run("array-element-newline", rule, {
         { code: "var foo = [1, (\n2\n), 3];", options: ["never"] },
         { code: "var foo = [\nfunction foo() {\ndosomething();\n}, function bar() {\ndosomething();\n}\n];", options: ["never"] },
 
+        // "consistent"
+        { code: "var foo = [];", options: ["consistent"] },
+        { code: "var foo = [1];", options: ["consistent"] },
+        { code: "var foo = [1, 2];", options: ["consistent"] },
+        { code: "var foo = [1,\n2];", options: ["consistent"] },
+        { code: "var foo = [1, 2, 3];", options: ["consistent"] },
+        { code: "var foo = [1,\n2,\n3];", options: ["consistent"] },
+        { code: "var foo = [1,\n2,\n,\n3];", options: ["consistent"] },
+        { code: "var foo = [1, // any comment\n2];", options: ["consistent"] },
+        { code: "var foo = [/* any comment */ 1, 2];", options: ["consistent"] },
+        { code: "var foo = [1, (\n2\n), 3];", options: ["consistent"] },
+        { code: "var foo = [1,\n(2)\n, 3];", options: ["consistent"] },
+        { code: "var foo = [\nfunction foo() {\ndosomething();\n},\nfunction bar() {\ndosomething();\n}\n];", options: ["consistent"] },
+        { code: "var foo = [\nfunction foo() {\ndosomething();\n}, function bar() {\ndosomething();\n}\n];", options: ["consistent"] },
+        { code: "var foo = [\nfunction foo() {\ndosomething();\n},\nfunction bar() {\ndosomething();\n},\nfunction bar() {\ndosomething();\n}];", options: ["consistent"] },
+        { code: "var foo = [\nfunction foo() {\ndosomething();\n}, function bar() {\ndosomething();\n}, function bar() {\ndosomething();\n}];", options: ["consistent"] },
+
         // { multiline: true }
         { code: "var foo = [];", options: [{ multiline: true }] },
         { code: "var foo = [1];", options: [{ multiline: true }] },
@@ -450,6 +467,88 @@ ruleTester.run("array-element-newline", rule, {
             ]
         },
 
+        // "consistent"
+        {
+            code: "var foo = [1,\n2, 3];",
+            output: "var foo = [1,\n2,\n3];",
+            options: ["consistent"],
+            errors: [
+                {
+                    messageId: "missingLineBreak",
+                    line: 2,
+                    column: 3,
+                    endLine: 2,
+                    endColumn: 4
+                }
+            ]
+        },
+        {
+            code: "var foo = [1, 2,\n3];",
+            output: "var foo = [1,\n2,\n3];",
+            options: ["consistent"],
+            errors: [
+                {
+                    messageId: "missingLineBreak",
+                    line: 1,
+                    column: 14,
+                    endLine: 1,
+                    endColumn: 15
+                }
+            ]
+        },
+        {
+            code: "var foo = [1,\n(\n2), 3];",
+            output: "var foo = [1,\n(\n2),\n3];",
+            options: ["consistent"],
+            errors: [
+                {
+                    messageId: "missingLineBreak",
+                    line: 3,
+                    column: 4,
+                    endLine: 3,
+                    endColumn: 5
+                }
+            ]
+        },
+        {
+            code: "var foo = [1,        \t      (\n2\n),\n3];",
+            output: "var foo = [1,\n(\n2\n),\n3];",
+            options: ["consistent"],
+            errors: [
+                {
+                    messageId: "missingLineBreak",
+                    line: 1,
+                    column: 14,
+                    endLine: 1,
+                    endColumn: 29
+                }
+            ]
+        },
+        {
+            code: "var foo = [1, /* any comment */(2),\n3];",
+            output: "var foo = [1, /* any comment */\n(2),\n3];",
+            options: ["consistent"],
+            errors: [
+                {
+                    messageId: "missingLineBreak",
+                    line: 1,
+                    column: 32
+                }
+            ]
+        },
+        {
+            code: "var foo = [\nfunction foo() {\ndosomething();\n},function bar() {\ndosomething();\n},\nfunction bar() {\ndosomething();\n}];",
+            output: "var foo = [\nfunction foo() {\ndosomething();\n},\nfunction bar() {\ndosomething();\n},\nfunction bar() {\ndosomething();\n}];",
+            options: ["consistent"],
+            errors: [
+                {
+                    messageId: "missingLineBreak",
+                    line: 4,
+                    column: 3
+                }
+            ]
+        },
+
         // { multiline: true }
         {
             code: "var foo = [1,\n2, 3];",
diff --git a/tests/lib/rules/no-extra-parens.js b/tests/lib/rules/no-extra-parens.js
index 1738b1a66..b3481d06a 100644
--- a/tests/lib/rules/no-extra-parens.js
+++ b/tests/lib/rules/no-extra-parens.js
@@ -288,6 +288,13 @@ ruleTester.run("no-extra-parens", rule, {
             "    );",
             "}"
         ].join("\n"),
+        [
+            "function a() {",
+            "    return (",
+            "        <></>",
+            "    );",
+            "}"
+        ].join("\n"),
         [
             "throw (",
             "    a",
@@ -321,6 +328,14 @@ ruleTester.run("no-extra-parens", rule, {
 
         // ["all", { ignoreJSX: "all" }]
         { code: "const Component = (<div />)", options: ["all", { ignoreJSX: "all" }] },
+        {
+            code: [
+                "const Component = (<>",
+                "  <p />",
+                "</>);"
+            ].join("\n"),
+            options: ["all", { ignoreJSX: "all" }]
+        },
         {
             code: [
                 "const Component = (<div>",
@@ -663,6 +678,19 @@ ruleTester.run("no-extra-parens", rule, {
             "    );",
             "}"
         ].join("\n"), "JSXElement", null),
+        invalid([
+            "function a() {",
+            "    return ((",
+            "       <></>",
+            "    ));",
+            "}"
+        ].join("\n"), [
+            "function a() {",
+            "    return (",
+            "       <></>",
+            "    );",
+            "}"
+        ].join("\n"), "JSXFragment", null),
         invalid("throw (a);", "throw a;", "Identifier"),
         invalid([
             "throw ((",
@@ -884,6 +912,13 @@ ruleTester.run("no-extra-parens", rule, {
         ].join("\n"), "const Component = \n  <div />\n;", "JSXElement", 1, {
             options: ["all", { ignoreJSX: "multi-line" }]
         }),
+        invalid([
+            "const Component = (",
+            "  <></>",
+            ");"
+        ].join("\n"), "const Component = \n  <></>\n;", "JSXFragment", 1, {
+            options: ["all", { ignoreJSX: "multi-line" }]
+        }),
 
         // ["all", { ignoreJSX: "single-line" }]
         invalid([
diff --git a/tests/lib/rules/no-useless-escape.js b/tests/lib/rules/no-useless-escape.js
index b22309956..636149635 100644
--- a/tests/lib/rules/no-useless-escape.js
+++ b/tests/lib/rules/no-useless-escape.js
@@ -50,6 +50,8 @@ ruleTester.run("no-useless-escape", rule, {
         { code: "<div> Testing: \\ </div>", parserOptions: { ecmaFeatures: { jsx: true } } },
         { code: "<div> Testing: &#x5C </div>", parserOptions: { ecmaFeatures: { jsx: true } } },
         { code: "<foo attr='\\d'></foo>", parserOptions: { ecmaFeatures: { jsx: true } } },
+        { code: "<> Testing: \\ </>", parserOptions: { ecmaFeatures: { jsx: true } } },
+        { code: "<> Testing: &#x5C </>", parserOptions: { ecmaFeatures: { jsx: true } } },
         { code: "var foo = `\\x123`", parserOptions: { ecmaVersion: 6 } },
         { code: "var foo = `\\u00a9`", parserOptions: { ecmaVersion: 6 } },
         { code: "var foo = `xs\\u2111`", parserOptions: { ecmaVersion: 6 } },
diff --git a/tests/lib/rules/prefer-const.js b/tests/lib/rules/prefer-const.js
index 85916648f..59865ec86 100644
--- a/tests/lib/rules/prefer-const.js
+++ b/tests/lib/rules/prefer-const.js
@@ -69,6 +69,22 @@ ruleTester.run("prefer-const", rule, {
         "/*exported a*/ let a; function init() { a = foo(); }",
         "/*exported a*/ let a = 1",
         "let a; if (true) a = 0; foo(a);",
+        `
+        (function (a) {
+            let b;
+            ({ a, b } = obj);
+        })();
+        `,
+        `
+        (function (a) {
+            let b;
+            ([ a, b ] = obj);
+        })();
+        `,
+        "var a; { var b; ({ a, b } = obj); }",
+        "let a; { let b; ({ a, b } = obj); }",
+        "var a; { var b; ([ a, b ] = obj); }",
+        "let a; { let b; ([ a, b ] = obj); }",
 
         /*
          * The assignment is located in a different scope.
diff --git a/tests/lib/rules/prefer-object-spread.js b/tests/lib/rules/prefer-object-spread.js
index 75b422f8b..14bfa2f1e 100644
--- a/tests/lib/rules/prefer-object-spread.js
+++ b/tests/lib/rules/prefer-object-spread.js
@@ -14,7 +14,8 @@ const parserOptions = {
     ecmaVersion: 2018,
     ecmaFeatures: {
         experimentalObjectRestSpread: true
-    }
+    },
+    sourceType: "module"
 };
 
 const ruleTester = new RuleTester({ parserOptions });
@@ -45,6 +46,22 @@ ruleTester.run("prefer-object-spread", rule, {
         `
         Object = {};
         Object.assign({ foo: 'bar' });
+        `,
+        `
+        const Object = require('foo');
+        Object.assign({ foo: 'bar' });
+        `,
+        `
+        import Object from 'foo';
+        Object.assign({ foo: 'bar' });
+        `,
+        `
+        import { Something as Object } from 'foo';
+        Object.assign({ foo: 'bar' });
+        `,
+        `
+        import { Object, Array } from 'globals';
+        Object.assign({ foo: 'bar' });
         `
     ],
 
@@ -291,6 +308,9 @@ ruleTester.run("prefer-object-spread", rule, {
                 baz: "cats"
                 --> weird
 }`,
+            parserOptions: {
+                sourceType: "script"
+            },
             errors: [
                 {
                     messageId: "useSpreadMessage",
@@ -572,6 +592,114 @@ ruleTester.run("prefer-object-spread", rule, {
                     column: 30
                 }
             ]
+        },
+        {
+            code: `
+                import Foo from 'foo';
+                Object.assign({ foo: Foo });
+            `,
+            output: `
+                import Foo from 'foo';
+                ({ foo: Foo });
+            `,
+            errors: [
+                {
+                    messageId: "useLiteralMessage",
+                    type: "CallExpression",
+                    line: 3,
+                    column: 17
+                }
+            ]
+        },
+        {
+            code: `
+                import Foo from 'foo';
+                Object.assign({}, Foo);
+            `,
+            output: `
+                import Foo from 'foo';
+                ({...Foo});
+            `,
+            errors: [
+                {
+                    messageId: "useSpreadMessage",
+                    type: "CallExpression",
+                    line: 3,
+                    column: 17
+                }
+            ]
+        },
+        {
+            code: `
+                const Foo = require('foo');
+                Object.assign({ foo: Foo });
+            `,
+            output: `
+                const Foo = require('foo');
+                ({ foo: Foo });
+            `,
+            errors: [
+                {
+                    messageId: "useLiteralMessage",
+                    type: "CallExpression",
+                    line: 3,
+                    column: 17
+                }
+            ]
+        },
+        {
+            code: `
+                import { Something as somethingelse } from 'foo';
+                Object.assign({}, somethingelse);
+            `,
+            output: `
+                import { Something as somethingelse } from 'foo';
+                ({...somethingelse});
+            `,
+            errors: [
+                {
+                    messageId: "useSpreadMessage",
+                    type: "CallExpression",
+                    line: 3,
+                    column: 17
+                }
+            ]
+        },
+        {
+            code: `
+                import { foo } from 'foo';
+                Object.assign({ foo: Foo });
+            `,
+            output: `
+                import { foo } from 'foo';
+                ({ foo: Foo });
+            `,
+            errors: [
+                {
+                    messageId: "useLiteralMessage",
+                    type: "CallExpression",
+                    line: 3,
+                    column: 17
+                }
+            ]
+        },
+        {
+            code: `
+                const Foo = require('foo');
+                Object.assign({}, Foo);
+            `,
+            output: `
+                const Foo = require('foo');
+                ({...Foo});
+            `,
+            errors: [
+                {
+                    messageId: "useSpreadMessage",
+                    type: "CallExpression",
+                    line: 3,
+                    column: 17
+                }
+            ]
         }
     ]
 });
diff --git a/tests/lib/rules/quotes.js b/tests/lib/rules/quotes.js
index b6ea51362..812ea737b 100644
--- a/tests/lib/rules/quotes.js
+++ b/tests/lib/rules/quotes.js
@@ -23,6 +23,10 @@ ruleTester.run("quotes", rule, {
         { code: "var foo = 1;", options: ["double"] },
         { code: "var foo = \"'\";", options: ["single", { avoidEscape: true }] },
         { code: "var foo = '\"';", options: ["double", { avoidEscape: true }] },
+        { code: "var foo = <>Hello world</>;", options: ["single"], parserOptions: { ecmaVersion: 6, ecmaFeatures: { jsx: true } } },
+        { code: "var foo = <>Hello world</>;", options: ["double"], parserOptions: { ecmaVersion: 6, ecmaFeatures: { jsx: true } } },
+        { code: "var foo = <>Hello world</>;", options: ["double", { avoidEscape: true }], parserOptions: { ecmaVersion: 6, ecmaFeatures: { jsx: true } } },
+        { code: "var foo = <>Hello world</>;", options: ["backtick"], parserOptions: { ecmaVersion: 6, ecmaFeatures: { jsx: true } } },
         { code: "var foo = <div>Hello world</div>;", options: ["single"], parserOptions: { ecmaVersion: 6, ecmaFeatures: { jsx: true } } },
         { code: "var foo = <div id=\"foo\"></div>;", options: ["single"], parserOptions: { ecmaVersion: 6, ecmaFeatures: { jsx: true } } },
         { code: "var foo = <div>Hello world</div>;", options: ["double"], parserOptions: { ecmaVersion: 6, ecmaFeatures: { jsx: true } } },
diff --git a/tests/lib/testers/no-test-runners.js b/tests/lib/testers/no-test-runners.js
index 34d8a2a09..a14ac3bab 100644
--- a/tests/lib/testers/no-test-runners.js
+++ b/tests/lib/testers/no-test-runners.js
@@ -6,8 +6,8 @@
 
 /* global describe, it */
 /* eslint-disable no-global-assign*/
-const assert = require("assert"),
-    RuleTester = require("../../../lib/testers/rule-tester");
+const assert = require("assert");
+const RuleTester = require("../../../lib/testers/rule-tester");
 const tmpIt = it;
 const tmpDescribe = describe;
 
@@ -26,7 +26,7 @@ try {
                 { code: "var foo = bar;", output: "invalid output", errors: 1 }
             ]
         });
-    }, /Output is incorrect\. \(' foo = bar;' === 'invalid output'\)$/);
+    }, new assert.AssertionError({ actual: " foo = bar;", expected: "invalid output", operator: "===" }).message);
 } finally {
     it = tmpIt;
     describe = tmpDescribe;
diff --git a/tests/lib/util/npm-util.js b/tests/lib/util/npm-util.js
index bdf34666a..48b0b0c97 100644
--- a/tests/lib/util/npm-util.js
+++ b/tests/lib/util/npm-util.js
@@ -70,17 +70,18 @@ describe("npmUtil", () => {
         });
 
         it("should throw with message when parsing invalid package.json", () => {
-            const logInfo = sandbox.stub(log, "info");
-
             mockFs({
                 "package.json": "{ \"not: \"valid json\" }"
             });
 
-            const fn = npmUtil.checkDevDeps.bind(null, ["some-package"]);
-
-            assert.throws(fn, "SyntaxError: Unexpected token v");
-            assert(logInfo.calledOnce);
-            assert.strictEqual(logInfo.firstCall.args[0], "Could not read package.json file. Please check that the file contains valid JSON.");
+            assert.throws(() => {
+                try {
+                    npmUtil.checkDevDeps(["some-package"]);
+                } catch (error) {
+                    assert.strictEqual(error.messageTemplate, "failed-to-read-json");
+                    throw error;
+                }
+            }, "SyntaxError: Unexpected token v");
         });
     });
 
@@ -132,18 +133,18 @@ describe("npmUtil", () => {
         });
 
         it("should throw with message when parsing invalid package.json", () => {
-            const logInfo = sandbox.stub(log, "info");
-
             mockFs({
                 "package.json": "{ \"not: \"valid json\" }"
             });
 
-            const fn = npmUtil.checkDevDeps.bind(null, ["some-package"]);
-
-            assert.throws(fn, "SyntaxError: Unexpected token v");
-            assert(logInfo.calledOnce);
-            assert.strictEqual(logInfo.firstCall.args[0], "Could not read package.json file. Please check that the file contains valid JSON.");
-            logInfo.restore();
+            assert.throws(() => {
+                try {
+                    npmUtil.checkDeps(["some-package"]);
+                } catch (error) {
+                    assert.strictEqual(error.messageTemplate, "failed-to-read-json");
+                    throw error;
+                }
+            }, "SyntaxError: Unexpected token v");
         });
     });