1
1
use std:: {
2
2
cell:: RefCell ,
3
- collections:: HashMap ,
3
+ collections:: { HashMap , VecDeque } ,
4
4
hash:: { Hash , Hasher } ,
5
5
rc:: Rc ,
6
6
} ;
@@ -12,7 +12,7 @@ use swc_ecma_ast::{
12
12
Expr ,
13
13
Ident , JSXAttr , JSXAttrName , JSXAttrOrSpread , JSXAttrValue , JSXElement ,
14
14
JSXElementName , JSXExpr , KeyValueProp , Lit , Prop , PropName ,
15
- PropOrSpread , Str , JSXFragment , ImportDecl , ImportSpecifier ,
15
+ PropOrSpread , Str , JSXFragment , ImportDecl , ImportSpecifier , CallExpr , Callee , Null , ExprOrSpread , JSXExprContainer ,
16
16
} ;
17
17
use swc_ecma_visit:: {
18
18
noop_visit_mut_type, noop_visit_type, VisitMut , VisitMutWith , VisitAll , Visit , VisitAllWith ,
@@ -200,6 +200,30 @@ impl<'a> VisitMut for AstMutVisitor<'a> {
200
200
let attrs = & mut n. opening . attrs ;
201
201
let mut has_style = false ;
202
202
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
+ } ) ;
203
227
for attr in attrs {
204
228
if let JSXAttrOrSpread :: JSXAttr ( attr) = attr {
205
229
if let JSXAttrName :: Ident ( ident) = & attr. name {
@@ -212,46 +236,48 @@ impl<'a> VisitMut for AstMutVisitor<'a> {
212
236
JSXAttrValue :: Lit ( lit) => {
213
237
match lit {
214
238
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 ( ";" )
237
245
. map ( |s| s. to_owned ( ) )
238
246
. 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
+ }
241
258
}
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
+ } ) ) ) ;
242
280
}
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
- } ) ) ) ;
255
281
}
256
282
_ => { }
257
283
}
@@ -262,65 +288,78 @@ impl<'a> VisitMut for AstMutVisitor<'a> {
262
288
has_empty_style = true ;
263
289
has_style = false ;
264
290
}
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
+ }
292
326
}
293
327
}
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
+ ) ) ) ) ;
296
346
}
347
+ lit. props = deque. into ( ) ;
297
348
}
298
349
}
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 ;
316
352
}
317
353
}
318
- _ => { }
319
354
} ,
320
355
}
321
356
}
322
- JSXAttrValue :: JSXElement ( _) => { }
323
- JSXAttrValue :: JSXFragment ( _) => { }
357
+ JSXAttrValue :: JSXElement ( _) => {
358
+ has_dynamic_style = true ;
359
+ }
360
+ JSXAttrValue :: JSXFragment ( _) => {
361
+ has_dynamic_style = true ;
362
+ }
324
363
}
325
364
}
326
365
None => {
@@ -333,51 +372,87 @@ impl<'a> VisitMut for AstMutVisitor<'a> {
333
372
}
334
373
}
335
374
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
+ }
342
382
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
+ }
367
408
}
368
409
}
369
410
}
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 {
376
413
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
+ }
381
456
}
382
457
}
383
458
}
0 commit comments