@tarojs/helper 3.8.0-canary.0 → 4.0.0-beta.0

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 (85) hide show
  1. package/README.md +22 -0
  2. package/dist/constants.d.ts +5 -3
  3. package/dist/constants.js +24 -22
  4. package/dist/constants.js.map +1 -1
  5. package/dist/dotenv.js.map +1 -1
  6. package/dist/esbuild/index.js +6 -4
  7. package/dist/esbuild/index.js.map +1 -1
  8. package/dist/npm.d.ts +2 -2
  9. package/dist/npm.js +6 -6
  10. package/dist/npm.js.map +1 -1
  11. package/dist/swcRegister.d.ts +0 -6
  12. package/dist/swcRegister.js +0 -15
  13. package/dist/swcRegister.js.map +1 -1
  14. package/dist/utils.d.ts +33 -1
  15. package/dist/utils.js +87 -34
  16. package/dist/utils.js.map +1 -1
  17. package/package.json +19 -15
  18. package/swc/plugin-compile-mode/.cargo/config +5 -0
  19. package/swc/plugin-compile-mode/.editorconfig +6 -0
  20. package/swc/plugin-compile-mode/.vscode/settings.json +3 -0
  21. package/swc/plugin-compile-mode/Cargo.lock +195 -260
  22. package/swc/plugin-compile-mode/Cargo.toml +6 -4
  23. package/swc/plugin-compile-mode/package.json +15 -0
  24. package/swc/plugin-compile-mode/src/lib.rs +21 -2
  25. package/swc/plugin-compile-mode/src/tests/attributes.rs +1 -32
  26. package/swc/plugin-compile-mode/src/tests/children.rs +86 -0
  27. package/swc/plugin-compile-mode/src/tests/condition.rs +8 -29
  28. package/swc/plugin-compile-mode/src/tests/entry.rs +1 -13
  29. package/swc/plugin-compile-mode/src/tests/harmony/attributes.rs +45 -0
  30. package/swc/plugin-compile-mode/src/tests/harmony/children.rs +74 -0
  31. package/swc/plugin-compile-mode/src/tests/harmony/condition.rs +79 -0
  32. package/swc/plugin-compile-mode/src/tests/harmony/entry.rs +67 -0
  33. package/swc/plugin-compile-mode/src/tests/harmony/looping.rs +62 -0
  34. package/swc/plugin-compile-mode/src/tests/harmony/mod.rs +45 -0
  35. package/swc/plugin-compile-mode/src/tests/looping.rs +1 -51
  36. package/swc/plugin-compile-mode/src/tests/mod.rs +11 -9
  37. package/swc/plugin-compile-mode/src/tests/shake.rs +1 -15
  38. package/swc/plugin-compile-mode/src/transform.rs +142 -134
  39. package/swc/plugin-compile-mode/src/transform_harmony.rs +526 -0
  40. package/swc/plugin-compile-mode/src/utils/constants.rs +141 -0
  41. package/swc/plugin-compile-mode/src/utils/harmony/components.rs +61 -0
  42. package/swc/plugin-compile-mode/src/utils/harmony/mod.rs +1 -0
  43. package/swc/plugin-compile-mode/src/utils/mod.rs +126 -15
  44. package/swc/plugin-compile-mode/target/wasm32-wasi/release/swc_plugin_compile_mode.wasm +0 -0
  45. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/attributes.rs/should_handle_events.js +8 -0
  46. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/attributes.rs/should_keep_static_attrs_only_in_templates.js +8 -0
  47. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/attributes.rs/should_turn_dynamic_attrs.js +11 -0
  48. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/children.rs/should_render_native_component.js +7 -0
  49. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/children.rs/should_render_react_component.js +7 -0
  50. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/children.rs/should_support_fragment.js +44 -0
  51. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/children.rs/should_support_render_fn.js +8 -0
  52. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/condition.rs/should_support_and_expr.js +14 -0
  53. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/condition.rs/should_support_conditional_expr.js +15 -0
  54. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/entry.rs/should_support_multi_compile_mode.js +10 -0
  55. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/attributes.rs/should_handle_events.js +183 -0
  56. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/attributes.rs/should_turn_dynamic_attrs.js +186 -0
  57. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/children.rs/should_render_react_component.js +76 -0
  58. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/children.rs/should_support_fragment.js +341 -0
  59. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/children.rs/should_support_render_fn.js +186 -0
  60. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/condition.rs/should_support_and_expr.js +211 -0
  61. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/condition.rs/should_support_complex_condition.js +244 -0
  62. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/condition.rs/should_support_conditional_and_unkonw_component.js +139 -0
  63. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/condition.rs/should_support_conditional_expr.js +344 -0
  64. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/entry.rs/should_support_compile_child_node.js +141 -0
  65. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/entry.rs/should_support_component_not_in_config.js +91 -0
  66. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/entry.rs/should_support_multi_compile_mode.js +209 -0
  67. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/entry.rs/should_support_single_compile_mode.js +66 -0
  68. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/looping.rs/should_loop_with_arrow_function_with_blockstmt.js +76 -0
  69. 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 +89 -0
  70. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/looping.rs/should_loop_with_function_expr.js +86 -0
  71. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/looping.rs/should_loop_with_arrow_function_with_blockstmt.js +8 -0
  72. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/looping.rs/should_loop_with_arrow_function_with_expr.js +6 -0
  73. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/looping.rs/should_loop_with_function_expr.js +20 -0
  74. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/looping.rs/should_support_nested_loop.js +15 -0
  75. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/shake.rs/should_static_jsx_being_shaked.js +20 -0
  76. package/swc/plugin-define-config/.cargo/config +5 -0
  77. package/swc/plugin-define-config/Cargo.lock +582 -506
  78. package/swc/plugin-define-config/Cargo.toml +2 -11
  79. package/swc/plugin-define-config/src/lib.rs +81 -128
  80. package/swc/plugin-define-config/target/wasm32-wasi/release/swc_plugin_define_config.wasm +0 -0
  81. package/swc/plugin-define-config/tests/__swc_snapshots__/src/lib.rs/module_decl_default_app.js +2 -0
  82. package/swc/plugin-define-config/tests/__swc_snapshots__/src/lib.rs/module_decl_default_page.js +2 -0
  83. package/swc/plugin-define-config/tests/__swc_snapshots__/src/lib.rs/module_exports.js +11 -0
  84. package/swc/plugin-define-config/tests/__swc_snapshots__/src/lib.rs/var_decl_app.js +3 -0
  85. package/swc/plugin-define-config/tests/__swc_snapshots__/src/lib.rs/var_decl_page.js +3 -0
