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

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 (76) hide show
  1. package/dist/esbuild/index.js +2 -2
  2. package/dist/esbuild/index.js.map +1 -1
  3. package/dist/utils.js +3 -6
  4. package/dist/utils.js.map +1 -1
  5. package/package.json +4 -3
  6. package/swc/.gitkeep +0 -0
  7. package/swc/swc_plugin_compile_mode.wasm +0 -0
  8. package/swc/swc_plugin_define_config.wasm +0 -0
  9. package/swc/plugin-compile-mode/.cargo/config +0 -5
  10. package/swc/plugin-compile-mode/.editorconfig +0 -6
  11. package/swc/plugin-compile-mode/.vscode/settings.json +0 -3
  12. package/swc/plugin-compile-mode/Cargo.lock +0 -2021
  13. package/swc/plugin-compile-mode/Cargo.toml +0 -22
  14. package/swc/plugin-compile-mode/package.json +0 -15
  15. package/swc/plugin-compile-mode/src/lib.rs +0 -71
  16. package/swc/plugin-compile-mode/src/tests/attributes.rs +0 -54
  17. package/swc/plugin-compile-mode/src/tests/children.rs +0 -86
  18. package/swc/plugin-compile-mode/src/tests/condition.rs +0 -50
  19. package/swc/plugin-compile-mode/src/tests/entry.rs +0 -20
  20. package/swc/plugin-compile-mode/src/tests/harmony/attributes.rs +0 -45
  21. package/swc/plugin-compile-mode/src/tests/harmony/children.rs +0 -74
  22. package/swc/plugin-compile-mode/src/tests/harmony/condition.rs +0 -79
  23. package/swc/plugin-compile-mode/src/tests/harmony/entry.rs +0 -67
  24. package/swc/plugin-compile-mode/src/tests/harmony/looping.rs +0 -62
  25. package/swc/plugin-compile-mode/src/tests/harmony/mod.rs +0 -45
  26. package/swc/plugin-compile-mode/src/tests/looping.rs +0 -84
  27. package/swc/plugin-compile-mode/src/tests/mod.rs +0 -100
  28. package/swc/plugin-compile-mode/src/tests/shake.rs +0 -27
  29. package/swc/plugin-compile-mode/src/transform.rs +0 -474
  30. package/swc/plugin-compile-mode/src/transform_harmony.rs +0 -526
  31. package/swc/plugin-compile-mode/src/utils/constants.rs +0 -152
  32. package/swc/plugin-compile-mode/src/utils/harmony/components.rs +0 -61
  33. package/swc/plugin-compile-mode/src/utils/harmony/mod.rs +0 -1
  34. package/swc/plugin-compile-mode/src/utils/mod.rs +0 -347
  35. package/swc/plugin-compile-mode/target/wasm32-wasi/release/swc_plugin_compile_mode.wasm +0 -0
  36. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/attributes.rs/should_handle_events.js +0 -8
  37. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/attributes.rs/should_keep_static_attrs_only_in_templates.js +0 -8
  38. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/attributes.rs/should_turn_dynamic_attrs.js +0 -11
  39. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/children.rs/should_render_native_component.js +0 -7
  40. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/children.rs/should_render_react_component.js +0 -7
  41. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/children.rs/should_support_fragment.js +0 -44
  42. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/children.rs/should_support_render_fn.js +0 -8
  43. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/condition.rs/should_support_and_expr.js +0 -14
  44. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/condition.rs/should_support_conditional_expr.js +0 -15
  45. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/entry.rs/should_support_multi_compile_mode.js +0 -10
  46. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/attributes.rs/should_handle_events.js +0 -183
  47. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/attributes.rs/should_turn_dynamic_attrs.js +0 -186
  48. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/children.rs/should_render_react_component.js +0 -76
  49. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/children.rs/should_support_fragment.js +0 -341
  50. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/children.rs/should_support_render_fn.js +0 -186
  51. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/condition.rs/should_support_and_expr.js +0 -211
  52. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/condition.rs/should_support_complex_condition.js +0 -244
  53. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/condition.rs/should_support_conditional_and_unkonw_component.js +0 -139
  54. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/condition.rs/should_support_conditional_expr.js +0 -344
  55. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/entry.rs/should_support_compile_child_node.js +0 -141
  56. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/entry.rs/should_support_component_not_in_config.js +0 -91
  57. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/entry.rs/should_support_multi_compile_mode.js +0 -209
  58. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/entry.rs/should_support_single_compile_mode.js +0 -66
  59. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/looping.rs/should_loop_with_arrow_function_with_blockstmt.js +0 -76
  60. 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 +0 -89
  61. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/harmony/looping.rs/should_loop_with_function_expr.js +0 -86
  62. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/looping.rs/should_loop_with_arrow_function_with_blockstmt.js +0 -8
  63. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/looping.rs/should_loop_with_arrow_function_with_expr.js +0 -6
  64. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/looping.rs/should_loop_with_function_expr.js +0 -20
  65. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/looping.rs/should_support_nested_loop.js +0 -15
  66. package/swc/plugin-compile-mode/tests/__swc_snapshots__/src/tests/shake.rs/should_static_jsx_being_shaked.js +0 -20
  67. package/swc/plugin-define-config/.cargo/config +0 -5
  68. package/swc/plugin-define-config/Cargo.lock +0 -2110
  69. package/swc/plugin-define-config/Cargo.toml +0 -18
  70. package/swc/plugin-define-config/src/lib.rs +0 -141
  71. package/swc/plugin-define-config/target/wasm32-wasi/release/swc_plugin_define_config.wasm +0 -0
  72. package/swc/plugin-define-config/tests/__swc_snapshots__/src/lib.rs/module_decl_default_app.js +0 -2
  73. package/swc/plugin-define-config/tests/__swc_snapshots__/src/lib.rs/module_decl_default_page.js +0 -2
  74. package/swc/plugin-define-config/tests/__swc_snapshots__/src/lib.rs/module_exports.js +0 -11
  75. package/swc/plugin-define-config/tests/__swc_snapshots__/src/lib.rs/var_decl_app.js +0 -3
  76. package/swc/plugin-define-config/tests/__swc_snapshots__/src/lib.rs/var_decl_page.js +0 -3
