@tarojs/helper 3.7.0-alpha.25 → 3.7.0-alpha.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/dist/constants.d.ts +3 -3
  2. package/dist/constants.js +3 -3
  3. package/dist/constants.js.map +1 -1
  4. package/dist/esbuild/index.js +1 -0
  5. package/dist/esbuild/index.js.map +1 -1
  6. package/dist/swcRegister.d.ts +0 -6
  7. package/dist/swcRegister.js +0 -15
  8. package/dist/swcRegister.js.map +1 -1
  9. package/dist/utils.d.ts +8 -2
  10. package/dist/utils.js +12 -3
  11. package/dist/utils.js.map +1 -1
  12. package/package.json +5 -5
  13. package/swc/plugin-compile-mode/.cargo/config +5 -0
  14. package/swc/plugin-compile-mode/.editorconfig +6 -0
  15. package/swc/plugin-compile-mode/.vscode/settings.json +3 -0
  16. package/swc/plugin-compile-mode/Cargo.lock +2021 -0
  17. package/swc/plugin-compile-mode/Cargo.toml +19 -0
  18. package/swc/plugin-compile-mode/package.json +15 -0
  19. package/swc/plugin-compile-mode/src/lib.rs +71 -0
  20. package/swc/plugin-compile-mode/src/tests/attributes.rs +54 -0
  21. package/swc/plugin-compile-mode/src/tests/children.rs +86 -0
  22. package/swc/plugin-compile-mode/src/tests/condition.rs +50 -0
  23. package/swc/plugin-compile-mode/src/tests/entry.rs +20 -0
  24. package/swc/plugin-compile-mode/src/tests/harmony/attributes.rs +45 -0
  25. package/swc/plugin-compile-mode/src/tests/harmony/children.rs +74 -0
  26. package/swc/plugin-compile-mode/src/tests/harmony/condition.rs +79 -0
  27. package/swc/plugin-compile-mode/src/tests/harmony/entry.rs +67 -0
  28. package/swc/plugin-compile-mode/src/tests/harmony/looping.rs +62 -0
  29. package/swc/plugin-compile-mode/src/tests/harmony/mod.rs +45 -0
  30. package/swc/plugin-compile-mode/src/tests/looping.rs +84 -0
  31. package/swc/plugin-compile-mode/src/tests/mod.rs +100 -0
  32. package/swc/plugin-compile-mode/src/tests/shake.rs +27 -0
  33. package/swc/plugin-compile-mode/src/transform.rs +480 -0
  34. package/swc/plugin-compile-mode/src/transform_harmony.rs +526 -0
  35. package/swc/plugin-compile-mode/src/utils/constants.rs +149 -0
  36. package/swc/plugin-compile-mode/src/utils/harmony/components.rs +61 -0
  37. package/swc/plugin-compile-mode/src/utils/harmony/mod.rs +1 -0
  38. package/swc/plugin-compile-mode/src/utils/mod.rs +346 -0
  39. package/swc/plugin-compile-mode/target/wasm32-wasi/release/swc_plugin_compile_mode.wasm +0 -0
  40. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/attributes.rs/should_handle_events.js +8 -0
  41. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/attributes.rs/should_keep_static_attrs_only_in_templates.js +8 -0
  42. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/attributes.rs/should_turn_dynamic_attrs.js +11 -0
  43. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/children.rs/should_render_native_component.js +7 -0
  44. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/children.rs/should_render_react_component.js +7 -0
  45. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/children.rs/should_support_fragment.js +44 -0
  46. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/children.rs/should_support_render_fn.js +8 -0
  47. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/condition.rs/should_support_and_expr.js +14 -0
  48. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/condition.rs/should_support_conditional_expr.js +15 -0
  49. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/entry.rs/should_support_multi_compile_mode.js +10 -0
  50. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/attributes.rs/should_handle_events.js +181 -0
  51. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/attributes.rs/should_turn_dynamic_attrs.js +184 -0
  52. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/children.rs/should_render_react_component.js +75 -0
  53. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/children.rs/should_support_fragment.js +339 -0
  54. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/children.rs/should_support_render_fn.js +184 -0
  55. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/condition.rs/should_support_and_expr.js +209 -0
  56. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/condition.rs/should_support_complex_condition.js +242 -0
  57. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/condition.rs/should_support_conditional_and_unkonw_component.js +137 -0
  58. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/condition.rs/should_support_conditional_expr.js +342 -0
  59. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/entry.rs/should_support_compile_child_node.js +139 -0
  60. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/entry.rs/should_support_component_not_in_config.js +90 -0
  61. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/entry.rs/should_support_multi_compile_mode.js +206 -0
  62. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/entry.rs/should_support_single_compile_mode.js +65 -0
  63. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/looping.rs/should_loop_with_arrow_function_with_blockstmt.js +75 -0
  64. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/looping.rs/should_loop_with_arrow_function_with_blockstmt_and_set_parent_dynamic_id.js +88 -0
  65. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/looping.rs/should_loop_with_function_expr.js +85 -0
  66. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/looping.rs/should_loop_with_arrow_function_with_blockstmt.js +8 -0
  67. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/looping.rs/should_loop_with_arrow_function_with_expr.js +6 -0
  68. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/looping.rs/should_loop_with_function_expr.js +20 -0
  69. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/looping.rs/should_support_nested_loop.js +15 -0
  70. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/shake.rs/should_static_jsx_being_shaked.js +20 -0
  71. package/swc/plugin-define-config/.cargo/config +5 -0
  72. package/swc/plugin-define-config/Cargo.lock +582 -506
  73. package/swc/plugin-define-config/Cargo.toml +2 -11
  74. package/swc/plugin-define-config/src/lib.rs +81 -128
  75. package/swc/plugin-define-config/target/wasm32-wasi/release/swc_plugin_define_config.wasm +0 -0
  76. package/swc/plugin-define-config/tests/__swc_snapshots__/src/lib.rs/module_decl_default_app.js +2 -0
  77. package/swc/plugin-define-config/tests/__swc_snapshots__/src/lib.rs/module_decl_default_page.js +2 -0
  78. package/swc/plugin-define-config/tests/__swc_snapshots__/src/lib.rs/module_exports.js +11 -0
  79. package/swc/plugin-define-config/tests/__swc_snapshots__/src/lib.rs/var_decl_app.js +3 -0
  80. package/swc/plugin-define-config/tests/__swc_snapshots__/src/lib.rs/var_decl_page.js +3 -0