@@ -0,0 +1,45 @@
1
+ pub use super::get_syntax_config;
2
+ use swc_core::ecma::visit::{as_folder, Fold, VisitMut};
3
+ use crate::{
4
+ PluginConfig,
5
+ transform_harmony::*,
6
+ };
7
+
8
+ mod entry;
9
+ mod attributes;
10
+ mod condition;
11
+ mod looping;
12
+ mod children;
13
+
14
+ pub fn tr () -> impl Fold + VisitMut {
15
+ let config = serde_json::from_str::<PluginConfig>(
16
+ r#"
17
+ {
18
+ "is_harmony": true,
19
+ "tmpl_prefix": "f0",
20
+ "support_events": [
21
+ "onLoad",
22
+ "onClick",
23
+ "onTouchEnd",
24
+ "onTouchMove",
25
+ "onTouchStart",
26
+ "onTouchCancel"
27
+ ],
28
+ "support_components": [
29
+ "view",
30
+ "text",
31
+ "image"
32
+ ],
33
+ "event_adapter": {
34
+ "onTouchEnd": "onTouch",
35
+ "onTouchMove": "onTouch",
36
+ "onTouchStart": "onTouch",
37
+ "onTouchCancel": "onTouch",
38
+ "onLoad": "onComplete"
39
+ }
40
+ }"#
41
+ )
42
+ .unwrap();
43
+ let visitor = TransformVisitor::new(config);
44
+ as_folder(visitor)
45
+ }
@@ -22,21 +22,6 @@ test!(
22
22
  </View>
23
23
  )
24
24
  }
