Repository: eslint/eslint
Pull request #11391 (2019-02-14 07:16:32)

Docs: fix correct code for "classes": "never"
<!--
    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)**

[X] Documentation update

<!--
    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)**

Examples of **correct** code for this rule when configured `{ "functions": "never", "keywords": "always", "classes": "never" }`:

Replaced
```js
class Foo {
  constructor(){}
}
```
with
```js
class Foo{
  constructor(){}
}
```


**Is there anything you'd like reviewers to focus on?**

No.



Patch:
diff --git a/README.md b/README.md
index 5c4267dfe..e0ee6a74f 100644
--- a/README.md
+++ b/README.md
@@ -266,7 +266,8 @@ The following companies, organizations, and individuals support ESLint's ongoing
 <!-- NOTE: This section is autogenerated. Do not manually edit.-->
 <!--sponsorsstart-->
 <h3>Gold Sponsors</h3>
-<p><a href="https://code.facebook.com/projects/"><img src="https://images.opencollective.com/proxy/images/?src=https%3A%2F%2Fres.cloudinary.com%2Fopencollective%2Fimage%2Fupload%2Fv1508519428%2FS9gk78AS_400x400_fulq2l.jpg&height=96" alt="Facebook Open Source" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/proxy/images/?src=https%3A%2F%2Fopencollective-production.s3-us-west-1.amazonaws.com%2F098e3bd0-4d57-11e8-9324-0f6cc1f92bf1.png&height=96" alt="Airbnb" height="96"></a></p><h3>Bronze Sponsors</h3>
+<p><a href="https://code.facebook.com/projects/"><img src="https://images.opencollective.com/proxy/images/?src=https%3A%2F%2Fres.cloudinary.com%2Fopencollective%2Fimage%2Fupload%2Fv1508519428%2FS9gk78AS_400x400_fulq2l.jpg&height=96" alt="Facebook Open Source" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/proxy/images/?src=https%3A%2F%2Fopencollective-production.s3-us-west-1.amazonaws.com%2F098e3bd0-4d57-11e8-9324-0f6cc1f92bf1.png&height=96" alt="Airbnb" height="96"></a></p><h3>Silver Sponsors</h3>
+<p><a href="https://www.ampproject.org/"><img src="https://images.opencollective.com/proxy/images/?src=https%3A%2F%2Fopencollective-production.s3-us-west-1.amazonaws.com%2F68ed8b70-ebf2-11e6-9958-cb7e79408c56.png&height=96" alt="AMP Project" height="64"></a></p><h3>Bronze Sponsors</h3>
 <p><a href="http://faithlife.com/ref/about"><img src="https://images.opencollective.com/proxy/images/?src=https%3A%2F%2Flogo.clearbit.com%2Ffaithlife.com&height=96" alt="Faithlife" height="32"></a></p>
 <!--sponsorsend-->
 
diff --git a/docs/rules/object-curly-spacing.md b/docs/rules/object-curly-spacing.md
index 8f88fc260..e7b054cdd 100644
--- a/docs/rules/object-curly-spacing.md
+++ b/docs/rules/object-curly-spacing.md
@@ -20,7 +20,7 @@ export { foo };
 
 ## Rule Details
 
-This rule enforce consistent spacing inside braces of object literals, destructuring assignments, and import/export specifiers.
+This rule enforces consistent spacing inside braces of object literals, destructuring assignments, and import/export specifiers.
 
 ## Options
 
diff --git a/docs/rules/prefer-object-spread.md b/docs/rules/prefer-object-spread.md
index b50e39716..95a646068 100644
--- a/docs/rules/prefer-object-spread.md
+++ b/docs/rules/prefer-object-spread.md
@@ -2,7 +2,7 @@
 
 When Object.assign is called using an object literal as the first argument, this rule requires using the object spread syntax instead. This rule also warns on cases where an `Object.assign` call is made using a single argument that is an object literal, in this case, the `Object.assign` call is not needed.
 
-Object spread is a declarative alternative which may perform better than the more dynamic, imperative `Object.assign`.
+Introduced in ES2018, object spread is a declarative alternative which may perform better than the more dynamic, imperative `Object.assign`.
 
 ## Rule Details
 
@@ -46,4 +46,4 @@ Object.assign(foo, { ...baz });
 
 ## When Not To Use It
 
