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