fix(rome_js_analyze): false positives for `noUselessFragments`
MODIFY
crates/rome_js_analyze/src/lib.rs
crates/rome_js_analyze/src/lib.rs
@@ -134,6 +134,7 @@ mod tests {
use rome_diagnostics::{Diagnostic, DiagnosticExt, PrintDiagnostic, Severity};
use rome_js_parser::parse;
use rome_js_syntax::{SourceType, TextRange, TextSize};
+ use std::slice;
use crate::{analyze, AnalysisFilter, ControlFlow};
@@ -149,25 +150,21 @@ mod tests {
String::from_utf8(buffer).unwrap()
}
- const SOURCE: &str = r#"function f() {
- return (
- <div
- ><img /></div>
- )
+ const SOURCE: &str = r#"const obj = {
+ element: <>test</>
};
- f();
"#;
let parsed = parse(SOURCE, FileId::zero(), SourceType::jsx());
let mut error_ranges: Vec<TextRange> = Vec::new();
let options = AnalyzerOptions::default();
- let _rule_filter = RuleFilter::Rule("correctness", "flipBinExp");
+ let rule_filter = RuleFilter::Rule("correctness", "noUselessFragments");
analyze(
FileId::zero(),
&parsed.tree(),
AnalysisFilter {
- // enabled_rules: Some(slice::from_ref(&rule_filter)),
+ enabled_rules: Some(slice::from_ref(&rule_filter)),
..AnalysisFilter::default()
},
&options,

MODIFY
crates/rome_js_analyze/src/semantic_analyzers/correctness/no_useless_fragments.rs
crates/rome_js_analyze/src/semantic_analyzers/correctness/no_useless_fragments.rs
@@ -9,12 +9,10 @@ use rome_js_factory::make::{
ident, js_expression_statement, js_string_literal_expression, jsx_tag_expression,
};
use rome_js_syntax::{
- JsLanguage, JsSyntaxKind, JsxAnyChild, JsxAnyElementName, JsxAnyTag, JsxChildList, JsxElement,
- JsxFragment, JsxTagExpression,
-};
-use rome_rowan::{
- declare_node_union, AstNode, AstNodeList, BatchMutation, BatchMutationExt, SyntaxNodeOptionExt,
+ JsLanguage, JsParenthesizedExpression, JsSyntaxKind, JsxAnyChild, JsxAnyElementName, JsxAnyTag,
+ JsxChildList, JsxElement, JsxFragment, JsxTagExpression,
};
+use rome_rowan::{declare_node_union, AstNode, AstNodeList, BatchMutation, BatchMutationExt};
declare_rule! {
/// Disallow unnecessary fragments
@@ -108,31 +106,42 @@ impl Rule for NoUselessFragments {
let model = ctx.model();
match node {
NoUselessFragmentsQuery::JsxFragment(fragment) => {
- let matches_allowed_parents = node
+ let parents_where_fragments_must_be_preserved = node
.syntax()
.parent()
.map(|parent| match JsxTagExpression::try_cast(parent) {
- Ok(parent) => {
- let parent_kind = parent.syntax().parent().kind();
+ Ok(parent) => parent
+ .syntax()
+ .parent()
+ .and_then(|parent| {
+ if let Some(parenthesized_expression) =
+ JsParenthesizedExpression::cast_ref(&parent)
+ {
+ parenthesized_expression.syntax().parent()
+ } else {
+ Some(parent)
+ }
+ })
+ .map(|parent| {
matches!(
- parent_kind,
- Some(
+ parent.kind(),
JsSyntaxKind::JS_RETURN_STATEMENT
| JsSyntaxKind::JS_INITIALIZER_CLAUSE
| JsSyntaxKind::JS_CONDITIONAL_EXPRESSION
| JsSyntaxKind::JS_ARROW_FUNCTION_EXPRESSION
| JsSyntaxKind::JS_FUNCTION_EXPRESSION
| JsSyntaxKind::JS_FUNCTION_DECLARATION
+ | JsSyntaxKind::JS_PROPERTY_OBJECT_MEMBER
)
- )
- }
+ })
+ .unwrap_or(false),
Err(_) => false,
})
.unwrap_or(false);
let child_list = fragment.children();
- if !matches_allowed_parents {
+ if !parents_where_fragments_must_be_preserved {
match child_list.first() {
Some(first) if child_list.len() == 1 => {
Some(NoUselessFragmentsState::Child(first))

ADD
crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/issue_3668.jsx
+// should not trigger
+function Component2() {
+ const str = 'str';
+ return (<>{str}</>);
+}
+
+const obj = {
+ element: <>test</>
+};

ADD
crates/rome_js_analyze/tests/specs/correctness/noUselessFragments/issue_3668.jsx.snap
+---
+source: crates/rome_js_analyze/tests/spec_tests.rs
+expression: issue_3668.jsx
+---
+# Input
+```js
+// should not trigger
+function Component2() {
+ const str = 'str';
+ return (<>{str}</>);
+}
+
+const obj = {
+ element: <>test</>
+};
+
+```
+
+

fix(rome_js_analyze): false positives for `noUselessFragments` #3668 (#3858)