Skip to content

Commit 15b425f

Browse files
committed
Merge remote-tracking branch 'origin/feat/nesting'
# Conflicts: # src/visitor.rs
2 parents aa0c128 + 4af4b9a commit 15b425f

File tree

6 files changed

+214
-99
lines changed

6 files changed

+214
-99
lines changed

__test__/fixure/pesudo.scss

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
.pesudo {
22
height: 400px;
33
width: 400px;
4+
margin-top: calc(100% - 30px);
45
}
56

67
.pesudo:last-child {
78
color: red;
89
}
910

10-
.text {
11+
.a, .a .b {
1112
font-size: 20px;
1213
text-overflow: ellipsis;
1314
}

__test__/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ const fs = require('fs')
22
const path = require('path')
33
process.env.platform = 'arm64'
44
const { parse } = require('../index.js')
5-
const component = fs.readFileSync(path.resolve(__dirname, 'fixure/mod.jsx'), 'utf8')
6-
const css1 = fs.readFileSync(path.resolve(__dirname, 'fixure/Mod.scss'), 'utf8')
5+
const component = fs.readFileSync(path.resolve(__dirname, 'fixure/pesudo.jsx'), 'utf8')
6+
const css1 = fs.readFileSync(path.resolve(__dirname, 'fixure/pesudo.scss'), 'utf8')
77
const code = parse(component, [css1], "Harmony")
88

99
console.log(code)

src/constants.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ pub const CONVERT_STYLE_PREFIX: &'static str = "_";
22
pub const CONVERT_STYLE_PX_FN: &'static str = "convertNumber2VP";
33
pub const INNER_STYLE: &'static str = "__inner_style__";
44
pub const INNER_STYLE_DATA: &'static str = "__inner_style_data__";
5+
pub const NESTING_STYLE: &'static str = "__nesting_style__";
6+
pub const NESTINT_STYLE_DATA: &'static str = "__nesting_style_data__";
57
pub const CALC_DYMAMIC_STYLE: &'static str = "calcDynamicStyle";
68

79
pub const RN_CONVERT_STYLE_PX_FN: &'static str = "scalePx2dp";

src/style_propetries/marin_padding.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ impl ToExpr for MarginPadding {
4242
// 判断self.id是否padding开头
4343
let is_padding = self.id.starts_with("padding");
4444
let key_name = if is_padding { "padding" } else { "margin" };
45+
4546
PropertyTuple::Array(vec![
4647
(format!("{}Top", key_name), generate_expr_by_length_percentage_or_auto!(self.top.as_ref().unwrap(), Platform::Harmony)),
4748
(format!("{}Right", key_name), generate_expr_by_length_percentage_or_auto!(self.right.as_ref().unwrap(), Platform::Harmony)),

src/utils.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,4 +174,42 @@ pub fn color_string(value: &Property) -> String {
174174
},
175175
..PrinterOptions::default()
176176
}).unwrap()
177+
}
178+
179+
// 分割选择器
180+
pub fn split_selector(selector: &str) -> Vec<String> {
181+
let mut result = Vec::new();
182+
let mut current_word = String::new();
183+
let mut buffer = String::new();
184+
185+
for c in selector.chars() {
186+
if c == ' ' || c == '>' || c == '+' || c == '~' {
187+
if !current_word.is_empty() {
188+
result.push(current_word.clone());
189+
current_word.clear();
190+
}
191+
192+
buffer.push(c);
193+
if buffer == " > " || buffer == " + " || buffer == " ~ " {
194+
result.push(buffer.clone());
195+
buffer.clear();
196+
}
197+
} else {
198+
current_word.push(c);
199+
if buffer == ' '.to_string() {
200+
result.push(buffer.clone());
201+
buffer.clear();
202+
}
203+
}
204+
}
205+
206+
if !current_word.is_empty() {
207+
result.push(current_word.clone());
208+
}
209+
210+
if !buffer.is_empty() {
211+
result.push(buffer.clone());
212+
}
213+
214+
result
177215
}

src/visitor.rs

Lines changed: 169 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ use swc_ecma_visit::{
2323
};
2424

2525
use crate::{
26-
constants::{CALC_DYMAMIC_STYLE, CONVERT_STYLE_PX_FN, INNER_STYLE, INNER_STYLE_DATA, RN_CONVERT_STYLE_PX_FN, RN_CONVERT_STYLE_VU_FN}, parse_style_properties::parse_style_properties, scraper::Element, style_parser::StyleValue, style_propetries::{style_value_type::StyleValueType, traits::ToStyleValue, unit::{Platform, PropertyTuple}}, utils::{
27-
create_qualname, get_callee_attributes, prefix_style_key, recursion_jsx_member, to_camel_case, to_kebab_case
26+
constants::{CALC_DYMAMIC_STYLE, CONVERT_STYLE_PX_FN, INNER_STYLE, INNER_STYLE_DATA, NESTING_STYLE, NESTINT_STYLE_DATA, RN_CONVERT_STYLE_PX_FN, RN_CONVERT_STYLE_VU_FN}, parse_style_properties::parse_style_properties, scraper::Element, style_parser::StyleValue, style_propetries::{style_value_type::StyleValueType, traits::ToStyleValue, unit::{Platform, PropertyTuple}}, utils::{
27+
create_qualname, get_callee_attributes, prefix_style_key, recursion_jsx_member, split_selector, to_camel_case, to_kebab_case
2828
}
2929
};
3030

@@ -479,26 +479,27 @@ impl VisitMut for ModuleMutVisitor {
479479
let binding = self.all_style.borrow();
480480
let style_entries: BTreeMap<_, _> = binding.iter().collect();
481481

482-
let ident = Ident::new(INNER_STYLE_DATA.into(), DUMMY_SP);
483-
484-
let identifier = Stmt::Decl(Decl::Var(Box::new(VarDecl {
485-
span: DUMMY_SP,
486-
kind: swc_ecma_ast::VarDeclKind::Let,
487-
declare: false,
488-
decls: vec![swc_ecma_ast::VarDeclarator {
489-
span: DUMMY_SP,
490-
name: swc_ecma_ast::Pat::Ident(BindingIdent {
491-
id: ident.clone(),
492-
type_ann: None,
493-
}),
494-
init: None,
495-
definite: false,
496-
}]
497-
})));
482+
498483

484+
// __inner_style__普通样式对象
499485
let mut final_style_entries: BTreeMap<String, Vec<PropOrSpread>> = BTreeMap::new();
486+
// __nesting_style__嵌套样式对象
487+
let mut nesting_style_entries: BTreeMap<Vec<String>, Vec<PropOrSpread>> = BTreeMap::new();
488+
500489
// 合并伪类样式, .pesudo {}、.pesudo:after {} => .pesudo: { xxx, ["::after"]: {xxx}}
501490
style_entries.iter().for_each(|(key, value)| {
491+
// 判断是否嵌套样式
492+
if self.platform == Platform::Harmony {
493+
if key.contains(" ") {
494+
// 拆分选择器字符串,安装' ' 或 '>' 拆分,如:container > wrapper item => ['container', '>', 'wrapper', ' ', 'item']
495+
let selectors = split_selector(key);
496+
println!("{:?}", key);
497+
println!("{:?}", selectors);
498+
nesting_style_entries.insert(selectors, parse_style_values(value.to_vec(), self.platform.clone()));
499+
return;
500+
}
501+
}
502+
502503
// 判断key是否伪类
503504
if key.contains(":") && self.platform == Platform::Harmony {
504505
let mut element_key = String::new();
@@ -543,83 +544,6 @@ impl VisitMut for ModuleMutVisitor {
543544
}
544545
}
545546
});
546-
547-
548-
let inner_style_func = {
549-
550-
let style_object = Box::new(Expr::Object(ObjectLit {
551-
span: DUMMY_SP,
552-
props: final_style_entries
553-
.iter()
554-
.map(|(key, value)| {
555-
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
556-
key: PropName::Str(Str::from(key.as_str())),
557-
value: Box::new(Expr::Object(ObjectLit {
558-
span: DUMMY_SP,
559-
props: value.to_vec()
560-
})),
561-
})))
562-
})
563-
.collect::<Vec<PropOrSpread>>()
564-
.into(),
565-
}));
566-
567-
let body = vec![
568-
// if (__inner_style_data__) return __inner_style_data__
569-
Stmt::If(IfStmt {
570-
span: DUMMY_SP,
571-
test: Box::new(Expr::Ident(ident.clone())),
572-
cons: Box::new(
573-
Stmt::Return(ReturnStmt {
574-
span: DUMMY_SP,
575-
arg: Some(Box::new(Expr::Ident(ident.clone())))
576-
})
577-
),
578-
alt: None
579-
}),
580-
// __inner_style_data__ = { ... }
581-
Stmt::Expr(
582-
ExprStmt {
583-
span: DUMMY_SP,
584-
expr: Box::new(
585-
Expr::Assign(AssignExpr { span: DUMMY_SP, op: AssignOp::Assign,
586-
left: swc_ecma_ast::PatOrExpr::Expr(Box::new(Expr::Ident(ident.clone()))),
587-
right: style_object
588-
})
589-
)
590-
}
591-
),
592-
// return __inner_style_data__
593-
Stmt::Return(ReturnStmt {
594-
span: DUMMY_SP,
595-
arg: Some(Box::new(Expr::Ident(ident)))
596-
})
597-
];
598-
599-
600-
let func = FnExpr {
601-
ident: Some(Ident::new(INNER_STYLE.into(), DUMMY_SP)) ,
602-
function: Box::new(Function {
603-
params: vec![],
604-
decorators: vec![],
605-
span: DUMMY_SP,
606-
body: Some(BlockStmt {
607-
span: DUMMY_SP,
608-
stmts: body,
609-
}),
610-
is_generator: false,
611-
is_async: false,
612-
type_params: None,
613-
return_type: None,
614-
})
615-
};
616-
617-
Stmt::Decl(Decl::Fn(FnDecl {
618-
ident: func.ident.clone().unwrap(),
619-
function: func.function,
620-
declare: false
621-
}))
622-
};
623547

