Skip to content

Commit ae91b2c

Browse files
committed
feat: 支持处理动态类名情况
1 parent 0752a13 commit ae91b2c

File tree

2 files changed

+203
-128
lines changed

2 files changed

+203
-128
lines changed

__test__/fixure/mod.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export default class Mod extends React.Component {
3030
render () {
3131
return (
3232
<div className='mod' style={{ width: '500px', height: 800 }}>
33-
<div className='cnt_row' style>
33+
<div className={classnames('cnt_row')} style>
3434
<>
3535
<img
3636
className='icon'

src/visitor.rs

Lines changed: 202 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use 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
};
1717
use 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

Comments
 (0)