25
- "#,
26
- r#"
27
- const TARO_TEMPLATES_f0t0 = '<template name="tmpl_0_f0t0"><view><view hover-class="{{xs.b(item.p1,\'none\')}}" wx:for="{{i.cn}}" wx:key="sid"><text>index:</text><text>{{item.cn[0].cn[0].v}}</text><text>item:</text><text>{{item.cn[1].cn[0].v}}</text></view></view></template>';
28
- function Index () {
29
- return <View compileMode="f0t0">
30
- {list.map(function(item, index) {
31
- return <View hoverClass={myClass}>
32
-
33
- <Text>{index}</Text>
34
-
35
- <Text>{item}</Text>
36
- </View>
37
- })}
38
- </View>
39
- }
40
25
  "#
41
26
  );
42
27
 
@@ -54,16 +39,6 @@ test!(
54
39
  </View>
55
40
  )
56
41
  }
57
- "#,
58
- r#"
59
- const TARO_TEMPLATES_f0t0 = '<template name="tmpl_0_f0t0"><view><view wx:for="{{i.cn}}" wx:key="sid">{{item.cn[0].v}}</view></view></template>';
60
- function Index () {
61
- return <View compileMode="f0t0">
62
- {list.map(item => {
63
- return <View>{item}</View>
64
- })}
65
- </View>
66
- }
67
42
  "#
68
43
  );
69
44
 
@@ -79,14 +54,6 @@ test!(
79
54
  </View>
80
55
  )
81
56
  }
82
- "#,
83
- r#"
84
- const TARO_TEMPLATES_f0t0 = '<template name="tmpl_0_f0t0"><view><view wx:for="{{i.cn}}" wx:key="sid">{{item.cn[0].v}}</view></view></template>';
85
- function Index () {
86
- return <View compileMode="f0t0">
87
- {list.map(item => <View>{item}</View>)}
88
- </View>
89
- }
90
57
  "#
91
58
  );
92
59
 
@@ -113,22 +80,5 @@ test!(
113
80
  </View>
114
81
  )
115
82
  }
116
- "#,
117
- r#"
118
- const TARO_TEMPLATES_f0t0 = '<template name="tmpl_0_f0t0"><view><view hover-class="{{xs.b(item.p1,\'none\')}}" wx:for="{{i.cn}}" wx:key="sid"><view>title: {{item.cn[0].cn[0].v}}</view><view><text selectable="{{xs.b(item.p1,!1)}}" wx:for="{{item.cn[1].cn}}" wx:key="sid">content: {{item.cn[0].v}}</text></view></view></view></template>';
119
- function Index () {
120
- return <View compileMode="f0t0">
121
- {list.map(function(item, index) {
122
- return <View hoverClass={myClass} key={index}>
123
- <View>{item}</View>
124
- <View>
125
- {sublist.map(function(c) {
126
- return <Text selectable={isSelectable}>{c}</Text>
127
- })}
128
- </View>
129
- </View>
130
- })}
131
- </View>
132
- }
133
83
  "#
134
- );
84
+ );
@@ -1,19 +1,21 @@
1
- mod entry;
2
- mod attributes;
3
- mod shake;
4
- mod condition;
5
- mod looping;
6
-
7
1
  use swc_core::ecma::{
8
2
  parser,
9
- visit::{as_folder, Fold, VisitMut},
3
+ visit::{as_folder, Fold},
10
4
  };
11
5
  use crate::{
12
6
  PluginConfig,
13
7
  transform::*,
14
8
  };
15
9
 
16
- pub fn tr () -> impl Fold + VisitMut {
10
+ mod entry;
11
+ mod attributes;
12
+ mod shake;
13
+ mod condition;
14
+ mod looping;
15
+ mod children;
16
+ mod harmony;
17
+
18
+ pub fn tr () -> impl Fold {
17
19
  let config = serde_json::from_str::<PluginConfig>(
18
20
  r#"
19
21
  {
@@ -95,4 +97,4 @@ pub fn get_syntax_config () -> parser::Syntax {
95
97
  jsx: true,
96
98
  ..Default::default()
97
99
  })
98
- }
100
+ }
@@ -23,19 +23,5 @@ test!(
23
23
  </View>
24
24
  )
25
25
  }