@@ -0,0 +1,480 @@
1
+
2
+ use swc_core::{
3
+ common::{
4
+ iter::IdentifyLast,
5
+ util::take::Take,
6
+ DUMMY_SP as span
7
+ },
8
+ ecma::{
9
+ self,
10
+ ast::*,
11
+ visit::{VisitMut, VisitMutWith},
12
+ },
13
+ };
14
+ use std::collections::HashMap;
15
+ use crate::PluginConfig;
16
+ use crate::utils::{self, constants::*};
17
+
18
+ struct PreVisitor {
19
+ is_in_and_expr: bool,
20
+ }
21
+ impl PreVisitor {
22
+ fn new () -> Self {
23
+ Self {
24
+ is_in_and_expr: false
25
+ }
26
+ }
27
+ }
28
+ impl VisitMut for PreVisitor {
29
+ fn visit_mut_jsx_element_child (&mut self, child: &mut JSXElementChild) {
30
+ if let JSXElementChild::JSXExprContainer(JSXExprContainer { expr: JSXExpr::Expr(expr), .. }) = child {
31
+ let mut is_first_and_expr = false;
32
+
33
+ if let Expr::Paren(ParenExpr { expr: e, .. }) = &mut **expr {
34
+ *expr = e.take();
35
+ }
36
+
37
+ match &mut **expr {
38
+ Expr::Bin(BinExpr { op, left, right, ..}) => {
39
+ // C&&A 替换为 C?A:A',原因是为了无论显示还是隐藏都保留一个元素,从而不影响兄弟节点的变量路径
40
+ if *op == op!("&&") && !self.is_in_and_expr {
41
+ is_first_and_expr = true;
42
+ fn inject_compile_if (el: &mut Box<JSXElement>, condition: &mut Box<Expr>) -> () {
43
+ el.opening.attrs.push(utils::create_jsx_expr_attr(COMPILE_IF, condition.clone()));
44
+ }
45
+ fn get_element_double (element_name: JSXElementName, condition: &mut Box<Expr>, right: &mut Box<Expr>) -> Expr {
46
+ Expr::Cond(CondExpr {
47
+ span,
48
+ test: condition.take(),
49
+ cons: right.take(),
50
+ alt: Box::new(utils::create_self_closing_jsx_element_expr(
51
+ element_name, // element 替换为同类型的元素。在显示/隐藏切换时,让运行时 diff 只更新必要属性而不是整个节点刷新
52
+ Some(vec![utils::create_jsx_bool_attr(COMPILE_IGNORE)]
53
+ )))
54
+ })
55
+ }
56
+ match &mut **right {
57
+ Expr::JSXElement(el) => {
58
+ let element_name = el.opening.name.clone();
59
+ inject_compile_if(el, left);
60
+ **expr = get_element_double(element_name, left, right);
61
+ },
62
+ Expr::Paren(ParenExpr { expr: paren_expr, .. }) => {
63
+ if paren_expr.is_jsx_element() {
64
+ let el: &mut Box<JSXElement> = paren_expr.as_mut_jsx_element().unwrap();
65
+ let element_name = el.opening.name.clone();
66
+ inject_compile_if(el, left);
67
+ **expr = get_element_double(element_name, left, paren_expr);
68
+ }
69
+ },
70
+ Expr::Lit(_) => {
71
+ **expr = Expr::Cond(CondExpr {
72
+ span,
73
+ test: left.take(),
74
+ cons: right.take(),
75
+ alt: Box::new(Expr::Lit(Lit::Str(Str { span, value: COMPILE_IGNORE.into(), raw: None })))
76
+ })
77
+ },
78
+ _ => {
79
+ let jsx_el_name = JSXElementName::Ident(Ident { span, sym: "block".into(), optional: false });
80
+ let mut block = Box::new(JSXElement {
81
+ span,
82
+ opening: JSXOpeningElement { name: jsx_el_name.clone(), span, attrs: vec![], self_closing: false, type_args: None },
83
+ children: vec![JSXElementChild::JSXExprContainer(JSXExprContainer { span, expr: JSXExpr::Expr(right.take()) })],
84
+ closing: Some(JSXClosingElement { span, name: jsx_el_name.clone() })
85
+ });
86
+ inject_compile_if(&mut block, left);
87
+ **expr = get_element_double(jsx_el_name, left, &mut Box::new(Expr::JSXElement(block)));
88
+ }
89
+ }
90
+ }
91
+ },
92
+ Expr::Cond(CondExpr { test, cons, alt, ..}) => {
93
+ let compile_if = utils::create_jsx_expr_attr(COMPILE_IF, test.clone());
94
+ let compile_else = utils::create_jsx_bool_attr(COMPILE_ELSE);
95
+ let process_cond_arm = |arm: &mut Box<Expr>, attr: JSXAttrOrSpread| {
96
+ match &mut **arm {
97
+ Expr::JSXElement(el) => {
98
+ el.opening.attrs.push(attr);
99
+ },
100
+ _ => {
101
+ let temp = arm.take();
102
+ let jsx_el_name = JSXElementName::Ident(Ident { span, sym: "block".into(), optional: false });
103
+ **arm = Expr::JSXElement(Box::new(JSXElement {
104
+ span,
105
+ opening: JSXOpeningElement { name: jsx_el_name.clone(), span, attrs: vec![attr], self_closing: false, type_args: None },
106
+ children: vec![JSXElementChild::JSXExprContainer(JSXExprContainer { span, expr: JSXExpr::Expr(temp)})],
107
+ closing: Some(JSXClosingElement { span, name: jsx_el_name })
108
+ }))
109
+ }
110
+ }
111
+ };
112
+ process_cond_arm(cons, compile_if);
113
+ process_cond_arm(alt, compile_else);
114
+ },
115
+ _ => (),
116
+ }
117
+
118
+ if is_first_and_expr {
119
+ self.is_in_and_expr = true;
120
+ }
121
+
122
+ expr.visit_mut_children_with(self);
123
+
124
+ if is_first_and_expr {
125
+ self.is_in_and_expr = false;
126
+ }
127
+ } else {
128
+ child.visit_mut_children_with(self);
129
+ }
130
+ }
131
+ }
132
+
133
+ pub struct TransformVisitor {
134
+ pub config: PluginConfig,
135
+ pub is_compile_mode: bool,
136
+ pub node_stack: Vec<i32>,
137
+ pub templates: HashMap<String, String>,
138
+ pub get_tmpl_name: Box<dyn FnMut() -> String>
139
+ }
140
+
141
+ impl TransformVisitor {
142
+ pub fn new (config: PluginConfig) -> Self {
143
+ let get_tmpl_name = Box::new(utils::named_iter(
144
+ format!("{}t", config.tmpl_prefix)
145
+ ));
146
+ Self {
147
+ config,
148
+ is_compile_mode: false,
149
+ node_stack: vec![],
150
+ templates: HashMap::new(),
151
+ get_tmpl_name
152
+ }
153
+ }
154
+
155
+ fn build_xml_element (&mut self, el: &mut JSXElement) -> String {
156
+ let opening_element = &mut el.opening;
157
+ match &opening_element.name {
158
+ JSXElementName::Ident(ident) => {
159
+ let name = utils::to_kebab_case(&ident.sym);
160
+ match self.config.components.get(&name) {
161
+ // 内置组件
162
+ Some(attrs_map) => {
163
+ let attrs = self.build_xml_attrs(opening_element, attrs_map);
164
+ if attrs.is_none() { return String::new() };
165
+ let (children, ..) = self.build_xml_children(&mut el.children, None);
166
+ format!("<{}{}>{}</{}>", name, attrs.unwrap(), children, name)
167
+ },
168
+ None => {
169
+ // React 组件
170
+ // 原生自定义组件
171
+ let node_path = self.get_current_node_path();
172
+ format!(r#"<template is="{{{{xs.a(c, {}.nn, l)}}}}" data="{{{{i:{},c:c+1,l:xs.f(l,{}.nn)}}}}" />"#, node_path, node_path, node_path)
173
+ }
174
+ }
175
+ }
176
+ _ => String::new()
177
+ }
178
+ }
179
+
180
+ fn build_xml_attrs (&self, opening_element: &mut JSXOpeningElement, attrs_map: &HashMap<String, String>) -> Option<String> {
181
+ let mut props = HashMap::new();
182
+ let mut attrs_string = String::new();
183
+
184
+ opening_element.attrs.retain_mut(|attr| {
185
+ if let JSXAttrOrSpread::JSXAttr(jsx_attr) = attr {
186
+ if let JSXAttrName::Ident(Ident { sym: name, .. }) = &jsx_attr.name {
187
+ let jsx_attr_name = name.to_string();
188
+
189
+ if REACT_RESERVED.contains(&jsx_attr_name.as_str()) {
190
+ return true;
191
+ }
192
+
193
+ let miniapp_attr_name = utils::convert_jsx_attr_key(&jsx_attr_name, &self.config.adapter);
194
+ let event_name = utils::identify_jsx_event_key(&jsx_attr_name);
195
+ let is_event = event_name.is_some();
196
+ match &jsx_attr.value {
197
+ Some(jsx_attr_value) => {
198
+ match jsx_attr_value {
199
+ JSXAttrValue::Lit(Lit::Str(Str { value, .. })) => {
200
+ // 静态属性在 xml 中保留即可,jsx 中可以删除
201
+ if jsx_attr_name != COMPILE_MODE {
202
+ props.insert(miniapp_attr_name, value.to_string());
203
+ return false
204
+ }
205
+ },
206
+ JSXAttrValue::JSXExprContainer(..) => {
207
+ let mut node_path = self.get_current_node_path();
208
+ if is_event {
209
+ props.insert(event_name.unwrap(), String::from(EVENT_HANDLER));
210
+ if props.get(DATA_SID).is_none() {
211
+ props.insert(String::from(DATA_SID), format!("{{{{{}.sid}}}}", node_path));
212
+ }
213
+ return true
214
+ }
215
+
216
+ // 小程序组件标准属性 -> 取 @tarojs/shared 传递过来的属性值;非标准属性 -> 取属性名
217
+ let value: &str = attrs_map.get(&miniapp_attr_name).unwrap_or(&jsx_attr_name);
218
+ // 按当前节点在节点树中的位置换算路径
219
+ node_path.push('.');
220
+ let value = if value.contains(TMPL_DATA_ROOT) {
221
+ value.replace(TMPL_DATA_ROOT, &node_path)
222
+ } else {
223
+ format!("{}{}", node_path, value)
224
+ };
225
+ // 得出最终的模板属性值
226
+ let miniapp_attr_value = format!("{{{{{}}}}}", value);
227
+
228
+ props.insert(miniapp_attr_name, miniapp_attr_value);
229
+ },
230
+ _ => ()
231
+ }
232
+ },
233
+ None => {
234
+ if
235
+ jsx_attr_name == COMPILE_ELSE ||
236
+ jsx_attr_name == COMPILE_IGNORE
237
+ {
238
+ props.insert(miniapp_attr_name, String::from(jsx_attr_name));
239
+ } else if jsx_attr_name == COMPILE_FOR {
240
+ let current_path = self.get_current_loop_path();
241
+ let miniapp_attr_value = format!("{{{{{}}}}}", current_path);
242
+ props.insert(miniapp_attr_name, miniapp_attr_value);
243
+ } else {
244
+ props.insert(miniapp_attr_name, String::from("true"));
245
+ }
246
+ // 布尔值在 jsx 中也可以删除了
247
+ return false
248
+ }
249
+ }
250
+ }
251
+ }
252
+ return true
253
+ });
254
+
255
+ // 组件包含事件,但没有设置自定义 id 的话,把 id 设为 sid
256
+ if props.get(DATA_SID).is_some() && props.get(ID).is_none() {
257
+ props.insert(String::from(ID), props.get(DATA_SID).unwrap().clone());
258
+ }
259
+
260
+ // 生成的 template 需要幂等
261
+ let mut keys: Vec<&String> = props.keys().collect();
262
+ keys.sort();
263
+ for key in keys {
264
+ let value = props.get(key).unwrap();
265
+ if value == COMPILE_IGNORE {
266
+ return None
267
+ } else if value == COMPILE_ELSE {
268
+ attrs_string.push_str(&format!(" {}", key));
269
+ } else {
270
+ attrs_string.push_str(&format!(r#" {}="{}""#, key, value));
271
+ }
272
+ }
273
+
274
+ Some(attrs_string)
275
+ }
276
+
277
+ fn build_xml_children (&mut self, children: &mut Vec<JSXElementChild>, retain_start_from: Option<i32>) -> (String, i32) {
278
+ let mut children_string = String::new();
279
+ let start = if retain_start_from.is_some() { retain_start_from.unwrap() } else { 0 };
280
+ let mut retain_child_counter = start;
281
+
282
+ children
283
+ .retain_mut(|child| {
284
+ let mut is_retain = true;
285
+ self.node_stack.push(retain_child_counter);
286
+ match child {
287
+ JSXElementChild::JSXElement(child_el) => {
288
+ let child_string = self.build_xml_element(&mut **child_el);
289
+ children_string.push_str(&child_string);
290
+
291
+ if utils::is_static_jsx(child_el) && utils::is_inner_component(child_el, &self.config) {
292
+ is_retain = false
293
+ } else {
294
+ retain_child_counter += 1;
295
+ }
296
+ },
297
+ JSXElementChild::JSXExprContainer(JSXExprContainer {
298
+ expr: JSXExpr::Expr(jsx_expr),
299
+ ..
300
+ }) => {
301
+ if let Expr::Paren(ParenExpr { expr, .. }) = &mut **jsx_expr {
302
+ *jsx_expr = expr.take();
303
+ }
304
+ let node_path = self.get_current_node_path();
305
+ match &mut **jsx_expr {
306
+ Expr::Cond(CondExpr { cons, alt, ..}) => {
307
+ let mut process_condition_expr = |arm: &mut Box<Expr>| {
308
+ match &mut **arm {
309
+ Expr::JSXElement(el) => {
310
+ let child_string = self.build_xml_element(el);
311
+ children_string.push_str(&child_string);
312
+ },
313
+ Expr::Lit(lit) => {
314
+ if let Lit::Str(Str { value, .. }) = lit {
315
+ if &*value == COMPILE_IGNORE {
316
+ return ();
317
+ }
318
+ }
319
+ // {condition1 && 'Hello'} 在预处理时会变成 {condition1 ? 'Hello' : "compileIgnore"}
320
+ // 而普通文本三元则会被 block 标签包裹,因此处理后只有上述情况会存在 lit 类型的表达式
321
+ // 由于这种情况没有办法使用 wx:if 来处理,需要特殊处理成 {{i.cn[3].v==="compileIgnore"?"":i.cn[3].v}} 的形式
322
+ let str = format!(r#"{{{{{}.v==="{}"?"":{}.v}}}}"#, node_path, COMPILE_IGNORE, node_path);
323
+ children_string.push_str(&str);
324
+ },
325
+ _ => ()
326
+ }
327
+ };
328
+ process_condition_expr(cons);
329
+ process_condition_expr(alt);
330
+ },
331
+ Expr::Call(CallExpr {
332
+ callee: Callee::Expr(callee_expr),
333
+ args,
334
+ ..
335
+ }) => {
336
+ // 处理循环
337
+ if let Some(return_value) = utils::extract_jsx_loop(callee_expr, args) {
338
+ self.node_stack.pop();
339
+ self.node_stack.push(LOOP_WRAPPER_ID);
340
+ let child_string = self.build_xml_element(&mut *return_value);
341
+ children_string.push_str(&child_string);
342
+ } else if utils::is_render_fn(callee_expr) {
343
+ let tmpl = format!(r#"<template is="{{{{xs.a(c, {}.nn, l)}}}}" data="{{{{i:{},c:c+1,l:xs.f(l,{}.nn)}}}}" />"#, node_path, node_path, node_path);
344
+ children_string.push_str(&tmpl)
345
+ } else {
346
+ let code = utils::gen_template_v(&node_path);
347
+ children_string.push_str(&code);
348
+ }
349
+ },
350
+ _ => {
351
+ let code = utils::gen_template_v(&node_path);
352
+ children_string.push_str(&code);
353
+ }
354
+ }
355
+ retain_child_counter = retain_child_counter + 1
356
+ },
357
+ JSXElementChild::JSXText(JSXText { value, .. }) => {
358
+ let content = utils::jsx_text_to_string(value);
359
+ if !content.is_empty() {
360
+ children_string.push_str(&content);
361
+ // JSX 过滤掉静态文本节点,只在模板中保留。同时保留用于换行、空格的静态文本节点
362
+ is_retain = false
363
+ }
364
+ },
365
+ JSXElementChild::JSXFragment(child_el) => {
366
+ self.node_stack.pop();
367
+ let (child_string, inner_retain) = self.build_xml_children(&mut child_el.children, Some(retain_child_counter));
368
+ children_string.push_str(&child_string);
369
+ if inner_retain == 0 {
370
+ // 静态 fragment,在 JSX 中删除
371
+ is_retain = false
372
+ } else {
373
+ retain_child_counter += inner_retain;
374
+ }
375
+ self.node_stack.push(retain_child_counter);
376
+ },
377
+ _ => ()
378
+ }
379
+ self.node_stack.pop();
380
+ return is_retain
381
+ });
382
+
383
+ (children_string, retain_child_counter - start)
384
+ }
385
+
386
+ fn get_current_node_path (&self) -> String {
387
+ // return: i.cn[0].cn[0]....
388
+ self.node_stack
389
+ .iter()
390
+ .fold(String::from("i"), |mut acc, item| {
391
+ if item == &LOOP_WRAPPER_ID {
392
+ return String::from("item")
393
+ }
394
+ acc.push_str(&format!(".cn[{}]", item));
395
+ return acc;
396
+ })
397
+ }
398
+
399
+ fn get_current_loop_path (&self) -> String {
400
+ // return: i.cn[0]...cn
401
+ self.node_stack
402
+ .iter()
403
+ .identify_last()
404
+ .fold(String::from("i"), |mut acc, (is_last, item)| {
405
+ let str = if is_last {
406
+ String::from(".cn")
407
+ } else {
408
+ if item == &LOOP_WRAPPER_ID {
409
+ return String::from("item")
410
+ }
411
+ format!(".cn[{}]", item)
412
+ };
413
+ acc.push_str(&str);
414
+ return acc;
415
+ })
416
+ }
417
+ }
418
+
419
+ impl VisitMut for TransformVisitor {
420
+ // Implement necessary visit_mut_* methods for actual custom transform.
421
+ // A comprehensive list of possible visitor methods can be found here:
422
+ // https://rustdoc.swc.rs/swc_ecma_visit/trait.VisitMut.html
423
+ fn visit_mut_jsx_element (&mut self, el: &mut JSXElement) {
424
+ let mut tmpl_name = String::new();
425
+ for attr in &mut el.opening.attrs {
426
+ if let JSXAttrOrSpread::JSXAttr(jsx_attr) = attr {
427
+ if let JSXAttrName::Ident(jsx_attr_name) = &jsx_attr.name {
428
+ if &*jsx_attr_name.sym == COMPILE_MODE {
429
+ self.is_compile_mode = true;
430
+ tmpl_name = (self.get_tmpl_name)();
431
+ jsx_attr.value = Some(JSXAttrValue::Lit(Lit::Str(Str {
432
+ span,
433
+ value: tmpl_name.clone().into(),
434
+ raw: None,
435
+ })));
436
+ break;
437
+ }
438
+ }
439
+ }
440
+ }
441
+ if self.is_compile_mode {
442
+ el.visit_mut_children_with(&mut PreVisitor::new());
443
+ let tmpl_contents = format!(r#"<template name="tmpl_0_{}">{}</template>"#,
444
+ &tmpl_name,
445
+ self.build_xml_element(el)
446
+ );
447
+ self.templates.insert(tmpl_name, tmpl_contents);
448
+ self.is_compile_mode = false;
449
+ } else {
450
+ el.visit_mut_children_with(self)
451
+ }
452
+ }
453
+
454
+ fn visit_mut_module_items (&mut self, body_stmts: &mut Vec<ModuleItem>) {
455
+ body_stmts.visit_mut_children_with(self);
456
+
457
+ let mut keys: Vec<&String> = self.templates.keys().collect();
458
+ keys.sort();
459
+ let stmts_being_inserted = keys.into_iter()
460
+ .map(|key| {
461
+ let value = self.templates.get(key).unwrap();
462
+ ModuleItem::Stmt(Stmt::Decl(Decl::Var(Box::new(VarDecl {
463
+ span,
464
+ kind: VarDeclKind::Const,
465
+ declare: false,
466
+ decls: vec![VarDeclarator {
467
+ span,
468
+ name: Pat::Ident(Ident::new(format!("TARO_TEMPLATES_{}", key).as_str().into(), span).into()),
469
+ init: Some(Box::new(Expr::Lit(Lit::Str(Str {
470
+ span,
471
+ value: value.as_str().into(),
472
+ raw: None
473
+ })))),
474
+ definite: false,
475
+ }],
476
+ }))))
477
+ });
478
+ ecma::utils::prepend_stmts(body_stmts, stmts_being_inserted);
479
+ }
480
+ }