-When object spread is not available in your codebase.
+This rule should not be used unless ES2018 is supported in your codebase.
diff --git a/docs/rules/semi.md b/docs/rules/semi.md
index c49b08faa..e345b0006 100644
--- a/docs/rules/semi.md
+++ b/docs/rules/semi.md
@@ -31,7 +31,7 @@ return;
 
 Effectively, a semicolon is inserted after the `return` statement, causing the code below it (a labeled literal inside a block) to be unreachable. This rule and the [no-unreachable](no-unreachable.md) rule will protect your code from such cases.
 
-On the other side of the argument are those who says that since semicolons are inserted automatically, they are optional and do not need to be inserted manually. However, the ASI mechanism can also be tricky to people who don't use semicolons. For example, consider this code:
+On the other side of the argument are those who say that since semicolons are inserted automatically, they are optional and do not need to be inserted manually. However, the ASI mechanism can also be tricky to people who don't use semicolons. For example, consider this code:
 
 ```js
 var globalCounter = { }
diff --git a/docs/rules/space-before-blocks.md b/docs/rules/space-before-blocks.md
index ab4c2a2b4..0b188f260 100644
--- a/docs/rules/space-before-blocks.md
+++ b/docs/rules/space-before-blocks.md
@@ -143,7 +143,7 @@ describe(function(){
   // ...
 });
 
-class Foo {
+class Foo{
   constructor(){}
 }
 ```
diff --git a/lib/config/config-initializer.js b/lib/config/config-initializer.js
index a6791ba85..b8126d473 100644
--- a/lib/config/config-initializer.js
+++ b/lib/config/config-initializer.js
@@ -3,6 +3,7 @@
  * @author Ilya Volodin
  */
 
+
 "use strict";
 
 //------------------------------------------------------------------------------
@@ -28,6 +29,8 @@ const debug = require("debug")("eslint:config-initializer");
 // Private
 //------------------------------------------------------------------------------
 
