@@ -299,11 +299,87 @@ pub fn css_to_style_literal<'a>(
299299 for ( placeholder, idx) in & found_placeholders {
300300 if * idx < css. expressions . len ( ) {
301301 let expr = & css. expressions [ * idx] ;
302+
303+ // Check if expression is a function (arrow function or function expression)
304+ let is_function = matches ! (
305+ expr,
306+ oxc_ast:: ast:: Expression :: ArrowFunctionExpression ( _)
307+ | oxc_ast:: ast:: Expression :: FunctionExpression ( _)
308+ ) ;
309+
302310 let expr_code = expression_to_code ( expr) ;
303311 // Normalize the expression code while preserving string literals
304- let normalized_code =
312+ let mut normalized_code =
305313 normalize_whitespace_preserving_strings ( & expr_code) ;
306314
315+ if is_function {
316+ // Normalize arrow function whitespace
317+ normalized_code = normalized_code
318+ . replace ( " => " , "=>" )
319+ . replace ( " =>" , "=>" )
320+ . replace ( "=> " , "=>" ) ;
321+ // Normalize function() { } to function(){ }
322+ normalized_code =
323+ normalized_code. replace ( "function() {" , "function(){" ) ;
324+ normalized_code =
325+ normalized_code. replace ( "function (" , "function(" ) ;
326+ // Remove trailing semicolon and spaces before closing brace
327+ normalized_code = normalized_code. replace ( "; }" , "}" ) ;
328+ normalized_code = normalized_code. replace ( " }" , "}" ) ;
329+
330+ // Wrap function in parentheses if not already wrapped
331+ let trimmed = normalized_code. trim ( ) ;
332+ if !( trimmed. starts_with ( '(' ) && trimmed. ends_with ( ')' ) ) {
333+ normalized_code = format ! ( "({})" , trimmed) ;
334+ }
335+ // Add (rest) call
336+ normalized_code = format ! ( "{}(rest)" , normalized_code) ;
337+
338+ // For function expressions, convert string literals in ternary operators
339+ let mut result = String :: new ( ) ;
340+ let mut chars = normalized_code. chars ( ) . peekable ( ) ;
341+ let mut in_ternary_string = false ;
342+
343+ while let Some ( ch) = chars. next ( ) {
344+ if ch == '?' || ch == ':' {
345+ result. push ( ch) ;
346+ // Skip whitespace
347+ while let Some ( & ' ' ) = chars. peek ( ) {
348+ result. push ( chars. next ( ) . unwrap ( ) ) ;
349+ }
350+ // Check if next is a string literal
351+ if let Some ( & '"' ) = chars. peek ( ) {
352+ in_ternary_string = true ;
353+ result. push ( '\'' ) ;
354+ chars. next ( ) ; // consume the "
355+ }
356+ } else if in_ternary_string && ch == '"' {
357+ // Check if this is a closing quote by looking ahead
358+ let mut peeked = chars. clone ( ) ;
359+ // Skip whitespace
360+ while let Some ( & ' ' ) = peeked. peek ( ) {
361+ peeked. next ( ) ;
362+ }
363+ // If next is : or ? or ) or } or end, it's a closing quote
364+ if peeked. peek ( ) . is_none ( )
365+ || matches ! (
366+ peeked. peek( ) ,
367+ Some ( & ':' ) | Some ( & '?' ) | Some ( & ')' ) | Some ( & '}' )
368+ )
369+ {
370+ result. push ( '\'' ) ;
371+ in_ternary_string = false ;
372+ } else {
373+ // Not a closing quote, keep as is
374+ result. push ( ch) ;
375+ }
376+ } else {
377+ result. push ( ch) ;
378+ }
379+ }
380+ normalized_code = result;
381+ }
382+
307383 // Replace placeholder with ${expr} syntax
308384 let expr_template = format ! ( "${{{}}}" , normalized_code) ;
309385 template_literal =
@@ -896,6 +972,9 @@ mod tests {
896972 #[ case( "`width: ${1}${2}px;`" , vec![ ( "width" , "12px" , None ) ] ) ]
897973 #[ case( "`width: ${func(\n \t 1 , \n \t 2\n )}px;`" , vec![ ( "width" , "`${func(1,2)}px`" , None ) ] ) ]
898974 #[ case( "`width: ${func(\" wow \" )}px;`" , vec![ ( "width" , "`${func(\" wow \" )}px`" , None ) ] ) ]
975+ #[ case( "`width: ${func(\" hello\\ nworld\" )}px;`" , vec![ ( "width" , "`${func(\" hello\\ nworld\" )}px`" , None ) ] ) ]
976+ #[ case( "`width: ${func('test\\ 'quote')}px;`" , vec![ ( "width" , "`${func(\" test'quote\" )}px`" , None ) ] ) ]
977+ #[ case( "`width: ${(props)=>props.b ? \" hello\\ \" world\" : \" test\" }px;`" , vec![ ( "width" , "`${((props)=>props.b ? 'hello\\ \" world' : 'test')(rest)}px`" , None ) ] ) ]
899978 // wrong cases
900979 #[ case(
901980 "`@media (min-width: 768px) {
0 commit comments