Skip to content

Commit c9e20c3

Browse files
feat(lint): implement noContinue (#7856)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 82dd523 commit c9e20c3

File tree

14 files changed

+362
-66
lines changed

14 files changed

+362
-66
lines changed

.changeset/yellow-crews-guess.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
"@biomejs/biome": patch
3+
---
4+
5+
Added the nursery rule [`noContinue`](https://biomejs.dev/linter/rules/no-continue/). Disallowing the usage of the `continue` statement, structured control flow statements such as `if` should be used instead.
6+
7+
**Invalid:**
8+
```js
9+
let sum = 0,
10+
i;
11+
12+
for(i = 0; i < 10; i++) {
13+
if(i >= 5) {
14+
continue;
15+
}
16+
17+
sum += i;
18+
}
19+
```
20+
21+
**Valid:**
22+
```js
23+
let sum = 0,
24+
i;
25+
26+
for(i = 0; i < 10; i++) {
27+
if(i < 5) {
28+
sum += i;
29+
}
30+
}
31+
```

crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/biome_configuration/src/analyzer/linter/rules.rs

Lines changed: 86 additions & 65 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/biome_diagnostics_categories/src/categories.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ define_categories! {
165165
"lint/correctness/useValidTypeof": "https://biomejs.dev/linter/rules/use-valid-typeof",
166166
"lint/correctness/useYield": "https://biomejs.dev/linter/rules/use-yield",
167167
"lint/nursery/noColorInvalidHex": "https://biomejs.dev/linter/rules/no-color-invalid-hex",
168+
"lint/nursery/noContinue": "https://biomejs.dev/linter/rules/no-continue",
168169
"lint/nursery/noDeprecatedImports": "https://biomejs.dev/linter/rules/no-deprecated-imports",
169170
"lint/nursery/noDuplicateDependencies": "https://biomejs.dev/linter/rules/no-duplicate-dependencies",
170171
"lint/nursery/noEmptySource": "https://biomejs.dev/linter/rules/no-empty-source",

crates/biome_js_analyze/src/lint/nursery.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//! Generated file, do not edit by hand, see `xtask/codegen`
44
55
use biome_analyze::declare_lint_group;
6+
pub mod no_continue;
67
pub mod no_deprecated_imports;
78
pub mod no_empty_source;
89
pub mod no_floating_promises;
@@ -33,4 +34,4 @@ pub mod use_qwik_valid_lexical_scope;
3334
pub mod use_sorted_classes;
3435
pub mod use_vue_define_macros_order;
3536
pub mod use_vue_multi_word_component_names;
36-
declare_lint_group! { pub Nursery { name : "nursery" , rules : [self :: no_deprecated_imports :: NoDeprecatedImports , self :: no_empty_source :: NoEmptySource , self :: no_floating_promises :: NoFloatingPromises , self :: no_import_cycles :: NoImportCycles , self :: no_increment_decrement :: NoIncrementDecrement , self :: no_jsx_literals :: NoJsxLiterals , self :: no_misused_promises :: NoMisusedPromises , self :: no_next_async_client_component :: NoNextAsyncClientComponent , self :: no_parameters_only_used_in_recursion :: NoParametersOnlyUsedInRecursion , self :: no_react_forward_ref :: NoReactForwardRef , self :: no_shadow :: NoShadow , self :: no_unknown_attribute :: NoUnknownAttribute , self :: no_unnecessary_conditions :: NoUnnecessaryConditions , self :: no_unresolved_imports :: NoUnresolvedImports , self :: no_unused_expressions :: NoUnusedExpressions , self :: no_useless_catch_binding :: NoUselessCatchBinding , self :: no_useless_undefined :: NoUselessUndefined , self :: no_vue_data_object_declaration :: NoVueDataObjectDeclaration , self :: no_vue_duplicate_keys :: NoVueDuplicateKeys , self :: no_vue_reserved_keys :: NoVueReservedKeys , self :: no_vue_reserved_props :: NoVueReservedProps , self :: use_consistent_arrow_return :: UseConsistentArrowReturn , self :: use_exhaustive_switch_cases :: UseExhaustiveSwitchCases , self :: use_explicit_type :: UseExplicitType , self :: use_max_params :: UseMaxParams , self :: use_qwik_method_usage :: UseQwikMethodUsage , self :: use_qwik_valid_lexical_scope :: UseQwikValidLexicalScope , self :: use_sorted_classes :: UseSortedClasses , self :: use_vue_define_macros_order :: UseVueDefineMacrosOrder , self :: use_vue_multi_word_component_names :: UseVueMultiWordComponentNames ,] } }
37+
declare_lint_group! { pub Nursery { name : "nursery" , rules : [self :: no_continue :: NoContinue , self :: no_deprecated_imports :: NoDeprecatedImports , self :: no_empty_source :: NoEmptySource , self :: no_floating_promises :: NoFloatingPromises , self :: no_import_cycles :: NoImportCycles , self :: no_increment_decrement :: NoIncrementDecrement , self :: no_jsx_literals :: NoJsxLiterals , self :: no_misused_promises :: NoMisusedPromises , self :: no_next_async_client_component :: NoNextAsyncClientComponent , self :: no_parameters_only_used_in_recursion :: NoParametersOnlyUsedInRecursion , self :: no_react_forward_ref :: NoReactForwardRef , self :: no_shadow :: NoShadow , self :: no_unknown_attribute :: NoUnknownAttribute , self :: no_unnecessary_conditions :: NoUnnecessaryConditions , self :: no_unresolved_imports :: NoUnresolvedImports , self :: no_unused_expressions :: NoUnusedExpressions , self :: no_useless_catch_binding :: NoUselessCatchBinding , self :: no_useless_undefined :: NoUselessUndefined , self :: no_vue_data_object_declaration :: NoVueDataObjectDeclaration , self :: no_vue_duplicate_keys :: NoVueDuplicateKeys , self :: no_vue_reserved_keys :: NoVueReservedKeys , self :: no_vue_reserved_props :: NoVueReservedProps , self :: use_consistent_arrow_return :: UseConsistentArrowReturn , self :: use_exhaustive_switch_cases :: UseExhaustiveSwitchCases , self :: use_explicit_type :: UseExplicitType , self :: use_max_params :: UseMaxParams , self :: use_qwik_method_usage :: UseQwikMethodUsage , self :: use_qwik_valid_lexical_scope :: UseQwikValidLexicalScope , self :: use_sorted_classes :: UseSortedClasses , self :: use_vue_define_macros_order :: UseVueDefineMacrosOrder , self :: use_vue_multi_word_component_names :: UseVueMultiWordComponentNames ,] } }
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
use biome_analyze::{
2+
Ast, Rule, RuleDiagnostic, RuleSource, context::RuleContext, declare_lint_rule,
3+
};
4+
use biome_console::markup;
5+
use biome_js_syntax::JsContinueStatement;
6+
use biome_rowan::AstNode;
7+
use biome_rule_options::no_continue::NoContinueOptions;
8+
9+
declare_lint_rule! {
10+
/// Disallow continue statements.
11+
///
12+
/// The continue statement terminates execution of the statements in the current iteration of the current or labeled loop, and continues execution of the loop with the next iteration.
13+
/// When used incorrectly it makes code less testable, less readable and less maintainable.
14+
/// Structured control flow statements such as if should be used instead.
15+
///
16+
/// ## Examples
17+
///
18+
/// ### Invalid
19+
///
20+
/// ```js,expect_diagnostic
21+
/// let sum = 0,
22+
/// i;
23+
///
24+
/// for(i = 0; i < 10; i++) {
25+
/// if(i >= 5) {
26+
/// continue;
27+
/// }
28+
///
29+
/// sum += i;
30+
/// }
31+
/// ```
32+
///
33+
/// ### Valid
34+
///
35+
/// ```js
36+
/// let sum = 0,
37+
/// i;
38+
///
39+
/// for(i = 0; i < 10; i++) {
40+
/// if(i < 5) {
41+
/// sum += i;
42+
/// }
43+
/// }
44+
/// ```
45+
///
46+
pub NoContinue {
47+
version: "next",
48+
name: "noContinue",
49+
language: "js",
50+
recommended: false,
51+
sources: &[RuleSource::Eslint("no-continue").same()],
52+
}
53+
}
54+
55+
impl Rule for NoContinue {
56+
type Query = Ast<JsContinueStatement>;
57+
type State = ();
58+
type Signals = Option<Self::State>;
59+
type Options = NoContinueOptions;
60+
61+
fn run(_ctx: &RuleContext<Self>) -> Self::Signals {
62+
Some(())
63+
}
64+
65+
fn diagnostic(ctx: &RuleContext<Self>, _state: &Self::State) -> Option<RuleDiagnostic> {
66+
let node = ctx.query();
67+
Some(
68+
RuleDiagnostic::new(
69+
rule_category!(),
70+
node.range(),
71+
markup! {
72+
"Unexpected use of continue statement."
73+
},
74+
)
75+
.note(markup! {
76+
"The continue statement terminates execution of the statements in the current iteration, when used incorrectly it makes code less testable, less readable and less maintainable. Structured control flow statements such as if should be used instead."
77+
}),
78+
)
79+
}
80+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
var sum = 0, i; for (i = 0; i < 10; i++) { if (i <= 5) { continue; } sum += i; }
2+
var sum = 0, i; myLabel: for (i = 0; i < 10; i++) { if (i <= 5) { continue myLabel; } sum += i; }
3+
var sum = 0, i = 0; while (i < 10) { if (i <= 5) { i++; continue; } sum += i; i++; }
4+
var sum = 0, i = 0; myLabel: while (i < 10) { if (i <= 5) { i++; continue myLabel; } sum += i; i++; }
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
---
2+
source: crates/biome_js_analyze/tests/spec_tests.rs
3+
expression: invalid.js
4+
---
5+
# Input
6+
```js
7+
var sum = 0, i; for (i = 0; i < 10; i++) { if (i <= 5) { continue; } sum += i; }
8+
var sum = 0, i; myLabel: for (i = 0; i < 10; i++) { if (i <= 5) { continue myLabel; } sum += i; }
9+
var sum = 0, i = 0; while (i < 10) { if (i <= 5) { i++; continue; } sum += i; i++; }
10+
var sum = 0, i = 0; myLabel: while (i < 10) { if (i <= 5) { i++; continue myLabel; } sum += i; i++; }
11+
12+
```
13+
14+
# Diagnostics
15+
```
16+
invalid.js:1:58 lint/nursery/noContinue ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
17+
18+
i Unexpected use of continue statement.
19+
20+
> 1 │ var sum = 0, i; for (i = 0; i < 10; i++) { if (i <= 5) { continue; } sum += i; }
21+
│ ^^^^^^^^^
22+
2 │ var sum = 0, i; myLabel: for (i = 0; i < 10; i++) { if (i <= 5) { continue myLabel; } sum += i; }
23+
3 │ var sum = 0, i = 0; while (i < 10) { if (i <= 5) { i++; continue; } sum += i; i++; }
24+
25+
i The continue statement terminates execution of the statements in the current iteration, when used incorrectly it makes code less testable, less readable and less maintainable. Structured control flow statements such as if should be used instead.
26+
27+
28+
```
29+
30+
```
31+
invalid.js:2:67 lint/nursery/noContinue ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
32+
33+
i Unexpected use of continue statement.
34+
35+
1 │ var sum = 0, i; for (i = 0; i < 10; i++) { if (i <= 5) { continue; } sum += i; }
36+
> 2 │ var sum = 0, i; myLabel: for (i = 0; i < 10; i++) { if (i <= 5) { continue myLabel; } sum += i; }
37+
│ ^^^^^^^^^^^^^^^^^
38+
3 │ var sum = 0, i = 0; while (i < 10) { if (i <= 5) { i++; continue; } sum += i; i++; }
39+
4 │ var sum = 0, i = 0; myLabel: while (i < 10) { if (i <= 5) { i++; continue myLabel; } sum += i; i++; }
40+
41+
i The continue statement terminates execution of the statements in the current iteration, when used incorrectly it makes code less testable, less readable and less maintainable. Structured control flow statements such as if should be used instead.
42+
43+
44+
```
45+
46+
```
47+
invalid.js:3:57 lint/nursery/noContinue ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
48+
49+
i Unexpected use of continue statement.
50+
51+
1 │ var sum = 0, i; for (i = 0; i < 10; i++) { if (i <= 5) { continue; } sum += i; }
52+
2 │ var sum = 0, i; myLabel: for (i = 0; i < 10; i++) { if (i <= 5) { continue myLabel; } sum += i; }
53+
> 3 │ var sum = 0, i = 0; while (i < 10) { if (i <= 5) { i++; continue; } sum += i; i++; }
54+
│ ^^^^^^^^^
55+
4 │ var sum = 0, i = 0; myLabel: while (i < 10) { if (i <= 5) { i++; continue myLabel; } sum += i; i++; }
56+
5 │
57+
58+
i The continue statement terminates execution of the statements in the current iteration, when used incorrectly it makes code less testable, less readable and less maintainable. Structured control flow statements such as if should be used instead.
59+
60+
61+
```
62+
63+
```
64+
invalid.js:4:66 lint/nursery/noContinue ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
65+
66+
i Unexpected use of continue statement.
67+
68+
2 │ var sum = 0, i; myLabel: for (i = 0; i < 10; i++) { if (i <= 5) { continue myLabel; } sum += i; }
69+
3 │ var sum = 0, i = 0; while (i < 10) { if (i <= 5) { i++; continue; } sum += i; i++; }
70+
> 4 │ var sum = 0, i = 0; myLabel: while (i < 10) { if (i <= 5) { i++; continue myLabel; } sum += i; i++; }
71+
│ ^^^^^^^^^^^^^^^^^
72+
5 │
73+
74+
i The continue statement terminates execution of the statements in the current iteration, when used incorrectly it makes code less testable, less readable and less maintainable. Structured control flow statements such as if should be used instead.
75+
76+
77+
```
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/* should not generate diagnostics */
2+
var sum = 0, i; for (i = 0; i < 10; i++) { if (i > 5) { sum += i; } }
3+
var sum = 0, i = 0; while (i < 10) { if (i > 5) { sum += i; } i++; }
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
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 sum = 0, i; for (i = 0; i < 10; i++) { if (i > 5) { sum += i; } }
9+
var sum = 0, i = 0; while (i < 10) { if (i > 5) { sum += i; } i++; }
10+
11+
```

0 commit comments

Comments
 (0)