624548
// 将 inner_style_stmt 插入到 module 的最后一条 import 语句之后
625549
let mut last_import_index = 0;
@@ -663,17 +587,166 @@ impl VisitMut for ModuleMutVisitor {
663587
let mut var_checker = VarChecker { found: false };
664588
module.visit_with(&mut var_checker);
665589
if var_checker.found {
590+
let style_object = Box::new(Expr::Object(ObjectLit {
591+
span: DUMMY_SP,
592+
props: final_style_entries
593+
.iter()
594+
.map(|(key, value)| {
595+
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
596+
key: PropName::Str(Str::from(key.as_str())),
597+
value: Box::new(Expr::Object(ObjectLit {
598+
span: DUMMY_SP,
599+
props: value.to_vec()
600+
})),
601+
})))
602+
})
603+
.collect::<Vec<PropOrSpread>>()
604+
.into(),
605+
}));
606+
607+
let (identifier, style_func) = generate_stylesheet(INNER_STYLE.to_string(), INNER_STYLE_DATA.to_string(), style_object);
666608
// 插入代码 let __inner_style_data__;
667609
module.body.insert(last_import_index, ModuleItem::Stmt(identifier));
668610
last_import_index += 1;
669611
// 插入代码 function __inner_style__() { ... }
670612
module
671613
.body
672-
.insert(last_import_index, ModuleItem::Stmt(inner_style_func));
614+
.insert(last_import_index, ModuleItem::Stmt(style_func));
673615
}
616+
617+
// 插入嵌套样式
618+
let nesting_style_object = Box::new(Expr::Array(ArrayLit {
619+
span: DUMMY_SP,
620+
elems: nesting_style_entries
621+
.iter()
622+
.map(|(key, value)| {
623+
Some(ExprOrSpread {
624+
spread: None,
625+
expr: Box::new(Expr::Object(ObjectLit {
626+
span: DUMMY_SP,
627+
props: vec![
628+
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
629+
key: PropName::Str(Str::from("selectors")),
630+
value: Box::new(Expr::Array(ArrayLit {
631+
span: DUMMY_SP,
632+
elems: key.iter().map(|prop| {
633+
Some(ExprOrSpread {
634+
spread: None,
635+
expr: Box::new(Expr::Lit(Lit::Str(Str::from(prop.as_str()))))
636+
})
637+
}).collect::<Vec<Option<ExprOrSpread>>>()
638+
})),
639+
}))),
640+
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
641+
key: PropName::Str(Str::from("declaration")),
642+
value: Box::new(Expr::Object(ObjectLit {
643+
span: DUMMY_SP,
644+
props: value.to_vec()
645+
})),
646+
})))
647+
648+
]
649+
}))
650+
})
651+
})
652+
.collect::<Vec<Option<ExprOrSpread>>>()
653+
.into(),
654+
}));
655+
656+
let (identifier, style_func) = generate_stylesheet(NESTING_STYLE.to_string(), NESTINT_STYLE_DATA.to_string(), nesting_style_object);
657+
// 插入代码 let __inner_style_data__;
658+
module.body.insert(last_import_index, ModuleItem::Stmt(identifier));
659+
last_import_index += 1;
660+
// 插入代码 function __inner_style__() { ... }
661+
module
662+
.body
663+
.insert(last_import_index, ModuleItem::Stmt(style_func))
674664
}
675665
}
676666