+const DEFAULT_ECMA_VERSION = 2018;
+
 /* istanbul ignore next: hard to test fs function */
 /**
  * Create .eslintrc file in the current working directory
@@ -239,43 +242,65 @@ function configureRules(answers, config) {
  * @returns {Object} config object
  */
 function processAnswers(answers) {
-    let config = { rules: {}, env: {}, parserOptions: {} };
+    let config = {
+        rules: {},
+        env: {},
+        parserOptions: {},
+        extends: []
+    };
 
-    config.parserOptions.ecmaVersion = answers.ecmaVersion;
-    if (answers.ecmaVersion >= 2015) {
-        if (answers.modules) {
-            config.parserOptions.sourceType = "module";
-        }
-        config.env.es6 = true;
-    }
+    // set the latest ECMAScript version
+    config.parserOptions.ecmaVersion = DEFAULT_ECMA_VERSION;
+    config.env.es6 = true;
+    config.globals = {
+        Atomics: "readonly",
+        SharedArrayBuffer: "readonly"
+    };
 
-    if (answers.commonjs) {
+    // set the module type
+    if (answers.moduleType === "esm") {
+        config.parserOptions.sourceType = "module";
+    } else if (answers.moduleType === "commonjs") {
         config.env.commonjs = true;
     }
+
+    // add in browser and node environments if necessary
     answers.env.forEach(env => {
         config.env[env] = true;
     });
-    if (answers.jsx) {
-        config.parserOptions = config.parserOptions || {};
-        config.parserOptions.ecmaFeatures = config.parserOptions.ecmaFeatures || {};
-        config.parserOptions.ecmaFeatures.jsx = true;
-        if (answers.react) {
-            config.plugins = ["react"];
-            config.parserOptions.ecmaVersion = 2018;
-        }
+
+    // add in library information
+    if (answers.framework === "react") {
+        config.parserOptions.ecmaFeatures = {
+            jsx: true
+        };
+        config.plugins = ["react"];
+    } else if (answers.framework === "vue") {
+        config.plugins = ["vue"];
+        config.extends.push("plugin:vue/essential");
     }
 
-    if (answers.source === "prompt") {
-        config.extends = "eslint:recommended";
-        config.rules.indent = ["error", answers.indent];
-        config.rules.quotes = ["error", answers.quotes];
-        config.rules["linebreak-style"] = ["error", answers.linebreak];
-        config.rules.semi = ["error", answers.semi ? "always" : "never"];
+    // setup rules based on problems/style enforcement preferences
+    if (answers.purpose === "problems") {
+        config.extends.unshift("eslint:recommended");
+    } else if (answers.purpose === "style") {
+        if (answers.source === "prompt") {
+            config.extends.unshift("eslint:recommended");
+            config.rules.indent = ["error", answers.indent];
+            config.rules.quotes = ["error", answers.quotes];
+            config.rules["linebreak-style"] = ["error", answers.linebreak];
+            config.rules.semi = ["error", answers.semi ? "always" : "never"];
+        } else if (answers.source === "auto") {
+            config = configureRules(answers, config);
+            config = autoconfig.extendFromRecommended(config);
+        }
     }
 
-    if (answers.source === "auto") {
-        config = configureRules(answers, config);
-        config = autoconfig.extendFromRecommended(config);
+    // normalize extends
+    if (config.extends.length === 0) {
+        delete config.extends;
+    } else if (config.extends.length === 1) {
+        config.extends = config.extends[0];
     }
 
     ConfigOps.normalizeToStrings(config);
@@ -324,7 +349,7 @@ function getLocalESLintVersion() {
  * @returns {string} The shareable config name.
  */
 function getStyleGuideName(answers) {
-    if (answers.styleguide === "airbnb" && !answers.airbnbReact) {
+    if (answers.styleguide === "airbnb" && answers.framework !== "react") {
         return "airbnb-base";
     }
     return answers.styleguide;
@@ -417,16 +442,62 @@ function askInstallModules(modules, packageJsonExists) {
 function promptUser() {
 
     return inquirer.prompt([
+        {
+            type: "list",
+            name: "purpose",
+            message: "How would you like to use ESLint?",
+            default: "problems",
+            choices: [
+                { name: "To check syntax only", value: "syntax" },
+                { name: "To check syntax and find problems", value: "problems" },
+                { name: "To check syntax, find problems, and enforce code style", value: "style" }
+            ]
+        },
+        {
+            type: "list",
+            name: "moduleType",
+            message: "What type of modules does your project use?",
+            default: "esm",
+            choices: [
+                { name: "JavaScript modules (import/export)", value: "esm" },
+                { name: "CommonJS (require/exports)", value: "commonjs" },
+                { name: "None of these", value: "none" }
+            ]
+        },
+        {
+            type: "list",
+            name: "framework",
+            message: "Which framework does your project use?",
+            default: "react",
+            choices: [
+                { name: "React", value: "react" },
+                { name: "Vue.js", value: "vue" },
+                { name: "None of these", value: "none" }
+            ]
+        },
+        {
+            type: "checkbox",
+            name: "env",
+            message: "Where does your code run?",
+            default: ["browser"],
+            choices: [
+                { name: "Browser", value: "browser" },
+                { name: "Node", value: "node" }
+            ]
+        },
         {
             type: "list",
             name: "source",
-            message: "How would you like to configure ESLint?",
-            default: "prompt",
+            message: "How would you like to define a style for your project?",
+            default: "guide",
             choices: [
                 { name: "Use a popular style guide", value: "guide" },
                 { name: "Answer questions about your style", value: "prompt" },
                 { name: "Inspect your JavaScript file(s)", value: "auto" }
-            ]
+            ],
+            when(answers) {
+                return answers.purpose === "style";
+            }
         },
         {
             type: "list",
@@ -442,15 +513,6 @@ function promptUser() {
                 return answers.source === "guide" && answers.packageJsonExists;
             }
         },
-        {
-            type: "confirm",
-            name: "airbnbReact",
-            message: "Do you use React?",
-            default: false,
-            when(answers) {
-                return answers.styleguide === "airbnb";
-            }
-        },
         {
             type: "input",
             name: "patterns",
@@ -470,10 +532,7 @@ function promptUser() {
             name: "format",
             message: "What format do you want your config file to be in?",
             default: "JavaScript",
-            choices: ["JavaScript", "YAML", "JSON"],
-            when(answers) {
-                return ((answers.source === "guide" && answers.packageJsonExists) || answers.source === "auto");
-            }
+            choices: ["JavaScript", "YAML", "JSON"]
         },
         {
             type: "confirm",
@@ -492,6 +551,15 @@ function promptUser() {
         }
     ]).then(earlyAnswers => {
 
+        // early exit if no style guide is necessary
+        if (earlyAnswers.purpose !== "style") {
+            const config = processAnswers(earlyAnswers);
+            const modules = getModulesList(config);
+
+            return askInstallModules(modules, earlyAnswers.packageJsonExists)
+                .then(() => writeFile(config, earlyAnswers.format));
+        }
+
         // early exit if you are using a style guide
         if (earlyAnswers.source === "guide") {
             if (!earlyAnswers.packageJsonExists) {
@@ -501,130 +569,69 @@ function promptUser() {
             if (earlyAnswers.installESLint === false && !semver.satisfies(earlyAnswers.localESLintVersion, earlyAnswers.requiredESLintVersionRange)) {
                 log.info(`Note: it might not work since ESLint's version is mismatched with the ${earlyAnswers.styleguide} config.`);
             }
-            if (earlyAnswers.styleguide === "airbnb" && !earlyAnswers.airbnbReact) {
+            if (earlyAnswers.styleguide === "airbnb" && earlyAnswers.framework !== "react") {
                 earlyAnswers.styleguide = "airbnb-base";
             }
 
-            const config = getConfigForStyleGuide(earlyAnswers.styleguide);
+            const config = ConfigOps.merge(processAnswers(earlyAnswers), getConfigForStyleGuide(earlyAnswers.styleguide));
             const modules = getModulesList(config);
 
             return askInstallModules(modules, earlyAnswers.packageJsonExists)
                 .then(() => writeFile(config, earlyAnswers.format));
+
         }
 
-        // continue with the questions otherwise...
+        if (earlyAnswers.source === "auto") {
+            const combinedAnswers = Object.assign({}, earlyAnswers);
+            const config = processAnswers(combinedAnswers);
+            const modules = getModulesList(config);
+
+            return askInstallModules(modules).then(() => writeFile(config, earlyAnswers.format));
+        }
+
+        // continue with the style questions otherwise...
         return inquirer.prompt([
             {
                 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
+                name: "indent",
+                message: "What style of indentation do you use?",
+                default: "tab",
+                choices: [{ name: "Tabs", value: "tab" }, { name: "Spaces", value: 4 }]
             },
             {
-                type: "confirm",
-                name: "modules",
-                message: "Are you using ES6 modules?",
-                default: false,
-                when(answers) {
-                    return answers.ecmaVersion >= 2015;
-                }
-            },
-            {
-                type: "checkbox",
-                name: "env",
-                message: "Where will your code run?",
-                default: ["browser"],
-                choices: [{ name: "Browser", value: "browser" }, { name: "Node", value: "node" }]
+                type: "list",
+                name: "quotes",
+                message: "What quotes do you use for strings?",
+                default: "double",
+                choices: [{ name: "Double", value: "double" }, { name: "Single", value: "single" }]
             },
             {
-                type: "confirm",
-                name: "commonjs",
-                message: "Do you use CommonJS?",
-                default: false,
-                when(answers) {
-                    return answers.env.some(env => env === "browser");
-                }
+                type: "list",
+                name: "linebreak",
+                message: "What line endings do you use?",
+                default: "unix",
+                choices: [{ name: "Unix", value: "unix" }, { name: "Windows", value: "windows" }]
             },
             {
                 type: "confirm",
-                name: "jsx",
-                message: "Do you use JSX?",
-                default: false
+                name: "semi",
+                message: "Do you require semicolons?",
+                default: true
             },
             {
-                type: "confirm",
-                name: "react",
-                message: "Do you use React?",
-                default: false,
-                when(answers) {
-                    return answers.jsx;
-                }
-            }
-        ]).then(secondAnswers => {
-
-            // early exit if you are using automatic style generation
-            if (earlyAnswers.source === "auto") {
-                const combinedAnswers = Object.assign({}, earlyAnswers, secondAnswers);
-
-                const config = processAnswers(combinedAnswers);
-
-                const modules = getModulesList(config);
-
-                return askInstallModules(modules).then(() => writeFile(config, earlyAnswers.format));
+                type: "list",
+                name: "format",
+                message: "What format do you want your config file to be in?",
+                default: "JavaScript",
+                choices: ["JavaScript", "YAML", "JSON"]
             }
+        ]).then(answers => {
+            const totalAnswers = Object.assign({}, earlyAnswers, answers);
 
-            // continue with the style questions otherwise...
-            return inquirer.prompt([
-                {
-                    type: "list",
-                    name: "indent",
-                    message: "What style of indentation do you use?",
-                    default: "tab",
-                    choices: [{ name: "Tabs", value: "tab" }, { name: "Spaces", value: 4 }]
-                },
-                {
-                    type: "list",
-                    name: "quotes",
-                    message: "What quotes do you use for strings?",
-                    default: "double",
-                    choices: [{ name: "Double", value: "double" }, { name: "Single", value: "single" }]
-                },
-                {
-                    type: "list",
-                    name: "linebreak",
-                    message: "What line endings do you use?",
-                    default: "unix",
-                    choices: [{ name: "Unix", value: "unix" }, { name: "Windows", value: "windows" }]
-                },
-                {
-                    type: "confirm",
-                    name: "semi",
-                    message: "Do you require semicolons?",
-                    default: true
-                },
-                {
-                    type: "list",
-                    name: "format",
-                    message: "What format do you want your config file to be in?",
-                    default: "JavaScript",
-                    choices: ["JavaScript", "YAML", "JSON"]
-                }
-            ]).then(answers => {
-                const totalAnswers = Object.assign({}, earlyAnswers, secondAnswers, answers);
-
-                const config = processAnswers(totalAnswers);
-                const modules = getModulesList(config);
+            const config = processAnswers(totalAnswers);
+            const modules = getModulesList(config);
 
-                return askInstallModules(modules).then(() => writeFile(config, answers.format));
-            });
+            return askInstallModules(modules).then(() => writeFile(config, answers.format));
         });
     });
 }


Test patch:
diff --git a/tests/lib/config/config-initializer.js b/tests/lib/config/config-initializer.js
index 3767fe376..d78651b1b 100644
--- a/tests/lib/config/config-initializer.js
+++ b/tests/lib/config/config-initializer.js
@@ -117,20 +117,17 @@ describe("configInitializer", () => {
 
             beforeEach(() => {
                 answers = {
+                    purpose: "style",
                     source: "prompt",
                     extendDefault: true,
                     indent: 2,
                     quotes: "single",
                     linebreak: "unix",
                     semi: true,
-                    ecmaVersion: 2015,
-                    modules: true,
+                    moduleType: "esm",
                     es6Globals: true,
                     env: ["browser"],
-                    jsx: false,
-                    react: false,
-                    format: "JSON",
-                    commonjs: false
+                    format: "JSON"
                 };
             });
 
@@ -142,7 +139,9 @@ 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.globals.Atomics, "readonly");
+                assert.strictEqual(config.globals.SharedArrayBuffer, "readonly");
+                assert.strictEqual(config.parserOptions.ecmaVersion, 2018);
                 assert.strictEqual(config.parserOptions.sourceType, "module");
                 assert.strictEqual(config.env.browser, true);
                 assert.strictEqual(config.extends, "eslint:recommended");
@@ -155,16 +154,8 @@ describe("configInitializer", () => {
                 assert.deepStrictEqual(config.rules.semi, ["error", "never"]);
             });
 
-            it("should enable jsx flag", () => {
-                answers.jsx = true;
-                const config = init.processAnswers(answers);
-
-                assert.strictEqual(config.parserOptions.ecmaFeatures.jsx, true);
-            });
-
             it("should enable react plugin", () => {
-                answers.jsx = true;
-                answers.react = true;
+                answers.framework = "react";
                 const config = init.processAnswers(answers);
 
                 assert.strictEqual(config.parserOptions.ecmaFeatures.jsx, true);
@@ -172,12 +163,13 @@ describe("configInitializer", () => {
                 assert.deepStrictEqual(config.plugins, ["react"]);
             });
 
-            it("should not enable es6", () => {
-                answers.ecmaVersion = 5;
+            it("should enable vue plugin", () => {
+                answers.framework = "vue";
                 const config = init.processAnswers(answers);
 
-                assert.strictEqual(config.parserOptions.ecmaVersion, 5);
-                assert.isUndefined(config.env.es6);
+                assert.strictEqual(config.parserOptions.ecmaVersion, 2018);
+                assert.deepStrictEqual(config.plugins, ["vue"]);
+                assert.deepStrictEqual(config.extends, ["eslint:recommended", "plugin:vue/essential"]);
             });
 
             it("should extend eslint:recommended", () => {
@@ -193,7 +185,7 @@ describe("configInitializer", () => {
             });
 
             it("should use commonjs when set", () => {
-                answers.commonjs = true;
+                answers.moduleType = "commonjs";
                 const config = init.processAnswers(answers);
 
                 assert.isTrue(config.env.commonjs);
@@ -338,14 +330,11 @@ describe("configInitializer", () => {
                 ].join(" ");
 
                 answers = {
+                    purpose: "style",
                     source: "auto",
                     patterns,
-                    ecmaVersion: 5,
                     env: ["browser"],
-                    jsx: false,
-                    react: false,
-                    format: "JSON",
-                    commonjs: false
+                    format: "JSON"
                 };
 
                 sandbox = sinon.sandbox.create();