Skip to content

Commit 53cbe69

Browse files
committed
fix: support JsSequenceExpression & JsParenthesizedExpression
1 parent 44911bb commit 53cbe69

File tree

11 files changed

+379
-143
lines changed

11 files changed

+379
-143
lines changed

crates/biome_js_analyze/src/lint/nursery/no_increment_decrement.rs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use biome_analyze::{
22
Ast, Rule, RuleDiagnostic, RuleSource, context::RuleContext, declare_lint_rule,
33
};
44
use biome_console::markup;
5-
use biome_js_syntax::{JsForStatement, JsPostUpdateExpression, JsPreUpdateExpression};
6-
use biome_rowan::{AstNode, declare_node_union};
5+
use biome_js_syntax::{JsLanguage, JsPostUpdateExpression, JsPreUpdateExpression, JsSyntaxKind};
6+
use biome_rowan::{AstNode, SyntaxNode, declare_node_union};
77
use biome_rule_options::no_increment_decrement::NoIncrementDecrementOptions;
88

99
declare_lint_rule! {
@@ -152,11 +152,7 @@ impl Rule for NoIncrementDecrement {
152152
fn run(ctx: &RuleContext<Self>) -> Self::Signals {
153153
let node = ctx.query();
154154

155-
if ctx.options().allow_for_loop_afterthoughts
156-
&& let Some(parent) = node.parent::<JsForStatement>()
157-
&& let Some(update) = parent.update()
158-
&& update.syntax().eq(node.syntax())
159-
{
155+
if ctx.options().allow_for_loop_afterthoughts && is_for_loop_afterthought(node.syntax()) {
160156
return None;
161157
}
162158

@@ -179,3 +175,24 @@ impl Rule for NoIncrementDecrement {
179175
)
180176
}
181177
}
178+
179+
fn is_for_loop_afterthought(node: &SyntaxNode<JsLanguage>) -> bool {
180+
let Some(parent) = node.parent() else {
181+
return false;
182+
};
183+
184+
match parent.kind() {
185+
JsSyntaxKind::JS_PARENTHESIZED_EXPRESSION | JsSyntaxKind::JS_SEQUENCE_EXPRESSION => {
186+
is_for_loop_afterthought(&parent)
187+
}
188+
JsSyntaxKind::JS_FOR_STATEMENT => {
189+
if let Some(for_stmt) = biome_js_syntax::JsForStatement::cast(parent.clone())
190+
&& let Some(update) = for_stmt.update()
191+
{
192+
return update.syntax().eq(node);
193+
}
194+
false
195+
}
196+
_ => false,
197+
}
198+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
let foo = 0;
2+
foo++;
3+
4+
let bar = 0;
5+
++bar;
6+
7+
for (let i = 0; i < 10; j = i++) {
8+
doSomething(i, j);
9+
}
10+
11+
for (let i = 10; i--;) {
12+
doSomething(i);
13+
}
14+
15+
for (let i = 0; i < 10;) i++;
16+
17+
for (i = 0; i < l; i++) { v++; }
18+
19+
for (i++;;);
20+
21+
for (;--i;);
22+
23+
for (;;) ++i;
24+
25+
for (;; i = j++);
26+
27+
for (;; i++, f(--j));
28+
29+
for (;; foo + (i++, bar));
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
---
2+
source: crates/biome_js_analyze/tests/spec_tests.rs
3+
expression: invalid.js
4+
---
5+
# Input
6+
```js
7+
let foo = 0;
8+
foo++;
9+
10+
let bar = 0;
11+
++bar;
12+
13+
for (let i = 0; i < 10; j = i++) {
14+
doSomething(i, j);
15+
}
16+
17+
for (let i = 10; i--;) {
18+
doSomething(i);
19+
}
20+
21+
for (let i = 0; i < 10;) i++;
22+
23+
for (i = 0; i < l; i++) { v++; }
24+
25+
for (i++;;);
26+
27+
for (;--i;);
28+
29+
for (;;) ++i;
30+
31+
for (;; i = j++);
32+
33+
for (;; i++, f(--j));
34+
35+
for (;; foo + (i++, bar));
36+
```
37+
38+
# Diagnostics
39+
```
40+
invalid.js:2:1 lint/nursery/noIncrementDecrement ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
41+
42+
i Unexpected use of increment/decrement unary operator.
43+
44+
1 │ let foo = 0;
45+
> 2 │ foo++;
46+
│ ^^^^^
47+
3 │
48+
4 │ let bar = 0;
49+
50+
i The unary ++ and -- operators are subject to automatic semicolon insertion, differences in whitespace can change semantics of source code. Instead use += or -=.
51+
52+
53+
```
54+
55+
```
56+
invalid.js:5:1 lint/nursery/noIncrementDecrement ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
57+
58+
i Unexpected use of increment/decrement unary operator.
59+
60+
4 │ let bar = 0;
61+
> 5 │ ++bar;
62+
│ ^^^^^
63+
6 │
64+
7 │ for (let i = 0; i < 10; j = i++) {
65+
66+
i The unary ++ and -- operators are subject to automatic semicolon insertion, differences in whitespace can change semantics of source code. Instead use += or -=.
67+
68+
69+
```
70+
71+
```
72+
invalid.js:7:29 lint/nursery/noIncrementDecrement ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
73+
74+
i Unexpected use of increment/decrement unary operator.
75+
76+
5++bar;
77+
6
78+
> 7for (let i = 0; i < 10; j = i++) {
79+
│ ^^^
80+
8 │ doSomething(i, j);
81+
9 │ }
82+
83+
i The unary ++ and -- operators are subject to automatic semicolon insertion, differences in whitespace can change semantics of source code. Instead use += or -=.
84+
85+
86+
```
87+
88+
```
89+
invalid.js:11:18 lint/nursery/noIncrementDecrement ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
90+
91+
i Unexpected use of increment/decrement unary operator.
92+
93+
9}
94+
10 │
95+
> 11 │ for (let i = 10; i--;) {
96+
^^^
97+
12doSomething(i);
98+
13}
99+
100+
i The unary ++ and -- operators are subject to automatic semicolon insertion, differences in whitespace can change semantics of source code. Instead use += or -=.
101+
102+
103+
```
104+
105+
```
106+
invalid.js:15:26 lint/nursery/noIncrementDecrement ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
107+
108+
i Unexpected use of increment/decrement unary operator.
109+
110+
13 │ }
111+
14 │
112+
> 15 │ for (let i = 0; i < 10;) i++;
113+
│ ^^^
114+
16 │
115+
17 │ for (i = 0; i < l; i++) { v++; }
116+
117+
i The unary ++ and -- operators are subject to automatic semicolon insertion, differences in whitespace can change semantics of source code. Instead use += or -=.
118+
119+
120+
```
121+
122+
```
123+
invalid.js:17:27 lint/nursery/noIncrementDecrement ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
124+
125+
i Unexpected use of increment/decrement unary operator.
126+
127+
15 │ for (let i = 0; i < 10;) i++;
128+
16 │
129+
> 17 │ for (i = 0; i < l; i++) { v++; }
130+
│ ^^^
131+
18 │
132+
19 │ for (i++;;);
133+
134+
i The unary ++ and -- operators are subject to automatic semicolon insertion, differences in whitespace can change semantics of source code. Instead use += or -=.
135+
136+
137+
```
138+
139+
```
140+
invalid.js:19:6 lint/nursery/noIncrementDecrement ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
141+
142+
i Unexpected use of increment/decrement unary operator.
143+
144+
17 │ for (i = 0; i < l; i++) { v++; }
145+
18 │
146+
> 19 │ for (i++;;);
147+
│ ^^^
148+
20 │
149+
21 │ for (;--i;);
150+
151+
i The unary ++ and -- operators are subject to automatic semicolon insertion, differences in whitespace can change semantics of source code. Instead use += or -=.
152+
153+
154+
```
155+
156+
```
157+
invalid.js:21:7 lint/nursery/noIncrementDecrement ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
158+
159+
i Unexpected use of increment/decrement unary operator.
160+
161+
19 │ for (i++;;);
162+
20 │
163+
> 21 │ for (;--i;);
164+
│ ^^^
165+
22 │
166+
23 │ for (;;) ++i;
167+
168+
i The unary ++ and -- operators are subject to automatic semicolon insertion, differences in whitespace can change semantics of source code. Instead use += or -=.
169+
170+
171+
```
172+
173+
```
174+
invalid.js:23:10 lint/nursery/noIncrementDecrement ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
175+
176+
i Unexpected use of increment/decrement unary operator.
177+
178+
21 │ for (;--i;);
179+
22 │
180+
> 23 │ for (;;) ++i;
181+
│ ^^^
182+
24 │
183+
25 │ for (;; i = j++);
184+
185+
i The unary ++ and -- operators are subject to automatic semicolon insertion, differences in whitespace can change semantics of source code. Instead use += or -=.
186+
187+
188+
```
189+
190+
```
191+
invalid.js:25:13 lint/nursery/noIncrementDecrement ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
192+
193+
i Unexpected use of increment/decrement unary operator.
194+
195+
23 │ for (;;) ++i;
196+
24 │
197+
> 25 │ for (;; i = j++);
198+
│ ^^^
199+
26 │
200+
27 │ for (;; i++, f(--j));
201+
202+
i The unary ++ and -- operators are subject to automatic semicolon insertion, differences in whitespace can change semantics of source code. Instead use += or -=.
203+
204+
205+
```
206+
207+
```
208+
invalid.js:27:16 lint/nursery/noIncrementDecrement ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
209+
210+
i Unexpected use of increment/decrement unary operator.
211+
212+
25 │ for (;; i = j++);
213+
26 │
214+
> 27 │ for (;; i++, f(--j));
215+
│ ^^^
216+
28 │
217+
29 │ for (;; foo + (i++, bar));
218+
219+
i The unary ++ and -- operators are subject to automatic semicolon insertion, differences in whitespace can change semantics of source code. Instead use += or -=.
220+
221+
222+
```
223+
224+
```
225+
invalid.js:29:16 lint/nursery/noIncrementDecrement ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
226+
227+
i Unexpected use of increment/decrement unary operator.
228+
229+
27 │ for (;; i++, f(--j));
230+
28 │
231+
> 29 │ for (;; foo + (i++, bar));
232+
│ ^^^
233+
234+
i The unary ++ and -- operators are subject to automatic semicolon insertion, differences in whitespace can change semantics of source code. Instead use += or -=.
235+
236+
237+
```

crates/biome_js_analyze/tests/specs/nursery/noIncrementDecrement/allowForLoopAfterthoughts.options.json renamed to crates/biome_js_analyze/tests/specs/nursery/noIncrementDecrement/allowForLoopAfterthought/invalid.options.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"$schema": "../../../../../../packages/@biomejs/biome/configuration_schema.json",
2+
"$schema": "../../../../../../../packages/@biomejs/biome/configuration_schema.json",
33
"linter": {
44
"rules": {
55
"nursery": {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/* should not generate diagnostics */
2+
var foo = 0; foo = +1;
3+
4+
for (i = 0; i < l; i++) { console.log(i); }
5+
6+
for (var i = 0, j = i + 1; j < example.length; i++, j++) { }
7+
8+
for (; ; i--, foo());
9+
10+
for (;; foo(), --i);
11+
12+
for (;; foo(), ++i, bar);
13+
14+
for (;; i++, (++j, k--));
15+
16+
for (;; foo(), (bar(), i++), baz());
17+
18+
for (;; (--i, j += 2), bar = j + 1);
19+
20+
for (;; a, (i--, (b, ++j, c)), d);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
source: crates/biome_js_analyze/tests/spec_tests.rs
3+
expression: valid.js
4+
---
5+
# Input
6+
```js
7+
/* should not generate diagnostics */
8+
var foo = 0; foo = +1;
9+
10+
for (i = 0; i < l; i++) { console.log(i); }
11+
12+
for (var i = 0, j = i + 1; j < example.length; i++, j++) { }
13+
14+
for (; ; i--, foo());
15+
16+
for (;; foo(), --i);
17+
18+
for (;; foo(), ++i, bar);
19+
20+
for (;; i++, (++j, k--));
21+
22+
for (;; foo(), (bar(), i++), baz());
23+
24+
for (;; (--i, j += 2), bar = j + 1);
25+
26+
for (;; a, (i--, (b, ++j, c)), d);
27+
28+
```
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"$schema": "../../../../../../../packages/@biomejs/biome/configuration_schema.json",
3+
"linter": {
4+
"rules": {
5+
"nursery": {
6+
"noIncrementDecrement": {
7+
"level": "error",
8+
"options": {
9+
"allowForLoopAfterthoughts": true
10+
}
11+
}
12+
}
13+
}
14+
}
15+
}

0 commit comments

Comments
 (0)