26
- "#,
27
- r#"
28
- const TARO_TEMPLATES_f0t0 = '<template name="tmpl_0_f0t0"><view><text>Hello World!</text><text>Hello{{i.cn[0].cn[0].v}}World{{i.cn[0].cn[1].v}}!</text><view><text></text></view><view hover-stop-propagation="true" style="color: red"><text>Hello World!</text></view><view style="{{i.cn[1].st}}"><text>Hello World!</text></view></view></template>';
29
- function Index () {
30
- return <View compileMode="f0t0">
31
-
32
- <Text>{T1}{T2}</Text>
33
-
34
-
35
- <View style={myStyle}>
36
-
37
- </View>
38
- </View>
39
- }
40
26
  "#
41
- );
27
+ );
@@ -3,124 +3,131 @@ use swc_core::{
3
3
  common::{
4
4
  iter::IdentifyLast,
5
5
  util::take::Take,
6
- DUMMY_SP as span
6
+ DUMMY_SP as span,
7
7
  },
8
8
  ecma::{
9
9
  self,
10
10
  ast::*,
11
- atoms::Atom,
12
11
  visit::{VisitMut, VisitMutWith},
12
+ utils::{quote_ident, quote_str},
13
13
  },
14
+ atoms::Atom,
14
15
  };
15
16
  use std::collections::HashMap;
16
- use std::rc::Rc;
17
17
  use crate::PluginConfig;
18
18
  use crate::utils::{self, constants::*};
19
19
 
20
20
  struct PreVisitor {
21
- is_in_jsx_expr_container: Rc<bool>,
22
21
  is_in_and_expr: bool,
23
22
  }
24
23
  impl PreVisitor {
25
24
  fn new () -> Self {
26
25
  Self {
27
- is_in_jsx_expr_container: Rc::new(true),
28
26
  is_in_and_expr: false
29
27
  }
30
28
  }
31
29
  }
