Skip to content
This repository was archived by the owner on Aug 31, 2023. It is now read-only.

Commit 97e48b4

Browse files
authored
feat(rome_js_analyze): noConfusingLabels (#4114)
Closes #4113
1 parent 5c60450 commit 97e48b4

File tree

14 files changed

+677
-111
lines changed

14 files changed

+677
-111
lines changed

crates/rome_diagnostics_categories/src/categories.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ define_dategories! {
6161
"lint/nursery/noHeaderScope": "https://docs.rome.tools/lint/rules/noHeaderScope",
6262
"lint/nursery/noInnerDeclarations": "https://docs.rome.tools/lint/rules/noInnerDeclarations",
6363
"lint/nursery/noInvalidConstructorSuper": "https://docs.rome.tools/lint/rules/noInvalidConstructorSuper",
64+
"lint/nursery/noConfusingLabels": "https://docs.rome.tools/lint/rules/noConfusingLabels",
6465
"lint/nursery/noNonNullAssertion": "https://docs.rome.tools/lint/rules/noNonNullAssertion",
6566
"lint/nursery/noPrecisionLoss": "https://docs.rome.tools/lint/rules/noPrecisionLoss",
6667
"lint/nursery/noRedundantAlt": "https://docs.rome.tools/lint/rules/noRedundantAlt",

crates/rome_js_analyze/src/analyzers/nursery.rs

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
use rome_analyze::context::RuleContext;
2+
use rome_analyze::{declare_rule, Ast, Rule, RuleDiagnostic};
3+
use rome_console::markup;
4+
use rome_js_syntax::{AnyJsStatement, JsLabeledStatement};
5+
6+
declare_rule! {
7+
/// Disallow labeled statements that are not loops.
8+
///
9+
/// Labeled statements in JavaScript are used in conjunction with `break` and `continue` to control flow around multiple loops.
10+
/// Their use for other statements is suspicious and unfamiliar.
11+
///
12+
/// Source: https://eslint.org/docs/latest/rules/no-labels
13+
///
14+
/// ## Examples
15+
///
16+
/// ### Invalid
17+
///
18+
/// ```js,expect_diagnostic
19+
/// label: f();
20+
/// ```
21+
///
22+
/// ```js,expect_diagnostic
23+
/// label: {
24+
/// f();
25+
/// break label;
26+
/// }
27+
/// ```
28+
///
29+
/// ```js,expect_diagnostic
30+
/// label: if (a) {
31+
/// f()
32+
/// break label;
33+
/// }
34+
/// ```
35+
///
36+
/// ```js,expect_diagnostic
37+
/// label: switch (a) {
38+
/// case 0:
39+
/// break label;
40+
/// }
41+
/// ```
42+
///
43+
/// ### Valid
44+
///
45+
/// ```js
46+
/// outer: while (a) {
47+
/// while(b) {
48+
/// break outer;
49+
/// }
50+
/// }
51+
/// ```
52+
pub(crate) NoConfusingLabels {
53+
version: "next",
54+
name: "noConfusingLabels",
55+
recommended: true,
56+
}
57+
}
58+
59+
impl Rule for NoConfusingLabels {
60+
type Query = Ast<JsLabeledStatement>;
61+
type State = ();
62+
type Signals = Option<Self::State>;
63+
type Options = ();
64+
65+
fn run(ctx: &RuleContext<Self>) -> Option<Self::State> {
66+
let labeled_stmt = ctx.query();
67+
match labeled_stmt.body().ok()? {
68+
AnyJsStatement::JsDoWhileStatement(_)
69+
| AnyJsStatement::JsForInStatement(_)
70+
| AnyJsStatement::JsForOfStatement(_)
71+
| AnyJsStatement::JsForStatement(_)
72+
| AnyJsStatement::JsWhileStatement(_) => None,
73+
_ => Some(()),
74+
}
75+
}
76+
77+
fn diagnostic(ctx: &RuleContext<Self>, _: &Self::State) -> Option<RuleDiagnostic> {
78+
let labeled_stmt = ctx.query();
79+
Some(
80+
RuleDiagnostic::new(
81+
rule_category!(),
82+
labeled_stmt.label_token().ok()?.text_trimmed_range(),
83+
markup! {
84+
"Unexpected "<Emphasis>"label"</Emphasis>"."
85+
},
86+
)
87+
.note("Only loops should be labeled.\nThe use of labels for other statements is suspicious and unfamiliar."),
88+
)
89+
}
90+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[
2+
"label: foo();",
3+
"A: const foo = 0;",
4+
"A: break A = 0;",
5+
"A: let foo = 0;",
6+
7+
// ifs
8+
"A: if (a) { if (foo()) { break A; } bar(); };",
9+
"A: { if (foo()) { break A; } bar(); };",
10+
11+
// blocks
12+
"A: { if (foo()) { break A; } bar(); };",
13+
"A: { if (foo()) { break A; } bar(); };",
14+
15+
// switches
16+
"A: switch (a) { case 0: break A; default: break; };",
17+
"A: switch (a) { case 0: break A; default: break; };"
18+
]
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
---
2+
source: crates/rome_js_analyze/tests/spec_tests.rs
3+
assertion_line: 92
4+
expression: invalid.jsonc
5+
---
6+
# Input
7+
```js
8+
label: foo();
9+
```
10+
11+
# Diagnostics
12+
```
13+
invalid.jsonc:1:1 lint/nursery/noConfusingLabels ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
14+
15+
! Unexpected label.
16+
17+
> 1 │ label: foo();
18+
│ ^^^^^
19+
20+
i Only loops should be labeled.
21+
The use of labels for other statements is suspicious and unfamiliar.
22+
23+
24+
```
25+
26+
# Input
27+
```js
28+
A: const foo = 0;
29+
```
30+
31+
# Diagnostics
32+
```
33+
invalid.jsonc:1:1 lint/nursery/noConfusingLabels ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
34+
35+
! Unexpected label.
36+
37+
> 1 │ A: const foo = 0;
38+
│ ^
39+
40+
i Only loops should be labeled.
41+
The use of labels for other statements is suspicious and unfamiliar.
42+
43+
44+
```
45+
46+
# Input
47+
```js
48+
A: break A = 0;
49+
```
50+
51+
# Diagnostics
52+
```
53+
invalid.jsonc:1:1 lint/nursery/noConfusingLabels ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
54+
55+
! Unexpected label.
56+
57+
> 1 │ A: break A = 0;
58+
│ ^
59+
60+
i Only loops should be labeled.
61+
The use of labels for other statements is suspicious and unfamiliar.
62+
63+
64+
```
65+
66+
# Input
67+
```js
68+
A: let foo = 0;
69+
```
70+
71+
# Diagnostics
72+
```
73+
invalid.jsonc:1:1 lint/nursery/noConfusingLabels ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
74+
75+
! Unexpected label.
76+
77+
> 1 │ A: let foo = 0;
78+
│ ^
79+
80+
i Only loops should be labeled.
81+
The use of labels for other statements is suspicious and unfamiliar.
82+
83+
84+
```
85+
86+
# Input
87+
```js
88+
A: if (a) { if (foo()) { break A; } bar(); };
89+
```
90+
91+
# Diagnostics
92+
```
93+
invalid.jsonc:1:1 lint/nursery/noConfusingLabels ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
94+
95+
! Unexpected label.
96+
97+
> 1 │ A: if (a) { if (foo()) { break A; } bar(); };
98+
│ ^
99+
100+
i Only loops should be labeled.
101+
The use of labels for other statements is suspicious and unfamiliar.
102+
103+
104+
```
105+
106+
# Input
107+
```js
108+
A: { if (foo()) { break A; } bar(); };
109+
```
110+
111+
# Diagnostics
112+
```
113+
invalid.jsonc:1:1 lint/nursery/noConfusingLabels ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
114+
115+
! Unexpected label.
116+
117+
> 1 │ A: { if (foo()) { break A; } bar(); };
118+
│ ^
119+
120+
i Only loops should be labeled.
121+
The use of labels for other statements is suspicious and unfamiliar.
122+
123+
124+
```
125+
126+
# Input
127+
```js
128+
A: { if (foo()) { break A; } bar(); };
129+
```
130+
131+
# Diagnostics
132+
```
133+
invalid.jsonc:1:1 lint/nursery/noConfusingLabels ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
134+
135+
! Unexpected label.
136+
137+
> 1 │ A: { if (foo()) { break A; } bar(); };
138+
│ ^
139+
140+
i Only loops should be labeled.
141+
The use of labels for other statements is suspicious and unfamiliar.
142+
143+
144+
```
145+
146+
# Input
147+
```js
148+
A: { if (foo()) { break A; } bar(); };
149+
```
150+
151+
# Diagnostics
152+
```
153+
invalid.jsonc:1:1 lint/nursery/noConfusingLabels ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
154+
155+
! Unexpected label.
156+
157+
> 1 │ A: { if (foo()) { break A; } bar(); };
158+
│ ^
159+
160+
i Only loops should be labeled.
161+
The use of labels for other statements is suspicious and unfamiliar.
162+
163+
164+
```
165+
166+
# Input
167+
```js
168+
A: switch (a) { case 0: break A; default: break; };
169+
```
170+
171+
# Diagnostics
172+
```
173+
invalid.jsonc:1:1 lint/nursery/noConfusingLabels ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
174+
175+
! Unexpected label.
176+
177+
> 1 │ A: switch (a) { case 0: break A; default: break; };
178+
│ ^
179+
180+
i Only loops should be labeled.
181+
The use of labels for other statements is suspicious and unfamiliar.
182+
183+
184+
```
185+
186+
# Input
187+
```js
188+
A: switch (a) { case 0: break A; default: break; };
189+
```
190+
191+
# Diagnostics
192+
```
193+
invalid.jsonc:1:1 lint/nursery/noConfusingLabels ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
194+
195+
! Unexpected label.
196+
197+
> 1 │ A: switch (a) { case 0: break A; default: break; };
198+
│ ^
199+
200+
i Only loops should be labeled.
201+
The use of labels for other statements is suspicious and unfamiliar.
202+
203+
204+
```
205+
206+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[
2+
// no labels
3+
"const f = { label: foo ()}",
4+
"while (true) {}",
5+
"while (true) { break; }",
6+
"while (true) { continue; }",
7+
8+
// loops
9+
"label: while(true) {}",
10+
"label: while (true) { break label; }",
11+
"label: while (true) { continue label; }",
12+
"A: while (a) { break A; }",
13+
"A: do { if (b) { break A; } } while (a);",
14+
"A: for (let a in obj) { for (;;) { switch (a) { case 0: break A; } } }",
15+
"A: for (let a of arr) { for (;;) { switch (a) { case 0: break A; } } }"
16+
]

0 commit comments

Comments
 (0)