Skip to content

Commit 73a5bcb

Browse files
committed
feat: 支持函数调用方式的子 JSX 拆分写法
1 parent ac404c8 commit 73a5bcb

File tree

3 files changed

+112
-18
lines changed

3 files changed

+112
-18
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
### JSX DOM 树构造
1818
- [x] 支持函数组件
1919
- [x] 支持类组件
20-
- [ ] 支持 JSX 分离的写法
20+
- [x] 支持 JSX 分离的写法
2121
- [ ] 支持遍历子组件
2222

2323
### 样式计算

asset/mod.jsx

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,31 @@ function Cc() {
1515
}
1616

1717
export default class Mod extends React.Component {
18+
getDom () {
19+
return (
20+
<div className='cc'>
21+
<span className='line1 txt'>成员123: 4000+</span>
22+
<div className='cnt_row4'>
23+
<img className='icon2' src='//img11.360buyimg.com/img/jfs/t1/175578/35/40256/1981/64f58062Fddaf1a21/f1111d9988a65ccc.png'></img>
24+
<span className='instruction3'>slslsl-jsj</span>
25+
<span className='txt3'>复制</span>
26+
</div>
27+
</div>
28+
)
29+
}
1830
render () {
1931
return (
2032
<div className='mod' style={{ width: '500px', height: 800 }}>
2133
<div className='cnt_row'>
22-
<img
23-
className='icon'
24-
src='//img20.360buyimg.com/img/jfs/t1/166410/12/38783/3147/64f58062Fd7737e2b/5aaf0205cd1ce175.png'
25-
></img>
26-
<span className='line1 instruction'>超能芭比 5分钟前查看团购</span>
34+
<>
35+
<img
36+
className='icon'
37+
src='//img20.360buyimg.com/img/jfs/t1/166410/12/38783/3147/64f58062Fd7737e2b/5aaf0205cd1ce175.png'
38+
></img>
39+
<>
40+
<span className='line1 instruction'>超能芭比 5分钟前查看团购</span>
41+
</>
42+
</>
2743
</div>
2844
<div className='cnt_row1'>
2945
<img
@@ -35,7 +51,7 @@ export default class Mod extends React.Component {
3551
<span className='line1 txt'>成员: 4000+</span>
3652
</div>
3753
<div className='cnt_row2'>
38-
<Cc />
54+
{ this.getDom() }
3955
<img
4056
className='icon1'
4157
src='//img11.360buyimg.com/img/jfs/t1/175578/35/40256/1981/64f58062Fddaf1a21/f1111d9988a65ccc.png'

src/visitor.rs

Lines changed: 89 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use ego_tree::{NodeId, Tree, NodeMut, NodeRef};
22
use html5ever::{Attribute, tendril::StrTendril};
3-
use swc_ecma_ast::{JSXElement, JSXElementName, JSXAttrOrSpread, JSXAttrName, JSXAttrValue, Lit, JSXExpr, Expr, JSXElementChild, Module, Function, Stmt, ExportDefaultExpr, ExportDefaultDecl, DefaultDecl, ClassDecl, ClassMember, PropName, FnDecl, JSXFragment};
3+
use swc_ecma_ast::{JSXElement, JSXElementName, JSXAttrOrSpread, JSXAttrName, JSXAttrValue, Lit, JSXExpr, Expr, JSXElementChild, Module, Function, Stmt, ExportDefaultExpr, ExportDefaultDecl, DefaultDecl, ClassDecl, ClassMember, PropName, FnDecl, Callee, MemberProp};
44
use swc_ecma_visit::{Visit, VisitWith};
55

66
use crate::{scraper::{Node, Element, Fragment}, utils::{recursion_jsx_member, create_qualname, is_starts_with_uppercase}};
@@ -119,14 +119,14 @@ impl<'a> Visit for JSXVisitor<'a> {
119119

120120
fn visit_jsx_element_children(&mut self, n: &[JSXElementChild]) {
121121
let mut nodes = vec![];
122-
let mut elements: Vec<JSXElementChild> = vec![];
122+
let mut elements: Vec<&JSXElementChild> = vec![];
123123
for child in n.iter() {
124124
match child {
125125
JSXElementChild::JSXElement(element) => {
126126
if let JSXElementName::Ident(ident) = &element.opening.name {
127127
let name = ident.sym.to_string();
128128
if is_starts_with_uppercase(name.as_str()) {
129-
let mut visitor = JSXFragmentVisitor::new(self.module, name.as_str());
129+
let mut visitor = JSXFragmentVisitor::new(self.module, name.as_str(), SearchType::Normal);
130130
self.module.visit_with(&mut visitor);
131131
let mut current = self.tree.get_mut(self.current_node.unwrap()).unwrap();
132132
// 将 Fragment 的子节点添加到当前节点
@@ -136,22 +136,66 @@ impl<'a> Visit for JSXVisitor<'a> {
136136
let mut current = self.tree.get_mut(self.current_node.unwrap()).unwrap();
137137
let tree_node = current.append(node);
138138
nodes.push(tree_node.id());
139-
elements.push(JSXElementChild::JSXElement(element.clone()));
139+
elements.push(child);
140140
}
141141
} else {
142142
let node = self.create_element(element);
143143
let mut current = self.tree.get_mut(self.current_node.unwrap()).unwrap();
144144
let tree_node = current.append(node);
145145
nodes.push(tree_node.id());
146-
elements.push(JSXElementChild::JSXElement(element.clone()));
146+
elements.push(child);
147147
}
148148
},
149-
JSXElementChild::JSXFragment(fragment) => {
149+
JSXElementChild::JSXFragment(_) => {
150150
let node = self.create_fragment();
151151
let mut current = self.tree.get_mut(self.current_node.unwrap()).unwrap();
152152
let tree_node = current.append(node);
153153
nodes.push(tree_node.id());
154-
elements.push(JSXElementChild::JSXFragment(fragment.clone()));
154+
elements.push(child);
155+
},
156+
// 找到函数调用中的 JSX
157+
JSXElementChild::JSXExprContainer(expr) => {
158+
match &expr.expr {
159+
JSXExpr::JSXEmptyExpr(_) => {},
160+
JSXExpr::Expr(expr) => {
161+
match &**expr {
162+
Expr::Call(call_expr) => {
163+
match &call_expr.callee {
164+
Callee::Expr(expr) => {
165+
match &**expr {
166+
Expr::Ident(ident) => {
167+
let name = ident.sym.to_string();
168+
let mut visitor = JSXFragmentVisitor::new(self.module, name.as_str(), SearchType::Normal);
169+
self.module.visit_with(&mut visitor);
170+
let mut current = self.tree.get_mut(self.current_node.unwrap()).unwrap();
171+
// 将 Fragment 的子节点添加到当前节点
172+
recursion_sub_tree(&visitor.tree.root(), &mut current);
173+
},
174+
Expr::Member(member_expr) => {
175+
if let Expr::This(_) = &*member_expr.obj {
176+
match &member_expr.prop {
177+
MemberProp::Ident(ident) => {
178+
let name = ident.sym.to_string();
179+
let mut visitor = JSXFragmentVisitor::new(self.module, name.as_str(), SearchType::Class);
180+
self.module.visit_with(&mut visitor);
181+
let mut current = self.tree.get_mut(self.current_node.unwrap()).unwrap();
182+
// 将 Fragment 的子节点添加到当前节点
183+
recursion_sub_tree(&visitor.tree.root(), &mut current);
184+
},
185+
_ => {}
186+
}
187+
}
188+
},
189+
_ => {}
190+
}
191+
},
192+
_ => {}
193+
}
194+
},
195+
_ => {}
196+
}
197+
},
198+
}
155199
},
156200
_ => {}
157201
}
@@ -165,27 +209,35 @@ impl<'a> Visit for JSXVisitor<'a> {
165209
}
166210
}
167211

212+
#[derive(PartialEq)]
213+
pub enum SearchType {
214+
Normal,
215+
Class
216+
}
217+
168218
pub struct JSXFragmentVisitor<'a> {
169219
pub module: &'a Module,
170220
pub tree: Tree<Node>,
171-
pub search_fn: &'a str
221+
pub search_fn: &'a str,
222+
pub search_type: SearchType
172223
}
173224

174225
impl<'a> JSXFragmentVisitor<'a> {
175-
pub fn new(module: &'a Module, search_fn: &'a str) -> Self {
226+
pub fn new(module: &'a Module, search_fn: &'a str, search_type: SearchType) -> Self {
176227
JSXFragmentVisitor {
177228
module,
178229
tree: Tree::new(Node::Fragment(
179230
Fragment::new(Some(create_qualname(search_fn)))
180231
)),
181-
search_fn
232+
search_fn,
233+
search_type
182234
}
183235
}
184236
}
185237

186238
impl<'a> Visit for JSXFragmentVisitor<'a> {
187239
fn visit_fn_decl(&mut self, n: &FnDecl) {
188-
if n.ident.sym.to_string() == self.search_fn {
240+
if n.ident.sym.to_string() == self.search_fn && self.search_type == SearchType::Normal {
189241
match &*n.function {
190242
Function { body: Some(body), .. } => {
191243
for stmt in &body.stmts {
@@ -202,6 +254,32 @@ impl<'a> Visit for JSXFragmentVisitor<'a> {
202254
}
203255
}
204256
}
257+
258+
fn visit_class_method(&mut self,n: &swc_ecma_ast::ClassMethod) {
259+
if self.search_type == SearchType::Class {
260+
match &n.key {
261+
PropName::Ident(ident) => {
262+
if ident.sym.to_string() == self.search_fn {
263+
match &*n.function {
264+
Function { body: Some(body), .. } => {
265+
for stmt in &body.stmts {
266+
match stmt {
267+
Stmt::Return(return_stmt) => {
268+
let mut jsx_visitor = JSXVisitor::new(&mut self.tree, self.module);
269+
return_stmt.visit_with(&mut jsx_visitor);
270+
},
271+
_ => {}
272+
}
273+
}
274+
},
275+
_ => {}
276+
}
277+
}
278+
},
279+
_ => {}
280+
}
281+
}
282+
}
205283
}
206284

207285
pub struct AstVisitor<'a> {

0 commit comments

Comments
 (0)