Repository: eslint/eslint
Pull request #10410 (2018-05-28 16:03:50)

Upgrade: Consume espree@4.0.0-alpha.1
<!--
    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).
-->

**What is the purpose of this pull request? (put an "X" next to item)**

[ ] Documentation update
[ ] Bug fix ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/bug-report.md))
[ ] New rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-proposal.md))
[ ] Changes an existing rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-change-proposal.md))
[ ] Add autofixing to a rule
[ ] Add a CLI option
[ ] Add something to the core
[x] Other, please explain: Upgrade to latest (alpha) espree

<!--
    If the item you've checked above has a template, please paste the template questions below and answer them. (If this pull request is addressing an issue, you can just paste a link to the issue here instead.)
-->

<!--
    Please ensure your pull request is ready:

    - Read the pull request guide (https://eslint.org/docs/developer-guide/contributing/pull-requests)
    - Include tests for this change
    - Update documentation for this change (if appropriate)
-->

<!--
    The following is required for all pull requests:
-->

**What changes did you make? (Give an overview)**

Upgraded espree to latest alpha.

**Is there anything you'd like reviewers to focus on?**

Not really.


Patch:
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 ab06909d8..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;
     }
@@ -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/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/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 e3bf2344b..0d6b322e7 100644
--- a/package.json
+++ b/package.json
@@ -42,7 +42,7 @@
     "doctrine": "^2.1.0",
     "eslint-scope": "^4.0.0-alpha.0",
     "eslint-visitor-keys": "^1.0.0",
-    "espree": "^4.0.0-alpha.0",
+    "espree": "^4.0.0-alpha.1",
     "esquery": "^1.0.1",
     "esutils": "^2.0.2",
     "file-entry-cache": "^2.0.0",


Test patch:
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/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/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");
         });
     });