667+
fn generate_stylesheet(fn_name: String, fn_data_name: String, style_object: Box<Expr>) -> (Stmt, Stmt) {
668+
669+
let ident = Ident::new(fn_data_name.into(), DUMMY_SP);
670+
671+
let identifier = Stmt::Decl(Decl::Var(Box::new(VarDecl {
672+
span: DUMMY_SP,
673+
kind: swc_ecma_ast::VarDeclKind::Let,
674+
declare: false,
675+
decls: vec![swc_ecma_ast::VarDeclarator {
676+
span: DUMMY_SP,
677+
name: swc_ecma_ast::Pat::Ident(BindingIdent {
678+
id: ident.clone(),
679+
type_ann: None,
680+
}),
681+
init: None,
682+
definite: false,
683+
}]
684+
})));
685+
686+
let inner_style_func = {
687+
688+
let body = vec![
689+
// if (__inner_style_data__) return __inner_style_data__
690+
Stmt::If(IfStmt {
691+
span: DUMMY_SP,
692+
test: Box::new(Expr::Ident(ident.clone())),
693+
cons: Box::new(
694+
Stmt::Return(ReturnStmt {
695+
span: DUMMY_SP,
696+
arg: Some(Box::new(Expr::Ident(ident.clone())))
697+
})
698+
),
699+
alt: None
700+
}),
701+
// __inner_style_data__ = { ... }
702+
Stmt::Expr(
703+
ExprStmt {
704+
span: DUMMY_SP,
705+
expr: Box::new(
706+
Expr::Assign(AssignExpr { span: DUMMY_SP, op: AssignOp::Assign,
707+
left: swc_ecma_ast::PatOrExpr::Expr(Box::new(Expr::Ident(ident.clone()))),
708+
right: style_object
709+
})
710+
)
711+
}
712+
),
713+
// return __inner_style_data__
714+
Stmt::Return(ReturnStmt {
715+
span: DUMMY_SP,
716+
arg: Some(Box::new(Expr::Ident(ident)))
717+
})
718+
];
719+
720+
721+
let func = FnExpr {
722+
ident: Some(Ident::new(fn_name.into(), DUMMY_SP)) ,
723+
function: Box::new(Function {
724+
params: vec![],
725+
decorators: vec![],
726+
span: DUMMY_SP,
727+
body: Some(BlockStmt {
728+
span: DUMMY_SP,
729+
stmts: body,
730+
}),
731+
is_generator: false,
732+
is_async: false,
733+
type_params: None,
734+
return_type: None,
735+
})
736+
};
737+
738+
Stmt::Decl(Decl::Fn(FnDecl {
739+
ident: func.ident.clone().unwrap(),
740+
function: func.function,
741+
declare: false
742+
}))
743+
};
744+
(
745+
identifier,
746+
inner_style_func
747+
)
748+
}
749+
677750
pub struct JSXMutVisitor<'i> {
678751
pub jsx_record: Rc<RefCell<JSXRecord>>,
679752
pub style_record: Rc<RefCell<HashMap<SpanKey, Vec<(String, Property<'i>)>>>>,

0 commit comments

Comments
 (0)