From d2731f268651ce76f42caa993b893b9da9ec984e Mon Sep 17 00:00:00 2001 From: xuanzebin Date: Wed, 29 Nov 2023 16:25:29 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=8A=BD=E7=A6=BB=E5=86=99=E5=85=A5?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E7=9A=84=E5=85=AC=E5=85=B1=E5=87=BD=E6=95=B0?= =?UTF-8?q?=EF=BC=8C=E6=94=AF=E6=8C=81=20React.createElement=20=E5=BD=A2?= =?UTF-8?q?=E5=BC=8F=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils.rs | 30 +- src/visitor.rs | 782 ++++++++++++++++++++++++++++++------------------- 2 files changed, 508 insertions(+), 304 deletions(-) diff --git a/src/utils.rs b/src/utils.rs index bebbec4..fd94fa3 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,8 +1,10 @@ +use std::collections::HashMap; + use html5ever::{namespace_url, ns, LocalName, QualName}; use regex::Regex; use swc_common::DUMMY_SP; // use lightningcss::values::number::CSSNumber; -use swc_ecma_ast::{JSXMemberExpr, JSXObject, Callee, Expr, CallExpr, Ident, Lit, Number}; +use swc_ecma_ast::{JSXMemberExpr, JSXObject, Callee, Expr, CallExpr, Ident, Lit, Number, PropOrSpread, Prop, PropName}; use crate::constants::{CONVERT_STYLE_PREFIX, CONVERT_STYLE_PX_FN}; @@ -91,4 +93,28 @@ pub fn convert_px_to_units(input: String) -> Expr { } // 如果没有匹配到,则返回原始字符串 Expr::Lit(Lit::Str(input.into())) -} \ No newline at end of file +} + +pub fn get_callee_attributes (callee: &CallExpr) -> HashMap> { + let mut attributes = HashMap::new(); + + if let Some(arg) = callee.args.get(1) { + if let Expr::Object(object) = &*arg.expr { + for prop in object.props.iter() { + if let PropOrSpread::Prop(prop) = prop { + if let Prop::KeyValue(key_value_prop) = &**prop { + let name = match &key_value_prop.key { + PropName::Ident(ident) => ident.sym.to_string(), + PropName::Str(str) => str.value.to_string(), + _ => "".to_string(), + }; + + attributes.insert(name, key_value_prop.value.clone()); + } + } + } + } + } + + attributes +} diff --git a/src/visitor.rs b/src/visitor.rs index f152e4c..d36c25f 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -1,3 +1,4 @@ + use std::{ cell::RefCell, collections::{BTreeMap, HashMap, VecDeque}, @@ -29,7 +30,7 @@ use crate::{ style_parser::{parse_style_properties, StyleValue}, style_transform::{style_value_type::StyleValueType, traits::ToExpr}, utils::{ - create_qualname, is_starts_with_uppercase, recursion_jsx_member, to_camel_case, to_kebab_case, + create_qualname, is_starts_with_uppercase, recursion_jsx_member, to_camel_case, to_kebab_case, get_callee_attributes }, constants::{CONVERT_STYLE_PX_FN, INNER_STYLE, INNER_STYLE_DATA, CALC_DYMAMIC_STYLE}, }; @@ -111,6 +112,13 @@ impl<'a> AstVisitor<'a> { } } + fn create_element(&mut self, jsx_element_or_callee: JSXElementOrJSXCallee) -> Element { + match jsx_element_or_callee { + JSXElementOrJSXCallee::JSXElement(&ref jsx_element) => self.create_element_from_jsx(&jsx_element), + JSXElementOrJSXCallee::JSXCallee(&ref call_expr) => self.create_element_from_call_expr(&call_expr), + } + } + fn create_element_from_jsx (&mut self, jsx_element: &JSXElement) -> Element { let name = match &jsx_element.opening.name { JSXElementName::Ident(ident) => ident.sym.to_string(), @@ -149,7 +157,6 @@ impl<'a> AstVisitor<'a> { Lit::JSXText(text) => text.value.to_string(), }, JSXAttrValue::JSXExprContainer(expr_container) => match &expr_container.expr { - JSXExpr::JSXEmptyExpr(_) => "{{}}".to_string(), JSXExpr::Expr(expr) => match &**expr { Expr::Lit(lit) => match lit { Lit::Str(str) => str.value.to_string(), @@ -162,6 +169,7 @@ impl<'a> AstVisitor<'a> { }, _ => "".to_string(), }, + _ => "".to_string(), }, JSXAttrValue::JSXElement(_) => "".to_string(), JSXAttrValue::JSXFragment(_) => "".to_string(), @@ -191,48 +199,26 @@ impl<'a> AstVisitor<'a> { _ => String::new(), }; let qual_name = create_qualname(name.as_str()); - let mut attributes = Vec::new(); - for arg in jsx_callee.args.iter().skip(1) { - if let Expr::Object(object) = &*arg.expr { - for prop in object.props.iter() { - if let PropOrSpread::Prop(prop) = prop { - if let Prop::KeyValue(key_value_prop) = &**prop { - let name = match &key_value_prop.key { - PropName::Ident(ident) => ident.sym.to_string(), - PropName::Str(str) => str.value.to_string(), - _ => "".to_string(), - }; - let value = match &*key_value_prop.value { - Expr::Lit(lit) => match lit { - Lit::Str(str) => str.value.to_string(), - Lit::Num(num) => num.value.to_string(), - Lit::Bool(bool) => bool.value.to_string(), - Lit::Null(_) => "null".to_string(), - Lit::BigInt(bigint) => bigint.value.to_string(), - Lit::Regex(regex) => regex.exp.to_string(), - Lit::JSXText(text) => text.value.to_string(), - }, - _ => "".to_string(), - }; - attributes.push(Attribute { - name: create_qualname(name.as_str()), - value: StrTendril::from(value), - }); - } - } - } + let attributes = get_callee_attributes(jsx_callee).iter().map(|(key, value)| { + let value: String = match &**value { + Expr::Lit(lit) => match lit { + Lit::Str(str) => str.value.to_string(), + Lit::Num(num) => num.value.to_string(), + Lit::Bool(bool) => bool.value.to_string(), + Lit::Null(_) => "null".to_string(), + Lit::BigInt(bigint) => bigint.value.to_string(), + Lit::Regex(regex) => regex.exp.to_string(), + Lit::JSXText(text) => text.value.to_string(), + }, + _ => "".to_string(), + }; + Attribute { + name: create_qualname(key.as_str()), + value: StrTendril::from(value.as_str()), } - } - println!("qual_name: {:?}", qual_name); - print!("attributes: {:?}", attributes); - Element::new(qual_name, SpanKey(jsx_callee.span), attributes) - } + }).collect::>(); - fn create_element(&mut self, jsx_element: JSXElementOrJSXCallee) -> Element { - match jsx_element { - JSXElementOrJSXCallee::JSXElement(&ref jsx_element) => self.create_element_from_jsx(&jsx_element), - JSXElementOrJSXCallee::JSXCallee(&ref call_expr) => self.create_element_from_call_expr(&call_expr), - } + Element::new(qual_name, SpanKey(jsx_callee.span), attributes) } } @@ -266,7 +252,26 @@ impl<'a> VisitAll for AstVisitor<'a> { if ident.sym.to_string() == "React" { if let MemberProp::Ident(ident) = &member.prop { if ident.sym.to_string() == "createElement" { - self.create_element(JSXElementOrJSXCallee::JSXCallee(call_expr)); + let element = self.create_element(JSXElementOrJSXCallee::JSXCallee(call_expr)); + let name_ident = call_expr.args.get(0).unwrap(); + let name = match &*name_ident.expr { + Expr::Ident(ident) => ident.sym.to_string(), + Expr::Lit(lit) => match lit { + Lit::Str(str) => str.value.to_string(), + _ => "".to_string(), + }, + _ => "".to_string() + }; + + if is_starts_with_uppercase(name.as_str()) { + if self.taro_components.contains(&name) { + self.jsx_record.insert(SpanKey(call_expr.span), element); + } + } else { + if !name.is_empty() { + self.jsx_record.insert(SpanKey(call_expr.span), element); + } + } } } } @@ -482,48 +487,419 @@ impl<'i> JSXMutVisitor<'i> { style_record, } } + + fn check_is_jsx_callee (&self, call_expr: &CallExpr) -> bool { + if let Callee::Expr(expr) = &call_expr.callee { + if let Expr::Member(member) = &**expr { + if let Expr::Ident(ident) = &*member.obj { + if ident.sym.to_string() == "React" { + if let MemberProp::Ident(ident) = &member.prop { + if ident.sym.to_string() == "createElement" { + return true + } + } + } + } + } + } + + return false + } + + fn get_jsx_element_or_callee_calss_value_and_dynamic_class_bool (&self, jsx_element_or_callee: &JSXElementOrJSXCallee) -> (Option, bool) { + let mut has_dynamic_class = false; + let mut class_attr_value = None; + + match jsx_element_or_callee { + JSXElementOrJSXCallee::JSXElement(jsx_element) => { + let attrs = &jsx_element.opening.attrs; + attrs.iter().for_each(|attr| { + if let JSXAttrOrSpread::JSXAttr(attr) = attr { + if let JSXAttrName::Ident(ident) = &attr.name { + if ident.sym.to_string() == "className" { + if let Some(value) = &attr.value { + match value { + JSXAttrValue::JSXExprContainer(expr_container) => { + match &expr_container.expr { + JSXExpr::Expr(expr) => { + class_attr_value = Some((**expr).clone()); + }, + _ => () + }; + has_dynamic_class = true; + }, + JSXAttrValue::Lit(lit) => { + class_attr_value = Some(lit.clone().into()); + }, + _ => () + } + } + } + } + } + }); + }, + JSXElementOrJSXCallee::JSXCallee(call_expr) => { + let mut attributes = get_callee_attributes(call_expr); + if let Some(value) = attributes.remove("className") { + class_attr_value = Some((*value).clone()); + + match *value { + Expr::Lit(lit) => { + class_attr_value = Some(lit.into()); + }, + _ => { + has_dynamic_class = true; + } + } + } + } + }; + + (class_attr_value, has_dynamic_class) + } + + fn process_attribute_lit_value (&self, lit: &Lit, has_dynamic_class: bool, element: &Element, style_record: &HashMap)>>) -> Option> { + match lit { + Lit::Str(str) => { + if !has_dynamic_class { + // 将 style 属性的值转换为对象形式 + let mut properties = HashMap::new(); + let style = str.value.to_string(); + let style = style + .split(";") + .map(|s| s.to_owned()) + .collect::>(); + if let Some(style_declaration) = style_record.get(&element.span) { + for (key, value) in style_declaration.iter() { + properties.insert(to_camel_case(key, false), value.clone()); + } + } + for property in style.iter() { + let property = property + .split(":") + .map(|s| s.to_owned()) + .collect::>(); + if property.len() == 2 { + let property_parsed = Property::parse_string( + PropertyId::from(property[0].as_str()), + property[1].as_str(), + ParserOptions::default(), + ); + if property_parsed.is_ok() { + properties.insert( + property[0].clone(), + property_parsed.unwrap().into_owned(), + ); + } + } + } + let parsed_properties = parse_style_properties( + &properties + .iter() + .map(|(key, value)| (key.to_owned(), value.clone())) + .collect::>(), + ); + + return Some(parsed_properties); + } + } + _ => {} + }; + + return None; + } + + fn process_attribute_expr_value (&self, expr: &mut Expr, has_dynamic_class: bool, element: &Element, style_record: &HashMap)>>) -> bool { + let mut has_dynamic_style = false; + + match expr { + Expr::Object(lit) => { + if !has_dynamic_class { + let mut properties = Vec::new(); + if let Some(style_declaration) = style_record.get(&element.span) { + for declaration in style_declaration.iter() { + let mut has_property = false; + for prop in lit.props.iter_mut() { + match prop { + PropOrSpread::Prop(prop) => match &mut **prop { + Prop::KeyValue(key_value_prop) => { + match &mut key_value_prop.key { + PropName::Ident(ident) => { + ident.sym = to_camel_case( + ident.sym.to_string().as_str(), + false, + ) + .into(); + let property_id = ident.sym.to_string(); + if property_id == declaration.0.to_string() { + has_property = true; + break; + } + } + _ => {} + } + } + _ => {} + }, + PropOrSpread::Spread(_) => {} + } + } + if !has_property { + properties.push(declaration.clone()); + } + } + } + let deque = VecDeque::from(lit.props.clone()); + let mut temp_properties = HashMap::new(); + for p in deque.iter() { + match p { + PropOrSpread::Prop(prop) => match &**prop { + Prop::KeyValue(key_value_prop) => { + let value = match &*key_value_prop.value { + Expr::Lit(lit) => match lit { + Lit::Str(str) => str.value.to_string(), + Lit::Num(num) => num.to_string(), + _ => "".to_string(), + }, + _ => { + has_dynamic_style = true; + "".to_string() + } + }; + let name = match &key_value_prop.key { + PropName::Ident(ident) => { + Some(to_kebab_case(ident.sym.to_string().as_str())) + } + PropName::Str(str) => { + Some(to_kebab_case(str.value.to_string().as_str())) + } + _ => None, + }; + if let Some(name) = name { + let property_id = PropertyId::from(name.as_str()); + let property = Property::parse_string( + property_id, + value.as_str(), + ParserOptions::default(), + ); + if property.is_ok() { + temp_properties.insert( + to_camel_case(name.as_str(), false), + property.unwrap().into_owned(), + ); + } + } + } + _ => {} + }, + PropOrSpread::Spread(_) => {} + } + } + let mut temp_props = vec![]; + + for property in properties.iter() { + temp_props.push((property.0.to_string(), property.1.clone())); + } + temp_props.extend( + temp_properties + .iter() + .map(|(key, value)| (key.to_string(), value.clone())), + ); + let mut temp_props = parse_style_properties(&temp_props); + + let mut props = temp_props + .iter_mut() + .map(|p| { + PropOrSpread::Prop( + Prop::KeyValue(parse_style_kv(p.0, p.1)).into(), + ) + }) + .collect::>(); + props.sort_by(|a, b| { + let a = match a { + PropOrSpread::Prop(prop) => match &**prop { + Prop::KeyValue(key_value_prop) => match &key_value_prop.key { + PropName::Ident(ident) => ident.sym.to_string(), + _ => "".to_string(), + }, + _ => "".to_string(), + }, + _ => "".to_string(), + }; + let b = match b { + PropOrSpread::Prop(prop) => match &**prop { + Prop::KeyValue(key_value_prop) => match &key_value_prop.key { + PropName::Ident(ident) => ident.sym.to_string(), + _ => "".to_string(), + }, + _ => "".to_string(), + }, + _ => "".to_string(), + }; + a.cmp(&b) + }); + lit.props.iter().for_each(|prop| { + if let PropOrSpread::Spread(_) = prop { + props.push(prop.clone()) + } + }); + lit.props = props; + } + } + _ => { + has_dynamic_style = true; + } + } + + has_dynamic_style + } } impl<'i> VisitMut for JSXMutVisitor<'i> { noop_visit_mut_type!(); - fn visit_mut_jsx_element(&mut self, n: &mut JSXElement) { - let span_key = SpanKey(n.span); - if let Some(element) = self.jsx_record.borrow().get(&span_key) { - // 将 style_record 中的样式添加到 JSXElement 的 style 属性中 - let style_record = self.style_record.borrow(); - let attrs = &mut n.opening.attrs; - let mut has_style = false; - let mut has_empty_style = false; - let mut has_dynamic_style = false; - let mut class_attr_value = None; - let mut style_attr_value = None; - let has_dynamic_class = attrs.iter().any(|attr| { - if let JSXAttrOrSpread::JSXAttr(attr) = attr { - if let JSXAttrName::Ident(ident) = &attr.name { - if ident.sym.to_string() == "className" { - if let Some(value) = &attr.value { - match value { - JSXAttrValue::JSXExprContainer(expr_container) => { - match &expr_container.expr { - JSXExpr::JSXEmptyExpr(_) => {} - JSXExpr::Expr(expr) => { - class_attr_value = Some((**expr).clone()); - } - }; - return true; + fn visit_mut_call_expr(&mut self, n: &mut CallExpr) { + let mut has_style = false; + let mut has_dynamic_style = false; + let mut style_attr_value = None; + + if self.check_is_jsx_callee(n) { + let span_key = SpanKey(n.span); + if let Some(element) = self.jsx_record.borrow().get(&span_key) { + let style_record = self.style_record.borrow(); + let jsx_element_or_callee = JSXElementOrJSXCallee::JSXCallee(&n); + let (class_attr_value, has_dynamic_class) = self.get_jsx_element_or_callee_calss_value_and_dynamic_class_bool(&jsx_element_or_callee); + + if let Some(attr) = n.args.get_mut(1) { + if let Expr::Object(object) = &mut *attr.expr { + for prop in object.props.iter_mut() { + if let PropOrSpread::Prop(prop) = prop { + if let Prop::KeyValue(key_value_prop) = &mut **prop { + if let PropName::Ident(ident) = &key_value_prop.key { + if ident.sym.to_string() == "style" { + has_style = true; + let expr = &mut *key_value_prop.value; + // 只支持值为字符串、对象形式的 style + match expr { + Expr::Lit(lit) => { + let value = self.process_attribute_lit_value(lit, has_dynamic_class, element, &self.style_record.borrow()); + + if let Some(value) = value { + let properties_entries: BTreeMap<_, _> = value.iter().collect(); + key_value_prop.value = Expr::Object(ObjectLit { + span: DUMMY_SP, + props: properties_to_object_lit_props(&properties_entries).into(), + }).into(); + } + } + _ => { + style_attr_value = Some((*expr).clone()); + has_dynamic_style = self.process_attribute_expr_value(&mut key_value_prop.value, has_dynamic_class, element, &self.style_record.borrow()); + } + }; + } } - JSXAttrValue::Lit(lit) => { - class_attr_value = Some(lit.clone().into()); + } + } + } + } + } + + if !has_dynamic_class && !has_dynamic_style && !has_style { + if let Some(style_declaration) = style_record.get(&element.span) { + let parsed_properties = parse_style_properties(&style_declaration); + let properties_entries: BTreeMap<_, _> = parsed_properties.iter().collect(); + let attrs = n.args.get_mut(1); + + if let Some(attr) = attrs { + if let Expr::Object(object) = &mut *attr.expr { + object.props.push(PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp { + key: PropName::Ident(Ident::new("style".into(), DUMMY_SP)), + value: Box::new(Expr::Object(ObjectLit { + span: DUMMY_SP, + props: properties_to_object_lit_props(&properties_entries).into(), + })), + })))); + } + } + } + } else { + let fun_call_expr = Expr::Call(CallExpr { + span: DUMMY_SP, + callee: Callee::Expr(Box::new(Expr::Ident(Ident::new( + CALC_DYMAMIC_STYLE.into(), + DUMMY_SP, + )))), + args: vec![ + ExprOrSpread::from(Box::new(Expr::Call(CallExpr { + span: DUMMY_SP, + callee: Callee::Expr(Box::new(Expr::Ident(Ident::new( + INNER_STYLE.into(), + DUMMY_SP, + )))), + type_args: None, + args: vec![] + }))), + match class_attr_value { + Some(value) => ExprOrSpread::from(Box::new(value)), + None => ExprOrSpread::from(Box::new(Expr::Lit(Lit::Null(Null { span: DUMMY_SP })))), + }, + match style_attr_value { + Some(value) => ExprOrSpread::from(Box::new(value)), + None => ExprOrSpread::from(Box::new(Expr::Lit(Lit::Null(Null { span: DUMMY_SP })))), + }, + ], + type_args: None, + }); + if has_style { + if let Some(attr) = n.args.get_mut(1) { + let expr = &mut attr.expr; + if let Expr::Object(object) = &mut **expr { + for prop in object.props.iter_mut() { + if let PropOrSpread::Prop(prop) = prop { + if let Prop::KeyValue(key_value_prop) = &mut **prop { + if let PropName::Ident(ident) = &key_value_prop.key { + if ident.sym.to_string() == "style" { + key_value_prop.value = Box::new(fun_call_expr.clone()); + } + } + } } - _ => {} } } } + } else { + let attrs = n.args.get_mut(1); + if let Some(attr) = attrs { + if let Expr::Object(object) = &mut *attr.expr { + object.props.push(PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp { + key: PropName::Ident(Ident::new("style".into(), DUMMY_SP)), + value: Box::new(fun_call_expr), + })))); + } + } } } - false - }); + } + } + + n.visit_mut_children_with(self); + } + + fn visit_mut_jsx_element(&mut self, n: &mut JSXElement) { + let mut has_style = false; + let mut has_dynamic_style = false; + let mut style_attr_value = None; + let span_key = SpanKey(n.span); + + if let Some(element) = self.jsx_record.borrow().get(&span_key) { + // 将 style_record 中的样式添加到 JSXElement 的 style 属性中 + let style_record = self.style_record.borrow(); + let jsx_element_or_callee = JSXElementOrJSXCallee::JSXElement(&n); + let (class_attr_value, has_dynamic_class) = self.get_jsx_element_or_callee_calss_value_and_dynamic_class_bool(&jsx_element_or_callee); + + let attrs = &mut n.opening.attrs; for attr in attrs.iter_mut() { if let JSXAttrOrSpread::JSXAttr(attr) = attr { if let JSXAttrName::Ident(ident) = &attr.name { @@ -534,206 +910,27 @@ impl<'i> VisitMut for JSXMutVisitor<'i> { Some(value) => { match value { JSXAttrValue::Lit(lit) => { - match lit { - Lit::Str(str) => { - if !has_dynamic_class { - // 将 style 属性的值转换为对象形式 - let mut properties = HashMap::new(); - let style = str.value.to_string(); - let style = style - .split(";") - .map(|s| s.to_owned()) - .collect::>(); - if let Some(style_declaration) = style_record.get(&element.span) { - for (key, value) in style_declaration.iter() { - properties.insert(to_camel_case(key, false), value.clone()); - } - } - for property in style.iter() { - let property = property - .split(":") - .map(|s| s.to_owned()) - .collect::>(); - if property.len() == 2 { - let property_parsed = Property::parse_string( - PropertyId::from(property[0].as_str()), - property[1].as_str(), - ParserOptions::default(), - ); - if property_parsed.is_ok() { - properties.insert( - property[0].clone(), - property_parsed.unwrap().into_owned(), - ); - } - } - } - let parsed_properties = parse_style_properties( - &properties - .iter() - .map(|(key, value)| (key.to_owned(), value.clone())) - .collect::>(), - ); - let properties_entries: BTreeMap<_, _> = - parsed_properties.iter().collect(); - attr.value = Some(JSXAttrValue::JSXExprContainer(JSXExprContainer { - span: DUMMY_SP, - expr: JSXExpr::Expr(Box::new(Expr::Object(ObjectLit { - span: DUMMY_SP, - props: properties_to_object_lit_props(&properties_entries).into(), - }))), - })); - } - } - _ => {} + let value = self.process_attribute_lit_value(lit, has_dynamic_class, element, &style_record); + + if let Some(value) = value { + let properties_entries: BTreeMap<_, _> = value.iter().collect(); + attr.value = Some(JSXAttrValue::JSXExprContainer(JSXExprContainer { + span: DUMMY_SP, + expr: JSXExpr::Expr(Box::new(Expr::Object(ObjectLit { + span: DUMMY_SP, + props: properties_to_object_lit_props(&properties_entries).into(), + }))), + })); } } JSXAttrValue::JSXExprContainer(expr_container) => { match &mut expr_container.expr { - JSXExpr::JSXEmptyExpr(_) => { - has_empty_style = true; - has_style = false; - } JSXExpr::Expr(expr) => { style_attr_value = Some((**expr).clone()); - match &mut **expr { - Expr::Object(lit) => { - if !has_dynamic_class { - let mut properties = Vec::new(); - if let Some(style_declaration) = style_record.get(&element.span) { - for declaration in style_declaration.iter() { - let mut has_property = false; - for prop in lit.props.iter_mut() { - match prop { - PropOrSpread::Prop(prop) => match &mut **prop { - Prop::KeyValue(key_value_prop) => { - match &mut key_value_prop.key { - PropName::Ident(ident) => { - ident.sym = to_camel_case( - ident.sym.to_string().as_str(), - false, - ) - .into(); - let property_id = ident.sym.to_string(); - if property_id == declaration.0.to_string() { - has_property = true; - break; - } - } - _ => {} - } - } - _ => {} - }, - PropOrSpread::Spread(_) => {} - } - } - if !has_property { - properties.push(declaration.clone()); - } - } - } - let deque = VecDeque::from(lit.props.clone()); - let mut temp_properties = HashMap::new(); - for p in deque.iter() { - match p { - PropOrSpread::Prop(prop) => match &**prop { - Prop::KeyValue(key_value_prop) => { - let value = match &*key_value_prop.value { - Expr::Lit(lit) => match lit { - Lit::Str(str) => str.value.to_string(), - Lit::Num(num) => num.to_string(), - _ => "".to_string(), - }, - _ => { - has_dynamic_style = true; - "".to_string() - } - }; - let name = match &key_value_prop.key { - PropName::Ident(ident) => { - Some(to_kebab_case(ident.sym.to_string().as_str())) - } - PropName::Str(str) => { - Some(to_kebab_case(str.value.to_string().as_str())) - } - _ => None, - }; - if let Some(name) = name { - let property_id = PropertyId::from(name.as_str()); - let property = Property::parse_string( - property_id, - value.as_str(), - ParserOptions::default(), - ); - if property.is_ok() { - temp_properties.insert( - to_camel_case(name.as_str(), false), - property.unwrap().into_owned(), - ); - } - } - } - _ => {} - }, - PropOrSpread::Spread(_) => {} - } - } - let mut temp_props = vec![]; - - for property in properties.iter() { - temp_props.push((property.0.to_string(), property.1.clone())); - } - temp_props.extend( - temp_properties - .iter() - .map(|(key, value)| (key.to_string(), value.clone())), - ); - let mut temp_props = parse_style_properties(&temp_props); - - let mut props = temp_props - .iter_mut() - .map(|p| { - PropOrSpread::Prop( - Prop::KeyValue(parse_style_kv(p.0, p.1)).into(), - ) - }) - .collect::>(); - props.sort_by(|a, b| { - let a = match a { - PropOrSpread::Prop(prop) => match &**prop { - Prop::KeyValue(key_value_prop) => match &key_value_prop.key { - PropName::Ident(ident) => ident.sym.to_string(), - _ => "".to_string(), - }, - _ => "".to_string(), - }, - _ => "".to_string(), - }; - let b = match b { - PropOrSpread::Prop(prop) => match &**prop { - Prop::KeyValue(key_value_prop) => match &key_value_prop.key { - PropName::Ident(ident) => ident.sym.to_string(), - _ => "".to_string(), - }, - _ => "".to_string(), - }, - _ => "".to_string(), - }; - a.cmp(&b) - }); - lit.props.iter().for_each(|prop| { - if let PropOrSpread::Spread(_) = prop { - props.push(prop.clone()) - } - }); - lit.props = props; - } - } - _ => { - has_dynamic_style = true; - } - } + has_dynamic_style = self.process_attribute_expr_value(expr, has_dynamic_class, element, &style_record); + } + _ => { + has_style = false; } } } @@ -746,7 +943,6 @@ impl<'i> VisitMut for JSXMutVisitor<'i> { } } None => { - has_empty_style = true; has_style = false; } }; @@ -754,41 +950,23 @@ impl<'i> VisitMut for JSXMutVisitor<'i> { } } } - if !has_dynamic_class && !has_dynamic_style { - if !has_style { - if let Some(style_declaration) = style_record.get(&element.span) { - let parsed_properties = parse_style_properties(&style_declaration); - let properties_entries: BTreeMap<_, _> = parsed_properties.iter().collect(); - if has_empty_style { - for attr in &mut n.opening.attrs { - if let JSXAttrOrSpread::JSXAttr(attr) = attr { - if let JSXAttrName::Ident(ident) = &attr.name { - if ident.sym.to_string() == "style" { - attr.value = Some(JSXAttrValue::JSXExprContainer(JSXExprContainer { - span: DUMMY_SP, - expr: JSXExpr::Expr(Box::new(Expr::Object(ObjectLit { - span: DUMMY_SP, - props: properties_to_object_lit_props(&properties_entries).into(), - }))), - })); - } - } - } - } - } else { - n.opening.attrs.push(JSXAttrOrSpread::JSXAttr(JSXAttr { + + if !has_dynamic_class && !has_dynamic_style && !has_style { + if let Some(style_declaration) = style_record.get(&element.span) { + let parsed_properties = parse_style_properties(&style_declaration); + let properties_entries: BTreeMap<_, _> = parsed_properties.iter().collect(); + + n.opening.attrs.push(JSXAttrOrSpread::JSXAttr(JSXAttr { + span: DUMMY_SP, + name: JSXAttrName::Ident(Ident::new("style".into(), DUMMY_SP)), + value: Some(JSXAttrValue::JSXExprContainer(JSXExprContainer { + span: DUMMY_SP, + expr: JSXExpr::Expr(Box::new(Expr::Object(ObjectLit { span: DUMMY_SP, - name: JSXAttrName::Ident(Ident::new("style".into(), DUMMY_SP)), - value: Some(JSXAttrValue::JSXExprContainer(JSXExprContainer { - span: DUMMY_SP, - expr: JSXExpr::Expr(Box::new(Expr::Object(ObjectLit { - span: DUMMY_SP, - props: properties_to_object_lit_props(&properties_entries).into(), - }))), - })), - })); - } - } + props: properties_to_object_lit_props(&properties_entries).into(), + }))), + })), + })); } } else { let fun_call_expr = Expr::Call(CallExpr {