fix(rsx): formatted attribute merging (#3719)

* test(rsx): add better tests for attributes merging

* fix(rsx): zero-lengthed source with non-empty segments is non-trivial

* refactor(rsx): use `is_empty` instead of `len() == 0` (clippy)

* fix(rsx): different asserts whether in release or not
This commit is contained in:
Youn Mélois authored and GitHub committed 2025-04-15 14:28:14 -07:00
1 parent c58d7303b8
commit fd65c12bf5
2 files changed
+129 -8

No files matched your search

+124 -8
View File
@@ -524,12 +524,11 @@ mod tests {
}
#[test]
fn merges_attributes() {
fn merge_trivial_attributes() {
let input = quote::quote! {
div {
class: "hello world",
class: if count > 3 { "abc {def}" },
class: if count < 50 { "small" } else { "big" }
class: "foo",
class: "bar",
}
};
@@ -543,12 +542,129 @@ mod tests {
let attr = &parsed.merged_attributes[0].value;
println!("{}", attr.to_token_stream().pretty_unparse());
assert_eq!(
attr.to_token_stream().pretty_unparse().as_str(),
"\"foo bar\""
);
let _attr = match attr {
AttributeValue::AttrLiteral(lit) => lit,
_ => panic!("expected literal"),
if let AttributeValue::AttrLiteral(_) = attr {
} else {
panic!("expected literal")
}
}
#[test]
fn merge_formatted_attributes() {
let input = quote::quote! {
div {
class: "foo",
class: "{bar}",
}
};
let parsed: Element = syn::parse2(input).unwrap();
assert_eq!(parsed.diagnostics.len(), 0);
assert_eq!(parsed.merged_attributes.len(), 1);
assert_eq!(
parsed.merged_attributes[0].name.to_string(),
"class".to_string()
);
let attr = &parsed.merged_attributes[0].value;
assert_eq!(
attr.to_token_stream().pretty_unparse().as_str(),
"::std::format!(\"foo {0:}\", bar)"
);
if let AttributeValue::AttrLiteral(_) = attr {
} else {
panic!("expected literal")
}
}
#[test]
fn merge_conditional_attributes() {
let input = quote::quote! {
div {
class: "foo",
class: if true { "bar" },
class: if false { "baz" } else { "qux" }
}
};
let parsed: Element = syn::parse2(input).unwrap();
assert_eq!(parsed.diagnostics.len(), 0);
assert_eq!(parsed.merged_attributes.len(), 1);
assert_eq!(
parsed.merged_attributes[0].name.to_string(),
"class".to_string()
);
let attr = &parsed.merged_attributes[0].value;
assert_eq!(
attr.to_token_stream().pretty_unparse().as_str(),
"::std::format!(\n \
\"foo {0:} {1:}\",\n \
{ if true { \"bar\".to_string() } else { ::std::string::String::new() } },\n \
{ if false { \"baz\".to_string() } else { \"qux\".to_string() } },\n\
)"
);
if let AttributeValue::AttrLiteral(_) = attr {
} else {
panic!("expected literal")
}
}
#[test]
fn merge_all_attributes() {
let input = quote::quote! {
div {
class: "foo",
class: "{bar}",
class: if true { "baz" },
class: if false { "{qux}" } else { "quux" }
}
};
let parsed: Element = syn::parse2(input).unwrap();
assert_eq!(parsed.diagnostics.len(), 0);
assert_eq!(parsed.merged_attributes.len(), 1);
assert_eq!(
parsed.merged_attributes[0].name.to_string(),
"class".to_string()
);
let attr = &parsed.merged_attributes[0].value;
if cfg!(debug_assertions) {
assert_eq!(
attr.to_token_stream().pretty_unparse().as_str(),
"::std::format!(\n \
\"foo {0:} {1:} {2:}\",\n \
bar,\n \
{ if true { \"baz\".to_string() } else { ::std::string::String::new() } },\n \
{ if false { ::std::format!(\"{qux}\").to_string() } else { \"quux\".to_string() } },\n\
)"
);
} else {
assert_eq!(
attr.to_token_stream().pretty_unparse().as_str(),
"::std::format!(\n \
\"foo {0:} {1:} {2:}\",\n \
bar,\n \
{ if true { \"baz\".to_string() } else { ::std::string::String::new() } },\n \
{ if false { (qux).to_string().to_string() } else { \"quux\".to_string() } },\n\
)"
);
}
if let AttributeValue::AttrLiteral(_) = attr {
} else {
panic!("expected literal")
}
}
/// There are a number of cases where merging attributes doesn't make sense
+5
View File
@@ -90,6 +90,11 @@ impl IfmtInput {
}
fn is_simple_expr(&self) -> bool {
// If there are segments but the source is empty, it's not a simple expression.
if !self.segments.is_empty() && self.source.span().byte_range().is_empty() {
return false;
}
self.segments.iter().all(|seg| match seg {
Segment::Literal(_) => true,
Segment::Formatted(FormattedSegment { segment, .. }) => {