Repository: eslint/eslint
Pull request #15609 (2022-02-15 02:35:08)

feat: `--debug` prints time it takes to parse a file
<!--
    Thank you for contributing!

    ESLint adheres to the [JS Foundation Code of Conduct](https://eslint.org/conduct).
-->

#### Prerequisites checklist

- [x] I have read the [contributing guidelines](https://github.com/eslint/eslint/blob/HEAD/CONTRIBUTING.md).

#### What is the purpose of this pull request? (put an "X" next to an item)

<!--
    The following template is intentionally not a markdown checkbox list for the reasons
    explained in https://github.com/eslint/eslint/pull/12848#issuecomment-580302888
-->

[ ] Documentation update
[ ] Bug fix ([template](https://raw.githubusercontent.com/eslint/eslint/HEAD/templates/bug-report.md))
[ ] New rule ([template](https://raw.githubusercontent.com/eslint/eslint/HEAD/templates/rule-proposal.md))
[ ] Changes an existing rule ([template](https://raw.githubusercontent.com/eslint/eslint/HEAD/templates/rule-change-proposal.md))
[ ] Add autofix to a rule
[ ] Add a CLI option
[x] 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.)
-->

<!--
    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)

#### Is there anything you'd like reviewers to focus on?

<!-- markdownlint-disable-file MD004 -->

Closes https://github.com/eslint/eslint/issues/15585

I think this is enough debug output, if parsing takes less <1ms then its cost is negligible anyway.


Patch:
diff --git a/Makefile.js b/Makefile.js
index 83c6d4095..54ef70606 100644
--- a/Makefile.js
+++ b/Makefile.js
@@ -73,7 +73,7 @@ const NODE = "node ", // intentional extra space
     JSON_FILES = find("conf/").filter(fileType("json")),
     MARKDOWNLINT_IGNORED_FILES = fs.readFileSync(path.join(__dirname, ".markdownlintignore"), "utf-8").split("\n"),
     MARKDOWN_FILES_ARRAY = find("docs/").concat(ls(".")).filter(fileType("md")).filter(file => !MARKDOWNLINT_IGNORED_FILES.includes(file)),
-    TEST_FILES = "\"tests/{bin,lib,tools}/**/*.js\"",
+    TEST_FILES = "\"tests/{bin,conf,lib,tools}/**/*.js\"",
     PERF_ESLINTRC = path.join(PERF_TMP_DIR, "eslintrc.yml"),
     PERF_MULTIFILES_TARGET_DIR = path.join(PERF_TMP_DIR, "eslint"),
     PERF_MULTIFILES_TARGETS = `"${PERF_MULTIFILES_TARGET_DIR + path.sep}{lib,tests${path.sep}lib}${path.sep}**${path.sep}*.js"`,
diff --git a/README.md b/README.md
index fe9812dcc..b0ef0d66b 100644
--- a/README.md
+++ b/README.md
@@ -291,7 +291,7 @@ The following companies, organizations, and individuals support ESLint's ongoing
 <!-- NOTE: This section is autogenerated. Do not manually edit.-->
 <!--sponsorsstart-->
 <h3>Platinum Sponsors</h3>
-<p><a href="https://automattic.com"><img src="https://images.opencollective.com/automattic/d0ef3e1/logo.png" alt="Automattic" height="undefined"></a> <a href="https://flux.industries"><img src="https://avatars.githubusercontent.com/u/88303769?u=1af1d13b48676ab5918770999361829fc90847c4&v=4" alt="Flux Industries" height="undefined"></a></p><h3>Gold Sponsors</h3>
+<p><a href="https://automattic.com"><img src="https://images.opencollective.com/automattic/d0ef3e1/logo.png" alt="Automattic" height="undefined"></a></p><h3>Gold Sponsors</h3>
 <p><a href="https://contra.com"><img src="https://images.opencollective.com/contra1/c70f93f/logo.png" alt="Contra" height="96"></a> <a href="https://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" height="96"></a> <a href="https://google.com/chrome"><img src="https://images.opencollective.com/chrome/dc55bd4/logo.png" alt="Chrome's Web Framework & Tools Performance Fund" height="96"></a> <a href="https://www.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301?v=4" alt="American Express" height="96"></a> <a href="https://substack.com/"><img src="https://avatars.githubusercontent.com/u/53023767?v=4" alt="Substack" height="96"></a></p><h3>Silver Sponsors</h3>
 <p><a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a></p><h3>Bronze Sponsors</h3>
 <p><a href="https://launchdarkly.com"><img src="https://images.opencollective.com/launchdarkly/574bb9e/logo.png" alt="launchdarkly" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS Server" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8: free icons, photos, illustrations, and music" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://www.ignitionapp.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Practice Ignition" height="32"></a></p>
diff --git a/docs/rules/no-confusing-arrow.md b/docs/rules/no-confusing-arrow.md
index 3671163ea..f88af8e5d 100644
--- a/docs/rules/no-confusing-arrow.md
+++ b/docs/rules/no-confusing-arrow.md
@@ -10,7 +10,9 @@ Here's an example where the usage of `=>` could be confusing:
 // The intent is not clear
 var x = a => 1 ? 2 : 3;
 // Did the author mean this
-var x = function (a) { return 1 ? 2 : 3 };
+var x = function (a) {
+    return 1 ? 2 : 3;
+};
 // Or this
 var x = a <= 1 ? 2 : 3;
 ```
@@ -32,21 +34,25 @@ Examples of **correct** code for this rule:
 ```js
 /*eslint no-confusing-arrow: "error"*/
 /*eslint-env es6*/
-
 var x = a => (1 ? 2 : 3);
 var x = (a) => (1 ? 2 : 3);
+var x = (a) => {
+    return 1 ? 2 : 3;
+};
 var x = a => { return 1 ? 2 : 3; };
-var x = (a) => { return 1 ? 2 : 3; };
 ```
 
 ## Options
 
-This rule accepts a single options argument with the following defaults:
+This rule accepts two options argument with the following defaults:
 
 ```json
 {
     "rules": {
-        "no-confusing-arrow": ["error", {"allowParens": true}]
+        "no-confusing-arrow": [
+            "error",
+            { "allowParens": true, "onlyOneSimpleParam": false }
+        ]
     }
 }
 ```
@@ -65,6 +71,24 @@ var x = a => (1 ? 2 : 3);
 var x = (a) => (1 ? 2 : 3);
 ```
 
+`onlyOneSimpleParam` is a boolean setting that can be `true` or `false`(default):
+
+1. `true` relaxes the rule and doesn't report errors if the arrow function has 0 or more than 1 parameters, or the parameter is not an identifier.
+2. `false` warns regardless of parameters.
+
+Examples of **correct** code for this rule with the `{"onlyOneSimpleParam": true}` option:
+
+```js
+/*eslint no-confusing-arrow: ["error", {"onlyOneSimpleParam": true}]*/
+/*eslint-env es6*/
+() => 1 ? 2 : 3;
+(a, b) => 1 ? 2 : 3;
+(a = b) => 1 ? 2 : 3;
+({ a }) => 1 ? 2 : 3;
+([a]) => 1 ? 2 : 3;
+(...a) => 1 ? 2 : 3;
+```
+
 ## Related Rules
 
 * [no-constant-condition](no-constant-condition.md)
diff --git a/lib/config/flat-config-array.js b/lib/config/flat-config-array.js
index cd439e552..fbedf139d 100644
--- a/lib/config/flat-config-array.js
+++ b/lib/config/flat-config-array.js
@@ -14,7 +14,6 @@ const { flatConfigSchema } = require("./flat-config-schema");
 const { RuleValidator } = require("./rule-validator");
 const { defaultConfig } = require("./default-config");
 const recommendedConfig = require("../../conf/eslint-recommended");
-const allConfig = require("../../conf/eslint-all");
 
 //-----------------------------------------------------------------------------
 // Helpers
@@ -79,7 +78,13 @@ class FlatConfigArray extends ConfigArray {
         }
 
         if (config === "eslint:all") {
-            return allConfig;
+
+            /*
+             * Load `eslint-all.js` here instead of at the top level to avoid loading all rule modules
+             * when it isn't necessary. `eslint-all.js` reads `meta` of rule objects to filter out deprecated ones,
+             * so requiring `eslint-all.js` module loads all rule modules as a consequence.
+             */
+            return require("../../conf/eslint-all");
         }
 
         return config;
diff --git a/lib/linter/linter.js b/lib/linter/linter.js
index 9b9f49192..5304a612a 100644
--- a/lib/linter/linter.js
+++ b/lib/linter/linter.js
@@ -800,14 +800,21 @@ function parse(text, languageOptions, filePath) {
      * problem that ESLint identified just like any other.
      */
     try {
+        debug("Parsing:", filePath);
         const parseResult = (typeof parser.parseForESLint === "function")
             ? parser.parseForESLint(textToParse, parserOptions)
             : { ast: parser.parse(textToParse, parserOptions) };
+
+        debug("Parsing successful:", filePath);
         const ast = parseResult.ast;
         const parserServices = parseResult.services || {};
         const visitorKeys = parseResult.visitorKeys || evk.KEYS;
+
+        debug("Scope analysis:", filePath);
         const scopeManager = parseResult.scopeManager || analyzeScope(ast, languageOptions, visitorKeys);
 
+        debug("Scope analysis successful:", filePath);
+
         return {
             success: true,
 
diff --git a/lib/rules/camelcase.js b/lib/rules/camelcase.js
index 6bb1838a7..e47614669 100644
--- a/lib/rules/camelcase.js
+++ b/lib/rules/camelcase.js
@@ -146,7 +146,7 @@ module.exports = {
 
         /**
          * Checks if a given binding identifier uses the original name as-is.
-         * - If it's in object destructuring, the original name is its property name.
+         * - If it's in object destructuring or object expression, the original name is its property name.
          * - If it's in import declaration, the original name is its exported name.
          * @param {ASTNode} node The `Identifier` node to check.
          * @returns {boolean} `true` if the identifier uses the original name as-is.
@@ -161,7 +161,7 @@ module.exports = {
             switch (parent.type) {
                 case "Property":
                     return (
-                        parent.parent.type === "ObjectPattern" &&
+                        (parent.parent.type === "ObjectPattern" || parent.parent.type === "ObjectExpression") &&
                         parent.value === valueNode &&
                         !parent.computed &&
                         parent.key.type === "Identifier" &&
diff --git a/lib/rules/no-confusing-arrow.js b/lib/rules/no-confusing-arrow.js
index 7b736c197..9cdd0a85d 100644
--- a/lib/rules/no-confusing-arrow.js
+++ b/lib/rules/no-confusing-arrow.js
@@ -41,7 +41,8 @@ module.exports = {
         schema: [{
             type: "object",
             properties: {
-                allowParens: { type: "boolean", default: true }
+                allowParens: { type: "boolean", default: true },
+                onlyOneSimpleParam: { type: "boolean", default: false }
             },
             additionalProperties: false
         }],
@@ -54,6 +55,7 @@ module.exports = {
     create(context) {
         const config = context.options[0] || {};
         const allowParens = config.allowParens || (config.allowParens === void 0);
+        const onlyOneSimpleParam = config.onlyOneSimpleParam;
         const sourceCode = context.getSourceCode();
 
 
@@ -65,7 +67,9 @@ module.exports = {
         function checkArrowFunc(node) {
             const body = node.body;
 
-            if (isConditional(body) && !(allowParens && astUtils.isParenthesised(sourceCode, body))) {
+            if (isConditional(body) &&
+                !(allowParens && astUtils.isParenthesised(sourceCode, body)) &&
+                !(onlyOneSimpleParam && !(node.params.length === 1 && node.params[0].type === "Identifier"))) {
                 context.report({
                     node,
                     messageId: "confusing",
diff --git a/package.json b/package.json
index b9018f7f0..b5dd76432 100644
--- a/package.json
+++ b/package.json
@@ -122,6 +122,7 @@
     "node-polyfill-webpack-plugin": "^1.0.3",
     "npm-license": "^0.3.3",
     "nyc": "^15.0.1",
+    "pirates": "^4.0.5",
     "progress": "^2.0.3",
     "proxyquire": "^2.0.1",
     "puppeteer": "^9.1.1",


Test patch:
diff --git a/tests/_utils/test-lazy-loading-rules.js b/tests/_utils/test-lazy-loading-rules.js
new file mode 100644
index 000000000..bac438324
--- /dev/null
+++ b/tests/_utils/test-lazy-loading-rules.js
@@ -0,0 +1,66 @@
+/**
+ * @fileoverview Tests lazy-loading of core rules
+ * @author Milos Djermanovic
+ */
+
+/*
+ * This module should be run as a child process, with `fork()`,
+ * because it is important to run this test with a separate, clean Node process
+ * in order to add hooks before any of the ESLint modules is loaded.
+ */
+
+"use strict";
+
+const path = require("path");
+const assert = require("assert");
+const { addHook } = require("pirates");
+
+const {
+    dir: rulesDirectoryPath,
+    name: rulesDirectoryIndexFilename
+} = path.parse(require.resolve("../../lib/rules"));
+
+// Show full stack trace. The default 10 is usually not enough to find the root cause of this problem.
+Error.stackTraceLimit = Infinity;
+
+const [cwd, pattern, usedRulesCommaSeparated] = process.argv.slice(2);
+
+assert.ok(cwd, "cwd argument isn't provided");
+assert.ok(pattern, "pattern argument isn't provided");
+assert.ok(usedRulesCommaSeparated, "used rules argument isn't provided");
+
+const usedRules = usedRulesCommaSeparated.split(",");
+
+// `require()` hook
+addHook(
+    (_code, filename) => {
+        throw new Error(`Unexpected attempt to load unused rule ${filename}`);
+    },
+    {
+
+        // returns `true` if the hook (the function passed in as the first argument) should be called for this filename
+        matcher(filename) {
+            const { dir, name } = path.parse(filename);
+
+            if (dir === rulesDirectoryPath && ![rulesDirectoryIndexFilename, ...usedRules].includes(name)) {
+                return true;
+            }
+
+            return false;
+        }
+
+    }
+);
+
+/*
+ * Everything related to loading any ESLint modules should be in this IIFE
+ */
+(async () => {
+    const { ESLint } = require("../..");
+    const eslint = new ESLint({ cwd });
+
+    await eslint.lintFiles([pattern]);
+})().catch(({ message, stack }) => {
+    process.send({ message, stack });
+    process.exit(1);
+});
diff --git a/tests/fixtures/lazy-loading-rules/.eslintrc.js b/tests/fixtures/lazy-loading-rules/.eslintrc.js
new file mode 100644
index 000000000..fc6500203
--- /dev/null
+++ b/tests/fixtures/lazy-loading-rules/.eslintrc.js
@@ -0,0 +1,6 @@
+module.exports = {
+    root: true,
+    rules: {
+        semi: 2
+    }
+};
diff --git a/tests/fixtures/lazy-loading-rules/foo.js b/tests/fixtures/lazy-loading-rules/foo.js
new file mode 100644
index 000000000..9b2b3016b
--- /dev/null
+++ b/tests/fixtures/lazy-loading-rules/foo.js
@@ -0,0 +1,1 @@
+/* content is not necessary */
diff --git a/tests/lib/cli-engine/file-enumerator.js b/tests/lib/cli-engine/file-enumerator.js
index a1de4cd21..2ccf15e73 100644
--- a/tests/lib/cli-engine/file-enumerator.js
+++ b/tests/lib/cli-engine/file-enumerator.js
@@ -550,7 +550,7 @@ describe("FileEnumerator", () => {
         const files = {
             "file.js": "",
             ".eslintrc.json": JSON.stringify({
-                extends: ["eslint:recommended"]
+                extends: ["eslint:recommended", "eslint:all"]
             })
         };
         const { prepare, cleanup, getPath } = createCustomTeardown({ cwd: root, files });
diff --git a/tests/lib/eslint/eslint.js b/tests/lib/eslint/eslint.js
index 9c84e979d..29c5fa164 100644
--- a/tests/lib/eslint/eslint.js
+++ b/tests/lib/eslint/eslint.js
@@ -27,6 +27,7 @@ const {
 const hash = require("../../../lib/cli-engine/hash");
 const { unIndent, createCustomTeardown } = require("../../_utils");
 const coreRules = require("../../../lib/rules");
+const childProcess = require("child_process");
 
 //------------------------------------------------------------------------------
 // Tests
@@ -412,6 +413,55 @@ describe("ESLint", () => {
             ]);
         });
 
+        it("should use eslint:recommended rules when eslint:recommended configuration is specified", async () => {
+            eslint = new ESLint({
+                useEslintrc: false,
+                overrideConfig: {
+                    extends: ["eslint:recommended"]
+                },
+                ignore: false,
+                cwd: getFixturePath()
+            });
+            const options = { filePath: "file.js" };
+            const results = await eslint.lintText("foo ()", options);
+
+            assert.strictEqual(results.length, 1);
+            assert.strictEqual(results[0].messages.length, 1);
+            assert.strictEqual(results[0].messages[0].ruleId, "no-undef");
+            assert.strictEqual(results[0].messages[0].severity, 2);
+        });
+
+        it("should use eslint:all rules when eslint:all configuration is specified", async () => {
+            eslint = new ESLint({
+                useEslintrc: false,
+                overrideConfig: {
+                    extends: ["eslint:all"]
+                },
+                ignore: false,
+                cwd: getFixturePath()
+            });
+            const options = { filePath: "file.js" };
+            const results = await eslint.lintText("foo ()", options);
+
+            assert.strictEqual(results.length, 1);
+
+            const { messages } = results[0];
+
+            // Some rules that should report errors in the given code. Not all, as we don't want to update this test when we add new rules.
+            const expectedRules = ["no-undef", "semi", "func-call-spacing"];
+
+            expectedRules.forEach(ruleId => {
+                const messageFromRule = messages.find(message => message.ruleId === ruleId);
+
+                assert.ok(
+                    typeof messageFromRule === "object" && messageFromRule !== null, // LintMessage object
+                    `Expected a message from rule '${ruleId}'`
+                );
+                assert.strictEqual(messageFromRule.severity, 2);
+            });
+
+        });
+
         it("correctly autofixes semicolon-conflicting-fixes", async () => {
             eslint = new ESLint({
                 cwd: path.join(fixtureDir, ".."),
@@ -6694,4 +6744,45 @@ describe("ESLint", () => {
             });
         });
     });
+
+    describe("loading rules", () => {
+        it("should not load unused core rules", done => {
+            let calledDone = false;
+
+            const cwd = getFixturePath("lazy-loading-rules");
+            const pattern = "foo.js";
+            const usedRules = ["semi"];
+
+            const forkedProcess = childProcess.fork(
+                path.join(__dirname, "../../_utils/test-lazy-loading-rules.js"),
+                [cwd, pattern, String(usedRules)]
+            );
+
+            // this is an error message
+            forkedProcess.on("message", ({ message, stack }) => {
+                if (calledDone) {
+                    return;
+                }
+                calledDone = true;
+
+                const error = new Error(message);
+
+                error.stack = stack;
+                done(error);
+            });
+
+            forkedProcess.on("exit", exitCode => {
+                if (calledDone) {
+                    return;
+                }
+                calledDone = true;
+
+                if (exitCode === 0) {
+                    done();
+                } else {
+                    done(new Error("Forked process exited with a non-zero exit code"));
+                }
+            });
+        });
+    });
 });
diff --git a/tests/lib/rules/camelcase.js b/tests/lib/rules/camelcase.js
index 3a47a1b4b..79c237ce2 100644
--- a/tests/lib/rules/camelcase.js
+++ b/tests/lib/rules/camelcase.js
@@ -407,6 +407,35 @@ ruleTester.run("camelcase", rule, {
             code: "class C { snake_case; #snake_case; #snake_case2() {} }",
             options: [{ properties: "never" }],
             parserOptions: { ecmaVersion: 2022 }
+        },
+
+        // Combinations of `properties` and `ignoreDestructring`
+        {
+            code: `
+            const { some_property } = obj;
+
+            const bar = { some_property };
+
+            obj.some_property = 10;
+
+            const xyz = { some_property: obj.some_property };
+
+            const foo = ({ some_property }) => {
+                console.log(some_property)
+            };
+            `,
+            options: [{ properties: "never", ignoreDestructuring: true }],
+            parserOptions: { ecmaVersion: 2022 }
+        },
+
+        // https://github.com/eslint/eslint/issues/15572
+        {
+            code: `
+            const { some_property } = obj;
+            doSomething({ some_property });
+            `,
+            options: [{ properties: "never", ignoreDestructuring: true }],
+            parserOptions: { ecmaVersion: 2022 }
         }
     ],
     invalid: [
@@ -1416,6 +1445,78 @@ ruleTester.run("camelcase", rule, {
             options: [{ properties: "always" }],
             parserOptions: { ecmaVersion: 2022 },
             errors: [{ messageId: "notCamelCasePrivate", data: { name: "snake_case" } }]
+        },
+
+        // Combinations of `properties` and `ignoreDestructring`
+        {
+            code: `
+            const { some_property } = obj;
+            doSomething({ some_property });
+            `,
+            options: [{ properties: "always", ignoreDestructuring: true }],
+            parserOptions: { ecmaVersion: 2022 },
+            errors: [
+                {
+                    messageId: "notCamelCase",
+                    data: { name: "some_property" },
+                    line: 3,
+                    column: 27
+                }
+            ]
+        },
+        {
+            code: `
+            const { some_property } = obj;
+            doSomething({ some_property });
+            doSomething({ [some_property]: "bar" });
+            `,
+            options: [{ properties: "never", ignoreDestructuring: true }],
+            parserOptions: { ecmaVersion: 2022 },
+            errors: [
+                {
+                    messageId: "notCamelCase",
+                    data: { name: "some_property" },
+                    line: 4,
+                    column: 28
+                }
+            ]
+        },
+        {
+            code: `
+            const { some_property } = obj;
+
+            const bar = { some_property };
+
+            obj.some_property = 10;
+
+            const xyz = { some_property: obj.some_property };
+
+            const foo = ({ some_property }) => {
+                console.log(some_property)
+            };
+            `,
+            options: [{ properties: "always", ignoreDestructuring: true }],
+            parserOptions: { ecmaVersion: 2022 },
+            errors: [
+                {
+                    messageId: "notCamelCase",
+                    data: { name: "some_property" },
+                    line: 4,
+                    column: 27
+                },
+                {
+                    messageId: "notCamelCase",
+                    data: { name: "some_property" },
+                    line: 6,
+                    column: 17
+                },
+                {
+                    messageId: "notCamelCase",
+                    data: { name: "some_property" },
+                    line: 8,
+                    column: 27
+                }
+            ]
         }
     ]
 });
diff --git a/tests/lib/rules/no-confusing-arrow.js b/tests/lib/rules/no-confusing-arrow.js
index 58724d9ac..372f2057b 100644
--- a/tests/lib/rules/no-confusing-arrow.js
+++ b/tests/lib/rules/no-confusing-arrow.js
@@ -30,7 +30,15 @@ ruleTester.run("no-confusing-arrow", rule, {
         { code: "var x = (a) => { return 1 ? 2 : 3; }", options: [{ allowParens: false }] },
 
         "var x = a => (1 ? 2 : 3)",
-        { code: "var x = a => (1 ? 2 : 3)", options: [{ allowParens: true }] }
+        { code: "var x = a => (1 ? 2 : 3)", options: [{ allowParens: true }] },
+
+        "var x = (a,b) => (1 ? 2 : 3)",
+        { code: "() => 1 ? 2 : 3", options: [{ onlyOneSimpleParam: true }] },
+        { code: "(a, b) => 1 ? 2 : 3", options: [{ onlyOneSimpleParam: true }] },
+        { code: "(a = b) => 1 ? 2 : 3", options: [{ onlyOneSimpleParam: true }] },
+        { code: "({ a }) => 1 ? 2 : 3", options: [{ onlyOneSimpleParam: true }] },
+        { code: "([a]) => 1 ? 2 : 3", options: [{ onlyOneSimpleParam: true }] },
+        { code: "(...a) => 1 ? 2 : 3", options: [{ onlyOneSimpleParam: true }] }
     ],
     invalid: [
         {
@@ -71,6 +79,48 @@ ruleTester.run("no-confusing-arrow", rule, {
             code: "var x = (a) => 1 ? 2 : 3",
             output: "var x = (a) => (1 ? 2 : 3)",
             errors: [{ messageId: "confusing" }]
+        },
+        {
+            code: "var x = () => 1 ? 2 : 3",
+            output: "var x = () => (1 ? 2 : 3)",
+            errors: [{ messageId: "confusing" }]
+        },
+        {
+            code: "var x = () => 1 ? 2 : 3",
+            output: "var x = () => (1 ? 2 : 3)",
+            options: [{}],
+            errors: [{ messageId: "confusing" }]
+        },
+        {
+            code: "var x = () => 1 ? 2 : 3",
+            output: "var x = () => (1 ? 2 : 3)",
+            options: [{ onlyOneSimpleParam: false }],
+            errors: [{ messageId: "confusing" }]
+        },
+        {
+            code: "var x = (a, b) => 1 ? 2 : 3",
+            output: "var x = (a, b) => (1 ? 2 : 3)",
+            errors: [{ messageId: "confusing" }]
+        },
+        {
+            code: "var x = (a = b) => 1 ? 2 : 3",
+            output: "var x = (a = b) => (1 ? 2 : 3)",
+            errors: [{ messageId: "confusing" }]
+        },
+        {
+            code: "var x = ({ a }) => 1 ? 2 : 3",
+            output: "var x = ({ a }) => (1 ? 2 : 3)",
+            errors: [{ messageId: "confusing" }]
+        },
+        {
+            code: "var x = ([a]) => 1 ? 2 : 3",
+            output: "var x = ([a]) => (1 ? 2 : 3)",
+            errors: [{ messageId: "confusing" }]
+        },
+        {
+            code: "var x = (...a) => 1 ? 2 : 3",
+            output: "var x = (...a) => (1 ? 2 : 3)",
+            errors: [{ messageId: "confusing" }]
         }
     ]
 });