32
30
  impl VisitMut for PreVisitor {
33
- fn visit_mut_jsx_expr_container (&mut self, container: &mut JSXExprContainer) {
34
- let _counter = Rc::clone(&self.is_in_jsx_expr_container);
35
- // TODO 目前的判断可能误伤函数内的三元表达式、条件表达式
36
- container.visit_mut_children_with(self);
37
- }
38
- fn visit_mut_expr (&mut self, expr: &mut Expr) {
39
- if Rc::strong_count(&self.is_in_jsx_expr_container) == 1 { return };
40
- let mut is_first_and_expr = false;
41
-
42
- match expr {
43
- Expr::Bin(BinExpr { op, left, right, ..}) => {
44
- // C&&A 替换为 C?A:A',原因是为了无论显示还是隐藏都保留一个元素,从而不影响兄弟节点的变量路径
45
- if *op == op!("&&") && !self.is_in_and_expr {
46
- is_first_and_expr = true;
47
- fn inject_compile_if (el: &mut Box<JSXElement>, condition: &mut Box<Expr>) -> () {
48
- el.opening.attrs.push(utils::create_jsx_expr_attr(COMPILE_IF, condition.clone()));
49
- }
50
- fn get_element_double (element_name: JSXElementName, condition: &mut Box<Expr>, right: &mut Box<Expr>) -> Expr {
51
- Expr::Cond(CondExpr {
52
- span,
53
- test: condition.take(),
54
- cons: right.take(),
55
- alt: Box::new(utils::create_self_closing_jsx_element_expr(
56
- element_name, // element 替换为同类型的元素。在显示/隐藏切换时,让运行时 diff 只更新必要属性而不是整个节点刷新
57
- Some(vec![utils::create_jsx_bool_attr(COMPILE_IGNORE)]
58
- )))
59
- })
60
- }
61
- match &mut **right {
62
- Expr::JSXElement(el) => {
63
- let element_name = el.opening.name.clone();
64
- inject_compile_if(el, left);
65
- *expr = get_element_double(element_name, left, right);
66
- },
67
- Expr::Paren(ParenExpr { expr: paren_expr, .. }) => {
68
- if paren_expr.is_jsx_element() {
69
- let el: &mut Box<JSXElement> = paren_expr.as_mut_jsx_element().unwrap();
70
- let element_name = el.opening.name.clone();
71
- inject_compile_if(el, left);
72
- *expr = get_element_double(element_name, left, paren_expr);
73
- }
74
- },
75
- Expr::Lit(_) => {
76
- *expr = Expr::Cond(CondExpr {
31
+ fn visit_mut_jsx_element_child (&mut self, child: &mut JSXElementChild) {
32
+ if let JSXElementChild::JSXExprContainer(JSXExprContainer { expr: JSXExpr::Expr(expr), .. }) = child {
33
+ let mut is_first_and_expr = false;
34
+
35
+ if let Expr::Paren(ParenExpr { expr: e, .. }) = &mut **expr {
36
+ *expr = e.take();
37
+ }
38
+
39
+ match &mut **expr {
40
+ Expr::Bin(BinExpr { op, left, right, ..}) => {
41
+ // C&&A 替换为 C?A:A',原因是为了无论显示还是隐藏都保留一个元素,从而不影响兄弟节点的变量路径
42
+ if *op == op!("&&") && !self.is_in_and_expr {
43
+ is_first_and_expr = true;
44
+ fn inject_compile_if (el: &mut Box<JSXElement>, condition: &mut Box<Expr>) -> () {
45
+ el.opening.attrs.push(utils::create_jsx_expr_attr(COMPILE_IF, condition.clone()));
46
+ }
47
+ fn get_element_double (element_name: JSXElementName, condition: &mut Box<Expr>, right: &mut Box<Expr>) -> Expr {
48
+ Expr::Cond(CondExpr {
77
49
  span,
78
- test: left.take(),
50
+ test: condition.take(),
79
51
  cons: right.take(),
80
- alt: Box::new(Expr::Lit(Lit::Str(Str { span, value: COMPILE_IGNORE.into(), raw: None })))
52
+ alt: Box::new(utils::create_self_closing_jsx_element_expr(
53
+ element_name, // element 替换为同类型的元素。在显示/隐藏切换时,让运行时 diff 只更新必要属性而不是整个节点刷新
54
+ Some(vec![utils::create_jsx_bool_attr(COMPILE_IGNORE)]
55
+ )))
81
56
  })
82
- },
83
- _ => {
84
- // TODO Unknown fallback to template
85
- println!("unknown expr: {right:?}");
86
57
  }
87
- }
88
- }
89
- },
90
- Expr::Cond(CondExpr { test, cons, alt, ..}) => {
91
- let compile_if = utils::create_jsx_expr_attr(COMPILE_IF, test.clone());
92
- let compile_else = utils::create_jsx_bool_attr(COMPILE_ELSE);
93
- let process_cond_arm = |arm: &mut Box<Expr>, attr: JSXAttrOrSpread| {
94
- match &mut **arm {
95
- Expr::JSXElement(el) => {
96
- el.opening.attrs.push(attr);
97
- },
98
- _ => {
99
- let temp = arm.take();
100
- let jsx_el_name = JSXElementName::Ident(Ident { span, sym: "block".into(), optional: false });
101
- **arm = Expr::JSXElement(Box::new(JSXElement {
102
- span,
103
- opening: JSXOpeningElement { name: jsx_el_name.clone(), span, attrs: vec![attr], self_closing: false, type_args: None },
104
- children: vec![JSXElementChild::JSXExprContainer(JSXExprContainer { span, expr: JSXExpr::Expr(temp)})],
105
- closing: Some(JSXClosingElement { span, name: jsx_el_name })
106
- }))
58
+ match &mut **right {
59
+ Expr::JSXElement(el) => {
60
+ let element_name = el.opening.name.clone();
61
+ inject_compile_if(el, left);
62
+ **expr = get_element_double(element_name, left, right);
63
+ },
64
+ Expr::Paren(ParenExpr { expr: paren_expr, .. }) => {
65
+ if paren_expr.is_jsx_element() {
66
+ let el: &mut Box<JSXElement> = paren_expr.as_mut_jsx_element().unwrap();
67
+ let element_name = el.opening.name.clone();
68
+ inject_compile_if(el, left);
69
+ **expr = get_element_double(element_name, left, paren_expr);
70
+ }
71
+ },
72
+ Expr::Lit(_) => {
73
+ **expr = Expr::Cond(CondExpr {
74
+ span,
75
+ test: left.take(),
76
+ cons: right.take(),
77
+ alt: Box::new(Expr::Lit(Lit::Str(quote_str!(COMPILE_IGNORE))))
78
+ })
79
+ },
80
+ _ => {
81
+ let jsx_el_name = JSXElementName::Ident(quote_ident!("block"));
82
+ let mut block = Box::new(JSXElement {
83
+ span,
84
+ opening: JSXOpeningElement { name: jsx_el_name.clone(), span, attrs: vec![], self_closing: false, type_args: None },
85
+ children: vec![JSXElementChild::JSXExprContainer(JSXExprContainer { span, expr: JSXExpr::Expr(right.take()) })],
86
+ closing: Some(JSXClosingElement { span, name: jsx_el_name.clone() })
87
+ });
88
+ inject_compile_if(&mut block, left);
89
+ **expr = get_element_double(jsx_el_name, left, &mut Box::new(Expr::JSXElement(block)));
90
+ }
107
91
  }
108
92
  }
109
- };
110
- process_cond_arm(cons, compile_if);
111
- process_cond_arm(alt, compile_else);
112
- },
113
- _ => (),
114
- }
93
+ },
94
+ Expr::Cond(CondExpr { test, cons, alt, ..}) => {
95
+ let compile_if = utils::create_jsx_expr_attr(COMPILE_IF, test.clone());
96
+ let compile_else = utils::create_jsx_bool_attr(COMPILE_ELSE);
97
+ let process_cond_arm = |arm: &mut Box<Expr>, attr: JSXAttrOrSpread| {
98
+ match &mut **arm {
99
+ Expr::JSXElement(el) => {
100
+ el.opening.attrs.push(attr);
101
+ },
102
+ _ => {
103
+ let temp = arm.take();
104
+ let jsx_el_name = JSXElementName::Ident(quote_ident!("block"));
105
+ **arm = Expr::JSXElement(Box::new(JSXElement {
106
+ span,
107
+ opening: JSXOpeningElement { name: jsx_el_name.clone(), span, attrs: vec![attr], self_closing: false, type_args: None },
108
+ children: vec![JSXElementChild::JSXExprContainer(JSXExprContainer { span, expr: JSXExpr::Expr(temp)})],
109
+ closing: Some(JSXClosingElement { span, name: jsx_el_name })
110
+ }))
111
+ }
112
+ }
113
+ };
114
+ process_cond_arm(cons, compile_if);
115
+ process_cond_arm(alt, compile_else);
116
+ },
117
+ _ => (),
118
+ }
115
119
 
116
- if is_first_and_expr {
117
- self.is_in_and_expr = true;
118
- }
120
+ if is_first_and_expr {
121
+ self.is_in_and_expr = true;
122
+ }
119
123
 
120
- expr.visit_mut_children_with(self);
124
+ expr.visit_mut_children_with(self);
121
125
 
122
- if is_first_and_expr {
123
- self.is_in_and_expr = false;
126
+ if is_first_and_expr {
127
+ self.is_in_and_expr = false;
128
+ }
129
+ } else {
130
+ child.visit_mut_children_with(self);
124
131
  }
125
132
  }
126
133
  }
@@ -151,13 +158,13 @@ impl TransformVisitor {
151
158
  let opening_element = &mut el.opening;
152
159
  match &opening_element.name {
153
160
  JSXElementName::Ident(ident) => {
154
- let name = utils::to_kebab_case(&ident.sym);
161
+ let name = utils::to_kebab_case(ident.as_ref());
155
162
  match self.config.components.get(&name) {
156
163
  // 内置组件
157
164
  Some(attrs_map) => {
158
165
  let attrs = self.build_xml_attrs(opening_element, attrs_map);
159
166
  if attrs.is_none() { return String::new() };
160
- let children = self.build_xml_children(el);
167
+ let (children, ..) = self.build_xml_children(&mut el.children, None);
161
168
  format!("<{}{}>{}</{}>", name, attrs.unwrap(), children, name)
162
169
  },
163
170
  None => {
@@ -180,8 +187,8 @@ impl TransformVisitor {
180
187
  if let JSXAttrOrSpread::JSXAttr(jsx_attr) = attr {
181
188
  if let JSXAttrName::Ident(Ident { sym: name, .. }) = &jsx_attr.name {
182
189
  let jsx_attr_name = name.to_string();
183
-
184
- if jsx_attr_name == "key" {
190
+
191
+ if REACT_RESERVED.contains(&jsx_attr_name.as_str()) {
185
192
  return true;
186
193
  }
187
194
 
@@ -269,25 +276,24 @@ impl TransformVisitor {
269
276
  Some(attrs_string)
270
277
  }
271
278
 
272
- fn build_xml_children (&mut self, el: &mut JSXElement) -> String {
279
+ fn build_xml_children (&mut self, children: &mut Vec<JSXElementChild>, retain_start_from: Option<i32>) -> (String, i32) {
273
280
  let mut children_string = String::new();
274
- let mut retain_child_counter = 0;
281
+ let start = if retain_start_from.is_some() { retain_start_from.unwrap() } else { 0 };
282
+ let mut retain_child_counter = start;
275
283
 
276
- el.children
277
- .iter_mut()
278
- .for_each(|child| {
284
+ children
285
+ .retain_mut(|child| {
286
+ let mut is_retain = true;
279
287
  self.node_stack.push(retain_child_counter);
280
288
  match child {
281
289
  JSXElementChild::JSXElement(child_el) => {
282
290
  let child_string = self.build_xml_element(&mut **child_el);
283
291
  children_string.push_str(&child_string);
284
292
 
285
- let is_pure = utils::is_static_jsx(child_el);
286
- if is_pure {
287
- let raw: Atom = "To be removed".into();
288
- *child = JSXElementChild::JSXText(JSXText { span, value: raw.clone(), raw });
293
+ if utils::is_static_jsx(child_el) && utils::is_inner_component(child_el, &self.config) {
294
+ is_retain = false
289
295
  } else {
290
- retain_child_counter = retain_child_counter + 1;
296
+ retain_child_counter += 1;
291
297
  }
292
298
  },
293
299
  JSXElementChild::JSXExprContainer(JSXExprContainer {
@@ -297,6 +303,7 @@ impl TransformVisitor {
297
303
  if let Expr::Paren(ParenExpr { expr, .. }) = &mut **jsx_expr {
298
304
  *jsx_expr = expr.take();
299
305
  }
306
+ let node_path = self.get_current_node_path();
300
307
  match &mut **jsx_expr {
301
308
  Expr::Cond(CondExpr { cons, alt, ..}) => {
302
309
  let mut process_condition_expr = |arm: &mut Box<Expr>| {
@@ -307,12 +314,14 @@ impl TransformVisitor {
307
314
  },
308
315
  Expr::Lit(lit) => {
309
316
  if let Lit::Str(Str { value, .. }) = lit {
310
- if &*value == COMPILE_IGNORE {
317
+ if value == COMPILE_IGNORE {
311
318
  return ();
312
319
  }
313
320
  }
314
- let current_path = self.get_current_node_path();
315
- let str = format!(r#"{{{{{}.v==="{}"?"":{}.v}}}}"#, current_path, COMPILE_IGNORE, current_path);
321
+ // {condition1 && 'Hello'} 在预处理时会变成 {condition1 ? 'Hello' : "compileIgnore"}
322
+ // 而普通文本三元则会被 block 标签包裹,因此处理后只有上述情况会存在 lit 类型的表达式
323
+ // 由于这种情况没有办法使用 wx:if 来处理,需要特殊处理成 {{i.cn[3].v==="compileIgnore"?"":i.cn[3].v}} 的形式
324
+ let str = format!(r#"{{{{{}.v==="{}"?"":{}.v}}}}"#, node_path, COMPILE_IGNORE, node_path);
316
325
  children_string.push_str(&str);
317
326
  },
318
327
  _ => ()
@@ -332,41 +341,48 @@ impl TransformVisitor {
332
341
  self.node_stack.push(LOOP_WRAPPER_ID);
333
342
  let child_string = self.build_xml_element(&mut *return_value);
334
343
  children_string.push_str(&child_string);
344
+ } else if utils::is_render_fn(callee_expr) {
345
+ 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);
346
+ children_string.push_str(&tmpl)
347
+ } else {
348
+ let code = utils::gen_template_v(&node_path);
349
+ children_string.push_str(&code);
335
350
  }
336
351
  },
337
- // TODO 只支持 render 开头的函数调用返回 JSX
338
- // Expr::Call(_)
339
352
  _ => {
340
- // println!("_ expr: {:?} ", jsx_expr);
341
- let node_path = self.get_current_node_path();
342
- let code = format!("{{{{{}.v}}}}", node_path);
353
+ let code = utils::gen_template_v(&node_path);
343
354
  children_string.push_str(&code);
344
355
  }
345
356
  }
346
357
  retain_child_counter = retain_child_counter + 1
347
358
  },
348
- JSXElementChild::JSXText(jsx_text) => {
349
- let content = utils::jsx_text_to_string(&jsx_text.value);
359
+ JSXElementChild::JSXText(JSXText { value, .. }) => {
360
+ let content = utils::jsx_text_to_string(value);
350
361
  if !content.is_empty() {
351
362
  children_string.push_str(&content);
363
+ // JSX 过滤掉静态文本节点,只在模板中保留。同时保留用于换行、空格的静态文本节点
364
+ is_retain = false
365
+ }
366
+ },
367
+ JSXElementChild::JSXFragment(child_el) => {
368
+ self.node_stack.pop();
369
+ let (child_string, inner_retain) = self.build_xml_children(&mut child_el.children, Some(retain_child_counter));
370
+ children_string.push_str(&child_string);
371
+ if inner_retain == 0 {
372
+ // 静态 fragment,在 JSX 中删除
373
+ is_retain = false
374
+ } else {
375
+ retain_child_counter += inner_retain;
352
376
  }
377
+ self.node_stack.push(retain_child_counter);
353
378
  },
354
379
  _ => ()
355
380
  }
356
381
  self.node_stack.pop();
382
+ return is_retain
357
383
  });
358
384
 
359
- el.children.retain_mut(|item| {
360
- // JSX 过滤掉静态文本节点,只在模板中保留
361
- match item {
362
- JSXElementChild::JSXText(jsx_text) => {
363
- utils::is_empty_jsx_text_line(&jsx_text.value)
364
- },
365
- _ => true
366
- }
367
- });
368
-
369
- children_string
385
+ (children_string, retain_child_counter - start)
370
386
  }
371
387
 
372
388
  fn get_current_node_path (&self) -> String {
@@ -411,14 +427,10 @@ impl VisitMut for TransformVisitor {
411
427
  for attr in &mut el.opening.attrs {
412
428
  if let JSXAttrOrSpread::JSXAttr(jsx_attr) = attr {
413
429
  if let JSXAttrName::Ident(jsx_attr_name) = &jsx_attr.name {
414
- if &*jsx_attr_name.sym == COMPILE_MODE {
430
+ if jsx_attr_name.sym == COMPILE_MODE {
415
431
  self.is_compile_mode = true;
416
432
  tmpl_name = (self.get_tmpl_name)();
417
- jsx_attr.value = Some(JSXAttrValue::Lit(Lit::Str(Str {
418
- span,
419
- value: tmpl_name.clone().into(),
420
- raw: None,
421
- })));
433
+ jsx_attr.value = Some(JSXAttrValue::Lit(Lit::Str(quote_str!(tmpl_name.as_str()))));
422
434
  break;
423
435
  }
424
436
  }
@@ -451,12 +463,8 @@ impl VisitMut for TransformVisitor {
451
463
  declare: false,
452
464
  decls: vec![VarDeclarator {
453
465
  span,
454
- name: Pat::Ident(Ident::new(format!("TARO_TEMPLATES_{}", key).as_str().into(), span).into()),
455
- init: Some(Box::new(Expr::Lit(Lit::Str(Str {
456
- span,
457
- value: value.as_str().into(),
458
- raw: None
459
- })))),
466
+ name: Pat::Ident(Ident::new(Atom::new(format!("TARO_TEMPLATES_{}", key)), span).into()),
467
+ init: Some(Box::new(Expr::Lit(Lit::Str(quote_str!(value.as_str()))))),
460
468
  definite: false,
461
469
  }],
462
470
  }))))