Skip to content

Commit c257048

Browse files
committed
Fix testcode
1 parent df0e94b commit c257048

File tree

1 file changed

+69
-23
lines changed

1 file changed

+69
-23
lines changed

libs/extractor/src/css_utils.rs

Lines changed: 69 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,59 @@ impl From<CssToStyleResult> for ExtractStyleValue {
2929
}
3030
}
3131
}
32+
33+
/// Normalize whitespace while preserving string literals
34+
fn normalize_whitespace_preserving_strings(input: &str) -> String {
35+
let mut result = String::with_capacity(input.len());
36+
let mut chars = input.chars().peekable();
37+
let mut string_placeholders = Vec::new();
38+
let mut placeholder_counter = 0;
39+
40+
while let Some(ch) = chars.next() {
41+
if ch == '"' || ch == '\'' || ch == '`' {
42+
// Found start of string literal
43+
let quote = ch;
44+
let mut string_content = String::from(quote);
45+
let mut escaped = false;
46+
47+
while let Some(&next_ch) = chars.peek() {
48+
chars.next();
49+
string_content.push(next_ch);
50+
51+
if escaped {
52+
escaped = false;
53+
} else if next_ch == '\\' {
54+
escaped = true;
55+
} else if next_ch == quote {
56+
// End of string literal
57+
break;
58+
}
59+
}
60+
61+
// Replace string literal with placeholder
62+
let placeholder = format!("__STRING_{}__", placeholder_counter);
63+
placeholder_counter += 1;
64+
string_placeholders.push((placeholder.clone(), string_content));
65+
result.push_str(&placeholder);
66+
} else {
67+
result.push(ch);
68+
}
69+
}
70+
71+
// Normalize whitespace (newlines, tabs, multiple spaces)
72+
result = result.replace(['\n', '\t'], " ");
73+
while result.contains(" ") {
74+
result = result.replace(" ", " ");
75+
}
76+
result = result.trim().to_string();
77+
78+
// Restore string literals
79+
for (placeholder, original_string) in string_placeholders.iter().rev() {
80+
result = result.replace(placeholder, original_string);
81+
}
82+
83+
result
84+
}
3285
pub fn css_to_style_literal<'a>(
3386
css: &TemplateLiteral<'a>,
3487
level: u8,
@@ -142,14 +195,9 @@ pub fn css_to_style_literal<'a>(
142195
let mut identifier = expression_to_code(expr);
143196

144197
// Normalize the code string
145-
// 1. Remove newlines and tabs, replace with spaces
146-
identifier = identifier.replace(['\n', '\t'], " ");
147-
// 2. Normalize multiple spaces to single space
148-
149-
while identifier.contains(" ") {
150-
identifier = identifier.replace(" ", " ");
151-
}
152-
// 3. Normalize arrow function whitespace
198+
// 1. Normalize whitespace while preserving string literals
199+
identifier = normalize_whitespace_preserving_strings(&identifier);
200+
// 2. Normalize arrow function whitespace
153201
identifier = identifier
154202
.replace(" => ", "=>")
155203
.replace(" =>", "=>")
@@ -253,12 +301,9 @@ pub fn css_to_style_literal<'a>(
253301
if *idx < css.expressions.len() {
254302
let expr = &css.expressions[*idx];
255303
let expr_code = expression_to_code(expr);
256-
// Normalize the expression code
257-
let mut normalized_code = expr_code.replace(['\n', '\t'], " ");
258-
while normalized_code.contains(" ") {
259-
normalized_code = normalized_code.replace(" ", " ");
260-
}
261-
normalized_code = normalized_code.trim().to_string();
304+
// Normalize the expression code while preserving string literals
305+
let normalized_code =
306+
normalize_whitespace_preserving_strings(&expr_code);
262307

263308
// Replace placeholder with ${expr} syntax
264309
let expr_template = format!("${{{}}}", normalized_code);
@@ -281,16 +326,8 @@ pub fn css_to_style_literal<'a>(
281326
} else {
282327
// Check if property name contains a dynamic expression placeholder
283328
let property = style.property();
284-
let mut prop_is_dynamic = false;
285-
286-
for placeholder in expression_map.keys() {
287-
if property.contains(placeholder) {
288-
prop_is_dynamic = true;
289-
break;
290-
}
291-
}
292329

293-
if !prop_is_dynamic {
330+
if !expression_map.keys().any(|p| property.contains(p)) {
294331
// Static style
295332
styles.push(CssToStyleResult::Static(style));
296333
}
@@ -858,6 +895,8 @@ mod tests {
858895
#[case("`width: ${func(1)}px;`", vec![("width", "`${func(1)}px`", None)])]
859896
#[case("`width: ${func(1)}${2}px;`", vec![("width", "`${func(1)}${2}px`", None)])]
860897
#[case("`width: ${1}${2}px;`", vec![("width", "12px", None)])]
898+
#[case("`width: ${func(\n\t 1 , \n\t2\n)}px;`", vec![("width", "`${func(1,2)}px`", None)])]
899+
#[case("`width: ${func(\" wow \")}px;`", vec![("width", "`${func(\" wow \")}px`", None)])]
861900
// wrong cases
862901
#[case(
863902
"`@media (min-width: 768px) {
@@ -1196,6 +1235,13 @@ mod tests {
11961235
("font-family", "\"Roboto Hello\",sans-serif", Some(StyleSelector::Selector("ul".to_string()))),
11971236
]
11981237
)]
1238+
#[case(
1239+
"div { color: red; ; { background: blue; } }",
1240+
vec![
1241+
("color", "red", Some(StyleSelector::Selector("div".to_string()))),
1242+
("background", "blue", Some(StyleSelector::Selector("div".to_string()))),
1243+
]
1244+
)]
11991245
fn test_css_to_style(
12001246
#[case] input: &str,
12011247
#[case] expected: Vec<(&str, &str, Option<StyleSelector>)>,

0 commit comments

Comments
 (0)