-
-
Notifications
You must be signed in to change notification settings - Fork 794
feat(lint): implement noContinue
#7856
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
5424ddd
e519896
8b4968e
c932779
419b3b4
7563e02
40bfcfe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| --- | ||
| "@biomejs/biome": patch | ||
| --- | ||
|
|
||
| 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. | ||
|
|
||
| **Invalid:** | ||
| ```js | ||
| let sum = 0, | ||
| i; | ||
|
|
||
| for(i = 0; i < 10; i++) { | ||
| if(i >= 5) { | ||
| continue; | ||
| } | ||
|
|
||
| sum += i; | ||
| } | ||
| ``` | ||
|
|
||
| **Valid:** | ||
| ```js | ||
| let sum = 0, | ||
| i; | ||
|
|
||
| for(i = 0; i < 10; i++) { | ||
| if(i < 5) { | ||
| sum += i; | ||
| } | ||
| } | ||
| ``` |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| use biome_analyze::{ | ||
| Ast, Rule, RuleDiagnostic, RuleSource, context::RuleContext, declare_lint_rule, | ||
| }; | ||
| use biome_console::markup; | ||
| use biome_js_syntax::JsContinueStatement; | ||
| use biome_rowan::AstNode; | ||
| use biome_rule_options::no_continue::NoContinueOptions; | ||
|
|
||
| declare_lint_rule! { | ||
| /// Disallow continue statements. | ||
| /// | ||
| /// 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. | ||
| /// When used incorrectly it makes code less testable, less readable and less maintainable. | ||
| /// Structured control flow statements such as if should be used instead. | ||
| /// | ||
| /// ## Examples | ||
| /// | ||
| /// ### Invalid | ||
| /// | ||
| /// ```js,expect_diagnostic | ||
| /// let sum = 0, | ||
| /// i; | ||
| /// | ||
| /// for(i = 0; i < 10; i++) { | ||
| /// if(i >= 5) { | ||
| /// continue; | ||
| /// } | ||
| /// | ||
| /// sum += i; | ||
| /// } | ||
| /// ``` | ||
| /// | ||
| /// ### Valid | ||
| /// | ||
| /// ```js | ||
| /// let sum = 0, | ||
| /// i; | ||
| /// | ||
| /// for(i = 0; i < 10; i++) { | ||
| /// if(i < 5) { | ||
| /// sum += i; | ||
| /// } | ||
| /// } | ||
| /// ``` | ||
| /// | ||
| pub NoContinue { | ||
| version: "next", | ||
| name: "noContinue", | ||
| language: "js", | ||
| recommended: false, | ||
| sources: &[RuleSource::Eslint("no-continue").same()], | ||
| } | ||
| } | ||
|
|
||
| impl Rule for NoContinue { | ||
| type Query = Ast<JsContinueStatement>; | ||
| type State = (); | ||
| type Signals = Option<Self::State>; | ||
| type Options = NoContinueOptions; | ||
|
|
||
| fn run(_ctx: &RuleContext<Self>) -> Self::Signals { | ||
| Some(()) | ||
| } | ||
|
|
||
| fn diagnostic(ctx: &RuleContext<Self>, _state: &Self::State) -> Option<RuleDiagnostic> { | ||
| let node = ctx.query(); | ||
| Some( | ||
| RuleDiagnostic::new( | ||
| rule_category!(), | ||
| node.range(), | ||
| markup! { | ||
| "Unexpected use of continue statement." | ||
| }, | ||
| ) | ||
| .note(markup! { | ||
| "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." | ||
| }), | ||
ematipico marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| var sum = 0, i; for (i = 0; i < 10; i++) { if (i <= 5) { continue; } sum += i; } | ||
| var sum = 0, i; myLabel: for (i = 0; i < 10; i++) { if (i <= 5) { continue myLabel; } sum += i; } | ||
| var sum = 0, i = 0; while (i < 10) { if (i <= 5) { i++; continue; } sum += i; i++; } | ||
| var sum = 0, i = 0; myLabel: while (i < 10) { if (i <= 5) { i++; continue myLabel; } sum += i; i++; } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| --- | ||
| source: crates/biome_js_analyze/tests/spec_tests.rs | ||
| expression: invalid.js | ||
| --- | ||
| # Input | ||
| ```js | ||
| var sum = 0, i; for (i = 0; i < 10; i++) { if (i <= 5) { continue; } sum += i; } | ||
| var sum = 0, i; myLabel: for (i = 0; i < 10; i++) { if (i <= 5) { continue myLabel; } sum += i; } | ||
| var sum = 0, i = 0; while (i < 10) { if (i <= 5) { i++; continue; } sum += i; i++; } | ||
| var sum = 0, i = 0; myLabel: while (i < 10) { if (i <= 5) { i++; continue myLabel; } sum += i; i++; } | ||
|
|
||
| ``` | ||
|
|
||
| # Diagnostics | ||
| ``` | ||
| invalid.js:1:58 lint/nursery/noContinue ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | ||
|
|
||
| i Unexpected use of continue statement. | ||
|
|
||
| > 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++; } | ||
|
|
||
| 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. | ||
|
|
||
|
|
||
| ``` | ||
|
|
||
| ``` | ||
| invalid.js:2:67 lint/nursery/noContinue ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | ||
|
|
||
| i Unexpected use of continue statement. | ||
|
|
||
| 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++; } | ||
|
|
||
| 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. | ||
|
|
||
|
|
||
| ``` | ||
|
|
||
| ``` | ||
| invalid.js:3:57 lint/nursery/noContinue ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | ||
|
|
||
| i Unexpected use of continue statement. | ||
|
|
||
| 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++; } | ||
| 5 │ | ||
|
|
||
| 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. | ||
|
|
||
|
|
||
| ``` | ||
|
|
||
| ``` | ||
| invalid.js:4:66 lint/nursery/noContinue ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | ||
|
|
||
| i Unexpected use of continue statement. | ||
|
|
||
| 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++; } | ||
| │ ^^^^^^^^^^^^^^^^^ | ||
| 5 │ | ||
|
|
||
| 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. | ||
|
|
||
|
|
||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| /* should not generate diagnostics */ | ||
| var sum = 0, i; for (i = 0; i < 10; i++) { if (i > 5) { sum += i; } } | ||
| var sum = 0, i = 0; while (i < 10) { if (i > 5) { sum += i; } i++; } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| --- | ||
| source: crates/biome_js_analyze/tests/spec_tests.rs | ||
| expression: valid.js | ||
| --- | ||
| # Input | ||
| ```js | ||
| /* should not generate diagnostics */ | ||
| var sum = 0, i; for (i = 0; i < 10; i++) { if (i > 5) { sum += i; } } | ||
| var sum = 0, i = 0; while (i < 10) { if (i > 5) { sum += i; } i++; } | ||
|
|
||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| use biome_deserialize_macros::Deserializable; | ||
| use serde::{Deserialize, Serialize}; | ||
| #[derive(Default, Clone, Debug, Deserialize, Deserializable, Eq, PartialEq, Serialize)] | ||
| #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] | ||
| #[serde(rename_all = "camelCase", deny_unknown_fields, default)] | ||
| pub struct NoContinueOptions {} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we check if this is inside a loop? That's what the docs say
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mhm, the source code of Eslint doesn't either 🤔.
Could also be confusing to use in switch statements
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, the docs and the rule must match. Docs are usually in higher order, and the code follows
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will add a mention of switch statements in the docs :)
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, what am I saying lol. Switch statements don't use
continue🤦, confused withbreakfor a secThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
continuestatement is only valid syntax in a loop to begin with