@@ -1,84 +0,0 @@
1
- use swc_core::ecma::transforms::testing::test;
2
- use super::{tr, get_syntax_config};
3
-
4
- test!(
5
- get_syntax_config(),
6
- |_| tr(),
7
- should_loop_with_function_expr,
8
- r#"
9
- function Index () {
10
- return (
11
- <View compileMode>
12
- {list.map(function(item, index) {
13
- return (
14
- <View hoverClass={myClass}>
15
- <Text>index:</Text>
16
- <Text>{index}</Text>
17
- <Text>item:</Text>
18
- <Text>{item}</Text>
19
- </View>
20
- )
21
- })}
22
- </View>
23
- )
24
- }
25
- "#
26
- );
27
-
28
- test!(
29
- get_syntax_config(),
30
- |_| tr(),
31
- should_loop_with_arrow_function_with_blockstmt,
32
- r#"
33
- function Index () {
34
- return (
35
- <View compileMode>
36
- {list.map(item => {
37
- return <View>{item}</View>
38
- })}
39
- </View>
40
- )
41
- }
42
- "#
43
- );
44
-
45
- test!(
46
- get_syntax_config(),
47
- |_| tr(),
48
- should_loop_with_arrow_function_with_expr,
49
- r#"
50
- function Index () {
51
- return (
52
- <View compileMode>
53
- {list.map(item => <View>{item}</View>)}
54
- </View>
55
- )
56
- }
57
- "#
58
- );
59
-
60
- test!(
61
- get_syntax_config(),
62
- |_| tr(),
63
- should_support_nested_loop,
64
- r#"
65
- function Index () {
66
- return (
67
- <View compileMode>
68
- {list.map(function(item, index) {
69
- return (
70
- <View hoverClass={myClass} key={index}>
71
- <View>title: {item}</View>
72
- <View>
73
- {sublist.map(function(c) {
74
- return <Text selectable={isSelectable}>content: {c}</Text>
75
- })}
76
- </View>
77
- </View>
78
- )
79
- })}
80
- </View>
81
- )
82
- }
83
- "#
84
- );
@@ -1,100 +0,0 @@
1
- use swc_core::ecma::{
2
- parser,
3
- visit::{as_folder, Fold},
4
- };
5
- use crate::{
6
- PluginConfig,
7
- transform::*,
8
- };
9
-
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 {
19
- let config = serde_json::from_str::<PluginConfig>(
20
- r#"
21
- {
22
- "tmpl_prefix": "f0",
23
- "components": {
24
- "block": {},
25
- "image": {
26
- "src": "i.p3",
27
- "mode": "xs.b(i.p1,'scaleToFill')",
28
- "lazy-load": "xs.b(i.p0,!1)",
29
- "binderror": "eh",
30
- "bindload": "eh",
31
- "bindtouchstart": "eh",
32
- "bindtouchmove": "eh",
33
- "bindtouchend": "eh",
34
- "bindtouchcancel": "eh",
35
- "bindlongpress": "eh",
36
- "webp": "xs.b(i.p4,false)",
37
- "show-menu-by-longpress": "xs.b(i.p2,false)",
38
- "style": "i.st",
39
- "class": "i.cl",
40
- "bindtap": "eh"
41
- },
42
- "view": {
43
- "hover-class": "xs.b(i.p1,'none')",
44
- "hover-stop-propagation": "xs.b(i.p4,!1)",
45
- "hover-start-time": "xs.b(i.p2,50)",
46
- "hover-stay-time": "xs.b(i.p3,400)",
47
- "bindtouchstart": "eh",
48
- "bindtouchmove": "eh",
49
- "bindtouchend": "eh",
50
- "bindtouchcancel": "eh",
51
- "bindlongpress": "eh",
52
- "animation": "i.p0",
53
- "bindanimationstart": "eh",
54
- "bindanimationiteration": "eh",
55
- "bindanimationend": "eh",
56
- "bindtransitionend": "eh",
57
- "style": "i.st",
58
- "class": "i.cl",
59
- "bindtap": "eh"
60
- },
61
- "text": {
62
- "selectable": "xs.b(i.p1,!1)",
63
- "space": "i.p2",
64
- "decode": "xs.b(i.p0,!1)",
65
- "user-select": "xs.b(i.p3,false)",
66
- "style": "i.st",
67
- "class": "i.cl",
68
- "bindtap": "eh"
69
- },
70
- "movable-area": {
71
- "scale-area": "xs.b(i.p0,!1)",
72
- "style": "i.st",
73
- "class": "i.cl",
74
- "bindtap": "eh"
75
- }
76
- },
77
- "adapter": {
78
- "if": "wx:if",
79
- "else": "wx:else",
80
- "elseif": "wx:elif",
81
- "for": "wx:for",
82
- "forItem": "wx:for-item",
83
- "forIndex": "wx:for-index",
84
- "key": "wx:key",
85
- "xs": "wxs",
86
- "type": "weapp"
87
- }
88
- }"#
89
- )
90
- .unwrap();
91
- let visitor = TransformVisitor::new(config);
92
- as_folder(visitor)
93
- }
94
-
95
- pub fn get_syntax_config () -> parser::Syntax {
96
- parser::Syntax::Es(parser::EsConfig {
97
- jsx: true,
98
- ..Default::default()
99
- })
100
- }
@@ -1,27 +0,0 @@
1
- use swc_core::ecma::transforms::testing::test;
2
- use super::{tr, get_syntax_config};
3
-
4
- test!(
5
- get_syntax_config(),
6
- |_| tr(),
7
- should_static_jsx_being_shaked,
8
- r#"
9
- function Index () {
10
- return (
11
- <View compileMode>
12
- <Text>Hello World!</Text>
13
- <Text>Hello{T1}World{T2}!</Text>
14
- <View>
15
- <Text></Text>
16
- </View>
17
- <View style="color: red" hoverStopPropagation>
18
- <Text>Hello World!</Text>
19
- </View>
20
- <View style={myStyle}>
21
- <Text>Hello World!</Text>
22
- </View>
23
- </View>
24
- )
25
- }
26
- "#
27
- );
@@ -1,474 +0,0 @@
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
- utils::{quote_ident, quote_str},
13
- },
14
- atoms::Atom,
15
- };
16
- use std::collections::HashMap;
17
- use crate::PluginConfig;
18
- use crate::utils::{self, constants::*};
19
-
20
- struct PreVisitor {
21
- is_in_and_expr: bool,
22
- }
23
- impl PreVisitor {
24
- fn new () -> Self {
25
- Self {
26
- is_in_and_expr: false
27
- }
28
- }
29
- }
30
- impl VisitMut for PreVisitor {
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 {
49
- span,
50
- test: condition.take(),
51
- cons: right.take(),
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
- )))
56
- })
57
- }
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
- }
91
- }
92
- }
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
- }
119
-
120
- if is_first_and_expr {
121
- self.is_in_and_expr = true;
122
- }
123
-
124
- expr.visit_mut_children_with(self);
125
-
126
- if is_first_and_expr {
127
- self.is_in_and_expr = false;
128
- }
129
- } else {
130
- child.visit_mut_children_with(self);
131
- }
132
- }
133
- }
134
-
135
- pub struct TransformVisitor {
136
- pub config: PluginConfig,
137
- pub is_compile_mode: bool,
138
- pub node_stack: Vec<i32>,
139
- pub templates: HashMap<String, String>,
140
- pub get_tmpl_name: Box<dyn FnMut() -> String>
141
- }
142
-
143
- impl TransformVisitor {
144
- pub fn new (config: PluginConfig) -> Self {
145
- let get_tmpl_name = Box::new(utils::named_iter(
146
- format!("{}t", config.tmpl_prefix)
147
- ));
148
- Self {
149
- config,
150
- is_compile_mode: false,
151
- node_stack: vec![],
152
- templates: HashMap::new(),
153
- get_tmpl_name
154
- }
155
- }
156
-
157
- fn build_xml_element (&mut self, el: &mut JSXElement) -> String {
158
- let opening_element = &mut el.opening;
159
- match &opening_element.name {
160
- JSXElementName::Ident(ident) => {
161
- let name = utils::to_kebab_case(ident.as_ref());
162
- match self.config.components.get(&name) {
163
- // 内置组件
164
- Some(attrs_map) => {
165
- let attrs = self.build_xml_attrs(opening_element, attrs_map);
166
- if attrs.is_none() { return String::new() };
167
- let (children, ..) = self.build_xml_children(&mut el.children, None);
168
- format!("<{}{}>{}</{}>", name, attrs.unwrap(), children, name)
169
- },
170
- None => {
171
- // React 组件
172
- // 原生自定义组件
173
- let node_path = self.get_current_node_path();
174
- 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)
175
- }
176
- }
177
- }
178
- _ => String::new()
179
- }
180
- }
181
-
182
- fn build_xml_attrs (&self, opening_element: &mut JSXOpeningElement, attrs_map: &HashMap<String, String>) -> Option<String> {
183
- let mut props = HashMap::new();
184
- let mut attrs_string = String::new();
185
-
186
- opening_element.attrs.retain_mut(|attr| {
187
- if let JSXAttrOrSpread::JSXAttr(jsx_attr) = attr {
188
- if let JSXAttrName::Ident(Ident { sym: name, .. }) = &jsx_attr.name {
189
- let jsx_attr_name = name.to_string();
190
-
191
- if REACT_RESERVED.contains(&jsx_attr_name.as_str()) {
192
- return true;
193
- }
194
-
195
- let miniapp_attr_name = utils::convert_jsx_attr_key(&jsx_attr_name, &self.config.adapter);
196
- let event_name = utils::identify_jsx_event_key(&jsx_attr_name);
197
- let is_event = event_name.is_some();
198
- match &jsx_attr.value {
199
- Some(jsx_attr_value) => {
200
- match jsx_attr_value {
201
- JSXAttrValue::Lit(Lit::Str(Str { value, .. })) => {
202
- // 静态属性在 xml 中保留即可,jsx 中可以删除
203
- if jsx_attr_name != COMPILE_MODE {
204
- props.insert(miniapp_attr_name, value.to_string());
205
- return false
206
- }
207
- },
208
- JSXAttrValue::JSXExprContainer(..) => {
209
- let mut node_path = self.get_current_node_path();
210
- if is_event {
211
- props.insert(event_name.unwrap(), String::from(EVENT_HANDLER));
212
- if props.get(DATA_SID).is_none() {
213
- props.insert(String::from(DATA_SID), format!("{{{{{}.sid}}}}", node_path));
214
- }
215
- return true
216
- }
217
-
218
- // 小程序组件标准属性 -> 取 @tarojs/shared 传递过来的属性值;非标准属性 -> 取属性名
219
- let value: &str = attrs_map.get(&miniapp_attr_name).unwrap_or(&jsx_attr_name);
220
- // 按当前节点在节点树中的位置换算路径
221
- node_path.push('.');
222
- let value = if value.contains(TMPL_DATA_ROOT) {
223
- value.replace(TMPL_DATA_ROOT, &node_path)
224
- } else {
225
- format!("{}{}", node_path, value)
226
- };
227
- // 得出最终的模板属性值
228
- let miniapp_attr_value = format!("{{{{{}}}}}", value);
229
-
230
- props.insert(miniapp_attr_name, miniapp_attr_value);
231
- },
232
- _ => ()
233
- }
234
- },
235
- None => {
236
- if
237
- jsx_attr_name == COMPILE_ELSE ||
238
- jsx_attr_name == COMPILE_IGNORE
239
- {
240
- props.insert(miniapp_attr_name, String::from(jsx_attr_name));
241
- } else if jsx_attr_name == COMPILE_FOR {
242
- let current_path = self.get_current_loop_path();
243
- let miniapp_attr_value = format!("{{{{{}}}}}", current_path);
244
- props.insert(miniapp_attr_name, miniapp_attr_value);
245
- } else {
246
- props.insert(miniapp_attr_name, String::from("true"));
247
- }
248
- // 布尔值在 jsx 中也可以删除了
249
- return false
250
- }
251
- }
252
- }
253
- }
254
- return true
255
- });
256
-
257
- // 组件包含事件,但没有设置自定义 id 的话,把 id 设为 sid
258
- if props.get(DATA_SID).is_some() && props.get(ID).is_none() {
259
- props.insert(String::from(ID), props.get(DATA_SID).unwrap().clone());
260
- }
261
-
262
- // 生成的 template 需要幂等
263
- let mut keys: Vec<&String> = props.keys().collect();
264
- keys.sort();
265
- for key in keys {
266
- let value = props.get(key).unwrap();
267
- if value == COMPILE_IGNORE {
268
- return None
269
- } else if value == COMPILE_ELSE {
270
- attrs_string.push_str(&format!(" {}", key));
271
- } else {
272
- attrs_string.push_str(&format!(r#" {}="{}""#, key, value));
273
- }
274
- }
275
-
276
- Some(attrs_string)
277
- }
278
-
279
- fn build_xml_children (&mut self, children: &mut Vec<JSXElementChild>, retain_start_from: Option<i32>) -> (String, i32) {
280
- let mut children_string = String::new();
281
- let start = if retain_start_from.is_some() { retain_start_from.unwrap() } else { 0 };
282
- let mut retain_child_counter = start;
283
-
284
- children
285
- .retain_mut(|child| {
286
- let mut is_retain = true;
287
- self.node_stack.push(retain_child_counter);
288
- match child {
289
- JSXElementChild::JSXElement(child_el) => {
290
- let child_string = self.build_xml_element(&mut **child_el);
291
- children_string.push_str(&child_string);
292
-
293
- if utils::is_static_jsx(child_el) && utils::is_inner_component(child_el, &self.config) {
294
- is_retain = false
295
- } else {
296
- retain_child_counter += 1;
297
- }
298
- },
299
- JSXElementChild::JSXExprContainer(JSXExprContainer {
300
- expr: JSXExpr::Expr(jsx_expr),
301
- ..
302
- }) => {
303
- if let Expr::Paren(ParenExpr { expr, .. }) = &mut **jsx_expr {
304
- *jsx_expr = expr.take();
305
- }
306
- let node_path = self.get_current_node_path();
307
- match &mut **jsx_expr {
308
- Expr::Cond(CondExpr { cons, alt, ..}) => {
309
- let mut process_condition_expr = |arm: &mut Box<Expr>| {
310
- match &mut **arm {
311
- Expr::JSXElement(el) => {
312
- let child_string = self.build_xml_element(el);
313
- children_string.push_str(&child_string);
314
- },
315
- Expr::Lit(lit) => {
316
- if let Lit::Str(Str { value, .. }) = lit {
317
- if value == COMPILE_IGNORE {
318
- return ();
319
- }
320
- }
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);
325
- children_string.push_str(&str);
326
- },
327
- _ => ()
328
- }
329
- };
330
- process_condition_expr(cons);
331
- process_condition_expr(alt);
332
- },
333
- Expr::Call(CallExpr {
334
- callee: Callee::Expr(callee_expr),
335
- args,
336
- ..
337
- }) => {
338
- // 处理循环
339
- if let Some(return_value) = utils::extract_jsx_loop(callee_expr, args) {
340
- self.node_stack.pop();
341
- self.node_stack.push(LOOP_WRAPPER_ID);
342
- let child_string = self.build_xml_element(&mut *return_value);
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);
350
- }
351
- },
352
- _ => {
353
- let code = utils::gen_template_v(&node_path);
354
- children_string.push_str(&code);
355
- }
356
- }
357
- retain_child_counter = retain_child_counter + 1
358
- },
359
- JSXElementChild::JSXText(JSXText { value, .. }) => {
360
- let content = utils::jsx_text_to_string(value);
361
- if !content.is_empty() {
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;
376
- }
377
- self.node_stack.push(retain_child_counter);
378
- },
379
- _ => ()
380
- }
381
- self.node_stack.pop();
382
- return is_retain
383
- });
384
-
385
- (children_string, retain_child_counter - start)
386
- }
387
-
388
- fn get_current_node_path (&self) -> String {
389
- // return: i.cn[0].cn[0]....
390
- self.node_stack
391
- .iter()
392
- .fold(String::from("i"), |mut acc, item| {
393
- if item == &LOOP_WRAPPER_ID {
394
- return String::from("item")
395
- }
396
- acc.push_str(&format!(".cn[{}]", item));
397
- return acc;
398
- })
399
- }
400
-
401
- fn get_current_loop_path (&self) -> String {
402
- // return: i.cn[0]...cn
403
- self.node_stack
404
- .iter()
405
- .identify_last()
406
- .fold(String::from("i"), |mut acc, (is_last, item)| {
407
- let str = if is_last {
408
- String::from(".cn")
409
- } else {
410
- if item == &LOOP_WRAPPER_ID {
411
- return String::from("item")
412
- }
413
- format!(".cn[{}]", item)
414
- };
415
- acc.push_str(&str);
416
- return acc;
417
- })
418
- }
419
- }
420
-
421
- impl VisitMut for TransformVisitor {
422
- // Implement necessary visit_mut_* methods for actual custom transform.
423
- // A comprehensive list of possible visitor methods can be found here:
424
- // https://rustdoc.swc.rs/swc_ecma_visit/trait.VisitMut.html
425
- fn visit_mut_jsx_element (&mut self, el: &mut JSXElement) {
426
- let mut tmpl_name = String::new();
427
- for attr in &mut el.opening.attrs {
428
- if let JSXAttrOrSpread::JSXAttr(jsx_attr) = attr {
429
- if let JSXAttrName::Ident(jsx_attr_name) = &jsx_attr.name {
430
- if jsx_attr_name.sym == COMPILE_MODE {
431
- self.is_compile_mode = true;
432
- tmpl_name = (self.get_tmpl_name)();
433
- jsx_attr.value = Some(JSXAttrValue::Lit(Lit::Str(quote_str!(tmpl_name.as_str()))));
434
- break;
435
- }
436
- }
437
- }
438
- }
439
- if self.is_compile_mode {
440
- el.visit_mut_children_with(&mut PreVisitor::new());
441
- let tmpl_contents = format!(r#"<template name="tmpl_0_{}">{}</template>"#,
442
- &tmpl_name,
443
- self.build_xml_element(el)
444
- );
445
- self.templates.insert(tmpl_name, tmpl_contents);
446
- self.is_compile_mode = false;
447
- } else {
448
- el.visit_mut_children_with(self)
449
- }
450
- }
451
-
452
- fn visit_mut_module_items (&mut self, body_stmts: &mut Vec<ModuleItem>) {
453
- body_stmts.visit_mut_children_with(self);
454
-
455
- let mut keys: Vec<&String> = self.templates.keys().collect();
456
- keys.sort();
457
- let stmts_being_inserted = keys.into_iter()
458
- .map(|key| {
459
- let value = self.templates.get(key).unwrap();
460
- ModuleItem::Stmt(Stmt::Decl(Decl::Var(Box::new(VarDecl {
461
- span,
462
- kind: VarDeclKind::Const,
463
- declare: false,
464
- decls: vec![VarDeclarator {
465
- span,
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()))))),
468
- definite: false,
469
- }],
470
- }))))
471
- });
472
- ecma::utils::prepend_stmts(body_stmts, stmts_being_inserted);
473
- }
474
- }