11use  std:: { 
22  cell:: RefCell , 
3-   collections:: HashMap , 
3+   collections:: { HashMap ,   VecDeque } , 
44  hash:: { Hash ,  Hasher } , 
55  rc:: Rc , 
66} ; 
@@ -12,7 +12,7 @@ use swc_ecma_ast::{
1212  Expr , 
1313   Ident ,  JSXAttr ,  JSXAttrName ,  JSXAttrOrSpread ,  JSXAttrValue ,  JSXElement , 
1414   JSXElementName ,  JSXExpr ,  KeyValueProp ,  Lit ,  Prop ,  PropName , 
15-   PropOrSpread ,  Str ,  JSXFragment ,  ImportDecl ,  ImportSpecifier , 
15+   PropOrSpread ,  Str ,  JSXFragment ,  ImportDecl ,  ImportSpecifier ,   CallExpr ,   Callee ,   Null ,   ExprOrSpread ,   JSXExprContainer , 
1616} ; 
1717use  swc_ecma_visit:: { 
1818  noop_visit_mut_type,  noop_visit_type,  VisitMut ,  VisitMutWith ,  VisitAll ,  Visit ,  VisitAllWith , 
@@ -200,6 +200,30 @@ impl<'a> VisitMut for AstMutVisitor<'a> {
200200      let  attrs = & mut  n. opening . attrs ; 
201201      let  mut  has_style = false ; 
202202      let  mut  has_empty_style = false ; 
203+       let  mut  has_dynamic_style = false ; 
204+       let  mut  class_attr_value = None ; 
205+       let  mut  style_attr_value = None ; 
206+       let  has_dynamic_class = attrs. iter ( ) 
207+         . any ( |attr| { 
208+           if  let  JSXAttrOrSpread :: JSXAttr ( attr)  = attr { 
209+             if  let  JSXAttrName :: Ident ( ident)  = & attr. name  { 
210+               if  ident. sym . to_string ( )  == "className"  { 
211+                 if  let  Some ( value)  = & attr. value  { 
212+                   if  let  JSXAttrValue :: JSXExprContainer ( expr_container)  = value { 
213+                     match  & expr_container. expr  { 
214+                       JSXExpr :: JSXEmptyExpr ( _)  => { } , 
215+                       JSXExpr :: Expr ( expr)  => { 
216+                         class_attr_value = Some ( ( * * expr) . clone ( ) ) ; 
217+                       } , 
218+                     } ; 
219+                     return  true ; 
220+                   } 
221+                 } 
222+               } 
223+             } 
224+           } 
225+           false 
226+         } ) ; 
203227      for  attr in  attrs { 
204228        if  let  JSXAttrOrSpread :: JSXAttr ( attr)  = attr { 
205229          if  let  JSXAttrName :: Ident ( ident)  = & attr. name  { 
@@ -212,46 +236,48 @@ impl<'a> VisitMut for AstMutVisitor<'a> {
212236                    JSXAttrValue :: Lit ( lit)  => { 
213237                      match  lit { 
214238                        Lit :: Str ( str)  => { 
215-                           // 将 style 属性的值转换为对象形式 
216-                           let  mut  properties = HashMap :: new ( ) ; 
217-                           let  style = str. value . to_string ( ) ; 
218-                           let  style = style
219-                             . split ( ";" ) 
220-                             . map ( |s| s. to_owned ( ) ) 
221-                             . collect :: < Vec < String > > ( ) ; 
222-                           if  let  Some ( style_declaration)  = style_record. get ( & element. span )  { 
223-                             for  declaration in  style_declaration. declaration . declarations . iter ( )  { 
224-                               let  property_id = declaration
225-                                 . property_id ( ) 
226-                                 . to_css_string ( PrinterOptions :: default ( ) ) 
227-                                 . unwrap ( ) ; 
228-                               let  property_value = declaration
229-                                 . value_to_css_string ( PrinterOptions :: default ( ) ) 
230-                                 . unwrap ( ) ; 
231-                               properties. insert ( property_id,  property_value) ; 
232-                             } 
233-                           } 
234-                           for  property in  style. iter ( )  { 
235-                             let  property = property
236-                               . split ( ":" ) 
239+                           if  !has_dynamic_class { 
240+                             // 将 style 属性的值转换为对象形式 
241+                             let  mut  properties = HashMap :: new ( ) ; 
242+                             let  style = str. value . to_string ( ) ; 
243+                             let  style = style
244+                               . split ( ";" ) 
237245                              . map ( |s| s. to_owned ( ) ) 
238246                              . collect :: < Vec < String > > ( ) ; 
239-                             if  property. len ( )  == 2  { 
240-                               properties. insert ( property[ 0 ] . clone ( ) ,  property[ 1 ] . clone ( ) ) ; 
247+                             if  let  Some ( style_declaration)  = style_record. get ( & element. span )  { 
248+                               for  declaration in  style_declaration. declaration . declarations . iter ( )  { 
249+                                 let  property_id = declaration
250+                                   . property_id ( ) 
251+                                   . to_css_string ( PrinterOptions :: default ( ) ) 
252+                                   . unwrap ( ) ; 
253+                                 let  property_value = declaration
254+                                   . value_to_css_string ( PrinterOptions :: default ( ) ) 
255+                                   . unwrap ( ) ; 
256+                                 properties. insert ( property_id,  property_value) ; 
257+                               } 
241258                            } 
259+                             for  property in  style. iter ( )  { 
260+                               let  property = property
261+                                 . split ( ":" ) 
262+                                 . map ( |s| s. to_owned ( ) ) 
263+                                 . collect :: < Vec < String > > ( ) ; 
264+                               if  property. len ( )  == 2  { 
265+                                 properties. insert ( property[ 0 ] . clone ( ) ,  property[ 1 ] . clone ( ) ) ; 
266+                               } 
267+                             } 
268+                             let  mut  style = String :: new ( ) ; 
269+                             for  ( property_id,  property_value)  in  properties. iter ( )  { 
270+                               style. push_str ( property_id. as_str ( ) ) ; 
271+                               style. push_str ( ":" ) ; 
272+                               style. push_str ( property_value. as_str ( ) ) ; 
273+                               style. push_str ( ";" ) ; 
274+                             } 
275+                             attr. value  = Some ( JSXAttrValue :: Lit ( Lit :: Str ( Str  { 
276+                               span :  DUMMY_SP , 
277+                               value :  style. into ( ) , 
278+                               raw :  None , 
279+                             } ) ) ) ; 
242280                          } 
243-                           let  mut  style = String :: new ( ) ; 
244-                           for  ( property_id,  property_value)  in  properties. iter ( )  { 
245-                             style. push_str ( property_id. as_str ( ) ) ; 
246-                             style. push_str ( ":" ) ; 
247-                             style. push_str ( property_value. as_str ( ) ) ; 
248-                             style. push_str ( ";" ) ; 
249-                           } 
250-                           attr. value  = Some ( JSXAttrValue :: Lit ( Lit :: Str ( Str  { 
251-                             span :  DUMMY_SP , 
252-                             value :  style. into ( ) , 
253-                             raw :  None , 
254-                           } ) ) ) ; 
255281                        } 
256282                        _ => { } 
257283                      } 
@@ -262,65 +288,78 @@ impl<'a> VisitMut for AstMutVisitor<'a> {
262288                          has_empty_style = true ; 
263289                          has_style = false ; 
264290                        } 
265-                         JSXExpr :: Expr ( expr)  => match  & mut  * * expr { 
266-                           Expr :: Object ( lit)  => { 
267-                             let  mut  properties = Vec :: new ( ) ; 
268-                             if  let  Some ( style_declaration)  = style_record. get ( & element. span )  { 
269-                               for  declaration in  style_declaration. declaration . declarations . iter ( )  { 
270-                                 let  mut  has_property = false ; 
271-                                 for  prop in  lit. props . iter_mut ( )  { 
272-                                   match  prop { 
273-                                     PropOrSpread :: Prop ( prop)  => match  & * * prop { 
274-                                       Prop :: KeyValue ( key_value_prop)  => match  & key_value_prop. key  { 
275-                                         PropName :: Ident ( ident)  => { 
276-                                           let  property_id = ident. sym . to_string ( ) ; 
277-                                           if  property_id
278-                                             == declaration
279-                                               . property_id ( ) 
280-                                               . to_css_string ( PrinterOptions :: default ( ) ) 
281-                                               . unwrap ( ) 
282-                                           { 
283-                                             has_property = true ; 
284-                                             break ; 
285-                                           } 
286-                                         } 
287-                                         _ => { } 
288-                                       } , 
289-                                       _ => { } 
290-                                     } , 
291-                                     PropOrSpread :: Spread ( _)  => { } 
291+                         JSXExpr :: Expr ( expr)  => { 
292+                           style_attr_value = Some ( ( * * expr) . clone ( ) ) ; 
293+                           match  & mut  * * expr { 
294+                             Expr :: Object ( lit)  => { 
295+                               if  !has_dynamic_class { 
296+                                 let  mut  properties = Vec :: new ( ) ; 
297+                                 if  let  Some ( style_declaration)  = style_record. get ( & element. span )  { 
298+                                   for  declaration in  style_declaration. declaration . declarations . iter ( )  { 
299+                                     let  mut  has_property = false ; 
300+                                     for  prop in  lit. props . iter_mut ( )  { 
301+                                       match  prop { 
302+                                         PropOrSpread :: Prop ( prop)  => match  & * * prop { 
303+                                           Prop :: KeyValue ( key_value_prop)  => match  & key_value_prop. key  { 
304+                                             PropName :: Ident ( ident)  => { 
305+                                               let  property_id = ident. sym . to_string ( ) ; 
306+                                               if  property_id
307+                                                 == declaration
308+                                                   . property_id ( ) 
309+                                                   . to_css_string ( PrinterOptions :: default ( ) ) 
310+                                                   . unwrap ( ) 
311+                                               { 
312+                                                 has_property = true ; 
313+                                                 break ; 
314+                                               } 
315+                                             } 
316+                                             _ => { } 
317+                                           } , 
318+                                           _ => { } 
319+                                         } , 
320+                                         PropOrSpread :: Spread ( _)  => { } 
321+                                       } 
322+                                     } 
323+                                     if  !has_property { 
324+                                       properties. push ( declaration. clone ( ) ) ; 
325+                                     } 
292326                                  } 
293327                                } 
294-                                 if  !has_property { 
295-                                   properties. push ( declaration. clone ( ) ) ; 
328+                                 let  mut  deque = VecDeque :: from ( lit. props . clone ( ) ) ; 
329+                                 for  property in  properties. iter ( )  { 
330+                                   deque. push_front ( PropOrSpread :: Prop ( Box :: new ( Prop :: KeyValue ( 
331+                                     KeyValueProp  { 
332+                                       key :  PropName :: Ident ( Ident :: new ( 
333+                                         property
334+                                           . property_id ( ) 
335+                                           . to_css_string ( PrinterOptions :: default ( ) ) 
336+                                           . unwrap ( ) 
337+                                           . into ( ) , 
338+                                         DUMMY_SP , 
339+                                       ) ) , 
340+                                       value :  property
341+                                         . value_to_css_string ( PrinterOptions :: default ( ) ) 
342+                                         . unwrap ( ) 
343+                                         . into ( ) , 
344+                                     } , 
345+                                   ) ) ) ) ; 
296346                                } 
347+                                 lit. props  = deque. into ( ) ; 
297348                              } 
298349                            } 
299-                             for  property in  properties. iter ( )  { 
300-                               lit. props . push ( PropOrSpread :: Prop ( Box :: new ( Prop :: KeyValue ( 
301-                                 KeyValueProp  { 
302-                                   key :  PropName :: Ident ( Ident :: new ( 
303-                                     property
304-                                       . property_id ( ) 
305-                                       . to_css_string ( PrinterOptions :: default ( ) ) 
306-                                       . unwrap ( ) 
307-                                       . into ( ) , 
308-                                     DUMMY_SP , 
309-                                   ) ) , 
310-                                   value :  property
311-                                     . value_to_css_string ( PrinterOptions :: default ( ) ) 
312-                                     . unwrap ( ) 
313-                                     . into ( ) , 
314-                                 } , 
315-                               ) ) ) ) ; 
350+                             _ => { 
351+                               has_dynamic_style = true ; 
316352                            } 
317353                          } 
318-                           _ => { } 
319354                        } , 
320355                      } 
321356                    } 
322-                     JSXAttrValue :: JSXElement ( _)  => { } 
323-                     JSXAttrValue :: JSXFragment ( _)  => { } 
357+                     JSXAttrValue :: JSXElement ( _)  => { 
358+                       has_dynamic_style = true ; 
359+                     } 
360+                     JSXAttrValue :: JSXFragment ( _)  => { 
361+                       has_dynamic_style = true ; 
362+                     } 
324363                  } 
325364                } 
326365                None  => { 
@@ -333,51 +372,87 @@ impl<'a> VisitMut for AstMutVisitor<'a> {
333372        } 
334373      } 
335374
336-       if  !has_style { 
337-         if  let  Some ( style_declaration)  = style_record. get ( & element. span )  { 
338-           let  mut  properties = Vec :: new ( ) ; 
339-           for  declaration in  style_declaration. declaration . declarations . iter ( )  { 
340-             properties. push ( declaration. clone ( ) ) ; 
341-           } 
375+       if  !has_dynamic_class && !has_dynamic_style { 
376+         if  !has_style { 
377+           if  let  Some ( style_declaration)  = style_record. get ( & element. span )  { 
378+             let  mut  properties = Vec :: new ( ) ; 
379+             for  declaration in  style_declaration. declaration . declarations . iter ( )  { 
380+               properties. push ( declaration. clone ( ) ) ; 
381+             } 
342382
343-           let  mut  style = String :: new ( ) ; 
344-           for  property in  properties. iter ( )  { 
345-             let  property_id = property
346-               . property_id ( ) 
347-               . to_css_string ( PrinterOptions :: default ( ) ) 
348-               . unwrap ( ) ; 
349-             let  property_value = property
350-               . value_to_css_string ( PrinterOptions :: default ( ) ) 
351-               . unwrap ( ) ; 
352-             style. push_str ( property_id. as_str ( ) ) ; 
353-             style. push_str ( ":" ) ; 
354-             style. push_str ( property_value. as_str ( ) ) ; 
355-             style. push_str ( ";" ) ; 
356-           } 
357-           if  has_empty_style { 
358-             for  attr in  & mut  n. opening . attrs  { 
359-               if  let  JSXAttrOrSpread :: JSXAttr ( attr)  = attr { 
360-                 if  let  JSXAttrName :: Ident ( ident)  = & attr. name  { 
361-                   if  ident. sym . to_string ( )  == "style"  { 
362-                     attr. value  = Some ( JSXAttrValue :: Lit ( Lit :: Str ( Str  { 
363-                       span :  DUMMY_SP , 
364-                       value :  style. clone ( ) . into ( ) , 
365-                       raw :  None , 
366-                     } ) ) ) ; 
383+             let  mut  style = String :: new ( ) ; 
384+             for  property in  properties. iter ( )  { 
385+               let  property_id = property
386+                 . property_id ( ) 
387+                 . to_css_string ( PrinterOptions :: default ( ) ) 
388+                 . unwrap ( ) ; 
389+               let  property_value = property
390+                 . value_to_css_string ( PrinterOptions :: default ( ) ) 
391+                 . unwrap ( ) ; 
392+               style. push_str ( property_id. as_str ( ) ) ; 
393+               style. push_str ( ":" ) ; 
394+               style. push_str ( property_value. as_str ( ) ) ; 
395+               style. push_str ( ";" ) ; 
396+             } 
397+             if  has_empty_style { 
398+               for  attr in  & mut  n. opening . attrs  { 
399+                 if  let  JSXAttrOrSpread :: JSXAttr ( attr)  = attr { 
400+                   if  let  JSXAttrName :: Ident ( ident)  = & attr. name  { 
401+                     if  ident. sym . to_string ( )  == "style"  { 
402+                       attr. value  = Some ( JSXAttrValue :: Lit ( Lit :: Str ( Str  { 
403+                         span :  DUMMY_SP , 
404+                         value :  style. clone ( ) . into ( ) , 
405+                         raw :  None , 
406+                       } ) ) ) ; 
407+                     } 
367408                  } 
368409                } 
369410              } 
370-             } 
371-           }  else  { 
372-             n. opening . attrs . push ( JSXAttrOrSpread :: JSXAttr ( JSXAttr  { 
373-               span :  DUMMY_SP , 
374-               name :  JSXAttrName :: Ident ( Ident :: new ( "style" . into ( ) ,  DUMMY_SP ) ) , 
375-               value :  Some ( JSXAttrValue :: Lit ( Lit :: Str ( Str  { 
411+             }  else  { 
412+               n. opening . attrs . push ( JSXAttrOrSpread :: JSXAttr ( JSXAttr  { 
376413                span :  DUMMY_SP , 
377-                 value :  style. into ( ) , 
378-                 raw :  None , 
379-               } ) ) ) , 
380-             } ) ) ; 
414+                 name :  JSXAttrName :: Ident ( Ident :: new ( "style" . into ( ) ,  DUMMY_SP ) ) , 
415+                 value :  Some ( JSXAttrValue :: Lit ( Lit :: Str ( Str  { 
416+                   span :  DUMMY_SP , 
417+                   value :  style. into ( ) , 
418+                   raw :  None , 
419+                 } ) ) ) , 
420+               } ) ) ; 
421+             } 
422+           } 
423+         } 
424+       }  else  { 
425+         let  fun_call_expr = Expr :: Call ( 
426+           CallExpr  { 
427+             span :  DUMMY_SP , 
428+             callee :  Callee :: Expr ( Box :: new ( Expr :: Ident ( Ident :: new ( "__calc_style__" . into ( ) ,  DUMMY_SP ) ) ) ) , 
429+             args :  vec ! [ 
430+               match  class_attr_value { 
431+                 Some ( value)  => ExprOrSpread :: from( Box :: new( value) ) , 
432+                 None  => ExprOrSpread :: from( Box :: new( Expr :: Lit ( Lit :: Null ( Null  {  span:  DUMMY_SP  } ) ) ) ) , 
433+               } , 
434+               match  style_attr_value { 
435+                 Some ( value)  => ExprOrSpread :: from( Box :: new( value) ) , 
436+                 None  => ExprOrSpread :: from( Box :: new( Expr :: Lit ( Lit :: Null ( Null  {  span:  DUMMY_SP  } ) ) ) ) , 
437+               } , 
438+             ] , 
439+             type_args :  None , 
440+           } 
441+         ) ; 
442+         for  attr in  & mut  n. opening . attrs  { 
443+           if  let  JSXAttrOrSpread :: JSXAttr ( attr)  = attr { 
444+             if  let  JSXAttrName :: Ident ( ident)  = & attr. name  { 
445+               if  ident. sym . to_string ( )  == "style"  { 
446+                 attr. value  = Some ( 
447+                   JSXAttrValue :: JSXExprContainer ( 
448+                     JSXExprContainer  { 
449+                       span :  DUMMY_SP , 
450+                       expr :  JSXExpr :: Expr ( Box :: new ( fun_call_expr. clone ( ) ) ) , 
451+                     } 
452+                   ) 
453+                 ) ; 
454+               } 
455+             } 
381456          } 
382457        } 
383458      } 
0 commit comments