Repository: eslint/eslint
Pull request #14578 (2021-05-08 01:08:25)

Docs: add more examples for `no-sequences` rule
<!--
    Thank you for contributing!

    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).
-->

#### Prerequisites checklist

- [x] I have read the [contributing guidelines](https://github.com/eslint/eslint/blob/master/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
-->

[X] 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
[ ] 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)

Add more examples.

Fixes https://github.com/eslint/eslint/issues/14572

#### Is there anything you'd like reviewers to focus on?

Nope

nzakas: Yes, I think we should add a note that explicitly states this exception case as it’s different from anywhere else in the rule. 
nzakas: @snitin315 are you still working on this?
snitin315: Yes, thanks for the ping. I will push an update today.
snitin315: Done ✅ 

Patch:
diff --git a/docs/rules/no-sequences.md b/docs/rules/no-sequences.md
index d4efc1c5b..87ba3c4b9 100644
--- a/docs/rules/no-sequences.md
+++ b/docs/rules/no-sequences.md
@@ -39,8 +39,6 @@ switch (val = foo(), val) {}
 while (val = foo(), val < 42);
 
 with (doSomething(), val) {}
-
-const foo = (val) => (console.log('bar'), val);
 ```
 
 Examples of **correct** code for this rule:
@@ -63,8 +61,32 @@ switch ((val = foo(), val)) {}
 while ((val = foo(), val < 42));
 
 with ((doSomething(), val)) {}
+```
+
+### Note about arrow function bodies
+
+If an arrow function body is a statement rather than a block, and that statement contains a sequence, you need to use double parentheses around the statement to indicate that the sequence is intentional.
+
+Examples of **incorrect** code for arrow functions:
+
+```js
+/*eslint no-sequences: "error"*/
+const foo = (val) => (console.log('bar'), val);
+
+const foo = () => ((bar = 123), 10));
+
+const foo = () => { return (bar = 123), 10 }
+```
+
+Examples of **correct** code for arrow functions:
 
+```js
+/*eslint no-sequences: "error"*/
 const foo = (val) => ((console.log('bar'), val));
+
+const foo = () => (((bar = 123), 10));
+
+const foo = () => { return ((bar = 123), 10) }
 ```
 
 ## Options
diff --git a/lib/rules/arrow-body-style.js b/lib/rules/arrow-body-style.js
index b2167fde7..5b8a5f011 100644
--- a/lib/rules/arrow-body-style.js
+++ b/lib/rules/arrow-body-style.js
@@ -87,17 +87,17 @@ module.exports = {
         }
 
         /**
-         * Gets the closing parenthesis which is the pair of the given opening parenthesis.
-         * @param {Token} token The opening parenthesis token to get.
+         * Gets the closing parenthesis by the given node.
+         * @param {ASTNode} node first node after an opening parenthesis.
          * @returns {Token} The found closing parenthesis token.
          */
-        function findClosingParen(token) {
-            let node = sourceCode.getNodeByRangeIndex(token.range[0]);
+        function findClosingParen(node) {
+            let nodeToCheck = node;
 
-            while (!astUtils.isParenthesised(sourceCode, node)) {
-                node = node.parent;
+            while (!astUtils.isParenthesised(sourceCode, nodeToCheck)) {
+                nodeToCheck = nodeToCheck.parent;
             }
-            return sourceCode.getTokenAfter(node);
+            return sourceCode.getTokenAfter(nodeToCheck);
         }
 
         /**
@@ -226,12 +226,22 @@ module.exports = {
                             const arrowToken = sourceCode.getTokenBefore(arrowBody, astUtils.isArrowToken);
                             const [firstTokenAfterArrow, secondTokenAfterArrow] = sourceCode.getTokensAfter(arrowToken, { count: 2 });
                             const lastToken = sourceCode.getLastToken(node);
-                            const isParenthesisedObjectLiteral =
+
+                            let parenthesisedObjectLiteral = null;
+
+                            if (
                                 astUtils.isOpeningParenToken(firstTokenAfterArrow) &&
-                                astUtils.isOpeningBraceToken(secondTokenAfterArrow);
+                                astUtils.isOpeningBraceToken(secondTokenAfterArrow)
+                            ) {
+                                const braceNode = sourceCode.getNodeByRangeIndex(secondTokenAfterArrow.range[0]);
+
+                                if (braceNode.type === "ObjectExpression") {
+                                    parenthesisedObjectLiteral = braceNode;
+                                }
+                            }
 
                             // If the value is object literal, remove parentheses which were forced by syntax.
-                            if (isParenthesisedObjectLiteral) {
+                            if (parenthesisedObjectLiteral) {
                                 const openingParenToken = firstTokenAfterArrow;
                                 const openingBraceToken = secondTokenAfterArrow;
 
@@ -247,7 +257,7 @@ module.exports = {
                                 }
 
                                 // Closing paren for the object doesn't have to be lastToken, e.g.: () => ({}).foo()
-                                fixes.push(fixer.remove(findClosingParen(openingBraceToken)));
+                                fixes.push(fixer.remove(findClosingParen(parenthesisedObjectLiteral)));
                                 fixes.push(fixer.insertTextAfter(lastToken, "}"));
 
                             } else {


Test patch:
diff --git a/tests/lib/rules/arrow-body-style.js b/tests/lib/rules/arrow-body-style.js
index 7a8de4fe5..0ccb440d3 100644
--- a/tests/lib/rules/arrow-body-style.js
+++ b/tests/lib/rules/arrow-body-style.js
@@ -810,6 +810,14 @@ ruleTester.run("arrow-body-style", rule, {
             `,
             options: ["always"],
             errors: [{ messageId: "expectedBlock" }]
+        },
+
+        // https://github.com/eslint/eslint/issues/14633
+        {
+            code: "const createMarker = (color) => ({ latitude, longitude }, index) => {};",
+            output: "const createMarker = (color) => {return ({ latitude, longitude }, index) => {}};",
+            options: ["always"],
+            errors: [{ messageId: "expectedBlock" }]
         }
     ]
 });