Skip to content

Commit 254f1fd

Browse files
committed
Add testcase
1 parent e66a868 commit 254f1fd

File tree

2 files changed

+190
-204
lines changed

2 files changed

+190
-204
lines changed

libs/extractor/src/css_utils.rs

Lines changed: 70 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use css::{
66
rm_css_comment::rm_css_comment,
77
style_selector::StyleSelector,
88
};
9+
10+
use crate::utils::expression_to_code;
911
use oxc_ast::ast::TemplateLiteral;
1012

1113
use crate::extract_style::{
@@ -32,8 +34,6 @@ pub fn css_to_style_literal<'a>(
3234
level: u8,
3335
selector: &Option<StyleSelector>,
3436
) -> Vec<CssToStyleResult> {
35-
use crate::utils::expression_to_code;
36-
3737
let mut styles = vec![];
3838

3939
// If there are no expressions, just process quasis as static CSS
@@ -93,15 +93,11 @@ pub fn css_to_style_literal<'a>(
9393
let mut literal_values = Vec::new();
9494

9595
for (_, idx) in &found_placeholders {
96-
if *idx < css.expressions.len() {
97-
if let Some(literal_value) =
96+
if *idx < css.expressions.len()
97+
&& let Some(literal_value) =
9898
get_string_by_literal_expression(&css.expressions[*idx])
99-
{
100-
literal_values.push((*idx, literal_value));
101-
} else {
102-
all_literals = false;
103-
break;
104-
}
99+
{
100+
literal_values.push((*idx, literal_value));
105101
} else {
106102
all_literals = false;
107103
break;
@@ -125,15 +121,14 @@ pub fn css_to_style_literal<'a>(
125121
style.level(),
126122
style.selector().cloned(),
127123
)));
128-
continue;
129-
}
130-
131-
// Not all expressions are literals - need to create dynamic style
132-
// Check if value is just a placeholder (no surrounding text)
133-
if found_placeholders.len() == 1 {
134-
let (placeholder, idx) = &found_placeholders[0];
135-
let trimmed_value = value.trim();
136-
if trimmed_value == placeholder.as_str() && *idx < css.expressions.len() {
124+
} else {
125+
// Not all expressions are literals - need to create dynamic style
126+
// Check if value is just a placeholder (no surrounding text)
127+
if found_placeholders.len() == 1
128+
&& let (placeholder, idx) = &found_placeholders[0]
129+
&& value.trim() == placeholder.as_str()
130+
&& *idx < css.expressions.len()
131+
{
137132
// Value is just the expression - use expression code directly
138133
let expr = &css.expressions[*idx];
139134

@@ -150,6 +145,7 @@ pub fn css_to_style_literal<'a>(
150145
// 1. Remove newlines and tabs, replace with spaces
151146
identifier = identifier.replace(['\n', '\t'], " ");
152147
// 2. Normalize multiple spaces to single space
148+
153149
while identifier.contains(" ") {
154150
identifier = identifier.replace(" ", " ");
155151
}
@@ -159,7 +155,12 @@ pub fn css_to_style_literal<'a>(
159155
.replace(" =>", "=>")
160156
.replace("=> ", "=>");
161157
// 4. Normalize function expression formatting
162-
if is_function {
158+
// 5. Normalize quotes
159+
if !is_function {
160+
// For non-function expressions, convert property access quotes
161+
// object["color"] -> object['color']
162+
identifier = identifier.replace("[\"", "['").replace("\"]", "']");
163+
} else {
163164
// Normalize function() { } to function(){ }
164165
identifier = identifier.replace("function() {", "function(){");
165166
identifier = identifier.replace("function (", "function(");
@@ -176,13 +177,6 @@ pub fn css_to_style_literal<'a>(
176177
}
177178
// Add (rest) call
178179
identifier = format!("{}(rest)", identifier);
179-
}
180-
// 5. Normalize quotes
181-
if !is_function {
182-
// For non-function expressions, convert property access quotes
183-
// object["color"] -> object['color']
184-
identifier = identifier.replace("[\"", "['").replace("\"]", "']");
185-
} else {
186180
// For function expressions, convert string literals in ternary operators
187181
// This handles cases like: (props)=>props.b ? "a" : "b" -> (props)=>props.b ? 'a' : 'b'
188182
// Use simple pattern matching for ternary operator string literals
@@ -240,72 +234,69 @@ pub fn css_to_style_literal<'a>(
240234
&identifier,
241235
style.selector().cloned(),
242236
)));
243-
continue;
244-
}
245-
}
237+
} else {
238+
// Value has surrounding text - need to create template literal
239+
// Reconstruct the template literal by replacing placeholders with ${expr} syntax
240+
// The value contains placeholders like "__EXPR_0__px", we need to convert to `${expr}px`
246241

247-
// Value has surrounding text - need to create template literal
248-
// Reconstruct the template literal by replacing placeholders with ${expr} syntax
249-
// The value contains placeholders like "__EXPR_0__px", we need to convert to `${expr}px`
242+
let mut template_literal = value.to_string();
250243

251-
let mut template_literal = value.to_string();
244+
// Sort placeholders by their position in reverse order to avoid index shifting
245+
found_placeholders.sort_by(|(a_placeholder, _), (b_placeholder, _)| {
246+
template_literal
247+
.rfind(a_placeholder)
248+
.cmp(&template_literal.rfind(b_placeholder))
249+
});
252250

253-
// Sort placeholders by their position in reverse order to avoid index shifting
254-
found_placeholders.sort_by(|(a_placeholder, _), (b_placeholder, _)| {
255-
template_literal
256-
.rfind(a_placeholder)
257-
.cmp(&template_literal.rfind(b_placeholder))
258-
});
251+
// Replace each placeholder with the actual expression in template literal format
252+
for (placeholder, idx) in &found_placeholders {
253+
if *idx < css.expressions.len() {
254+
let expr = &css.expressions[*idx];
255+
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();
259262

260-
// Replace each placeholder with the actual expression in template literal format
261-
for (placeholder, idx) in &found_placeholders {
262-
if *idx < css.expressions.len() {
263-
let expr = &css.expressions[*idx];
264-
let expr_code = expression_to_code(expr);
265-
// Normalize the expression code
266-
let mut normalized_code = expr_code.replace(['\n', '\t'], " ");
267-
while normalized_code.contains(" ") {
268-
normalized_code = normalized_code.replace(" ", " ");
263+
// Replace placeholder with ${expr} syntax
264+
let expr_template = format!("${{{}}}", normalized_code);
265+
template_literal =
266+
template_literal.replace(placeholder.as_str(), &expr_template);
267+
}
269268
}
270-
normalized_code = normalized_code.trim().to_string();
271269

272-
// Replace placeholder with ${expr} syntax
273-
let expr_template = format!("${{{}}}", normalized_code);
274-
template_literal =
275-
template_literal.replace(placeholder.as_str(), &expr_template);
270+
// Wrap in template literal backticks
271+
let final_identifier = format!("`{}`", template_literal);
272+
273+
styles.push(CssToStyleResult::Dynamic(ExtractDynamicStyle::new(
274+
style.property(),
275+
style.level(),
276+
&final_identifier,
277+
style.selector().cloned(),
278+
)));
276279
}
277280
}
281+
} else {
282+
// Check if property name contains a dynamic expression placeholder
283+
let property = style.property();
284+
let mut prop_is_dynamic = false;
278285

279-
// Wrap in template literal backticks
280-
let final_identifier = format!("`{}`", template_literal);
281-
282-
styles.push(CssToStyleResult::Dynamic(ExtractDynamicStyle::new(
283-
style.property(),
284-
style.level(),
285-
&final_identifier,
286-
style.selector().cloned(),
287-
)));
288-
continue;
289-
}
290-
291-
// Check if property name contains a dynamic expression placeholder
292-
let property = style.property();
293-
let mut prop_is_dynamic = false;
286+
for placeholder in expression_map.keys() {
287+
if property.contains(placeholder) {
288+
prop_is_dynamic = true;
289+
break;
290+
}
291+
}
294292

295-
for placeholder in expression_map.keys() {
296-
if property.contains(placeholder) {
297-
prop_is_dynamic = true;
298-
break;
293+
if !prop_is_dynamic {
294+
// Static style
295+
styles.push(CssToStyleResult::Static(style));
299296
}
300-
}
301297

302-
if prop_is_dynamic {
303298
// Property name is dynamic - skip for now as it's more complex
304-
continue;
305299
}
306-
307-
// Static style
308-
styles.push(CssToStyleResult::Static(style));
309300
}
310301

311302
styles

0 commit comments

Comments
 (0)