Skip to content

Commit 687ccae

Browse files
authored
Update: add option "allowInParentheses" to no-sequences (fixes #14197) (#14199)
* New: add option "allowInParentheses" to rule "no-sequences" * added documentation * [no-equence]: switch default of "allowInParentheses" to true * restored removed sentence * changes from code review * code review
1 parent dbf2529 commit 687ccae

3 files changed

Lines changed: 92 additions & 13 deletions

File tree

docs/rules/no-sequences.md

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ while (a = next(), a && a.length);
1717
This rule forbids the use of the comma operator, with the following exceptions:
1818

1919
* In the initialization or update portions of a `for` statement.
20-
* If the expression sequence is explicitly wrapped in parentheses.
20+
* By default, if the expression sequence is explicitly wrapped in parentheses. This exception can be removed with the `allowInParentheses` option.
2121

2222
Examples of **incorrect** code for this rule:
2323

@@ -63,10 +63,48 @@ while ((val = foo(), val < 42));
6363
with ((doSomething(), val)) {}
6464
```
6565

66+
## Options
67+
68+
This rule takes one option, an object, with the following properties:
69+
70+
* `"allowInParentheses"`: If set to `true` (default), this rule allows expression sequences that are explicitly wrapped in parentheses.
71+
72+
### allowInParentheses
73+
74+
Examples of **incorrect** code for this rule with the `{ "allowInParentheses": false }` option:
75+
76+
```js
77+
/*eslint no-sequences: ["error", { "allowInParentheses": false }]*/
78+
79+
foo = (doSomething(), val);
80+
81+
(0, eval)("doSomething();");
82+
83+
do {} while ((doSomething(), !!test));
84+
85+
for (; (doSomething(), !!test); );
86+
87+
if ((doSomething(), !!test));
88+
89+
switch ((val = foo(), val)) {}
90+
91+
while ((val = foo(), val < 42));
92+
93+
with ((doSomething(), val)) {}
94+
```
95+
96+
Examples of **correct** code for this rule with the `{ "allowInParentheses": false }` option:
97+
98+
```js
99+
/*eslint no-sequences: ["error", { "allowInParentheses": false }]*/
100+
101+
for (i = 0, j = 10; i < j; i++, j--);
102+
```
103+
66104
## When Not To Use It
67105

68106
Disable this rule if sequence expressions with the comma operator are acceptable.
69-
Another case is where you might want to report all usages of the comma operator, even if they are wrapped in parentheses or in a for loop. You can achieve this using rule `no-restricted-syntax`:
107+
Another case is where you might want to report all usages of the comma operator, even in a for loop. You can achieve this using rule `no-restricted-syntax`:
70108

71109
```js
72110
{

lib/rules/no-sequences.js

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@
1111

1212
const astUtils = require("./utils/ast-utils");
1313

14+
//------------------------------------------------------------------------------
15+
// Helpers
16+
//------------------------------------------------------------------------------
17+
18+
const DEFAULT_OPTIONS = {
19+
allowInParentheses: true
20+
};
21+
1422
//------------------------------------------------------------------------------
1523
// Rule Definition
1624
//------------------------------------------------------------------------------
@@ -26,14 +34,23 @@ module.exports = {
2634
url: "https://eslint.org/docs/rules/no-sequences"
2735
},
2836

29-
schema: [],
37+
schema: [{
38+
properties: {
39+
allowInParentheses: {
40+
type: "boolean",
41+
default: true
42+
}
43+
},
44+
additionalProperties: false
45+
}],
3046

3147
messages: {
3248
unexpectedCommaExpression: "Unexpected use of comma operator."
3349
}
3450
},
3551

3652
create(context) {
53+
const options = Object.assign({}, DEFAULT_OPTIONS, context.options[0]);
3754
const sourceCode = context.getSourceCode();
3855

3956
/**
@@ -99,13 +116,15 @@ module.exports = {
99116
}
100117

101118
// Wrapping a sequence in extra parens indicates intent
102-
if (requiresExtraParens(node)) {
103-
if (isParenthesisedTwice(node)) {
104-
return;
105-
}
106-
} else {
107-
if (isParenthesised(node)) {
108-
return;
119+
if (options.allowInParentheses) {
120+
if (requiresExtraParens(node)) {
121+
if (isParenthesisedTwice(node)) {
122+
return;
123+
}
124+
} else {
125+
if (isParenthesised(node)) {
126+
return;
127+
}
109128
}
110129
}
111130

tests/lib/rules/no-sequences.js

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,20 @@ ruleTester.run("no-sequences", rule, {
4646
"do {} while ((doSomething(), !!test));",
4747
"for ((doSomething(), somethingElse()); (doSomething(), !!test); );",
4848
"if ((doSomething(), !!test));",
49-
"switch ((doSomething(), !!test)) {}",
49+
"switch ((doSomething(), val)) {}",
5050
"while ((doSomething(), !!test));",
5151
"with ((doSomething(), val)) {}",
52-
{ code: "a => ((doSomething(), a))", env: { es6: true } }
52+
{ code: "a => ((doSomething(), a))", env: { es6: true } },
53+
54+
// options object without "allowInParentheses" property
55+
{ code: "var foo = (1, 2);", options: [{}] },
56+
57+
// explicitly set option "allowInParentheses" to default value
58+
{ code: "var foo = (1, 2);", options: [{ allowInParentheses: true }] },
59+
60+
// valid code with "allowInParentheses" set to `false`
61+
{ code: "for ((i = 0, j = 0); test; );", options: [{ allowInParentheses: false }] },
62+
{ code: "for (; test; (i++, j++));", options: [{ allowInParentheses: false }] }
5363
],
5464

5565
// Examples of code that should trigger the rule
@@ -75,6 +85,18 @@ ruleTester.run("no-sequences", rule, {
7585
{ code: "a => (doSomething(), a)", env: { es6: true }, errors: errors(20) },
7686
{ code: "(1), 2", errors: errors(4) },
7787
{ code: "((1)) , (2)", errors: errors(7) },
78-
{ code: "while((1) , 2);", errors: errors(11) }
88+
{ code: "while((1) , 2);", errors: errors(11) },
89+
90+
// option "allowInParentheses": do not allow sequence in parentheses
91+
{ code: "var foo = (1, 2);", options: [{ allowInParentheses: false }], errors: errors(13) },
92+
{ code: "(0,eval)(\"foo()\");", options: [{ allowInParentheses: false }], errors: errors(3) },
93+
{ code: "foo(a, (b, c), d);", options: [{ allowInParentheses: false }], errors: errors(10) },
94+
{ code: "do {} while ((doSomething(), !!test));", options: [{ allowInParentheses: false }], errors: errors(28) },
95+
{ code: "for (; (doSomething(), !!test); );", options: [{ allowInParentheses: false }], errors: errors(22) },
96+
{ code: "if ((doSomething(), !!test));", options: [{ allowInParentheses: false }], errors: errors(19) },
97+
{ code: "switch ((doSomething(), val)) {}", options: [{ allowInParentheses: false }], errors: errors(23) },
98+
{ code: "while ((doSomething(), !!test));", options: [{ allowInParentheses: false }], errors: errors(22) },
99+
{ code: "with ((doSomething(), val)) {}", options: [{ allowInParentheses: false }], errors: errors(21) },
100+
{ code: "a => ((doSomething(), a))", options: [{ allowInParentheses: false }], env: { es6: true }, errors: errors(21) }
79101
]
80102
});

0 commit comments

Comments
 (0)