Skip to content

Commit cd2edd7

Browse files
authored
feat(js_analyze): implement noTernary (#8201)
1 parent c085384 commit cd2edd7

File tree

14 files changed

+325
-71
lines changed

14 files changed

+325
-71
lines changed

.changeset/no-ternary.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
"@biomejs/biome": patch
3+
---
4+
5+
Added the nursery rule [`noTernary`](https://biomejs.dev/linter/rules/no-ternary/). Disallow ternary operators.
6+
7+
**Invalid:**
8+
9+
```js
10+
const foo = isBar ? baz : qux;
11+
```

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: 91 additions & 70 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
@@ -182,6 +182,7 @@ define_categories! {
182182
"lint/nursery/noReactForwardRef": "https://biomejs.dev/linter/rules/no-react-forward-ref",
183183
"lint/nursery/noShadow": "https://biomejs.dev/linter/rules/no-shadow",
184184
"lint/nursery/noSyncScripts": "https://biomejs.dev/linter/rules/no-sync-scripts",
185+
"lint/nursery/noTernary": "https://biomejs.dev/linter/rules/no-ternary",
185186
"lint/nursery/noUnknownAttribute": "https://biomejs.dev/linter/rules/no-unknown-attribute",
186187
"lint/nursery/noUnnecessaryConditions": "https://biomejs.dev/linter/rules/no-unnecessary-conditions",
187188
"lint/nursery/noUnresolvedImports": "https://biomejs.dev/linter/rules/no-unresolved-imports",

crates/biome_js_analyze/src/lint/nursery.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub mod no_parameters_only_used_in_recursion;
1717
pub mod no_react_forward_ref;
1818
pub mod no_shadow;
1919
pub mod no_sync_scripts;
20+
pub mod no_ternary;
2021
pub mod no_unknown_attribute;
2122
pub mod no_unnecessary_conditions;
2223
pub mod no_unresolved_imports;
@@ -39,4 +40,4 @@ pub mod use_sorted_classes;
3940
pub mod use_spread;
4041
pub mod use_vue_define_macros_order;
4142
pub mod use_vue_multi_word_component_names;
42-
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_for_in :: NoForIn , 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_sync_scripts :: NoSyncScripts , 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_array_sort_compare :: UseArraySortCompare , self :: use_consistent_arrow_return :: UseConsistentArrowReturn , self :: use_exhaustive_switch_cases :: UseExhaustiveSwitchCases , self :: use_explicit_type :: UseExplicitType , self :: use_find :: UseFind , 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_spread :: UseSpread , self :: use_vue_define_macros_order :: UseVueDefineMacrosOrder , self :: use_vue_multi_word_component_names :: UseVueMultiWordComponentNames ,] } }
43+
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_for_in :: NoForIn , 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_sync_scripts :: NoSyncScripts , self :: no_ternary :: NoTernary , 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_array_sort_compare :: UseArraySortCompare , self :: use_consistent_arrow_return :: UseConsistentArrowReturn , self :: use_exhaustive_switch_cases :: UseExhaustiveSwitchCases , self :: use_explicit_type :: UseExplicitType , self :: use_find :: UseFind , 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_spread :: UseSpread , self :: use_vue_define_macros_order :: UseVueDefineMacrosOrder , self :: use_vue_multi_word_component_names :: UseVueMultiWordComponentNames ,] } }
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
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::JsConditionalExpression;
6+
use biome_rowan::AstNode;
7+
use biome_rule_options::no_ternary::NoTernaryOptions;
8+
9+
declare_lint_rule! {
10+
/// Disallow ternary operators.
11+
///
12+
/// The ternary operator is used to conditionally assign a value to a variable.
13+
/// Some believe that the use of ternary operators leads to unclear code.
14+
///
15+
/// ## Examples
16+
///
17+
/// ### Invalid
18+
///
19+
/// ```js,expect_diagnostic
20+
/// const foo = isBar ? baz : qux;
21+
/// ```
22+
///
23+
/// ### Valid
24+
///
25+
/// ```js
26+
/// let foo;
27+
///
28+
/// if (isBar) {
29+
/// foo = baz;
30+
/// } else {
31+
/// foo = qux;
32+
/// }
33+
/// ```
34+
///
35+
pub NoTernary {
36+
version: "next",
37+
name: "noTernary",
38+
language: "js",
39+
recommended: false,
40+
sources: &[RuleSource::Eslint("no-ternary").same()],
41+
}
42+
}
43+
44+
impl Rule for NoTernary {
45+
type Query = Ast<JsConditionalExpression>;
46+
type State = ();
47+
type Signals = Option<Self::State>;
48+
type Options = NoTernaryOptions;
49+
50+
fn run(_ctx: &RuleContext<Self>) -> Self::Signals {
51+
Some(())
52+
}
53+
54+
fn diagnostic(ctx: &RuleContext<Self>, _state: &Self::State) -> Option<RuleDiagnostic> {
55+
let node = ctx.query();
56+
Some(
57+
RuleDiagnostic::new(
58+
rule_category!(),
59+
node.range(),
60+
markup! {
61+
"Unexpected ternary operator."
62+
},
63+
)
64+
.note(markup! {
65+
"Ternary operators can lead to unclear code. Use if-else statement instead."
66+
}),
67+
)
68+
}
69+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/* should generate diagnostics */
2+
const foo = isBar ? baz : qux;
3+
4+
function quux() {
5+
return foo ? bar() : baz();
6+
}
7+
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
source: crates/biome_js_analyze/tests/spec_tests.rs
3+
expression: invalid.js
4+
---
5+
# Input
6+
```js
7+
/* should generate diagnostics */
8+
const foo = isBar ? baz : qux;
9+
10+
function quux() {
11+
return foo ? bar() : baz();
12+
}
13+
14+
15+
```
16+
17+
# Diagnostics
18+
```
19+
invalid.js:2:13 lint/nursery/noTernary ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
20+
21+
i Unexpected ternary operator.
22+
23+
1 │ /* should generate diagnostics */
24+
> 2 │ const foo = isBar ? baz : qux;
25+
│ ^^^^^^^^^^^^^^^^^
26+
3 │
27+
4 │ function quux() {
28+
29+
i Ternary operators can lead to unclear code. Use if-else statement instead.
30+
31+
32+
```
33+
34+
```
35+
invalid.js:5:9 lint/nursery/noTernary ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
36+
37+
i Unexpected ternary operator.
38+
39+
4function quux() {
40+
> 5return foo ? bar() : baz();
41+
^^^^^^^^^^^^^^^^^^^
42+
6 │ }
43+
7
44+
45+
i Ternary operators can lead to unclear code. Use if-else statement instead.
46+
47+
48+
```
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/* should not generate diagnostics */
2+
let foo;
3+
4+
if (isBar) {
5+
foo = baz;
6+
} else {
7+
foo = qux;
8+
}
9+
10+
function quux() {
11+
if (foo) {
12+
return bar();
13+
} else {
14+
return baz();
15+
}
16+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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+
let foo;
9+
10+
if (isBar) {
11+
foo = baz;
12+
} else {
13+
foo = qux;
14+
}
15+
16+
function quux() {
17+
if (foo) {
18+
return bar();
19+
} else {
20+
return baz();
21+
}
22+
}
23+
24+
```

0 commit comments

Comments
 (0)