diff --git a/CHANGELOG.md b/CHANGELOG.md index c01b7d852519..0bb02740e06c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,11 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b #### Bug fixes - Fix case where `jsxRuntime` wasn't being respected by `useImportType` rule ([#2473](https://github.com/biomejs/biome/issues/2473)).Contributed by @arendjr +- Fix [#2460](https://github.com/biomejs/biome/issues/2460), where the rule `noUselessFragments` was crashing the linter in some cases. Now cases like these are correctly handled: + ```jsx + callFunction(<>{bar}>) + ``` + Contributed by @ematipico ### Parser diff --git a/crates/biome_js_analyze/src/lib.rs b/crates/biome_js_analyze/src/lib.rs index f14db5eab9b0..1daabb6c7456 100644 --- a/crates/biome_js_analyze/src/lib.rs +++ b/crates/biome_js_analyze/src/lib.rs @@ -240,7 +240,7 @@ mod tests { use crate::react::hooks::StableHookResult; use crate::{analyze, AnalysisFilter, ControlFlow}; - // #[ignore] + #[ignore] #[test] fn quick_test() { fn markup_to_string(markup: Markup) -> String { @@ -252,11 +252,7 @@ mod tests { String::from_utf8(buffer).unwrap() } - const SOURCE: &str = r#"
"#; + const SOURCE: &str = r#"foo(<>{bar}>);"#; let parsed = parse(SOURCE, JsFileSource::tsx(), JsParserOptions::default()); @@ -268,7 +264,7 @@ mod tests { dependencies_index: Some(1), stable_result: StableHookResult::None, }; - let rule_filter = RuleFilter::Rule("nursery", "useSortedClasses"); + let rule_filter = RuleFilter::Rule("complexity", "noUselessFragments"); options.configuration.rules.push_rule( RuleKey::new("nursery", "useHookAtTopLevel"), diff --git a/crates/biome_js_analyze/src/lint/complexity/no_useless_fragments.rs b/crates/biome_js_analyze/src/lint/complexity/no_useless_fragments.rs index ba90299bffd2..b484e000128d 100644 --- a/crates/biome_js_analyze/src/lint/complexity/no_useless_fragments.rs +++ b/crates/biome_js_analyze/src/lint/complexity/no_useless_fragments.rs @@ -10,9 +10,9 @@ use biome_js_factory::make::{ jsx_tag_expression, token, JsxExpressionChildBuilder, }; use biome_js_syntax::{ - AnyJsxChild, AnyJsxElementName, AnyJsxTag, JsLanguage, JsParenthesizedExpression, JsSyntaxKind, - JsxChildList, JsxElement, JsxExpressionAttributeValue, JsxFragment, JsxTagExpression, JsxText, - T, + AnyJsExpression, AnyJsxChild, AnyJsxElementName, AnyJsxTag, JsLanguage, + JsParenthesizedExpression, JsSyntaxKind, JsxChildList, JsxElement, JsxExpressionAttributeValue, + JsxFragment, JsxTagExpression, JsxText, T, }; use biome_rowan::{declare_node_union, AstNode, AstNodeList, BatchMutation, BatchMutationExt}; @@ -292,7 +292,11 @@ impl Rule for NoUselessFragments { }) } else { child.expression().map(|expression| { - js_expression_statement(expression).build().into_syntax() + if let AnyJsExpression::JsIdentifierExpression(node) = expression { + node.into_syntax() + } else { + js_expression_statement(expression).build().into_syntax() + } }) } } diff --git a/crates/biome_js_analyze/tests/specs/complexity/noUselessFragments/issue_2460.jsx b/crates/biome_js_analyze/tests/specs/complexity/noUselessFragments/issue_2460.jsx new file mode 100644 index 000000000000..3a850b670f53 --- /dev/null +++ b/crates/biome_js_analyze/tests/specs/complexity/noUselessFragments/issue_2460.jsx @@ -0,0 +1 @@ +callFunction(<>{bar}>) diff --git a/crates/biome_js_analyze/tests/specs/complexity/noUselessFragments/issue_2460.jsx.snap b/crates/biome_js_analyze/tests/specs/complexity/noUselessFragments/issue_2460.jsx.snap new file mode 100644 index 000000000000..2c1453d85834 --- /dev/null +++ b/crates/biome_js_analyze/tests/specs/complexity/noUselessFragments/issue_2460.jsx.snap @@ -0,0 +1,28 @@ +--- +source: crates/biome_js_analyze/tests/spec_tests.rs +expression: issue_2460.jsx +--- +# Input +```jsx +callFunction(<>{bar}>) + +``` + +# Diagnostics +``` +issue_2460.jsx:1:14 lint/complexity/noUselessFragments FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Avoid using unnecessary Fragment. + + > 1 │ callFunction(<>{bar}>) + │ ^^^^^^^^^^ + 2 │ + + i A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment. + + i Unsafe fix: Remove the Fragment + + 1 │ callFunction(<>{bar}>) + │ --- ---- + +```