Skip to content
This repository was archived by the owner on Aug 31, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/rome_diagnostics_categories/src/categories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ define_dategories! {
"lint/nursery/noHeaderScope": "https://docs.rome.tools/lint/rules/noHeaderScope",
"lint/nursery/noInnerDeclarations": "https://docs.rome.tools/lint/rules/noInnerDeclarations",
"lint/nursery/noInvalidConstructorSuper": "https://docs.rome.tools/lint/rules/noInvalidConstructorSuper",
"lint/nursery/noConfusingLabels": "https://docs.rome.tools/lint/rules/noConfusingLabels",
"lint/nursery/noNonNullAssertion": "https://docs.rome.tools/lint/rules/noNonNullAssertion",
"lint/nursery/noPrecisionLoss": "https://docs.rome.tools/lint/rules/noPrecisionLoss",
"lint/nursery/noRedundantAlt": "https://docs.rome.tools/lint/rules/noRedundantAlt",
Expand Down
3 changes: 2 additions & 1 deletion crates/rome_js_analyze/src/analyzers/nursery.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use rome_analyze::context::RuleContext;
use rome_analyze::{declare_rule, Ast, Rule, RuleDiagnostic};
use rome_console::markup;
use rome_js_syntax::{AnyJsStatement, JsLabeledStatement};

declare_rule! {
/// Disallow labeled statements that are not loops.
///
/// Labeled statements in JavaScript are used in conjunction with `break` and `continue` to control flow around multiple loops.
/// Their use for other statements is suspicious and unfamiliar.
///
/// Source: https://eslint.org/docs/latest/rules/no-labels
///
/// ## Examples
///
/// ### Invalid
///
/// ```js,expect_diagnostic
/// label: f();
/// ```
///
/// ```js,expect_diagnostic
/// label: {
/// f();
/// break label;
/// }
/// ```
///
/// ```js,expect_diagnostic
/// label: if (a) {
/// f()
/// break label;
/// }
/// ```
///
/// ```js,expect_diagnostic
/// label: switch (a) {
/// case 0:
/// break label;
/// }
/// ```
///
/// ### Valid
///
/// ```js
/// outer: while (a) {
/// while(b) {
/// break outer;
/// }
/// }
/// ```
pub(crate) NoConfusingLabels {
version: "next",
name: "noConfusingLabels",
recommended: true,
}
}

impl Rule for NoConfusingLabels {
type Query = Ast<JsLabeledStatement>;
type State = ();
type Signals = Option<Self::State>;
type Options = ();

fn run(ctx: &RuleContext<Self>) -> Option<Self::State> {
let labeled_stmt = ctx.query();
match labeled_stmt.body().ok()? {
AnyJsStatement::JsDoWhileStatement(_)
| AnyJsStatement::JsForInStatement(_)
| AnyJsStatement::JsForOfStatement(_)
| AnyJsStatement::JsForStatement(_)
| AnyJsStatement::JsWhileStatement(_) => None,
_ => Some(()),
}
}

fn diagnostic(ctx: &RuleContext<Self>, _: &Self::State) -> Option<RuleDiagnostic> {
let labeled_stmt = ctx.query();
Some(
RuleDiagnostic::new(
rule_category!(),
labeled_stmt.label_token().ok()?.text_trimmed_range(),
markup! {
"Unexpected "<Emphasis>"label"</Emphasis>"."
},
)
.note("Only loops should be labeled.\nThe use of labels for other statements is suspicious and unfamiliar."),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
"label: foo();",
"A: const foo = 0;",
"A: break A = 0;",
"A: let foo = 0;",

// ifs
"A: if (a) { if (foo()) { break A; } bar(); };",
"A: { if (foo()) { break A; } bar(); };",

// blocks
"A: { if (foo()) { break A; } bar(); };",
"A: { if (foo()) { break A; } bar(); };",

// switches
"A: switch (a) { case 0: break A; default: break; };",
"A: switch (a) { case 0: break A; default: break; };"
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
---
source: crates/rome_js_analyze/tests/spec_tests.rs
assertion_line: 92
expression: invalid.jsonc
---
# Input
```js
label: foo();
```

# Diagnostics
```
invalid.jsonc:1:1 lint/nursery/noConfusingLabels ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

! Unexpected label.

> 1 │ label: foo();
│ ^^^^^

i Only loops should be labeled.
The use of labels for other statements is suspicious and unfamiliar.


```

# Input
```js
A: const foo = 0;
```

# Diagnostics
```
invalid.jsonc:1:1 lint/nursery/noConfusingLabels ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

! Unexpected label.

> 1 │ A: const foo = 0;
│ ^

i Only loops should be labeled.
The use of labels for other statements is suspicious and unfamiliar.


```

# Input
```js
A: break A = 0;
```

# Diagnostics
```
invalid.jsonc:1:1 lint/nursery/noConfusingLabels ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

! Unexpected label.

> 1 │ A: break A = 0;
│ ^

i Only loops should be labeled.
The use of labels for other statements is suspicious and unfamiliar.


```

# Input
```js
A: let foo = 0;
```

# Diagnostics
```
invalid.jsonc:1:1 lint/nursery/noConfusingLabels ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

! Unexpected label.

> 1 │ A: let foo = 0;
│ ^

i Only loops should be labeled.
The use of labels for other statements is suspicious and unfamiliar.


```

# Input
```js
A: if (a) { if (foo()) { break A; } bar(); };
```

# Diagnostics
```
invalid.jsonc:1:1 lint/nursery/noConfusingLabels ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

! Unexpected label.

> 1 │ A: if (a) { if (foo()) { break A; } bar(); };
│ ^

i Only loops should be labeled.
The use of labels for other statements is suspicious and unfamiliar.


```

# Input
```js
A: { if (foo()) { break A; } bar(); };
```

# Diagnostics
```
invalid.jsonc:1:1 lint/nursery/noConfusingLabels ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

! Unexpected label.

> 1 │ A: { if (foo()) { break A; } bar(); };
│ ^

i Only loops should be labeled.
The use of labels for other statements is suspicious and unfamiliar.


```

# Input
```js
A: { if (foo()) { break A; } bar(); };
```

# Diagnostics
```
invalid.jsonc:1:1 lint/nursery/noConfusingLabels ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

! Unexpected label.

> 1 │ A: { if (foo()) { break A; } bar(); };
│ ^

i Only loops should be labeled.
The use of labels for other statements is suspicious and unfamiliar.


```

# Input
```js
A: { if (foo()) { break A; } bar(); };
```

# Diagnostics
```
invalid.jsonc:1:1 lint/nursery/noConfusingLabels ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

! Unexpected label.

> 1 │ A: { if (foo()) { break A; } bar(); };
│ ^

i Only loops should be labeled.
The use of labels for other statements is suspicious and unfamiliar.


```

# Input
```js
A: switch (a) { case 0: break A; default: break; };
```

# Diagnostics
```
invalid.jsonc:1:1 lint/nursery/noConfusingLabels ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

! Unexpected label.

> 1 │ A: switch (a) { case 0: break A; default: break; };
│ ^

i Only loops should be labeled.
The use of labels for other statements is suspicious and unfamiliar.


```

# Input
```js
A: switch (a) { case 0: break A; default: break; };
```

# Diagnostics
```
invalid.jsonc:1:1 lint/nursery/noConfusingLabels ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

! Unexpected label.

> 1 │ A: switch (a) { case 0: break A; default: break; };
│ ^

i Only loops should be labeled.
The use of labels for other statements is suspicious and unfamiliar.


```


Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[
// no labels
"const f = { label: foo ()}",
"while (true) {}",
"while (true) { break; }",
"while (true) { continue; }",

// loops
"label: while(true) {}",
"label: while (true) { break label; }",
"label: while (true) { continue label; }",
"A: while (a) { break A; }",
"A: do { if (b) { break A; } } while (a);",
"A: for (let a in obj) { for (;;) { switch (a) { case 0: break A; } } }",
"A: for (let a of arr) { for (;;) { switch (a) { case 0: break A; } } }"
]
Loading