From 62c23b9feb6245ff7c40cbfde1bbdeefcca03c07 Mon Sep 17 00:00:00 2001 From: liuzejia Date: Mon, 2 Sep 2024 20:59:31 +0800 Subject: [PATCH 01/29] feat: init --- Cargo.lock | 10 +++++ .../Cargo.toml | 16 +++++++ .../src/lib.rs | 42 +++++++++++++++++++ .../src/tests/init.rs | 21 ++++++++++ .../src/tests/mod.rs | 28 +++++++++++++ .../src/transform.rs | 36 ++++++++++++++++ .../src/tests/init.rs/should_do_nothing.js | 13 ++++++ 7 files changed, 166 insertions(+) create mode 100644 crates/swc_plugin_compile_mode_pre_process/Cargo.toml create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/lib.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/tests/init.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/tests/mod.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/transform.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/init.rs/should_do_nothing.js diff --git a/Cargo.lock b/Cargo.lock index 80018fcb0743..781aff52fea6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1975,6 +1975,16 @@ dependencies = [ "swc_core", ] +[[package]] +name = "swc_plugin_compile_mode_pre_process" +version = "0.1.0" +dependencies = [ + "regex", + "serde", + "serde_json", + "swc_core", +] + [[package]] name = "swc_plugin_define_config" version = "0.2.0" diff --git a/crates/swc_plugin_compile_mode_pre_process/Cargo.toml b/crates/swc_plugin_compile_mode_pre_process/Cargo.toml new file mode 100644 index 000000000000..fa1064cc8d35 --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "swc_plugin_compile_mode_pre_process" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +serde = { workspace = true } +serde_json = { workspace = true } +swc_core = { workspace = true } +regex = "1.10.2" + +[dev-dependencies] +swc_core = { workspace = true, features = ["ecma_parser", "ecma_codegen"] } diff --git a/crates/swc_plugin_compile_mode_pre_process/src/lib.rs b/crates/swc_plugin_compile_mode_pre_process/src/lib.rs new file mode 100644 index 000000000000..a6d4858b724a --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/src/lib.rs @@ -0,0 +1,42 @@ +use swc_core::{ + ecma::{ + ast::Program, + visit::{as_folder, FoldWith, VisitMut}, + }, + plugin::{ + plugin_transform, + proxies::TransformPluginProgramMetadata + } +}; +use serde::{Deserialize}; +use std::collections::HashMap; + +mod transform; +mod tests; +struct SerdeDefault; +impl SerdeDefault { + fn platform_default () -> String { + String::from("WEAPP") + } +} + + +#[derive(Deserialize, Debug)] +pub struct PluginConfig { + #[serde(default = "SerdeDefault::platform_default")] + pub platform: String, +} + +#[plugin_transform] +pub fn process_transform(program: Program, metadata: TransformPluginProgramMetadata) -> Program { + let config = serde_json::from_str::( + &metadata + .get_transform_plugin_config() + .unwrap() + ) + .unwrap(); + + let visitor: Box = Box::new(transform::TransformVisitor::new(config)); + + program.fold_with(&mut as_folder(visitor)) +} diff --git a/crates/swc_plugin_compile_mode_pre_process/src/tests/init.rs b/crates/swc_plugin_compile_mode_pre_process/src/tests/init.rs new file mode 100644 index 000000000000..3667e726b24a --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/src/tests/init.rs @@ -0,0 +1,21 @@ +use swc_core::ecma::transforms::testing::test; + +use super::{get_syntax_config, tr}; + +test!( + get_syntax_config(), + |_| tr(), + should_do_nothing, + r#" + function Index () { + return ( + + + + {myText} + + + ) + } + "# +); diff --git a/crates/swc_plugin_compile_mode_pre_process/src/tests/mod.rs b/crates/swc_plugin_compile_mode_pre_process/src/tests/mod.rs new file mode 100644 index 000000000000..4d4833b03a8e --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/src/tests/mod.rs @@ -0,0 +1,28 @@ +use swc_core::ecma::{ + parser, + visit::{as_folder, Fold}, +}; +use crate::{ + PluginConfig, + transform::*, +}; + +mod init; + +pub fn tr () -> impl Fold { + let config = serde_json::from_str::( + r#" + { + }"# + ) + .unwrap(); + let visitor = TransformVisitor::new(config); + as_folder(visitor) +} + +pub fn get_syntax_config () -> parser::Syntax { + parser::Syntax::Es(parser::EsConfig { + jsx: true, + ..Default::default() + }) +} diff --git a/crates/swc_plugin_compile_mode_pre_process/src/transform.rs b/crates/swc_plugin_compile_mode_pre_process/src/transform.rs new file mode 100644 index 000000000000..40569999b410 --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/src/transform.rs @@ -0,0 +1,36 @@ +use swc_core::{ + ecma::{ + ast::*, + visit::{VisitMutWith, VisitMut}, + }, + plugin::{ + plugin_transform, + proxies::TransformPluginProgramMetadata + } +}; +use crate::PluginConfig; +pub struct TransformVisitor { + +} + +impl TransformVisitor { + pub fn new(config: PluginConfig) -> Self { + TransformVisitor { + + } + } +} + +impl VisitMut for TransformVisitor { + fn visit_mut_jsx_element (&mut self, el: &mut JSXElement) { + match &el.opening.name { + JSXElementName::Ident(ident) => { + println!("TagName {}", ident.sym); + }, + _ => { + println!("??"); + } + } + el.visit_mut_children_with(self) + } +} \ No newline at end of file diff --git a/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/init.rs/should_do_nothing.js b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/init.rs/should_do_nothing.js new file mode 100644 index 000000000000..89f554adddd4 --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/init.rs/should_do_nothing.js @@ -0,0 +1,13 @@ +function Index() { + return + + + + + + {myText} + + + + ; +} From 3c08c90a95864789e56944cfa173518405c70911 Mon Sep 17 00:00:00 2001 From: liuzejia Date: Tue, 3 Sep 2024 22:23:29 +0800 Subject: [PATCH 02/29] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E6=8B=86=E5=88=86=E4=B8=8E=E5=9F=BA=E6=9C=AC=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../swc_plugin_compile_mode/src/transform.rs | 1 + .../src/lib.rs | 5 +- .../src/tests/init.rs | 5 + .../src/tests/mod.rs | 4 +- .../src/transform.rs | 36 ------ .../src/visitors/collect_render_fn.rs | 37 ++++++ .../src/visitors/common.rs | 62 ++++++++++ .../src/visitors/entry.rs | 117 ++++++++++++++++++ .../src/visitors/find_react_component.rs | 37 ++++++ .../src/visitors/mod.rs | 4 + 10 files changed, 268 insertions(+), 40 deletions(-) delete mode 100644 crates/swc_plugin_compile_mode_pre_process/src/transform.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/visitors/common.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/visitors/find_react_component.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/visitors/mod.rs diff --git a/crates/swc_plugin_compile_mode/src/transform.rs b/crates/swc_plugin_compile_mode/src/transform.rs index 723996323344..0ee3aa5bad97 100644 --- a/crates/swc_plugin_compile_mode/src/transform.rs +++ b/crates/swc_plugin_compile_mode/src/transform.rs @@ -722,6 +722,7 @@ impl VisitMut for TransformVisitor { if self.is_compile_mode { self.reset_states(); el.visit_mut_children_with(&mut PreVisitor::new()); + let tmpl_contents = format!(r#""#, &tmpl_name, self.build_xml_element(el) diff --git a/crates/swc_plugin_compile_mode_pre_process/src/lib.rs b/crates/swc_plugin_compile_mode_pre_process/src/lib.rs index a6d4858b724a..450ba01a76ea 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/lib.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/lib.rs @@ -11,8 +11,9 @@ use swc_core::{ use serde::{Deserialize}; use std::collections::HashMap; -mod transform; +mod visitors; mod tests; +use visitors::entry::EntryVisitor; struct SerdeDefault; impl SerdeDefault { fn platform_default () -> String { @@ -36,7 +37,7 @@ pub fn process_transform(program: Program, metadata: TransformPluginProgramMetad ) .unwrap(); - let visitor: Box = Box::new(transform::TransformVisitor::new(config)); + let visitor: Box = Box::new(EntryVisitor::new(config)); program.fold_with(&mut as_folder(visitor)) } diff --git a/crates/swc_plugin_compile_mode_pre_process/src/tests/init.rs b/crates/swc_plugin_compile_mode_pre_process/src/tests/init.rs index 3667e726b24a..099f95b6a430 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/tests/init.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/tests/init.rs @@ -7,6 +7,11 @@ test!( |_| tr(), should_do_nothing, r#" + const a = () =>{ + const b = ()=>{ + const c = ()=>{} + } + } function Index () { return ( diff --git a/crates/swc_plugin_compile_mode_pre_process/src/tests/mod.rs b/crates/swc_plugin_compile_mode_pre_process/src/tests/mod.rs index 4d4833b03a8e..aa9b6700be94 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/tests/mod.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/tests/mod.rs @@ -4,7 +4,7 @@ use swc_core::ecma::{ }; use crate::{ PluginConfig, - transform::*, + visitors::entry::EntryVisitor, }; mod init; @@ -16,7 +16,7 @@ pub fn tr () -> impl Fold { }"# ) .unwrap(); - let visitor = TransformVisitor::new(config); + let visitor = EntryVisitor::new(config); as_folder(visitor) } diff --git a/crates/swc_plugin_compile_mode_pre_process/src/transform.rs b/crates/swc_plugin_compile_mode_pre_process/src/transform.rs deleted file mode 100644 index 40569999b410..000000000000 --- a/crates/swc_plugin_compile_mode_pre_process/src/transform.rs +++ /dev/null @@ -1,36 +0,0 @@ -use swc_core::{ - ecma::{ - ast::*, - visit::{VisitMutWith, VisitMut}, - }, - plugin::{ - plugin_transform, - proxies::TransformPluginProgramMetadata - } -}; -use crate::PluginConfig; -pub struct TransformVisitor { - -} - -impl TransformVisitor { - pub fn new(config: PluginConfig) -> Self { - TransformVisitor { - - } - } -} - -impl VisitMut for TransformVisitor { - fn visit_mut_jsx_element (&mut self, el: &mut JSXElement) { - match &el.opening.name { - JSXElementName::Ident(ident) => { - println!("TagName {}", ident.sym); - }, - _ => { - println!("??"); - } - } - el.visit_mut_children_with(self) - } -} \ No newline at end of file diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs new file mode 100644 index 000000000000..19658077231b --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs @@ -0,0 +1,37 @@ +use std::collections::HashMap; +use swc_core::{ + ecma::{ + ast::*, + visit::{VisitMutWith, VisitMut}, + }, + plugin::{ + plugin_transform, + proxies::TransformPluginProgramMetadata + } +}; +use super::common::RenderFn; + +pub struct CollectRenderFnVisitor<'a> { + pub raw_render_fn_map: &'a mut HashMap>, + pub component_name:String, +} + +impl<'a> CollectRenderFnVisitor<'a> { + pub fn new(raw_render_fn_map: &'a mut HashMap>, component_name: String) -> Self { + CollectRenderFnVisitor { + raw_render_fn_map, + component_name + } + } +} + +impl VisitMut for CollectRenderFnVisitor<'_> { + // 先找到入口,首先函数名必须是大写的,然后返回值必须是 jsx 这样才是一个 react 组件 + fn visit_mut_arrow_expr(&mut self,n: &mut ArrowExpr) { + print!("visit_mut_arrow_expr"); + } + + fn visit_mut_fn_decl(&mut self,n: &mut FnDecl) { + print!("visit_mut_fn_decl"); + } +} diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/common.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/common.rs new file mode 100644 index 000000000000..1c989e2881ce --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/common.rs @@ -0,0 +1,62 @@ + +use std::collections::HashMap; + +use swc_core::{ + ecma::{ + ast::*, + visit::{VisitMutWith, VisitMut}, + }, + plugin::{ + plugin_transform, + proxies::TransformPluginProgramMetadata + } +}; + + + +pub struct RenderFn { + pub params: Vec, + pub jsx_element: JSXElement, +} + +impl Clone for RenderFn { + fn clone(&self) -> Self { + RenderFn { + params: self.params.clone(), + jsx_element: self.jsx_element.clone(), + } + } +} + + +pub struct ReactComponent { + pub name: String, + pub block_stmt: BlockStmt, +} + +impl Clone for ReactComponent { + fn clone(&self) -> Self { + ReactComponent { + name: self.name.clone(), + block_stmt: self.block_stmt.clone(), + } + } +} + +impl ReactComponent { + pub fn new(name: String, block_stmt: BlockStmt) -> Self { + ReactComponent { + name, + block_stmt, + } + } + + pub fn get_name(&self) -> String { + self.name.clone() + } + + pub fn is_valid (&self) -> bool { + // todo 还要判断返回的JSX里面有没有 compilerMode + self.name.chars().next().unwrap().is_uppercase() + } +} \ No newline at end of file diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs new file mode 100644 index 000000000000..8065be1b270a --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs @@ -0,0 +1,117 @@ +use std::collections::HashMap; + +use swc_core::{ + ecma::{ + ast::*, + visit::{VisitMutWith, VisitMut}, + }, + plugin::{ + plugin_transform, + proxies::TransformPluginProgramMetadata + } +}; +use crate::{visitors::find_react_component, PluginConfig}; + +use super::common::*; +use super::collect_render_fn::CollectRenderFnVisitor; +use super::find_react_component::FindReactComponentVisitor; +pub struct EntryVisitor { + visitorContext: VisitorContext, +} + +struct VisitorContext { + react_component: HashMap, + raw_render_fn_map: HashMap>, +} + +impl EntryVisitor { + pub fn new(config: PluginConfig) -> Self { + EntryVisitor { + visitorContext: VisitorContext { + raw_render_fn_map: HashMap::new(), + react_component: HashMap::new(), + } + } + } +} + + +impl VisitMut for EntryVisitor { + fn visit_mut_module(&mut self, n: &mut Module) { + print!("visit_mut_module start"); + //这个只是入口,这里面按顺序调用各种visitor,然后把处理的内容都挂在visitorContext上 + + // 先找到当前的文件中的 react 组件 因为有些人会在一个 jsx 文件中 写多个 react 组件,保留他的函数体 BlockStatement,用一个 HashMap 保存就行 + self.find_react_component(n); + // 这里处理收集到的 react_component 数据结构 hashMap:{name: react_component} + + self.collect_each_component_render_fn(); + // 这里处理收集到的 raw_render_fn_map 数据结构 hashMap:{name: raw_fn} + // let render_fn_deps_map = generate_render_fn_dep_map(self.visitorContext.raw_render_fn_map); + // 1. 可能存在互相引用,得梳理一下他们之间的依赖关系 数据结构 hashMap:{name:[dep1, dep2,...]} + + // 2. 根据依赖表,生成解析的列表 sort queue 先进先出 + // let sort_queue = generate_sort_queue(&render_fn_deps_map); + // 3. 根据 sort queue 生成 formatted_fn_map 数据结构 hashMap:{name: formatted_fn} + + // 4. 交给下一个 visitor 处理 + print!("visit_mut_module done"); + n.visit_mut_children_with(self); + } +} + + +impl EntryVisitor { + fn find_react_component (&mut self, n: &mut Module) { + // 先找到当前的文件中的 react 组件 因为有些人会在一个 jsx 文件中 写多个 react 组件,保留他的函数体 BlockStatement,他们各自是独立的,所以用数组保存就行 + let mut find_react_component_visitor = FindReactComponentVisitor::new(&mut self.visitorContext.react_component); + n.visit_mut_children_with(&mut find_react_component_visitor); + // 必须要合法的 react 组件才能继续往下走 + let valid_react_component = self.visitorContext.react_component.clone().into_iter().filter(|(_name, react_component)| { + react_component.is_valid() + }).collect::>(); + self.visitorContext.react_component = valid_react_component; + } + + fn collect_each_component_render_fn (&mut self) { + // 遍历每一个 react 组件,找到他们的 render 函数 + for (name, mut react_component) in self.visitorContext.react_component.clone() { + let mut collect_render_fn_visitor = CollectRenderFnVisitor::new(&mut self.visitorContext.raw_render_fn_map, name); + react_component.block_stmt.visit_mut_children_with(&mut collect_render_fn_visitor); + } + } +} + +fn generate_render_fn_dep_map (raw_fn_map: &HashMap)-> HashMap> { + let mut render_fn_deps_map = HashMap::new(); + for (name, render_fn) in raw_fn_map { + let mut deps: Vec = vec![]; + let cloned_jsx_element = render_fn.jsx_element.clone(); + // @todo use visitor to collect deps + render_fn_deps_map.insert(name.clone(), deps); + } + // todo:通过 visitor 收集依赖,只能收集到最表层的依赖,如果有嵌套的依赖,需要递归处理,可能会出现循环,如果出现循环的话,按么循环的那两个组件都要去掉 也是数据结构算法 + render_fn_deps_map +} + +fn generate_sort_queue (render_fn_deps_map: &HashMap>) -> Vec { + let mut sort_queue = vec![]; + for (name, deps) in render_fn_deps_map { + // todo 完全的数据结构算法 + } + sort_queue +} + +fn generate_formatted_fn_map (sort_queue: Vec, raw_fn_map: &HashMap) -> HashMap { + let mut formatted_fn_map = HashMap::new(); + for name in sort_queue { + if let Some(raw_fn) = raw_fn_map.get(&name) { + let mut formatted_fn = raw_fn.clone(); + // todo 格式化 raw_fn 为 formatted_fn + // 涉及模版拼接和参数转化,和下面的 transform 要做的事情一样,等抽象出来 + formatted_fn_map.insert(name, formatted_fn); + } + } + + formatted_fn_map +} \ No newline at end of file diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/find_react_component.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/find_react_component.rs new file mode 100644 index 000000000000..55d8628c5a4e --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/find_react_component.rs @@ -0,0 +1,37 @@ +use std::collections::HashMap; + +use swc_core::{ + ecma::{ + ast::*, + visit::{VisitMutWith, VisitMut}, + }, + plugin::{ + plugin_transform, + proxies::TransformPluginProgramMetadata + } +}; + +use super::common::ReactComponent; + +pub struct FindReactComponentVisitor<'a> { + raw_render_fn_map: &'a mut HashMap, +} + +impl<'a> FindReactComponentVisitor<'a> { + pub fn new(raw_render_fn_map: &'a mut HashMap,) -> Self { + FindReactComponentVisitor { + raw_render_fn_map + } + } +} + +impl VisitMut for FindReactComponentVisitor<'_> { + // 先找到入口,首先函数名必须是大写的,然后返回值必须是 jsx 这样才是一个 react 组件 + fn visit_mut_arrow_expr(&mut self,n: &mut ArrowExpr) { + print!("visit_mut_arrow_expr"); + } + + fn visit_mut_fn_decl(&mut self,n: &mut FnDecl) { + print!("visit_mut_fn_decl"); + } +} \ No newline at end of file diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/mod.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/mod.rs new file mode 100644 index 000000000000..1efb2dd66514 --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/mod.rs @@ -0,0 +1,4 @@ +pub mod entry; +pub mod common; +pub mod collect_render_fn; +pub mod find_react_component; \ No newline at end of file From ec46d05c7464b2411229c570b08d81eecc2b505b Mon Sep 17 00:00:00 2001 From: liuzejia Date: Tue, 10 Sep 2024 21:15:50 +0800 Subject: [PATCH 03/29] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E6=94=B6=E9=9B=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/visitors/collect_render_fn.rs | 12 ++- .../src/visitors/common.rs | 4 +- .../src/visitors/entry.rs | 25 +++--- .../src/visitors/find_react_component.rs | 90 ++++++++++++++++--- 4 files changed, 103 insertions(+), 28 deletions(-) diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs index 19658077231b..9ffc046f9a4a 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs @@ -27,11 +27,19 @@ impl<'a> CollectRenderFnVisitor<'a> { impl VisitMut for CollectRenderFnVisitor<'_> { // 先找到入口,首先函数名必须是大写的,然后返回值必须是 jsx 这样才是一个 react 组件 - fn visit_mut_arrow_expr(&mut self,n: &mut ArrowExpr) { + fn visit_mut_arrow_expr(&mut self, n: &mut ArrowExpr) { print!("visit_mut_arrow_expr"); } - fn visit_mut_fn_decl(&mut self,n: &mut FnDecl) { + fn visit_mut_fn_decl(&mut self, n: &mut FnDecl) { print!("visit_mut_fn_decl"); } + + fn visit_mut_return_stmt(&mut self, n: &mut ReturnStmt) { + print!("visit_mut_return_stmt"); + } + + fn visit_mut_jsx_element(&mut self, n: &mut JSXElement) { + print!("visit_mut_jsx_element"); + } } diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/common.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/common.rs index 1c989e2881ce..98ae7ec4bd96 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/common.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/common.rs @@ -31,7 +31,7 @@ impl Clone for RenderFn { pub struct ReactComponent { pub name: String, - pub block_stmt: BlockStmt, + pub block_stmt: Option, } impl Clone for ReactComponent { @@ -44,7 +44,7 @@ impl Clone for ReactComponent { } impl ReactComponent { - pub fn new(name: String, block_stmt: BlockStmt) -> Self { + pub fn new(name: String, block_stmt: Option) -> Self { ReactComponent { name, block_stmt, diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs index 8065be1b270a..fdd262e1aa49 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs @@ -16,20 +16,20 @@ use super::common::*; use super::collect_render_fn::CollectRenderFnVisitor; use super::find_react_component::FindReactComponentVisitor; pub struct EntryVisitor { - visitorContext: VisitorContext, + visitor_context: VisitorContext, } struct VisitorContext { - react_component: HashMap, + react_component_list: Vec, raw_render_fn_map: HashMap>, } impl EntryVisitor { pub fn new(config: PluginConfig) -> Self { EntryVisitor { - visitorContext: VisitorContext { + visitor_context: VisitorContext { raw_render_fn_map: HashMap::new(), - react_component: HashMap::new(), + react_component_list: vec![], } } } @@ -41,7 +41,6 @@ impl VisitMut for EntryVisitor { print!("visit_mut_module start"); //这个只是入口,这里面按顺序调用各种visitor,然后把处理的内容都挂在visitorContext上 - // 先找到当前的文件中的 react 组件 因为有些人会在一个 jsx 文件中 写多个 react 组件,保留他的函数体 BlockStatement,用一个 HashMap 保存就行 self.find_react_component(n); // 这里处理收集到的 react_component 数据结构 hashMap:{name: react_component} @@ -64,21 +63,19 @@ impl VisitMut for EntryVisitor { impl EntryVisitor { fn find_react_component (&mut self, n: &mut Module) { // 先找到当前的文件中的 react 组件 因为有些人会在一个 jsx 文件中 写多个 react 组件,保留他的函数体 BlockStatement,他们各自是独立的,所以用数组保存就行 - let mut find_react_component_visitor = FindReactComponentVisitor::new(&mut self.visitorContext.react_component); + let mut find_react_component_visitor = FindReactComponentVisitor::new(&mut self.visitor_context.react_component_list); n.visit_mut_children_with(&mut find_react_component_visitor); // 必须要合法的 react 组件才能继续往下走 - let valid_react_component = self.visitorContext.react_component.clone().into_iter().filter(|(_name, react_component)| { - react_component.is_valid() - }).collect::>(); - self.visitorContext.react_component = valid_react_component; + let valid_react_component_list = self.visitor_context.react_component_list.clone().into_iter().filter(|react_component| react_component.is_valid()).collect(); + self.visitor_context.react_component_list = valid_react_component_list; } fn collect_each_component_render_fn (&mut self) { - // 遍历每一个 react 组件,找到他们的 render 函数 - for (name, mut react_component) in self.visitorContext.react_component.clone() { - let mut collect_render_fn_visitor = CollectRenderFnVisitor::new(&mut self.visitorContext.raw_render_fn_map, name); + // 遍历每一个 react 组件,找到他们的 render 函数并收集起来 + self.visitor_context.react_component_list.clone().into_iter().for_each(|mut react_component| { + let mut collect_render_fn_visitor = CollectRenderFnVisitor::new(&mut self.visitor_context.raw_render_fn_map, react_component.get_name()); react_component.block_stmt.visit_mut_children_with(&mut collect_render_fn_visitor); - } + }); } } diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/find_react_component.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/find_react_component.rs index 55d8628c5a4e..e04d0ebe781e 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/find_react_component.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/find_react_component.rs @@ -1,9 +1,9 @@ use std::collections::HashMap; +use serde_json::de; use swc_core::{ ecma::{ - ast::*, - visit::{VisitMutWith, VisitMut}, + ast::*, utils::function, visit::{VisitMut, VisitMutWith} }, plugin::{ plugin_transform, @@ -14,24 +14,94 @@ use swc_core::{ use super::common::ReactComponent; pub struct FindReactComponentVisitor<'a> { - raw_render_fn_map: &'a mut HashMap, + react_component_list: &'a mut Vec, } impl<'a> FindReactComponentVisitor<'a> { - pub fn new(raw_render_fn_map: &'a mut HashMap,) -> Self { + pub fn new(react_component_list: &'a mut Vec,) -> Self { FindReactComponentVisitor { - raw_render_fn_map + react_component_list } } } +// 因为这个 visitor 只是用来找模块最外层的作用域的,所以都不需要递归去找 impl VisitMut for FindReactComponentVisitor<'_> { - // 先找到入口,首先函数名必须是大写的,然后返回值必须是 jsx 这样才是一个 react 组件 - fn visit_mut_arrow_expr(&mut self,n: &mut ArrowExpr) { - print!("visit_mut_arrow_expr"); + fn visit_mut_var_decl(&mut self,n: &mut VarDecl) { + for decl in &n.decls { + let init = decl.clone().init.unwrap(); + if let Expr::Arrow(arrow_expr) = *init { + match (&decl.name, *arrow_expr.body) { + (Pat::Ident(ident), BlockStmtOrExpr::BlockStmt(block_stmt)) => { + let react_component = ReactComponent::new(ident.sym.to_string(), Some(block_stmt)); + self.react_component_list.push(react_component); + }, + _ => {} + } + } + } } - fn visit_mut_fn_decl(&mut self,n: &mut FnDecl) { - print!("visit_mut_fn_decl"); + fn visit_mut_fn_decl(&mut self, n: &mut FnDecl) { + // 针对场景 function xxx () {} + let function_name = n.ident.sym.to_string(); + let block_stmt = n.function.body.clone(); + let react_component = ReactComponent::new(function_name, block_stmt); + self.react_component_list.push(react_component); + } + + fn visit_mut_export_decl(&mut self,n: &mut ExportDecl) { + match &n.decl { + // 针对场景 export function xxx () {} + Decl::Fn(fn_decl) => { + let function_name = fn_decl.ident.sym.to_string(); + let block_stmt = fn_decl.function.body.clone(); + let react_component = ReactComponent::new(function_name, block_stmt); + self.react_component_list.push(react_component); + }, + // 针对场景 export const xxx = () => {} + Decl::Var(var_decl) => { + for decl in &var_decl.decls { + let init = decl.clone().init.unwrap(); + if let Expr::Arrow(arrow_expr) = *init { + match (&decl.name, *arrow_expr.body) { + (Pat::Ident(ident), BlockStmtOrExpr::BlockStmt(block_stmt)) => { + let react_component = ReactComponent::new(ident.sym.to_string(), Some(block_stmt)); + self.react_component_list.push(react_component); + }, + _ => {} + } + } + } + }, + _ => {} + } + } + + fn visit_mut_export_default_decl(&mut self,n: &mut ExportDefaultDecl) { + // export default 可以是匿名的组件 + match &n.decl { + // 适配 export default function xxx () {} + DefaultDecl::Fn(fn_decl) => { + let block_stmt = fn_decl.function.body.clone(); + let react_component = ReactComponent::new(String::from("default"), block_stmt); + self.react_component_list.push(react_component); + }, + _ => {} + } + } + + fn visit_mut_export_default_expr(&mut self,n: &mut ExportDefaultExpr) { + // export default 可以是匿名的组件 + match &*n.expr { + // 适配 export default () => {} + Expr::Arrow(arrow_expr) => { + if let BlockStmtOrExpr::BlockStmt(block_stmt) = *arrow_expr.body.clone() { + let react_component = ReactComponent::new(String::from("default"), Some(block_stmt)); + self.react_component_list.push(react_component); + } + }, + _ => {} + } } } \ No newline at end of file From 4b3423cbccfe1339b8a123fb94fd225dcf348358 Mon Sep 17 00:00:00 2001 From: liuzejia Date: Thu, 12 Sep 2024 17:16:51 +0800 Subject: [PATCH 04/29] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=E6=94=B6?= =?UTF-8?q?=E9=9B=86=E7=8E=AF=E8=8A=82=E5=92=8C=E8=BD=AC=E5=8C=96=E7=8E=AF?= =?UTF-8?q?=E8=8A=82=E7=9A=84=E4=B8=B2=E8=81=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/tests/init.rs | 25 ++-- .../src/visitors/collect_render_fn.rs | 16 +-- .../src/visitors/common.rs | 8 +- .../src/visitors/entry.rs | 40 +++--- .../src/visitors/find_react_component.rs | 64 ++++------ .../src/visitors/mod.rs | 3 +- .../src/visitors/transform/component_entry.rs | 115 ++++++++++++++++++ .../src/visitors/transform/mod.rs | 2 + .../src/visitors/transform/process.rs | 49 ++++++++ 9 files changed, 234 insertions(+), 88 deletions(-) create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/component_entry.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/mod.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/process.rs diff --git a/crates/swc_plugin_compile_mode_pre_process/src/tests/init.rs b/crates/swc_plugin_compile_mode_pre_process/src/tests/init.rs index 099f95b6a430..4a98650da863 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/tests/init.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/tests/init.rs @@ -7,20 +7,15 @@ test!( |_| tr(), should_do_nothing, r#" - const a = () =>{ - const b = ()=>{ - const c = ()=>{} - } - } - function Index () { - return ( - - - - {myText} - - - ) - } + function ComponentA () {} + const ComponentB = function (){} + const ComponentC = () => {} + export const ComponentD = () => {} + export const ComponentE = () => {} + export default function ComponentF () {} + // export default function () {} + // export default () => {} + function normal () {} + const normal2 = function () {} "# ); diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs index 9ffc046f9a4a..b6f5e091a782 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs @@ -18,6 +18,7 @@ pub struct CollectRenderFnVisitor<'a> { impl<'a> CollectRenderFnVisitor<'a> { pub fn new(raw_render_fn_map: &'a mut HashMap>, component_name: String) -> Self { + raw_render_fn_map.insert(component_name.clone(), HashMap::new()); CollectRenderFnVisitor { raw_render_fn_map, component_name @@ -27,19 +28,4 @@ impl<'a> CollectRenderFnVisitor<'a> { impl VisitMut for CollectRenderFnVisitor<'_> { // 先找到入口,首先函数名必须是大写的,然后返回值必须是 jsx 这样才是一个 react 组件 - fn visit_mut_arrow_expr(&mut self, n: &mut ArrowExpr) { - print!("visit_mut_arrow_expr"); - } - - fn visit_mut_fn_decl(&mut self, n: &mut FnDecl) { - print!("visit_mut_fn_decl"); - } - - fn visit_mut_return_stmt(&mut self, n: &mut ReturnStmt) { - print!("visit_mut_return_stmt"); - } - - fn visit_mut_jsx_element(&mut self, n: &mut JSXElement) { - print!("visit_mut_jsx_element"); - } } diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/common.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/common.rs index 98ae7ec4bd96..6fc77630783c 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/common.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/common.rs @@ -13,7 +13,7 @@ use swc_core::{ }; - +pub const DEFAULT_COMPONENT: &str = "Default_Component"; pub struct RenderFn { pub params: Vec, pub jsx_element: JSXElement, @@ -56,7 +56,9 @@ impl ReactComponent { } pub fn is_valid (&self) -> bool { - // todo 还要判断返回的JSX里面有没有 compilerMode - self.name.chars().next().unwrap().is_uppercase() + // 1. 名称是否是大写字母开头 + let is_first_char_uppercase = self.get_name().chars().next().unwrap().is_uppercase(); + is_first_char_uppercase + //todo 2. 返回的 JSX 里面有没有 compilerMode } } \ No newline at end of file diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs index fdd262e1aa49..466ef416c598 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs @@ -12,9 +12,10 @@ use swc_core::{ }; use crate::{visitors::find_react_component, PluginConfig}; -use super::common::*; +use super::{common::*, transform}; use super::collect_render_fn::CollectRenderFnVisitor; use super::find_react_component::FindReactComponentVisitor; +use super::transform::component_entry::ComponentEntryVisitor; pub struct EntryVisitor { visitor_context: VisitorContext, } @@ -22,6 +23,7 @@ pub struct EntryVisitor { struct VisitorContext { react_component_list: Vec, raw_render_fn_map: HashMap>, + formatted_render_fn_map: HashMap>, } impl EntryVisitor { @@ -29,6 +31,7 @@ impl EntryVisitor { EntryVisitor { visitor_context: VisitorContext { raw_render_fn_map: HashMap::new(), + formatted_render_fn_map: HashMap::new(), react_component_list: vec![], } } @@ -38,24 +41,12 @@ impl EntryVisitor { impl VisitMut for EntryVisitor { fn visit_mut_module(&mut self, n: &mut Module) { - print!("visit_mut_module start"); //这个只是入口,这里面按顺序调用各种visitor,然后把处理的内容都挂在visitorContext上 - self.find_react_component(n); // 这里处理收集到的 react_component 数据结构 hashMap:{name: react_component} - self.collect_each_component_render_fn(); - // 这里处理收集到的 raw_render_fn_map 数据结构 hashMap:{name: raw_fn} - // let render_fn_deps_map = generate_render_fn_dep_map(self.visitorContext.raw_render_fn_map); - // 1. 可能存在互相引用,得梳理一下他们之间的依赖关系 数据结构 hashMap:{name:[dep1, dep2,...]} - - // 2. 根据依赖表,生成解析的列表 sort queue 先进先出 - // let sort_queue = generate_sort_queue(&render_fn_deps_map); - // 3. 根据 sort queue 生成 formatted_fn_map 数据结构 hashMap:{name: formatted_fn} - - // 4. 交给下一个 visitor 处理 - print!("visit_mut_module done"); - n.visit_mut_children_with(self); + self.transform_render_fn(); + self.transform(n); } } @@ -77,6 +68,25 @@ impl EntryVisitor { react_component.block_stmt.visit_mut_children_with(&mut collect_render_fn_visitor); }); } + + fn transform_render_fn (&mut self) { + let mut formatted_render_fn_map: HashMap> = HashMap::new(); + self.visitor_context.raw_render_fn_map.clone().into_iter().for_each(|(name, raw_fn_map)| { + // 1. 可能存在互相引用,得梳理一下他们之间的依赖关系 数据结构 hashMap:{name:[dep1, dep2,...]} + let render_fn_deps_map = generate_render_fn_dep_map(&raw_fn_map); + // 2. 根据依赖表,生成解析的列表 sort queue 先进先出 + let sort_queue = generate_sort_queue(&render_fn_deps_map); + // 3. 根据 sort queue 生成 formatted_fn_map 数据结构 hashMap:{name: formatted_fn} + let formatted_fn_map = generate_formatted_fn_map(sort_queue, &raw_fn_map); + formatted_render_fn_map.insert(name, formatted_fn_map); + }); + self.visitor_context.formatted_render_fn_map = formatted_render_fn_map; + } + + fn transform (&mut self, n: &mut Module) { + let mut transform_visitor = ComponentEntryVisitor::new(&self.visitor_context.formatted_render_fn_map); + n.visit_mut_children_with(&mut transform_visitor); + } } fn generate_render_fn_dep_map (raw_fn_map: &HashMap)-> HashMap> { diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/find_react_component.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/find_react_component.rs index e04d0ebe781e..7ae0694513c8 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/find_react_component.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/find_react_component.rs @@ -11,7 +11,7 @@ use swc_core::{ } }; -use super::common::ReactComponent; +use super::common::{ReactComponent, DEFAULT_COMPONENT}; pub struct FindReactComponentVisitor<'a> { react_component_list: &'a mut Vec, @@ -30,61 +30,47 @@ impl VisitMut for FindReactComponentVisitor<'_> { fn visit_mut_var_decl(&mut self,n: &mut VarDecl) { for decl in &n.decls { let init = decl.clone().init.unwrap(); - if let Expr::Arrow(arrow_expr) = *init { - match (&decl.name, *arrow_expr.body) { - (Pat::Ident(ident), BlockStmtOrExpr::BlockStmt(block_stmt)) => { - let react_component = ReactComponent::new(ident.sym.to_string(), Some(block_stmt)); - self.react_component_list.push(react_component); - }, - _ => {} + match *init { + // 适配 const xxx = () => {} + Expr::Arrow(arrow_expr) => { + match (&decl.name, *arrow_expr.body) { + (Pat::Ident(ident), BlockStmtOrExpr::BlockStmt(block_stmt)) => { + let react_component = ReactComponent::new(ident.sym.to_string(), Some(block_stmt)); + self.react_component_list.push(react_component); + }, + _ => {} } + }, + Expr::Fn(FnExpr { ident: _, function })=> { + // 适配 const xxx = function () {} + match (&decl.name, (*function).body) { + (Pat::Ident(ident), Some(block_stmt)) => { + let react_component = ReactComponent::new(ident.sym.to_string(), Some(block_stmt)); + self.react_component_list.push(react_component); + }, + _ => {} + } + }, + _ => {} } } } fn visit_mut_fn_decl(&mut self, n: &mut FnDecl) { - // 针对场景 function xxx () {} + // 针对场景 function xxx () {} 和 export function xxx () {} 和 export default function xxx () {} let function_name = n.ident.sym.to_string(); let block_stmt = n.function.body.clone(); let react_component = ReactComponent::new(function_name, block_stmt); self.react_component_list.push(react_component); } - fn visit_mut_export_decl(&mut self,n: &mut ExportDecl) { - match &n.decl { - // 针对场景 export function xxx () {} - Decl::Fn(fn_decl) => { - let function_name = fn_decl.ident.sym.to_string(); - let block_stmt = fn_decl.function.body.clone(); - let react_component = ReactComponent::new(function_name, block_stmt); - self.react_component_list.push(react_component); - }, - // 针对场景 export const xxx = () => {} - Decl::Var(var_decl) => { - for decl in &var_decl.decls { - let init = decl.clone().init.unwrap(); - if let Expr::Arrow(arrow_expr) = *init { - match (&decl.name, *arrow_expr.body) { - (Pat::Ident(ident), BlockStmtOrExpr::BlockStmt(block_stmt)) => { - let react_component = ReactComponent::new(ident.sym.to_string(), Some(block_stmt)); - self.react_component_list.push(react_component); - }, - _ => {} - } - } - } - }, - _ => {} - } - } - fn visit_mut_export_default_decl(&mut self,n: &mut ExportDefaultDecl) { // export default 可以是匿名的组件 match &n.decl { // 适配 export default function xxx () {} DefaultDecl::Fn(fn_decl) => { let block_stmt = fn_decl.function.body.clone(); - let react_component = ReactComponent::new(String::from("default"), block_stmt); + let react_component = ReactComponent::new(DEFAULT_COMPONENT.to_string(), block_stmt); self.react_component_list.push(react_component); }, _ => {} @@ -97,7 +83,7 @@ impl VisitMut for FindReactComponentVisitor<'_> { // 适配 export default () => {} Expr::Arrow(arrow_expr) => { if let BlockStmtOrExpr::BlockStmt(block_stmt) = *arrow_expr.body.clone() { - let react_component = ReactComponent::new(String::from("default"), Some(block_stmt)); + let react_component = ReactComponent::new(DEFAULT_COMPONENT.to_string(), Some(block_stmt)); self.react_component_list.push(react_component); } }, diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/mod.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/mod.rs index 1efb2dd66514..7f2f4264e1e7 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/mod.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/mod.rs @@ -1,4 +1,5 @@ pub mod entry; pub mod common; pub mod collect_render_fn; -pub mod find_react_component; \ No newline at end of file +pub mod find_react_component; +pub mod transform; \ No newline at end of file diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/component_entry.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/component_entry.rs new file mode 100644 index 000000000000..58499b721bff --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/component_entry.rs @@ -0,0 +1,115 @@ +use std::collections::HashMap; + +use serde_json::de; +use swc_core::{ + ecma::{ + ast::*, utils::function, visit::{VisitMut, VisitMutWith} + }, + plugin::{ + plugin_transform, + proxies::TransformPluginProgramMetadata + } +}; + +use crate::visitors::common::{RenderFn, DEFAULT_COMPONENT}; + +use super::process::TransformProcessVisitor; + +pub struct ComponentEntryVisitor<'a> { + format_render_fn_map: &'a HashMap>, +} + +impl<'a> ComponentEntryVisitor<'a> { + pub fn new(format_render_fn_map: &'a HashMap>) -> Self { + ComponentEntryVisitor { + format_render_fn_map, + } + } + + pub fn get_format_render_fn_map_by_component_name(&self, component_name: &String) -> Option> { + self.format_render_fn_map.get(component_name) + .map(|render_fn_map| render_fn_map.clone()) + } +} + +impl<'a> VisitMut for ComponentEntryVisitor<'a> { + fn visit_mut_var_decl(&mut self,n: &mut VarDecl) { + for decl in &mut n.decls { + let init = decl.clone().init.unwrap(); + match *init { + // 适配 const xxx = () => {} + Expr::Arrow(arrow_expr) => { + match (&decl.name, *arrow_expr.body) { + (Pat::Ident(ident), BlockStmtOrExpr::BlockStmt(_block_stmt)) => { + let component_name = ident.sym.to_string(); + let render_fn_map = self.get_format_render_fn_map_by_component_name(&component_name); + if let Some(render_fn_map) = render_fn_map { + let mut process_visitor = TransformProcessVisitor::new(component_name, &render_fn_map); + decl.init.visit_mut_children_with(&mut process_visitor); + } + }, + _ => {} + } + }, + Expr::Fn(FnExpr { ident: _, function })=> { + // 适配 const xxx = function () {} + match (&decl.name, (*function).body) { + (Pat::Ident(ident), Some(_block_stmt)) => { + let component_name = ident.sym.to_string(); + let render_fn_map = self.get_format_render_fn_map_by_component_name(&component_name); + if let Some(render_fn_map) = render_fn_map { + let mut process_visitor = TransformProcessVisitor::new(component_name, &render_fn_map); + decl.init.visit_mut_children_with(&mut process_visitor); + } + }, + _ => {} + } + }, + _ => {} + } + } + } + + fn visit_mut_fn_decl(&mut self, n: &mut FnDecl) { + // 针对场景 function xxx () {} 和 export function xxx () {} 和 export default function xxx () {} + let component_name = n.ident.sym.to_string(); + let render_fn_map = self.get_format_render_fn_map_by_component_name(&component_name); + if let Some(render_fn_map) = render_fn_map { + let mut process_visitor = TransformProcessVisitor::new(component_name, &render_fn_map); + n.function.body.visit_mut_children_with(&mut process_visitor); + } + } + + + fn visit_mut_export_default_decl(&mut self,n: &mut ExportDefaultDecl) { + // export default 可以是匿名的组件 + match &mut n.decl { + // 适配 export default function xxx () {} + DefaultDecl::Fn(fn_decl) => { + let render_fn_map = self.get_format_render_fn_map_by_component_name(&DEFAULT_COMPONENT.to_string()); + if let Some(render_fn_map) = render_fn_map { + let mut process_visitor = TransformProcessVisitor::new(DEFAULT_COMPONENT.to_string(), &render_fn_map); + fn_decl.function.body.visit_mut_children_with(&mut process_visitor); + } + }, + _ => {} + } + } + + fn visit_mut_export_default_expr(&mut self,n: &mut ExportDefaultExpr) { + // export default 可以是匿名的组件 + match &mut *n.expr { + // 适配 export default () => {} + Expr::Arrow(arrow_expr) => { + if let BlockStmtOrExpr::BlockStmt(_block_stmt) = *arrow_expr.body.clone() { + let render_fn_map = self.get_format_render_fn_map_by_component_name(&DEFAULT_COMPONENT.to_string()); + if let Some(render_fn_map) = render_fn_map { + let mut process_visitor = TransformProcessVisitor::new(DEFAULT_COMPONENT.to_string(), &render_fn_map); + n.expr.visit_mut_children_with(&mut process_visitor); + } + } + }, + _ => {} + } + } +} diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/mod.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/mod.rs new file mode 100644 index 000000000000..7ac12b609257 --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/mod.rs @@ -0,0 +1,2 @@ +pub mod component_entry; +pub mod process; \ No newline at end of file diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/process.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/process.rs new file mode 100644 index 000000000000..130df44f5994 --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/process.rs @@ -0,0 +1,49 @@ +use std::collections::HashMap; + +use serde_json::de; +use swc_core::{ + ecma::{ + ast::*, utils::{function, swc_common::*}, visit::{VisitMut, VisitMutWith} + }, + plugin::{ + plugin_transform, + proxies::TransformPluginProgramMetadata + } +}; + +use crate::visitors::common::RenderFn; +pub struct TransformProcessVisitor<'a> { + component_name: String, + render_fn_map: &'a HashMap +} + +impl<'a> TransformProcessVisitor<'a> { + pub fn new(component_name: String, render_fn_map: &'a HashMap) -> Self { + TransformProcessVisitor { + component_name, + render_fn_map + } + } +} + +impl<'a> VisitMut for TransformProcessVisitor<'a> { + fn visit_mut_block_stmt(&mut self, n: &mut BlockStmt) { + println!("process! component_name: {}\n", self.component_name); + let other_sts = Decl::Var(Box::new(VarDecl { + span: DUMMY_SP, + kind: VarDeclKind::Const, + declare: false, + decls: vec![VarDeclarator { + span: DUMMY_SP, + name: Pat::Ident(Ident::new("a".into(), DUMMY_SP).into()), + init: Some(Box::new(Expr::Lit(Lit::Num(Number { + span: DUMMY_SP, + value: 1.0, + raw: None + })))), + definite: false, + }], + })); + n.stmts.push(Stmt::Decl(other_sts)); + } +} \ No newline at end of file From 1c48427ec11d90eccee7063ad46c949134a86015 Mon Sep 17 00:00:00 2001 From: liuzejia Date: Fri, 13 Sep 2024 21:27:04 +0800 Subject: [PATCH 05/29] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90react=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E4=B8=ADrender=E7=BB=84=E4=BB=B6=E7=9A=84=E6=90=9C?= =?UTF-8?q?=E9=9B=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/visitors/collect_render_fn.rs | 115 ++++++++++++++++-- .../src/visitors/common.rs | 41 ++++++- .../src/visitors/entry.rs | 30 +++-- .../src/visitors/find_react_component.rs | 13 +- .../src/visitors/is_compile_mode_component.rs | 67 ++++++++++ .../src/visitors/mod.rs | 3 +- .../src/visitors/transform/component_entry.rs | 2 +- 7 files changed, 233 insertions(+), 38 deletions(-) create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/visitors/is_compile_mode_component.rs diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs index b6f5e091a782..8de45eb88b84 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs @@ -9,23 +9,118 @@ use swc_core::{ proxies::TransformPluginProgramMetadata } }; +use crate::visitors::common::{ COMPILE_MODE_SUB_COMPONENT, ArrowAndFnParams }; + use super::common::RenderFn; -pub struct CollectRenderFnVisitor<'a> { - pub raw_render_fn_map: &'a mut HashMap>, - pub component_name:String, +pub struct CollectRenderFnVisitor { + pub raw_render_fn_map: HashMap, + sub_component_name: Option, + sub_component_params: Option, + in_outmost_block_scope: bool, } -impl<'a> CollectRenderFnVisitor<'a> { - pub fn new(raw_render_fn_map: &'a mut HashMap>, component_name: String) -> Self { - raw_render_fn_map.insert(component_name.clone(), HashMap::new()); +impl CollectRenderFnVisitor { + pub fn new() -> Self { CollectRenderFnVisitor { - raw_render_fn_map, - component_name + raw_render_fn_map: HashMap::new(), + sub_component_name: None, + sub_component_params: None, + in_outmost_block_scope: true } } } +//只在最外层找就可以了,因为这个函数是一个 react 组件的入口 +impl VisitMut for CollectRenderFnVisitor { + fn visit_mut_block_stmt(&mut self, n: &mut BlockStmt) { + if !self.in_outmost_block_scope { + return; + } + for stmt in &mut n.stmts { + match stmt { + Stmt::Decl(Decl::Fn(fn_decl)) => { + // 适配 function xxx() {} + let component_name = fn_decl.ident.sym.to_string(); + // todo 需要调整 + let is_valid_sub_component = component_name.starts_with("render"); + match ((*fn_decl).function.body.as_mut(), is_valid_sub_component) { + (Some(block_stmt), true) => { + for stmt in &mut block_stmt.stmts { + match stmt { + Stmt::Return(return_stmt) => { + self.in_outmost_block_scope = true; + self.sub_component_name = Some(component_name.clone()); + self.sub_component_params = Some(ArrowAndFnParams::Fn(fn_decl.function.params.clone())); + return_stmt.visit_mut_with(self); + self.in_outmost_block_scope = false; + self.sub_component_name = None; + self.sub_component_params = None; + }, + _ => {} + } + } + }, + _ => {} + } + }, + Stmt::Decl(Decl::Var(var_dec))=>{ + for decl in &mut var_dec.decls { + let sub_component_name = &decl.name; + match (&mut decl.init, sub_component_name) { + (Some(expr), Pat::Ident(sub_component_name)) => { + if let Expr::Arrow(arrow) = &mut **expr { + if let BlockStmtOrExpr::BlockStmt(block_stmt) = &mut *arrow.body { + for stmt in &mut block_stmt.stmts { + match stmt { + Stmt::Return(return_stmt) => { + self.in_outmost_block_scope = true; + self.sub_component_name = Some(sub_component_name.sym.to_string()); + self.sub_component_params = Some(ArrowAndFnParams::Arrow(arrow.params.clone())); + return_stmt.visit_mut_with(self); + self.in_outmost_block_scope = false; + self.sub_component_name = None; + self.sub_component_params = None; + }, + _ => {} + } + } + } + } + }, + _ =>{} + } + } + } + _ => {} + } + } + self.in_outmost_block_scope = false + } -impl VisitMut for CollectRenderFnVisitor<'_> { - // 先找到入口,首先函数名必须是大写的,然后返回值必须是 jsx 这样才是一个 react 组件 + fn visit_mut_return_stmt(&mut self, n: &mut ReturnStmt) { + match (self.in_outmost_block_scope, &n.arg) { + (true, Some(arg))=>{ + match &**arg { + Expr::Paren(paren_expr)=>{ + if let Expr::JSXElement(jsx_element) = &*paren_expr.expr { + for attr in &jsx_element.opening.attrs { + if let JSXAttrOrSpread::JSXAttr(jsx_attr) = attr { + if let JSXAttrName::Ident(jsx_attr_name) = &jsx_attr.name { + match (jsx_attr_name.sym == COMPILE_MODE_SUB_COMPONENT, &self.sub_component_name, &self.sub_component_params) { + (true, Some(sub_component_name), Some(sub_component_params)) => { + self.raw_render_fn_map.insert(sub_component_name.clone(), RenderFn::new(sub_component_params.clone(), *jsx_element.clone())); + }, + _ => {} + } + } + } + } + } + }, + _ => {} + } + }, + _ => {} + } + } } diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/common.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/common.rs index 6fc77630783c..cb70c1cc44f9 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/common.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/common.rs @@ -1,5 +1,5 @@ -use std::collections::HashMap; +use std::{clone, collections::HashMap}; use swc_core::{ ecma::{ @@ -12,13 +12,27 @@ use swc_core::{ } }; +use super::is_compile_mode_component::IsCompileModeVisitor; + + +pub const COMPILE_MODE: &str = "compileMode"; pub const DEFAULT_COMPONENT: &str = "Default_Component"; +pub const COMPILE_MODE_SUB_COMPONENT: &str = "compileModeSubComponent"; pub struct RenderFn { - pub params: Vec, + pub params: ArrowAndFnParams, pub jsx_element: JSXElement, } +impl RenderFn { + pub fn new(params: ArrowAndFnParams, jsx_element: JSXElement) -> Self { + RenderFn { + params, + jsx_element, + } + } +} + impl Clone for RenderFn { fn clone(&self) -> Self { RenderFn { @@ -28,6 +42,19 @@ impl Clone for RenderFn { } } +pub enum ArrowAndFnParams { + Arrow(Vec), + Fn(Vec), +} + +impl clone::Clone for ArrowAndFnParams { + fn clone(&self) -> Self { + match self { + ArrowAndFnParams::Arrow(params) => ArrowAndFnParams::Arrow(params.clone()), + ArrowAndFnParams::Fn(params) => ArrowAndFnParams::Fn(params.clone()), + } + } +} pub struct ReactComponent { pub name: String, @@ -55,10 +82,14 @@ impl ReactComponent { self.name.clone() } - pub fn is_valid (&self) -> bool { + pub fn is_valid (&mut self) -> bool { // 1. 名称是否是大写字母开头 let is_first_char_uppercase = self.get_name().chars().next().unwrap().is_uppercase(); - is_first_char_uppercase - //todo 2. 返回的 JSX 里面有没有 compilerMode + // 2. 返回的 JSX 里面有没有 compilerMode + let mut is_compile_mode_component: IsCompileModeVisitor = IsCompileModeVisitor::new(); + if let Some(block_stmt) = &mut self.block_stmt { + block_stmt.visit_mut_with(&mut is_compile_mode_component); + } + is_first_char_uppercase && is_compile_mode_component.valid } } \ No newline at end of file diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs index 466ef416c598..d0cb10b8901b 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs @@ -22,16 +22,16 @@ pub struct EntryVisitor { struct VisitorContext { react_component_list: Vec, - raw_render_fn_map: HashMap>, - formatted_render_fn_map: HashMap>, + react_component_raw_render_fn_map: HashMap>, + react_component_formatted_render_fn_map: HashMap>, } impl EntryVisitor { pub fn new(config: PluginConfig) -> Self { EntryVisitor { visitor_context: VisitorContext { - raw_render_fn_map: HashMap::new(), - formatted_render_fn_map: HashMap::new(), + react_component_raw_render_fn_map: HashMap::new(), + react_component_formatted_render_fn_map: HashMap::new(), react_component_list: vec![], } } @@ -57,21 +57,31 @@ impl EntryVisitor { let mut find_react_component_visitor = FindReactComponentVisitor::new(&mut self.visitor_context.react_component_list); n.visit_mut_children_with(&mut find_react_component_visitor); // 必须要合法的 react 组件才能继续往下走 - let valid_react_component_list = self.visitor_context.react_component_list.clone().into_iter().filter(|react_component| react_component.is_valid()).collect(); + let mut valid_react_component_list = vec![]; + self.visitor_context.react_component_list.clone().into_iter().for_each(| mut react_component| { + if react_component.is_valid() { + valid_react_component_list.push(react_component); + } + }); self.visitor_context.react_component_list = valid_react_component_list; } fn collect_each_component_render_fn (&mut self) { // 遍历每一个 react 组件,找到他们的 render 函数并收集起来 self.visitor_context.react_component_list.clone().into_iter().for_each(|mut react_component| { - let mut collect_render_fn_visitor = CollectRenderFnVisitor::new(&mut self.visitor_context.raw_render_fn_map, react_component.get_name()); - react_component.block_stmt.visit_mut_children_with(&mut collect_render_fn_visitor); + let mut collect_render_fn_visitor = CollectRenderFnVisitor::new(); + react_component.block_stmt.visit_mut_with(&mut collect_render_fn_visitor); + + collect_render_fn_visitor.raw_render_fn_map.clone().into_iter().for_each(|(name, render_fn)| { + println!("fuck name: {}", name); + }); + self.visitor_context.react_component_raw_render_fn_map.insert(react_component.get_name(), collect_render_fn_visitor.raw_render_fn_map.clone()); }); } fn transform_render_fn (&mut self) { let mut formatted_render_fn_map: HashMap> = HashMap::new(); - self.visitor_context.raw_render_fn_map.clone().into_iter().for_each(|(name, raw_fn_map)| { + self.visitor_context.react_component_raw_render_fn_map.clone().into_iter().for_each(|(name, raw_fn_map)| { // 1. 可能存在互相引用,得梳理一下他们之间的依赖关系 数据结构 hashMap:{name:[dep1, dep2,...]} let render_fn_deps_map = generate_render_fn_dep_map(&raw_fn_map); // 2. 根据依赖表,生成解析的列表 sort queue 先进先出 @@ -80,11 +90,11 @@ impl EntryVisitor { let formatted_fn_map = generate_formatted_fn_map(sort_queue, &raw_fn_map); formatted_render_fn_map.insert(name, formatted_fn_map); }); - self.visitor_context.formatted_render_fn_map = formatted_render_fn_map; + self.visitor_context.react_component_formatted_render_fn_map = formatted_render_fn_map; } fn transform (&mut self, n: &mut Module) { - let mut transform_visitor = ComponentEntryVisitor::new(&self.visitor_context.formatted_render_fn_map); + let mut transform_visitor = ComponentEntryVisitor::new(&self.visitor_context.react_component_formatted_render_fn_map); n.visit_mut_children_with(&mut transform_visitor); } } diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/find_react_component.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/find_react_component.rs index 7ae0694513c8..2f93487ead7b 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/find_react_component.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/find_react_component.rs @@ -1,14 +1,5 @@ -use std::collections::HashMap; - -use serde_json::de; -use swc_core::{ - ecma::{ - ast::*, utils::function, visit::{VisitMut, VisitMutWith} - }, - plugin::{ - plugin_transform, - proxies::TransformPluginProgramMetadata - } +use swc_core::ecma::{ + ast::*, visit::VisitMut }; use super::common::{ReactComponent, DEFAULT_COMPONENT}; diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/is_compile_mode_component.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/is_compile_mode_component.rs new file mode 100644 index 000000000000..6d6855bcee84 --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/is_compile_mode_component.rs @@ -0,0 +1,67 @@ +use std::collections::HashMap; + +use serde_json::de; +use swc_core::{ + ecma::{ + ast::*, utils::function, visit::{VisitMut, VisitMutWith} + }, + plugin::{ + plugin_transform, + proxies::TransformPluginProgramMetadata + } +}; + +use super::common::COMPILE_MODE; + +pub struct IsCompileModeVisitor { + pub valid: bool, + in_component_return_block: bool, + in_outmost_block_scope: bool, +} + +impl IsCompileModeVisitor { + pub fn new() -> Self { + IsCompileModeVisitor { + valid: false, + in_component_return_block: false, + in_outmost_block_scope: true, + } + } +} + +impl VisitMut for IsCompileModeVisitor { + fn visit_mut_block_stmt(&mut self,n: &mut BlockStmt) { + if !self.in_outmost_block_scope { + return; + } + for stmt in &mut n.stmts { + match stmt { + Stmt::Return(return_stmt) => { + self.in_component_return_block = true; + return_stmt.visit_mut_children_with(self); + self.in_component_return_block = false; + }, + _ => {} + } + } + self.in_outmost_block_scope = false + } + + fn visit_mut_jsx_element(&mut self, el: &mut JSXElement) { + if self.in_component_return_block && !self.valid { + for attr in &mut el.opening.attrs { + if let JSXAttrOrSpread::JSXAttr(jsx_attr) = attr { + if let JSXAttrName::Ident(jsx_attr_name) = &jsx_attr.name { + if jsx_attr_name.sym == COMPILE_MODE { + self.valid = true; + println!("valid component!\n"); + break; + } + } + } + } + el.visit_mut_children_with(self); + } + + } +} \ No newline at end of file diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/mod.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/mod.rs index 7f2f4264e1e7..216ebfd482d1 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/mod.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/mod.rs @@ -2,4 +2,5 @@ pub mod entry; pub mod common; pub mod collect_render_fn; pub mod find_react_component; -pub mod transform; \ No newline at end of file +pub mod transform; +pub mod is_compile_mode_component; \ No newline at end of file diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/component_entry.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/component_entry.rs index 58499b721bff..9deddeb1091d 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/component_entry.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/component_entry.rs @@ -101,7 +101,7 @@ impl<'a> VisitMut for ComponentEntryVisitor<'a> { match &mut *n.expr { // 适配 export default () => {} Expr::Arrow(arrow_expr) => { - if let BlockStmtOrExpr::BlockStmt(_block_stmt) = *arrow_expr.body.clone() { + if let BlockStmtOrExpr::BlockStmt(_block_stmt) = &*arrow_expr.body { let render_fn_map = self.get_format_render_fn_map_by_component_name(&DEFAULT_COMPONENT.to_string()); if let Some(render_fn_map) = render_fn_map { let mut process_visitor = TransformProcessVisitor::new(DEFAULT_COMPONENT.to_string(), &render_fn_map); From db36eca80581d6375ac9b5dbfe5be95b5e36b138 Mon Sep 17 00:00:00 2001 From: liuzejia Date: Sat, 14 Sep 2024 17:44:19 +0800 Subject: [PATCH 06/29] =?UTF-8?q?feat:=20=E6=8B=93=E6=89=91=E7=AE=97?= =?UTF-8?q?=E6=B3=95=E8=BE=93=E5=87=BA=E4=BE=9D=E8=B5=96=E9=A1=BA=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/visitors/collect_render_fn.rs | 14 ++++ .../src/visitors/entry.rs | 70 +++++++++++++++---- .../src/visitors/generate_deps.rs | 52 ++++++++++++++ .../src/visitors/mod.rs | 3 +- 4 files changed, 126 insertions(+), 13 deletions(-) create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/visitors/generate_deps.rs diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs index 8de45eb88b84..b30e4434f0b8 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs @@ -117,6 +117,20 @@ impl VisitMut for CollectRenderFnVisitor { } } }, + Expr::JSXElement(jsx_element)=>{ + for attr in &jsx_element.opening.attrs { + if let JSXAttrOrSpread::JSXAttr(jsx_attr) = attr { + if let JSXAttrName::Ident(jsx_attr_name) = &jsx_attr.name { + match (jsx_attr_name.sym == COMPILE_MODE_SUB_COMPONENT, &self.sub_component_name, &self.sub_component_params) { + (true, Some(sub_component_name), Some(sub_component_params)) => { + self.raw_render_fn_map.insert(sub_component_name.clone(), RenderFn::new(sub_component_params.clone(), *jsx_element.clone())); + }, + _ => {} + } + } + } + } + }, _ => {} } }, diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs index d0cb10b8901b..c2a8d34fb7bf 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet, VecDeque}; use swc_core::{ ecma::{ @@ -12,7 +12,7 @@ use swc_core::{ }; use crate::{visitors::find_react_component, PluginConfig}; -use super::{common::*, transform}; +use super::{common::*, generate_deps::{self, GenerateDepsVisitor}, transform}; use super::collect_render_fn::CollectRenderFnVisitor; use super::find_react_component::FindReactComponentVisitor; use super::transform::component_entry::ComponentEntryVisitor; @@ -72,8 +72,9 @@ impl EntryVisitor { let mut collect_render_fn_visitor = CollectRenderFnVisitor::new(); react_component.block_stmt.visit_mut_with(&mut collect_render_fn_visitor); - collect_render_fn_visitor.raw_render_fn_map.clone().into_iter().for_each(|(name, render_fn)| { - println!("fuck name: {}", name); + // debug + collect_render_fn_visitor.raw_render_fn_map.clone().into_iter().for_each(|(name, _render_fn)| { + println!("component name: {}, renderFnName{}\n", react_component.get_name(), name); }); self.visitor_context.react_component_raw_render_fn_map.insert(react_component.get_name(), collect_render_fn_visitor.raw_render_fn_map.clone()); }); @@ -84,8 +85,14 @@ impl EntryVisitor { self.visitor_context.react_component_raw_render_fn_map.clone().into_iter().for_each(|(name, raw_fn_map)| { // 1. 可能存在互相引用,得梳理一下他们之间的依赖关系 数据结构 hashMap:{name:[dep1, dep2,...]} let render_fn_deps_map = generate_render_fn_dep_map(&raw_fn_map); + + for (fn_name, deps) in &render_fn_deps_map { + println!("component_name: {}, fn_name: {} deps: {:?}", name, fn_name, deps); + } + // 2. 根据依赖表,生成解析的列表 sort queue 先进先出 let sort_queue = generate_sort_queue(&render_fn_deps_map); + println!("component_name: {}, sort_queue: {:?}", name, sort_queue); // 3. 根据 sort queue 生成 formatted_fn_map 数据结构 hashMap:{name: formatted_fn} let formatted_fn_map = generate_formatted_fn_map(sort_queue, &raw_fn_map); formatted_render_fn_map.insert(name, formatted_fn_map); @@ -102,21 +109,38 @@ impl EntryVisitor { fn generate_render_fn_dep_map (raw_fn_map: &HashMap)-> HashMap> { let mut render_fn_deps_map = HashMap::new(); for (name, render_fn) in raw_fn_map { - let mut deps: Vec = vec![]; - let cloned_jsx_element = render_fn.jsx_element.clone(); - // @todo use visitor to collect deps - render_fn_deps_map.insert(name.clone(), deps); + let mut cloned_jsx_element = render_fn.jsx_element.clone(); + let mut generate_deps_visitor = GenerateDepsVisitor::new(raw_fn_map, name.clone()); + cloned_jsx_element.visit_mut_with(&mut generate_deps_visitor); + let deps = generate_deps_visitor.deps_list.clone(); + if generate_deps_visitor.self_loop { + println!("self loop found in render function: {}", name); + } else { + render_fn_deps_map.insert(name.clone(), deps); + } + } // todo:通过 visitor 收集依赖,只能收集到最表层的依赖,如果有嵌套的依赖,需要递归处理,可能会出现循环,如果出现循环的话,按么循环的那两个组件都要去掉 也是数据结构算法 render_fn_deps_map } fn generate_sort_queue (render_fn_deps_map: &HashMap>) -> Vec { - let mut sort_queue = vec![]; - for (name, deps) in render_fn_deps_map { - // todo 完全的数据结构算法 + let mut visited = HashSet::new(); + let mut result = VecDeque::new(); + let mut cycles = Vec::new(); + + for key in render_fn_deps_map.keys() { + let mut path = Vec::new(); + if dfs(key, render_fn_deps_map, &mut visited, &mut path, &mut result, &mut cycles) { + cycles.push(path); + } + } + + for cycle in cycles { + println!("Detected cycle: {:?}", cycle); } - sort_queue + + result.into_iter().collect() } fn generate_formatted_fn_map (sort_queue: Vec, raw_fn_map: &HashMap) -> HashMap { @@ -131,4 +155,26 @@ fn generate_formatted_fn_map (sort_queue: Vec, raw_fn_map: &HashMap>, visited: &mut HashSet, path: &mut Vec, result: &mut VecDeque, cycles: &mut Vec>) -> bool { + if path.contains(node) { + return true; + } else if !visited.contains(node) { + visited.insert(node.clone()); + path.push(node.clone()); + + if let Some(neighbors) = map.get(node) { + for neighbor in neighbors { + if dfs(neighbor, map, visited, path, result, cycles) { + return true; + } + } + } + + path.pop(); + result.push_back(node.clone()); + } + + false } \ No newline at end of file diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/generate_deps.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/generate_deps.rs new file mode 100644 index 000000000000..c21501de10fb --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/generate_deps.rs @@ -0,0 +1,52 @@ +use std::collections::HashMap; +use swc_core::{ + ecma::{ + ast::*, + visit::{VisitMutWith, VisitMut}, + }, + plugin::{ + plugin_transform, + proxies::TransformPluginProgramMetadata + } +}; +use crate::visitors::common::{ COMPILE_MODE_SUB_COMPONENT, ArrowAndFnParams }; + +use super::common::RenderFn; + +pub struct GenerateDepsVisitor<'a> { + raw_fn_map: &'a HashMap, + fn_name: String, + pub self_loop: bool, + pub deps_list: Vec, +} + +impl<'a> GenerateDepsVisitor<'a> { + pub fn new(raw_fn_map: &'a HashMap, fn_name: String) -> Self { + GenerateDepsVisitor { + raw_fn_map, + fn_name, + self_loop: false, + deps_list: vec![], + } + } +} + +impl VisitMut for GenerateDepsVisitor<'_> { + fn visit_mut_call_expr(&mut self, n: &mut CallExpr) { + if self.self_loop { + return; + } + if let Callee::Expr(expr) = &n.callee { + if let Expr::Ident(ident) = &**expr { + if ident.sym.to_string() == self.fn_name { + self.self_loop = true; + } + if self.raw_fn_map.contains_key(&ident.sym.to_string()) && !self.deps_list.contains(&ident.sym.to_string()) { + self.deps_list.push(ident.sym.to_string()); + } + } + } + + n.visit_mut_children_with(self); + } +} \ No newline at end of file diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/mod.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/mod.rs index 216ebfd482d1..d453900c23d8 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/mod.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/mod.rs @@ -3,4 +3,5 @@ pub mod common; pub mod collect_render_fn; pub mod find_react_component; pub mod transform; -pub mod is_compile_mode_component; \ No newline at end of file +pub mod is_compile_mode_component; +pub mod generate_deps; \ No newline at end of file From 0bffcc0e0cb7865ea3e5a03a5056380cd4495e42 Mon Sep 17 00:00:00 2001 From: liuzejia Date: Mon, 23 Sep 2024 19:27:50 +0800 Subject: [PATCH 07/29] chore(release): publish 4.0.6-alpha.0 --tag=alpha --- crates/native_binding/package.json | 2 +- .../src/tests/entry.rs | 117 ++++++++++++++++ .../src/tests/render.rs | 126 ++++++++++++++++++ .../tests/entry.rs/should_support_arrow_fn.js | 10 ++ .../should_support_default_export_arrow_fn.js | 10 ++ .../should_support_default_export_fn.js | 10 ++ .../should_support_export_arrow_fn.js | 10 ++ .../entry.rs/should_support_export_fn.js | 10 ++ .../src/tests/entry.rs/should_support_fn.js | 10 ++ .../render.rs/should_render_with_recursion.js | 75 +++++++++++ .../should_render_with_sub_component_attr.js | 31 +++++ npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-x64-gnu/package.json | 2 +- npm/linux-x64-musl/package.json | 2 +- npm/win32-x64-msvc/package.json | 2 +- package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- packages/babel-preset-taro/package.json | 2 +- packages/create-app/package.json | 2 +- packages/css-to-react-native/package.json | 2 +- packages/eslint-config-taro/package.json | 2 +- packages/jest-helper/package.json | 2 +- packages/postcss-html-transform/package.json | 2 +- .../postcss-plugin-constparse/package.json | 2 +- packages/postcss-pxtransform/package.json | 2 +- packages/postcss-unit-transform/package.json | 2 +- packages/rollup-plugin-copy/package.json | 2 +- packages/shared/package.json | 2 +- .../stylelint-config-taro-rn/package.json | 2 +- packages/stylelint-taro-rn/package.json | 2 +- packages/stylelint-taro/package.json | 2 +- packages/taro-api/package.json | 2 +- packages/taro-cli-convertor/package.json | 2 +- packages/taro-cli/package.json | 2 +- .../taro-components-advanced/package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- .../taro-components-library-vue3/package.json | 2 +- packages/taro-components-react/package.json | 2 +- packages/taro-components-rn/package.json | 2 +- packages/taro-components/package.json | 2 +- packages/taro-extend/package.json | 2 +- packages/taro-framework-react/package.json | 2 +- packages/taro-framework-solid/package.json | 2 +- packages/taro-framework-vue3/package.json | 2 +- packages/taro-h5/package.json | 2 +- packages/taro-helper/package.json | 2 +- packages/taro-loader/package.json | 2 +- packages/taro-platform-alipay/package.json | 2 +- packages/taro-platform-h5/package.json | 2 +- .../taro-platform-harmony-hybrid/package.json | 2 +- packages/taro-platform-harmony/package.json | 2 +- packages/taro-platform-jd/package.json | 2 +- packages/taro-platform-qq/package.json | 2 +- packages/taro-platform-swan/package.json | 2 +- packages/taro-platform-tt/package.json | 2 +- packages/taro-platform-weapp/package.json | 2 +- packages/taro-plugin-html/package.json | 2 +- packages/taro-plugin-http/package.json | 2 +- packages/taro-plugin-inject/package.json | 2 +- packages/taro-plugin-mini-ci/package.json | 2 +- .../taro-plugin-react-devtools/package.json | 2 +- .../taro-plugin-vue-devtools/package.json | 2 +- packages/taro-react/package.json | 2 +- packages/taro-rn-runner/package.json | 2 +- .../taro-rn-style-transformer/package.json | 2 +- packages/taro-rn-supporter/package.json | 2 +- packages/taro-rn-transformer/package.json | 2 +- packages/taro-rn/package.json | 2 +- packages/taro-router-rn/package.json | 2 +- packages/taro-router/package.json | 2 +- packages/taro-runner-utils/package.json | 2 +- packages/taro-runtime-rn/package.json | 2 +- packages/taro-runtime/package.json | 2 +- packages/taro-service/package.json | 2 +- packages/taro-transformer-wx/package.json | 2 +- packages/taro-vite-runner/package.json | 2 +- packages/taro-webpack5-prebundle/package.json | 2 +- packages/taro-webpack5-runner/package.json | 2 +- packages/taro-with-weapp/package.json | 2 +- packages/taro/package.json | 2 +- packages/taroize/package.json | 2 +- 85 files changed, 484 insertions(+), 75 deletions(-) create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/tests/entry.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/tests/render.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_arrow_fn.js create mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_default_export_arrow_fn.js create mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_default_export_fn.js create mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_export_arrow_fn.js create mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_export_fn.js create mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_fn.js create mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/render.rs/should_render_with_recursion.js create mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/render.rs/should_render_with_sub_component_attr.js diff --git a/crates/native_binding/package.json b/crates/native_binding/package.json index 9e43f42970b4..cc92d6a0a859 100644 --- a/crates/native_binding/package.json +++ b/crates/native_binding/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/binding", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Node binding for taro", "main": "binding.js", "typings": "binding.d.ts", diff --git a/crates/swc_plugin_compile_mode_pre_process/src/tests/entry.rs b/crates/swc_plugin_compile_mode_pre_process/src/tests/entry.rs new file mode 100644 index 000000000000..6fc455b80fee --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/src/tests/entry.rs @@ -0,0 +1,117 @@ +use swc_core::ecma::transforms::testing::test; + +use super::{get_syntax_config, tr}; + +test!( + get_syntax_config(), + |_| tr(), + should_support_default_export_fn, + r#" + export default function Index () { + function renderA () { + return ComponentA + } + + return ( + + {renderA()} + + ) + } + "# +); + +test!( + get_syntax_config(), + |_| tr(), + should_support_default_export_arrow_fn, + r#" + export default () => { + function renderA () { + return ComponentA + } + + return ( + + {renderA()} + + ) + } + "# +); + +test!( + get_syntax_config(), + |_| tr(), + should_support_export_arrow_fn, + r#" + export const ComponentA = () => { + function renderA () { + return ComponentA + } + + return ( + + {renderA()} + + ) + } + "# +); + +test!( + get_syntax_config(), + |_| tr(), + should_support_export_fn, + r#" + export function ComponentA () { + function renderA () { + return ComponentA + } + + return ( + + {renderA()} + + ) + } + "# +); + +test!( + get_syntax_config(), + |_| tr(), + should_support_fn, + r#" + function ComponentA () { + function renderA () { + return ComponentA + } + + return ( + + {renderA()} + + ) + } + "# +); + +test!( + get_syntax_config(), + |_| tr(), + should_support_arrow_fn, + r#" + const ComponentA = () => { + function renderA () { + return ComponentA + } + + return ( + + {renderA()} + + ) + } + "# +); \ No newline at end of file diff --git a/crates/swc_plugin_compile_mode_pre_process/src/tests/render.rs b/crates/swc_plugin_compile_mode_pre_process/src/tests/render.rs new file mode 100644 index 000000000000..b4afe9e88574 --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/src/tests/render.rs @@ -0,0 +1,126 @@ +use swc_core::ecma::transforms::testing::test; + +use super::{get_syntax_config, tr}; + +test!( + get_syntax_config(), + |_| tr(), + should_render_with_sub_component_attr, + r#" + export default function Index () { + function renderB () { + return ComponentB + } + + function renderA () { + return + ComponentA + {renderB()} + + } + + return ( + + + {renderA()} + {renderB()} + + + ) + } + "# +); + +test!( + get_syntax_config(), + |_| tr(), + should_render_with_recursion, + r#" + export default function Index () { + function renderB () { + return ComponentB + } + + function renderC () { + return + ComponentC + {renderB()} + {renderA()} + + } + + function renderD () { + return + ComponentD + {renderB()} + + } + + function renderA () { + return + ComponentA + {renderB()} + + } + + return ( + + + {renderA()} + {renderB()} + {renderC()} + {renderD()} + + + ) + } + "# +); + +test!( + get_syntax_config(), + |_| tr(), + should_not_render_with_circle_recursion, + r#" + export default function Index () { + function renderB () { + return + ComponentB + {renderA()} + + } + + function renderC () { + return + ComponentC + {renderA()} + + } + + function renderD () { + return + ComponentD + {renderC()} + + } + + function renderA () { + return + ComponentA + {renderB()} + + } + + return ( + + + {renderA()} + {renderB()} + {renderC()} + {renderD()} + + + ) + } + "# +); diff --git a/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_arrow_fn.js b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_arrow_fn.js new file mode 100644 index 000000000000..0461f300d7de --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_arrow_fn.js @@ -0,0 +1,10 @@ +const ComponentA = ()=>{ + function renderA() { + return ComponentA ; + } + return + + { ComponentA } + + ; +}; diff --git a/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_default_export_arrow_fn.js b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_default_export_arrow_fn.js new file mode 100644 index 000000000000..d240d7d47deb --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_default_export_arrow_fn.js @@ -0,0 +1,10 @@ +export default (()=>{ + function renderA() { + return ComponentA ; + } + return + + { ComponentA } + + ; +}); diff --git a/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_default_export_fn.js b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_default_export_fn.js new file mode 100644 index 000000000000..112fb93bc825 --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_default_export_fn.js @@ -0,0 +1,10 @@ +export default function Index() { + function renderB() { + return ComponentA ; + } + return + + { ComponentA } + + ; +} diff --git a/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_export_arrow_fn.js b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_export_arrow_fn.js new file mode 100644 index 000000000000..4026d641fd72 --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_export_arrow_fn.js @@ -0,0 +1,10 @@ +export const ComponentA = ()=>{ + function renderA() { + return ComponentA ; + } + return + + { ComponentA } + + ; +}; diff --git a/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_export_fn.js b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_export_fn.js new file mode 100644 index 000000000000..74757ccd6e49 --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_export_fn.js @@ -0,0 +1,10 @@ +export function ComponentA() { + function renderA() { + return ComponentA ; + } + return + + { ComponentA } + + ; +} diff --git a/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_fn.js b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_fn.js new file mode 100644 index 000000000000..3877b1c1ee19 --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_fn.js @@ -0,0 +1,10 @@ +function ComponentA() { + function renderA() { + return ComponentA ; + } + return + + { ComponentA } + + ; +} diff --git a/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/render.rs/should_render_with_recursion.js b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/render.rs/should_render_with_recursion.js new file mode 100644 index 000000000000..bf74b3eb9df2 --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/render.rs/should_render_with_recursion.js @@ -0,0 +1,75 @@ +export default function Index() { + function renderB() { + return ComponentB ; + } + function renderC() { + return + + ComponentC + + {renderB()} + + {renderA()} + + ; + } + function renderD() { + return + + ComponentD + + {renderB()} + + ; + } + function renderA() { + return + + ComponentA + + {renderB()} + + ; + } + return + + + + { + + ComponentA + + { ComponentB } + + } + + { ComponentB } + + { + + ComponentC + + { ComponentB } + + { + + ComponentA + + { ComponentB } + + } + + } + + { + + ComponentD + + { ComponentB } + + } + + + + ; +} diff --git a/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/render.rs/should_render_with_sub_component_attr.js b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/render.rs/should_render_with_sub_component_attr.js new file mode 100644 index 000000000000..84f235c1f7bb --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/render.rs/should_render_with_sub_component_attr.js @@ -0,0 +1,31 @@ +export default function Index() { + function renderB() { + return ComponentB ; + } + function renderA() { + return + + ComponentA + + {renderB()} + + ; + } + return + + + + { + + ComponentA + + {renderB()} + + } + + {renderB()} + + + + ; +} diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index bb2f619226bb..511891612301 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -1,7 +1,7 @@ { "name": "@tarojs/binding-darwin-arm64", "description": "Native binding for taro", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "os": [ "darwin" ], diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index d530b07467d8..cdf330a53647 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -1,7 +1,7 @@ { "name": "@tarojs/binding-darwin-x64", "description": "Native binding for taro", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "os": [ "darwin" ], diff --git a/npm/linux-x64-gnu/package.json b/npm/linux-x64-gnu/package.json index 8138b9a626e9..3e1ba56ca2a7 100644 --- a/npm/linux-x64-gnu/package.json +++ b/npm/linux-x64-gnu/package.json @@ -1,7 +1,7 @@ { "name": "@tarojs/binding-linux-x64-gnu", "description": "Native binding for taro", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "os": [ "linux" ], diff --git a/npm/linux-x64-musl/package.json b/npm/linux-x64-musl/package.json index 513a39b1ffa3..26e839349dfb 100644 --- a/npm/linux-x64-musl/package.json +++ b/npm/linux-x64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/binding-linux-x64-musl", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "os": [ "linux" ], diff --git a/npm/win32-x64-msvc/package.json b/npm/win32-x64-msvc/package.json index 38233bd308e8..0a2b21a2f4bc 100644 --- a/npm/win32-x64-msvc/package.json +++ b/npm/win32-x64-msvc/package.json @@ -1,7 +1,7 @@ { "name": "@tarojs/binding-win32-x64-msvc", "description": "Native binding for taro", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "os": [ "win32" ], diff --git a/package.json b/package.json index af46677b6e0f..e2d4c238252f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "taro", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "开放式跨端跨框架开发解决方案", "homepage": "https://github.com/NervJS/taro#readme", "author": "O2Team", diff --git a/packages/babel-plugin-transform-react-jsx-to-rn-stylesheet/package.json b/packages/babel-plugin-transform-react-jsx-to-rn-stylesheet/package.json index 52822a4286e7..6ed1c69a1131 100644 --- a/packages/babel-plugin-transform-react-jsx-to-rn-stylesheet/package.json +++ b/packages/babel-plugin-transform-react-jsx-to-rn-stylesheet/package.json @@ -1,6 +1,6 @@ { "name": "babel-plugin-transform-react-jsx-to-rn-stylesheet", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Transform stylesheet selector to style in JSX Elements.", "author": "O2Team", "license": "MIT", diff --git a/packages/babel-plugin-transform-solid-jsx/package.json b/packages/babel-plugin-transform-solid-jsx/package.json index 276229988028..442a20bb7383 100644 --- a/packages/babel-plugin-transform-solid-jsx/package.json +++ b/packages/babel-plugin-transform-solid-jsx/package.json @@ -1,7 +1,7 @@ { "name": "babel-plugin-transform-solid-jsx", "description": "A JSX to DOM plugin that wraps expressions for fine grained change detection", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "license": "MIT", "repository": { "type": "git", diff --git a/packages/babel-plugin-transform-taroapi/package.json b/packages/babel-plugin-transform-taroapi/package.json index a3f8f4f58fc7..2bbcf49b8b20 100644 --- a/packages/babel-plugin-transform-taroapi/package.json +++ b/packages/babel-plugin-transform-taroapi/package.json @@ -1,6 +1,6 @@ { "name": "babel-plugin-transform-taroapi", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "author": "O2Team", "license": "MIT", "main": "dist/index.js", diff --git a/packages/babel-preset-taro/package.json b/packages/babel-preset-taro/package.json index 84e3b42bec72..0abb33b1dfe5 100644 --- a/packages/babel-preset-taro/package.json +++ b/packages/babel-preset-taro/package.json @@ -1,6 +1,6 @@ { "name": "babel-preset-taro", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro babel preset", "author": "O2Team", "license": "MIT", diff --git a/packages/create-app/package.json b/packages/create-app/package.json index af8c0778cb9e..39db9e0fb424 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/create-app", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "create taro app with one command", "author": "O2Team", "license": "MIT", diff --git a/packages/css-to-react-native/package.json b/packages/css-to-react-native/package.json index 5ee2c7907979..bd4255457a5e 100644 --- a/packages/css-to-react-native/package.json +++ b/packages/css-to-react-native/package.json @@ -1,7 +1,7 @@ { "name": "taro-css-to-react-native", "description": "Convert CSS text to a React Native stylesheet object", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "author": "O2Team", "license": "MIT", "main": "dist/index.js", diff --git a/packages/eslint-config-taro/package.json b/packages/eslint-config-taro/package.json index 26f8999d8474..858c3c93ebf0 100644 --- a/packages/eslint-config-taro/package.json +++ b/packages/eslint-config-taro/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-taro", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro specific linting rules for ESLint", "author": "O2Team", "license": "MIT", diff --git a/packages/jest-helper/package.json b/packages/jest-helper/package.json index 3cd22caf21d6..ffe25c91395c 100644 --- a/packages/jest-helper/package.json +++ b/packages/jest-helper/package.json @@ -1,6 +1,6 @@ { "name": "jest-taro-helper", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "jest helper for taro", "private": true, "author": "O2Team", diff --git a/packages/postcss-html-transform/package.json b/packages/postcss-html-transform/package.json index 290b61d3eb76..3c2517a8c4af 100644 --- a/packages/postcss-html-transform/package.json +++ b/packages/postcss-html-transform/package.json @@ -1,6 +1,6 @@ { "name": "postcss-html-transform", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "transform html tag name selector", "author": "O2Team", "license": "MIT", diff --git a/packages/postcss-plugin-constparse/package.json b/packages/postcss-plugin-constparse/package.json index 2f623b612b98..bf883f6b2909 100644 --- a/packages/postcss-plugin-constparse/package.json +++ b/packages/postcss-plugin-constparse/package.json @@ -1,6 +1,6 @@ { "name": "postcss-plugin-constparse", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "parse constants defined in config", "author": "O2Team", "license": "MIT", diff --git a/packages/postcss-pxtransform/package.json b/packages/postcss-pxtransform/package.json index 21ff9b201b3f..a9894b27b0b4 100644 --- a/packages/postcss-pxtransform/package.json +++ b/packages/postcss-pxtransform/package.json @@ -1,6 +1,6 @@ { "name": "postcss-pxtransform", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "PostCSS plugin px 转小程序 rpx及h5 rem 单位", "author": "O2Team", "license": "MIT", diff --git a/packages/postcss-unit-transform/package.json b/packages/postcss-unit-transform/package.json index 42364ac249c7..e743738adc61 100644 --- a/packages/postcss-unit-transform/package.json +++ b/packages/postcss-unit-transform/package.json @@ -1,6 +1,6 @@ { "name": "postcss-taro-unit-transform", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "小程序单位转换", "author": "O2Team", "license": "MIT", diff --git a/packages/rollup-plugin-copy/package.json b/packages/rollup-plugin-copy/package.json index 4801db207b71..cf512dd2ccf3 100644 --- a/packages/rollup-plugin-copy/package.json +++ b/packages/rollup-plugin-copy/package.json @@ -1,6 +1,6 @@ { "name": "rollup-plugin-copy", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "rollup-plugin-copy for taro", "private": true, "author": "O2Team", diff --git a/packages/shared/package.json b/packages/shared/package.json index 72f5a4ebd92d..f1d2129692a5 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/shared", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro utils internal use.", "author": "O2Team", "license": "MIT", diff --git a/packages/stylelint-config-taro-rn/package.json b/packages/stylelint-config-taro-rn/package.json index 770eee3a50ab..43a923bead00 100644 --- a/packages/stylelint-config-taro-rn/package.json +++ b/packages/stylelint-config-taro-rn/package.json @@ -1,6 +1,6 @@ { "name": "stylelint-config-taro-rn", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Shareable stylelint config for React Native CSS modules", "author": "O2Team", "license": "MIT", diff --git a/packages/stylelint-taro-rn/package.json b/packages/stylelint-taro-rn/package.json index de56662ca234..2b95bc74d8e2 100644 --- a/packages/stylelint-taro-rn/package.json +++ b/packages/stylelint-taro-rn/package.json @@ -1,6 +1,6 @@ { "name": "stylelint-taro-rn", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "A collection of React Native specific rules for stylelint", "author": "O2Team", "license": "MIT", diff --git a/packages/stylelint-taro/package.json b/packages/stylelint-taro/package.json index 8cb0e58521cf..d240f7fd82a8 100644 --- a/packages/stylelint-taro/package.json +++ b/packages/stylelint-taro/package.json @@ -1,6 +1,6 @@ { "name": "stylelint-taro", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro stylelint 规则集合", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-api/package.json b/packages/taro-api/package.json index ce4609f0dd69..095af1f91155 100644 --- a/packages/taro-api/package.json +++ b/packages/taro-api/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/api", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro common API", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-cli-convertor/package.json b/packages/taro-cli-convertor/package.json index bb4c6631a04f..3f99dfaea578 100644 --- a/packages/taro-cli-convertor/package.json +++ b/packages/taro-cli-convertor/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/cli-convertor", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "cli tool for taro-convert", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-cli/package.json b/packages/taro-cli/package.json index e0e19b15eceb..8bec2efd2be6 100644 --- a/packages/taro-cli/package.json +++ b/packages/taro-cli/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/cli", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "cli tool for taro", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-components-advanced/package.json b/packages/taro-components-advanced/package.json index c5cde19c2f46..d98c19494094 100644 --- a/packages/taro-components-advanced/package.json +++ b/packages/taro-components-advanced/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/components-advanced", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-components-library-react/package.json b/packages/taro-components-library-react/package.json index 6c606426f41d..270bfc6d2db2 100644 --- a/packages/taro-components-library-react/package.json +++ b/packages/taro-components-library-react/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/components-library-react", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro 组件库 React 版本库", "private": true, "author": "O2Team", diff --git a/packages/taro-components-library-solid/package.json b/packages/taro-components-library-solid/package.json index b35cfa740ad7..b8eb198af477 100644 --- a/packages/taro-components-library-solid/package.json +++ b/packages/taro-components-library-solid/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/components-library-solid", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro 组件库 Solid 版本库", "private": true, "main": "index.js", diff --git a/packages/taro-components-library-vue3/package.json b/packages/taro-components-library-vue3/package.json index 71c114e57f16..db445fc770d5 100644 --- a/packages/taro-components-library-vue3/package.json +++ b/packages/taro-components-library-vue3/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/components-library-vue3", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro 组件库 Vue3 版本库", "private": true, "author": "O2Team", diff --git a/packages/taro-components-react/package.json b/packages/taro-components-react/package.json index a4db2c267eb0..913c2c594358 100644 --- a/packages/taro-components-react/package.json +++ b/packages/taro-components-react/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/components-react", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "", "main:h5": "dist/index.js", "main": "dist/index.js", diff --git a/packages/taro-components-rn/package.json b/packages/taro-components-rn/package.json index d3e8375bb0c5..977283fd6d23 100644 --- a/packages/taro-components-rn/package.json +++ b/packages/taro-components-rn/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/components-rn", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "React Native 基础组件", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-components/package.json b/packages/taro-components/package.json index a81a4acfa85c..1dc37570a5af 100644 --- a/packages/taro-components/package.json +++ b/packages/taro-components/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/components", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro 组件库", "browser": "dist/index.js", "main:h5": "dist/index.js", diff --git a/packages/taro-extend/package.json b/packages/taro-extend/package.json index 7147870e67d4..659d01545309 100644 --- a/packages/taro-extend/package.json +++ b/packages/taro-extend/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/extend", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro extend functionality", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-framework-react/package.json b/packages/taro-framework-react/package.json index 01b0a410722d..aff0027420d6 100644 --- a/packages/taro-framework-react/package.json +++ b/packages/taro-framework-react/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/plugin-framework-react", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "React/Preact 框架插件", "author": "O2Team", "homepage": "https://github.com/nervjs/taro", diff --git a/packages/taro-framework-solid/package.json b/packages/taro-framework-solid/package.json index cc774f16e232..984967b13544 100644 --- a/packages/taro-framework-solid/package.json +++ b/packages/taro-framework-solid/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/plugin-framework-solid", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Solid 框架插件", "author": "drchan", "homepage": "https://github.com/nervjs/taro", diff --git a/packages/taro-framework-vue3/package.json b/packages/taro-framework-vue3/package.json index a737b18f9378..050d758b178c 100644 --- a/packages/taro-framework-vue3/package.json +++ b/packages/taro-framework-vue3/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/plugin-framework-vue3", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Vue3 框架插件", "author": "O2Team", "homepage": "https://github.com/nervjs/taro", diff --git a/packages/taro-h5/package.json b/packages/taro-h5/package.json index 5b7694647c58..740ccd29f27b 100644 --- a/packages/taro-h5/package.json +++ b/packages/taro-h5/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/taro-h5", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro h5 framework", "browser": "dist/index.js", "main:h5": "dist/index.esm.js", diff --git a/packages/taro-helper/package.json b/packages/taro-helper/package.json index 63460f93e58f..0a5bd3e79910 100644 --- a/packages/taro-helper/package.json +++ b/packages/taro-helper/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/helper", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro Helper", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-loader/package.json b/packages/taro-loader/package.json index 3a0277f46f8b..4175120453b7 100644 --- a/packages/taro-loader/package.json +++ b/packages/taro-loader/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/taro-loader", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro runner use webpack loader", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-platform-alipay/package.json b/packages/taro-platform-alipay/package.json index 8aaeb41f5396..e565574ecf46 100644 --- a/packages/taro-platform-alipay/package.json +++ b/packages/taro-platform-alipay/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/plugin-platform-alipay", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "支付宝小程序平台插件", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-platform-h5/package.json b/packages/taro-platform-h5/package.json index d7513195ca7a..f971246cb551 100644 --- a/packages/taro-platform-h5/package.json +++ b/packages/taro-platform-h5/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/plugin-platform-h5", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Web 端平台插件", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-platform-harmony-hybrid/package.json b/packages/taro-platform-harmony-hybrid/package.json index 35ad1426c4e5..9ea25cbdd176 100644 --- a/packages/taro-platform-harmony-hybrid/package.json +++ b/packages/taro-platform-harmony-hybrid/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/plugin-platform-harmony-hybrid", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Harmony 端平台插件", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-platform-harmony/package.json b/packages/taro-platform-harmony/package.json index d0e58c130dee..b3fc3e60d7a3 100644 --- a/packages/taro-platform-harmony/package.json +++ b/packages/taro-platform-harmony/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/plugin-platform-harmony-ets", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "OpenHarmony & 鸿蒙系统插件", "author": "O2Team", "homepage": "https://gitee.com/openharmony-sig/taro", diff --git a/packages/taro-platform-jd/package.json b/packages/taro-platform-jd/package.json index 46a48bb1fa05..5c05db5c77c6 100644 --- a/packages/taro-platform-jd/package.json +++ b/packages/taro-platform-jd/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/plugin-platform-jd", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "京东小程序平台插件", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-platform-qq/package.json b/packages/taro-platform-qq/package.json index c60e86594475..43d236248ee9 100644 --- a/packages/taro-platform-qq/package.json +++ b/packages/taro-platform-qq/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/plugin-platform-qq", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "QQ 小程序平台插件", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-platform-swan/package.json b/packages/taro-platform-swan/package.json index 708302850522..af2c3f6e41f3 100644 --- a/packages/taro-platform-swan/package.json +++ b/packages/taro-platform-swan/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/plugin-platform-swan", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "百度小程序平台插件", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-platform-tt/package.json b/packages/taro-platform-tt/package.json index 078d9038e042..a6940e42f1f5 100644 --- a/packages/taro-platform-tt/package.json +++ b/packages/taro-platform-tt/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/plugin-platform-tt", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "头条小程序平台插件", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-platform-weapp/package.json b/packages/taro-platform-weapp/package.json index 14edcf80c128..c2ffe1dd6c9f 100644 --- a/packages/taro-platform-weapp/package.json +++ b/packages/taro-platform-weapp/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/plugin-platform-weapp", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "微信小程序平台插件", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-plugin-html/package.json b/packages/taro-plugin-html/package.json index d50948661885..55ba360c4566 100644 --- a/packages/taro-plugin-html/package.json +++ b/packages/taro-plugin-html/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/plugin-html", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro 小程序端支持使用 HTML 标签的插件", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-plugin-http/package.json b/packages/taro-plugin-http/package.json index 74d697d7198a..a9bcde218bf2 100644 --- a/packages/taro-plugin-http/package.json +++ b/packages/taro-plugin-http/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/plugin-http", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro 小程序端支持使用 web 请求 的插件", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-plugin-inject/package.json b/packages/taro-plugin-inject/package.json index a1ebdfe7805f..24718d24e4ff 100644 --- a/packages/taro-plugin-inject/package.json +++ b/packages/taro-plugin-inject/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/plugin-inject", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro 小程序端平台中间层插件", "author": "O2Team", "homepage": "https://github.com/nervjs/taro", diff --git a/packages/taro-plugin-mini-ci/package.json b/packages/taro-plugin-mini-ci/package.json index 6e8a49e76dbd..151efb3cd52d 100644 --- a/packages/taro-plugin-mini-ci/package.json +++ b/packages/taro-plugin-mini-ci/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/plugin-mini-ci", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro 小程序端构建后支持CI(持续集成)的插件", "keywords": [ "Taro", diff --git a/packages/taro-plugin-react-devtools/package.json b/packages/taro-plugin-react-devtools/package.json index 5e09b9274c39..c140c1faad24 100644 --- a/packages/taro-plugin-react-devtools/package.json +++ b/packages/taro-plugin-react-devtools/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/plugin-react-devtools", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro 小程序端支持使用 React DevTools 的插件", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-plugin-vue-devtools/package.json b/packages/taro-plugin-vue-devtools/package.json index 5b4566600fba..c7852c4e27d4 100644 --- a/packages/taro-plugin-vue-devtools/package.json +++ b/packages/taro-plugin-vue-devtools/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/plugin-vue-devtools", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro 小程序端支持使用 Vue DevTools 的插件", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-react/package.json b/packages/taro-react/package.json index 2b97ade85282..d1f5ca03a7fb 100644 --- a/packages/taro-react/package.json +++ b/packages/taro-react/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/react", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "like react-dom, but for mini apps.", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-rn-runner/package.json b/packages/taro-rn-runner/package.json index fdcb61a617cb..07bf1279c633 100644 --- a/packages/taro-rn-runner/package.json +++ b/packages/taro-rn-runner/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/rn-runner", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "ReactNative build tool for taro", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-rn-style-transformer/package.json b/packages/taro-rn-style-transformer/package.json index 658e87ea2803..39ea6c9cac65 100644 --- a/packages/taro-rn-style-transformer/package.json +++ b/packages/taro-rn-style-transformer/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/rn-style-transformer", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "提供 Taro RN 统一处理样式文件能力", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-rn-supporter/package.json b/packages/taro-rn-supporter/package.json index 3467b2d7c7b4..69e71568eaf2 100644 --- a/packages/taro-rn-supporter/package.json +++ b/packages/taro-rn-supporter/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/rn-supporter", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro rn supporter", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-rn-transformer/package.json b/packages/taro-rn-transformer/package.json index cb92cf79247a..6045b8323117 100644 --- a/packages/taro-rn-transformer/package.json +++ b/packages/taro-rn-transformer/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/rn-transformer", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro RN 入口文件处理", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-rn/package.json b/packages/taro-rn/package.json index fc5d51ab74e5..ad897bbfb1ff 100644 --- a/packages/taro-rn/package.json +++ b/packages/taro-rn/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/taro-rn", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro RN framework", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-router-rn/package.json b/packages/taro-router-rn/package.json index ee45bfc4c71e..c2efda7e223e 100644 --- a/packages/taro-router-rn/package.json +++ b/packages/taro-router-rn/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/router-rn", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro-router-rn", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-router/package.json b/packages/taro-router/package.json index dfb3788e0458..d13c5b100d61 100644 --- a/packages/taro-router/package.json +++ b/packages/taro-router/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/router", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro-router", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-runner-utils/package.json b/packages/taro-runner-utils/package.json index 6f6c8cf75945..c48db8edc913 100644 --- a/packages/taro-runner-utils/package.json +++ b/packages/taro-runner-utils/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/runner-utils", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro runner utilities.", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-runtime-rn/package.json b/packages/taro-runtime-rn/package.json index c361413697e1..f375752e7f5c 100644 --- a/packages/taro-runtime-rn/package.json +++ b/packages/taro-runtime-rn/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/runtime-rn", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "taro-runtime-rn", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-runtime/package.json b/packages/taro-runtime/package.json index 51908a47f251..cdd88e88d3b7 100644 --- a/packages/taro-runtime/package.json +++ b/packages/taro-runtime/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/runtime", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "taro runtime for mini apps.", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-service/package.json b/packages/taro-service/package.json index b1e6345c187c..53accf5c41d9 100644 --- a/packages/taro-service/package.json +++ b/packages/taro-service/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/service", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro Service", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-transformer-wx/package.json b/packages/taro-transformer-wx/package.json index 6f5ce58eafa2..1542f211e33b 100644 --- a/packages/taro-transformer-wx/package.json +++ b/packages/taro-transformer-wx/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/transformer-wx", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Transfrom Nerv Component to Wechat mini program.", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-vite-runner/package.json b/packages/taro-vite-runner/package.json index 6414ff5b7cd9..8ecf93ced044 100644 --- a/packages/taro-vite-runner/package.json +++ b/packages/taro-vite-runner/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/vite-runner", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "main": "index.js", "license": "MIT", "files": [ diff --git a/packages/taro-webpack5-prebundle/package.json b/packages/taro-webpack5-prebundle/package.json index 32bf7968d746..5347c7ef28f2 100644 --- a/packages/taro-webpack5-prebundle/package.json +++ b/packages/taro-webpack5-prebundle/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/webpack5-prebundle", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro app webpack5 prebundle", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-webpack5-runner/package.json b/packages/taro-webpack5-runner/package.json index dd92d5ddd771..0aa3249693a2 100644 --- a/packages/taro-webpack5-runner/package.json +++ b/packages/taro-webpack5-runner/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/webpack5-runner", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro app runner", "author": "O2Team", "license": "MIT", diff --git a/packages/taro-with-weapp/package.json b/packages/taro-with-weapp/package.json index 085be6faa9db..3ecf39eea204 100644 --- a/packages/taro-with-weapp/package.json +++ b/packages/taro-with-weapp/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/with-weapp", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "taroize 之后的运行时", "author": "O2Team", "license": "MIT", diff --git a/packages/taro/package.json b/packages/taro/package.json index 59ead17418cb..3940f4164136 100644 --- a/packages/taro/package.json +++ b/packages/taro/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/taro", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "Taro framework", "author": "O2Team", "license": "MIT", diff --git a/packages/taroize/package.json b/packages/taroize/package.json index 215a1c08f2b3..4ca3c7d683d8 100644 --- a/packages/taroize/package.json +++ b/packages/taroize/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/taroize", - "version": "4.0.5", + "version": "4.0.6-alpha.0", "description": "转换原生微信小程序代码为 Taro 代码", "author": "O2Team", "license": "MIT", From c8b6520cd4de672f56a60b62357282e77f66beff Mon Sep 17 00:00:00 2001 From: liuzejia Date: Mon, 23 Sep 2024 19:47:03 +0800 Subject: [PATCH 08/29] =?UTF-8?q?feat:=20=E6=9A=82=E6=97=B6=E4=BF=9D?= =?UTF-8?q?=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 1 + .../src/tests/condition.rs | 35 +++--- .../swc_plugin_compile_mode/src/transform.rs | 4 + .../Cargo.toml | 1 + .../src/tests/init.rs | 21 ---- .../src/tests/mod.rs | 3 +- .../src/tests/render.rs | 1 + .../src/visitors/collect_render_fn.rs | 18 +-- .../src/visitors/common.rs | 35 +----- .../src/visitors/entry.rs | 84 ++++++++++---- .../src/visitors/generate_deps.rs | 11 +- .../src/visitors/is_compile_mode_component.rs | 16 +-- .../src/visitors/transform/component_entry.rs | 23 ++-- .../src/visitors/transform/process.rs | 105 ++++++++++++------ .../src/tests/init.rs/should_do_nothing.js | 13 --- 15 files changed, 190 insertions(+), 181 deletions(-) delete mode 100644 crates/swc_plugin_compile_mode_pre_process/src/tests/init.rs delete mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/init.rs/should_do_nothing.js diff --git a/Cargo.lock b/Cargo.lock index 781aff52fea6..87ef4ab62aa4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1980,6 +1980,7 @@ name = "swc_plugin_compile_mode_pre_process" version = "0.1.0" dependencies = [ "regex", + "rustc-hash", "serde", "serde_json", "swc_core", diff --git a/crates/swc_plugin_compile_mode/src/tests/condition.rs b/crates/swc_plugin_compile_mode/src/tests/condition.rs index e9001259505d..07705eb37113 100644 --- a/crates/swc_plugin_compile_mode/src/tests/condition.rs +++ b/crates/swc_plugin_compile_mode/src/tests/condition.rs @@ -40,20 +40,29 @@ test!( should_support_conditional_expr, r#" function Index () { - return ( - - {condition ? {content} : hello} - {condition1 ? condition2 ? {a} : {b} : {c}} - {condition1 ? {a} : condition2 ? {b} : {c}} - {condition1 ? {a} : (condition2 ? {b} : {c})} - {condition1 ? condition2 && {a} : {b}} - {condition1 ? {a} : condition2 && {b}} - {condition1 ? "someText" : 789} - {condition1 ? : } - {condition1 ? {condition2 ? : } : } - + const [list, setList] = useState([ + 1, + 2, + 3, + 4, + 5 + ]); + return + + { + + { + list.map((item) => { + return + hello world{item} + + }) + } + hello world - ) + } + + ; } "# ); diff --git a/crates/swc_plugin_compile_mode/src/transform.rs b/crates/swc_plugin_compile_mode/src/transform.rs index 0ee3aa5bad97..294dbc24a918 100644 --- a/crates/swc_plugin_compile_mode/src/transform.rs +++ b/crates/swc_plugin_compile_mode/src/transform.rs @@ -597,6 +597,10 @@ impl TransformVisitor { children_string.push_str(&code); } }, + Expr::JSXElement(el) => { + let child_string = self.build_xml_element(el); + children_string.push_str(&child_string); + }, _ => { let mut xscript_expr_string: Option = None; diff --git a/crates/swc_plugin_compile_mode_pre_process/Cargo.toml b/crates/swc_plugin_compile_mode_pre_process/Cargo.toml index fa1064cc8d35..5c84c9a911bb 100644 --- a/crates/swc_plugin_compile_mode_pre_process/Cargo.toml +++ b/crates/swc_plugin_compile_mode_pre_process/Cargo.toml @@ -11,6 +11,7 @@ serde = { workspace = true } serde_json = { workspace = true } swc_core = { workspace = true } regex = "1.10.2" +rustc-hash = "1.1.0" [dev-dependencies] swc_core = { workspace = true, features = ["ecma_parser", "ecma_codegen"] } diff --git a/crates/swc_plugin_compile_mode_pre_process/src/tests/init.rs b/crates/swc_plugin_compile_mode_pre_process/src/tests/init.rs deleted file mode 100644 index 4a98650da863..000000000000 --- a/crates/swc_plugin_compile_mode_pre_process/src/tests/init.rs +++ /dev/null @@ -1,21 +0,0 @@ -use swc_core::ecma::transforms::testing::test; - -use super::{get_syntax_config, tr}; - -test!( - get_syntax_config(), - |_| tr(), - should_do_nothing, - r#" - function ComponentA () {} - const ComponentB = function (){} - const ComponentC = () => {} - export const ComponentD = () => {} - export const ComponentE = () => {} - export default function ComponentF () {} - // export default function () {} - // export default () => {} - function normal () {} - const normal2 = function () {} - "# -); diff --git a/crates/swc_plugin_compile_mode_pre_process/src/tests/mod.rs b/crates/swc_plugin_compile_mode_pre_process/src/tests/mod.rs index aa9b6700be94..73015b4c3197 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/tests/mod.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/tests/mod.rs @@ -7,7 +7,8 @@ use crate::{ visitors::entry::EntryVisitor, }; -mod init; +mod entry; +mod render; pub fn tr () -> impl Fold { let config = serde_json::from_str::( diff --git a/crates/swc_plugin_compile_mode_pre_process/src/tests/render.rs b/crates/swc_plugin_compile_mode_pre_process/src/tests/render.rs index b4afe9e88574..7f301ff6607f 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/tests/render.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/tests/render.rs @@ -94,6 +94,7 @@ test!( return ComponentC {renderA()} + {renderD()} } diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs index b30e4434f0b8..08559c8edf09 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs @@ -1,22 +1,16 @@ use std::collections::HashMap; -use swc_core::{ - ecma::{ +use swc_core::ecma::{ ast::*, visit::{VisitMutWith, VisitMut}, - }, - plugin::{ - plugin_transform, - proxies::TransformPluginProgramMetadata - } -}; -use crate::visitors::common::{ COMPILE_MODE_SUB_COMPONENT, ArrowAndFnParams }; + }; +use crate::visitors::common::COMPILE_MODE_SUB_COMPONENT; use super::common::RenderFn; pub struct CollectRenderFnVisitor { pub raw_render_fn_map: HashMap, sub_component_name: Option, - sub_component_params: Option, + sub_component_params: Option>, in_outmost_block_scope: bool, } @@ -50,7 +44,7 @@ impl VisitMut for CollectRenderFnVisitor { Stmt::Return(return_stmt) => { self.in_outmost_block_scope = true; self.sub_component_name = Some(component_name.clone()); - self.sub_component_params = Some(ArrowAndFnParams::Fn(fn_decl.function.params.clone())); + self.sub_component_params = Some(fn_decl.function.params.clone().into_iter().map(|fn_param |fn_param.pat).collect()); return_stmt.visit_mut_with(self); self.in_outmost_block_scope = false; self.sub_component_name = None; @@ -75,7 +69,7 @@ impl VisitMut for CollectRenderFnVisitor { Stmt::Return(return_stmt) => { self.in_outmost_block_scope = true; self.sub_component_name = Some(sub_component_name.sym.to_string()); - self.sub_component_params = Some(ArrowAndFnParams::Arrow(arrow.params.clone())); + self.sub_component_params = Some(arrow.params.clone()); return_stmt.visit_mut_with(self); self.in_outmost_block_scope = false; self.sub_component_name = None; diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/common.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/common.rs index cb70c1cc44f9..c370457a07c4 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/common.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/common.rs @@ -1,31 +1,20 @@ - -use std::{clone, collections::HashMap}; - -use swc_core::{ - ecma::{ +use swc_core::ecma::{ ast::*, - visit::{VisitMutWith, VisitMut}, - }, - plugin::{ - plugin_transform, - proxies::TransformPluginProgramMetadata - } -}; + visit::VisitMutWith, + }; use super::is_compile_mode_component::IsCompileModeVisitor; - - pub const COMPILE_MODE: &str = "compileMode"; pub const DEFAULT_COMPONENT: &str = "Default_Component"; pub const COMPILE_MODE_SUB_COMPONENT: &str = "compileModeSubComponent"; pub struct RenderFn { - pub params: ArrowAndFnParams, + pub params: Vec, pub jsx_element: JSXElement, } impl RenderFn { - pub fn new(params: ArrowAndFnParams, jsx_element: JSXElement) -> Self { + pub fn new(params: Vec, jsx_element: JSXElement) -> Self { RenderFn { params, jsx_element, @@ -42,20 +31,6 @@ impl Clone for RenderFn { } } -pub enum ArrowAndFnParams { - Arrow(Vec), - Fn(Vec), -} - -impl clone::Clone for ArrowAndFnParams { - fn clone(&self) -> Self { - match self { - ArrowAndFnParams::Arrow(params) => ArrowAndFnParams::Arrow(params.clone()), - ArrowAndFnParams::Fn(params) => ArrowAndFnParams::Fn(params.clone()), - } - } -} - pub struct ReactComponent { pub name: String, pub block_stmt: Option, diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs index c2a8d34fb7bf..6896acb112f3 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs @@ -1,18 +1,12 @@ -use std::collections::{HashMap, HashSet, VecDeque}; +use std::{collections::{HashMap, HashSet, VecDeque}, ops::Index}; -use swc_core::{ - ecma::{ +use swc_core::ecma::{ ast::*, visit::{VisitMutWith, VisitMut}, - }, - plugin::{ - plugin_transform, - proxies::TransformPluginProgramMetadata - } -}; -use crate::{visitors::find_react_component, PluginConfig}; + }; +use crate::PluginConfig; -use super::{common::*, generate_deps::{self, GenerateDepsVisitor}, transform}; +use super::{common::*, generate_deps::GenerateDepsVisitor}; use super::collect_render_fn::CollectRenderFnVisitor; use super::find_react_component::FindReactComponentVisitor; use super::transform::component_entry::ComponentEntryVisitor; @@ -91,12 +85,18 @@ impl EntryVisitor { } // 2. 根据依赖表,生成解析的列表 sort queue 先进先出 + get_deps_circular(&render_fn_deps_map); let sort_queue = generate_sort_queue(&render_fn_deps_map); println!("component_name: {}, sort_queue: {:?}", name, sort_queue); // 3. 根据 sort queue 生成 formatted_fn_map 数据结构 hashMap:{name: formatted_fn} - let formatted_fn_map = generate_formatted_fn_map(sort_queue, &raw_fn_map); + let formatted_fn_map = generate_formatted_fn_map(sort_queue, &raw_fn_map, &render_fn_deps_map); formatted_render_fn_map.insert(name, formatted_fn_map); }); + for (component_name, formatted_fn_map) in &formatted_render_fn_map { + for (fn_name, formatted_fn) in formatted_fn_map { + println!("component_name: {}, fn_name: {}, formatted_fn: {:?}", component_name, fn_name, formatted_fn.jsx_element); + } + } self.visitor_context.react_component_formatted_render_fn_map = formatted_render_fn_map; } @@ -125,10 +125,11 @@ fn generate_render_fn_dep_map (raw_fn_map: &HashMap)-> HashMap } fn generate_sort_queue (render_fn_deps_map: &HashMap>) -> Vec { + //已经遍历过的节点 剪纸用的 let mut visited = HashSet::new(); let mut result = VecDeque::new(); let mut cycles = Vec::new(); - + for key in render_fn_deps_map.keys() { let mut path = Vec::new(); if dfs(key, render_fn_deps_map, &mut visited, &mut path, &mut result, &mut cycles) { @@ -143,24 +144,35 @@ fn generate_sort_queue (render_fn_deps_map: &HashMap>) -> Ve result.into_iter().collect() } -fn generate_formatted_fn_map (sort_queue: Vec, raw_fn_map: &HashMap) -> HashMap { +fn generate_formatted_fn_map (sort_queue: Vec, raw_fn_map: &HashMap, render_fn_deps_map: &HashMap>) -> HashMap { let mut formatted_fn_map = HashMap::new(); - for name in sort_queue { - if let Some(raw_fn) = raw_fn_map.get(&name) { - let mut formatted_fn = raw_fn.clone(); - // todo 格式化 raw_fn 为 formatted_fn - // 涉及模版拼接和参数转化,和下面的 transform 要做的事情一样,等抽象出来 - formatted_fn_map.insert(name, formatted_fn); + for name in &sort_queue { + match (raw_fn_map.get(name), render_fn_deps_map.get(name)) { + (Some(raw_fn), Some(deps)) => { + let mut dep_map = HashMap::new(); + for dep in deps { + let formatted_dep = formatted_fn_map.get(dep); + if formatted_dep.is_some() { + dep_map.insert(dep.clone(), formatted_dep.unwrap()); + } + } + formatted_fn_map.insert(name.clone(), raw_fn.clone()); + }, + _ => {} } } formatted_fn_map } + fn dfs(node: &String, map: &HashMap>, visited: &mut HashSet, path: &mut Vec, result: &mut VecDeque, cycles: &mut Vec>) -> bool { if path.contains(node) { + //这里就是发现循环了 + return true; } else if !visited.contains(node) { + // 已经遍历过就不需要再处理了,要么已经被 push 到 result 里面了,要么存在循环链,已经被摘除了 visited.insert(node.clone()); path.push(node.clone()); @@ -177,4 +189,36 @@ fn dfs(node: &String, map: &HashMap>, visited: &mut HashSet< } false +} + +fn get_deps_circular(map: &HashMap>)-> Vec> { + let mut result: Vec> = vec![]; + let mut visited: HashSet = HashSet::new(); + for key in map.keys() { + let mut path: Vec = vec![]; + dfs1(key, map, &mut visited, &mut path, &mut result); + } + println!("result: {:?}", result); + result +} + +fn dfs1(node: &String, map: &HashMap>, visited: &mut HashSet, path: &mut Vec, res: &mut Vec>){ + println!("node: {:?}", node); + println!("path: {:?}", path); + if let Some(index) = path.iter().position(|s| s == node) { + println!("Found at index {}", index); + print!("cycle found: "); + res.push(path[index..].to_vec()); + } else { + if !visited.contains(node) { + visited.insert(node.clone()); + if let Some(neighbors) = map.get(node) { + for neighbor in neighbors { + path.push(node.clone()); + dfs1(neighbor, map, visited, path, res); + path.pop(); + } + } + } + } } \ No newline at end of file diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/generate_deps.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/generate_deps.rs index c21501de10fb..6c3e0f97fd2a 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/generate_deps.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/generate_deps.rs @@ -1,15 +1,8 @@ use std::collections::HashMap; -use swc_core::{ - ecma::{ +use swc_core::ecma::{ ast::*, visit::{VisitMutWith, VisitMut}, - }, - plugin::{ - plugin_transform, - proxies::TransformPluginProgramMetadata - } -}; -use crate::visitors::common::{ COMPILE_MODE_SUB_COMPONENT, ArrowAndFnParams }; + }; use super::common::RenderFn; diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/is_compile_mode_component.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/is_compile_mode_component.rs index 6d6855bcee84..9f0e52db70a5 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/is_compile_mode_component.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/is_compile_mode_component.rs @@ -1,15 +1,6 @@ -use std::collections::HashMap; - -use serde_json::de; -use swc_core::{ - ecma::{ - ast::*, utils::function, visit::{VisitMut, VisitMutWith} - }, - plugin::{ - plugin_transform, - proxies::TransformPluginProgramMetadata - } -}; +use swc_core::ecma::{ + ast::*, visit::{VisitMut, VisitMutWith} + }; use super::common::COMPILE_MODE; @@ -62,6 +53,5 @@ impl VisitMut for IsCompileModeVisitor { } el.visit_mut_children_with(self); } - } } \ No newline at end of file diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/component_entry.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/component_entry.rs index 9deddeb1091d..dd459acff5a8 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/component_entry.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/component_entry.rs @@ -1,14 +1,7 @@ use std::collections::HashMap; -use serde_json::de; -use swc_core::{ - ecma::{ - ast::*, utils::function, visit::{VisitMut, VisitMutWith} - }, - plugin::{ - plugin_transform, - proxies::TransformPluginProgramMetadata - } +use swc_core::ecma::{ + ast::*, visit::{VisitMut, VisitMutWith} }; use crate::visitors::common::{RenderFn, DEFAULT_COMPONENT}; @@ -44,12 +37,12 @@ impl<'a> VisitMut for ComponentEntryVisitor<'a> { let component_name = ident.sym.to_string(); let render_fn_map = self.get_format_render_fn_map_by_component_name(&component_name); if let Some(render_fn_map) = render_fn_map { - let mut process_visitor = TransformProcessVisitor::new(component_name, &render_fn_map); + let mut process_visitor = TransformProcessVisitor::new(&render_fn_map); decl.init.visit_mut_children_with(&mut process_visitor); } }, _ => {} - } + } }, Expr::Fn(FnExpr { ident: _, function })=> { // 适配 const xxx = function () {} @@ -58,7 +51,7 @@ impl<'a> VisitMut for ComponentEntryVisitor<'a> { let component_name = ident.sym.to_string(); let render_fn_map = self.get_format_render_fn_map_by_component_name(&component_name); if let Some(render_fn_map) = render_fn_map { - let mut process_visitor = TransformProcessVisitor::new(component_name, &render_fn_map); + let mut process_visitor = TransformProcessVisitor::new(&render_fn_map); decl.init.visit_mut_children_with(&mut process_visitor); } }, @@ -75,7 +68,7 @@ impl<'a> VisitMut for ComponentEntryVisitor<'a> { let component_name = n.ident.sym.to_string(); let render_fn_map = self.get_format_render_fn_map_by_component_name(&component_name); if let Some(render_fn_map) = render_fn_map { - let mut process_visitor = TransformProcessVisitor::new(component_name, &render_fn_map); + let mut process_visitor = TransformProcessVisitor::new(&render_fn_map); n.function.body.visit_mut_children_with(&mut process_visitor); } } @@ -88,7 +81,7 @@ impl<'a> VisitMut for ComponentEntryVisitor<'a> { DefaultDecl::Fn(fn_decl) => { let render_fn_map = self.get_format_render_fn_map_by_component_name(&DEFAULT_COMPONENT.to_string()); if let Some(render_fn_map) = render_fn_map { - let mut process_visitor = TransformProcessVisitor::new(DEFAULT_COMPONENT.to_string(), &render_fn_map); + let mut process_visitor = TransformProcessVisitor::new(&render_fn_map); fn_decl.function.body.visit_mut_children_with(&mut process_visitor); } }, @@ -104,7 +97,7 @@ impl<'a> VisitMut for ComponentEntryVisitor<'a> { if let BlockStmtOrExpr::BlockStmt(_block_stmt) = &*arrow_expr.body { let render_fn_map = self.get_format_render_fn_map_by_component_name(&DEFAULT_COMPONENT.to_string()); if let Some(render_fn_map) = render_fn_map { - let mut process_visitor = TransformProcessVisitor::new(DEFAULT_COMPONENT.to_string(), &render_fn_map); + let mut process_visitor = TransformProcessVisitor::new(&render_fn_map); n.expr.visit_mut_children_with(&mut process_visitor); } } diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/process.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/process.rs index 130df44f5994..abcf9fcc3053 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/process.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/process.rs @@ -1,49 +1,86 @@ use std::collections::HashMap; - -use serde_json::de; -use swc_core::{ - ecma::{ - ast::*, utils::{function, swc_common::*}, visit::{VisitMut, VisitMutWith} - }, - plugin::{ - plugin_transform, - proxies::TransformPluginProgramMetadata - } +use swc_core::ecma::{ + ast::*, utils::IdentRenamer, visit::{VisitMut, VisitMutWith} }; +use rustc_hash::FxHashMap; -use crate::visitors::common::RenderFn; +use crate::visitors::common::{ RenderFn, COMPILE_MODE, COMPILE_MODE_SUB_COMPONENT }; pub struct TransformProcessVisitor<'a> { - component_name: String, - render_fn_map: &'a HashMap + render_fn_map: &'a HashMap, + in_compile_mode_jsx: bool, } impl<'a> TransformProcessVisitor<'a> { - pub fn new(component_name: String, render_fn_map: &'a HashMap) -> Self { + pub fn new(render_fn_map: &'a HashMap) -> Self { TransformProcessVisitor { - component_name, - render_fn_map + render_fn_map, + in_compile_mode_jsx: false, } } } impl<'a> VisitMut for TransformProcessVisitor<'a> { - fn visit_mut_block_stmt(&mut self, n: &mut BlockStmt) { - println!("process! component_name: {}\n", self.component_name); - let other_sts = Decl::Var(Box::new(VarDecl { - span: DUMMY_SP, - kind: VarDeclKind::Const, - declare: false, - decls: vec![VarDeclarator { - span: DUMMY_SP, - name: Pat::Ident(Ident::new("a".into(), DUMMY_SP).into()), - init: Some(Box::new(Expr::Lit(Lit::Num(Number { - span: DUMMY_SP, - value: 1.0, - raw: None - })))), - definite: false, - }], - })); - n.stmts.push(Stmt::Decl(other_sts)); + fn visit_mut_jsx_element(&mut self, el: &mut JSXElement) { + if !self.in_compile_mode_jsx { + for attr in &mut el.opening.attrs { + if let JSXAttrOrSpread::JSXAttr(jsx_attr) = attr { + if let JSXAttrName::Ident(jsx_attr_name) = &jsx_attr.name { + if jsx_attr_name.sym == COMPILE_MODE { + self.in_compile_mode_jsx = true; + print!("in_compile_mode_jsx\n,{:?}", el.children); + break; + } + } + } + } + } + + + el.opening.attrs.retain(|attr| match &attr { + JSXAttrOrSpread::JSXAttr(JSXAttr {name, ..}) => { + match name { + JSXAttrName::Ident(jsx_attr_name) => { + jsx_attr_name.sym != COMPILE_MODE_SUB_COMPONENT + }, + _=>true + } + }, + _=>true + }); + + el.visit_mut_children_with(self); + } + + fn visit_mut_expr(&mut self, n: &mut Expr) { + if self.in_compile_mode_jsx { + if let Expr::Call(CallExpr { callee: Callee::Expr(callee_expr), args, .. }) = n { + if let Expr::Ident(ident) = &**callee_expr { + if self.render_fn_map.contains_key(&ident.sym.to_string()) { + let mut jsx_ele = Expr::JSXElement(Box::new(self.render_fn_map.get(&ident.sym.to_string()).unwrap().jsx_element.clone())); + let mut name_map = FxHashMap::default(); + let old_args = &self.render_fn_map.get(&ident.sym.to_string()).unwrap().params; + let format_args: Vec<_> = args.into_iter() + .map(|arg| arg.expr.clone()) + .filter(|expr| matches!(**expr, Expr::Ident(_))) + .map(|expr| if let Expr::Ident(ident) = *expr { Some(ident) } else { None }) + .flatten() + .collect(); + if format_args.len() == old_args.len() { + for (i, arg) in format_args.iter().enumerate() { + let old_arg = &old_args[i]; + if let Pat::Ident(old_ident) = old_arg { + name_map.insert(old_ident.to_id(), arg.to_id()); + } + } + let mut ident_renamer_visitor = IdentRenamer::new(&name_map); + jsx_ele.visit_mut_with(&mut ident_renamer_visitor); + *n = jsx_ele; + } + + } + } + } + } + n.visit_mut_children_with(self); } } \ No newline at end of file diff --git a/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/init.rs/should_do_nothing.js b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/init.rs/should_do_nothing.js deleted file mode 100644 index 89f554adddd4..000000000000 --- a/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/init.rs/should_do_nothing.js +++ /dev/null @@ -1,13 +0,0 @@ -function Index() { - return - - - - - - {myText} - - - - ; -} From 43276a528e24b419d8f46e97818f3e86dd054fdc Mon Sep 17 00:00:00 2001 From: liuzejia Date: Mon, 23 Sep 2024 20:41:01 +0800 Subject: [PATCH 09/29] =?UTF-8?q?feat:=20=E8=A1=A5=E9=BD=90=E7=BB=9D?= =?UTF-8?q?=E5=A4=A7=E9=83=A8=E4=BB=BD=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/tests/mod.rs | 1 + .../src/tests/props.rs | 27 ++++++ .../src/tests/render.rs | 1 - .../src/visitors/entry.rs | 86 ++----------------- .../src/visitors/transform/process.rs | 2 - .../props.rs/should_replace_static_props.js | 19 ++++ ...should_not_render_with_circle_recursion.js | 71 +++++++++++++++ 7 files changed, 127 insertions(+), 80 deletions(-) create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/tests/props.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/props.rs/should_replace_static_props.js create mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/render.rs/should_not_render_with_circle_recursion.js diff --git a/crates/swc_plugin_compile_mode_pre_process/src/tests/mod.rs b/crates/swc_plugin_compile_mode_pre_process/src/tests/mod.rs index 73015b4c3197..645911c48845 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/tests/mod.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/tests/mod.rs @@ -9,6 +9,7 @@ use crate::{ mod entry; mod render; +mod props; pub fn tr () -> impl Fold { let config = serde_json::from_str::( diff --git a/crates/swc_plugin_compile_mode_pre_process/src/tests/props.rs b/crates/swc_plugin_compile_mode_pre_process/src/tests/props.rs new file mode 100644 index 000000000000..33978bcb70de --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/src/tests/props.rs @@ -0,0 +1,27 @@ +use swc_core::ecma::transforms::testing::test; + +use super::{get_syntax_config, tr}; + +test!( + get_syntax_config(), + |_| tr(), + should_replace_static_props, + r#" + export default function Index () { + const list = [1, 2, 3]; + function renderA (listA) { + return { + listA.map((item, index) => { + return {item} + }) + } + } + + return ( + + {renderA(list)} + + ) + } + "# +); \ No newline at end of file diff --git a/crates/swc_plugin_compile_mode_pre_process/src/tests/render.rs b/crates/swc_plugin_compile_mode_pre_process/src/tests/render.rs index 7f301ff6607f..b4afe9e88574 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/tests/render.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/tests/render.rs @@ -94,7 +94,6 @@ test!( return ComponentC {renderA()} - {renderD()} } diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs index 6896acb112f3..6fd831e4e9c5 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs @@ -79,17 +79,16 @@ impl EntryVisitor { self.visitor_context.react_component_raw_render_fn_map.clone().into_iter().for_each(|(name, raw_fn_map)| { // 1. 可能存在互相引用,得梳理一下他们之间的依赖关系 数据结构 hashMap:{name:[dep1, dep2,...]} let render_fn_deps_map = generate_render_fn_dep_map(&raw_fn_map); - - for (fn_name, deps) in &render_fn_deps_map { - println!("component_name: {}, fn_name: {} deps: {:?}", name, fn_name, deps); - } - // 2. 根据依赖表,生成解析的列表 sort queue 先进先出 - get_deps_circular(&render_fn_deps_map); - let sort_queue = generate_sort_queue(&render_fn_deps_map); - println!("component_name: {}, sort_queue: {:?}", name, sort_queue); - // 3. 根据 sort queue 生成 formatted_fn_map 数据结构 hashMap:{name: formatted_fn} - let formatted_fn_map = generate_formatted_fn_map(sort_queue, &raw_fn_map, &render_fn_deps_map); + // 2. 根据依赖表,检查里面有没有循环引用,如果有循环引用,需要把循环引用的那些函数都去掉 + let deps_circular_list = get_deps_circular(&render_fn_deps_map); + // 3. 根据 deps_circular_list 生成 formatted_fn_map 数据结构 hashMap:{name: formatted_fn} + let mut formatted_fn_map: HashMap = HashMap::new(); + raw_fn_map.clone().into_iter().for_each(|(fn_name, raw_fn)| { + if !deps_circular_list.iter().any(|circular| circular.contains(&fn_name)) { + formatted_fn_map.insert(fn_name, raw_fn); + } + }); formatted_render_fn_map.insert(name, formatted_fn_map); }); for (component_name, formatted_fn_map) in &formatted_render_fn_map { @@ -124,73 +123,6 @@ fn generate_render_fn_dep_map (raw_fn_map: &HashMap)-> HashMap render_fn_deps_map } -fn generate_sort_queue (render_fn_deps_map: &HashMap>) -> Vec { - //已经遍历过的节点 剪纸用的 - let mut visited = HashSet::new(); - let mut result = VecDeque::new(); - let mut cycles = Vec::new(); - - for key in render_fn_deps_map.keys() { - let mut path = Vec::new(); - if dfs(key, render_fn_deps_map, &mut visited, &mut path, &mut result, &mut cycles) { - cycles.push(path); - } - } - - for cycle in cycles { - println!("Detected cycle: {:?}", cycle); - } - - result.into_iter().collect() -} - -fn generate_formatted_fn_map (sort_queue: Vec, raw_fn_map: &HashMap, render_fn_deps_map: &HashMap>) -> HashMap { - let mut formatted_fn_map = HashMap::new(); - for name in &sort_queue { - match (raw_fn_map.get(name), render_fn_deps_map.get(name)) { - (Some(raw_fn), Some(deps)) => { - let mut dep_map = HashMap::new(); - for dep in deps { - let formatted_dep = formatted_fn_map.get(dep); - if formatted_dep.is_some() { - dep_map.insert(dep.clone(), formatted_dep.unwrap()); - } - } - formatted_fn_map.insert(name.clone(), raw_fn.clone()); - }, - _ => {} - } - } - - formatted_fn_map -} - - -fn dfs(node: &String, map: &HashMap>, visited: &mut HashSet, path: &mut Vec, result: &mut VecDeque, cycles: &mut Vec>) -> bool { - if path.contains(node) { - //这里就是发现循环了 - - return true; - } else if !visited.contains(node) { - // 已经遍历过就不需要再处理了,要么已经被 push 到 result 里面了,要么存在循环链,已经被摘除了 - visited.insert(node.clone()); - path.push(node.clone()); - - if let Some(neighbors) = map.get(node) { - for neighbor in neighbors { - if dfs(neighbor, map, visited, path, result, cycles) { - return true; - } - } - } - - path.pop(); - result.push_back(node.clone()); - } - - false -} - fn get_deps_circular(map: &HashMap>)-> Vec> { let mut result: Vec> = vec![]; let mut visited: HashSet = HashSet::new(); diff --git a/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/process.rs b/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/process.rs index abcf9fcc3053..5d0ead056cc0 100644 --- a/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/process.rs +++ b/crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/process.rs @@ -27,7 +27,6 @@ impl<'a> VisitMut for TransformProcessVisitor<'a> { if let JSXAttrName::Ident(jsx_attr_name) = &jsx_attr.name { if jsx_attr_name.sym == COMPILE_MODE { self.in_compile_mode_jsx = true; - print!("in_compile_mode_jsx\n,{:?}", el.children); break; } } @@ -35,7 +34,6 @@ impl<'a> VisitMut for TransformProcessVisitor<'a> { } } - el.opening.attrs.retain(|attr| match &attr { JSXAttrOrSpread::JSXAttr(JSXAttr {name, ..}) => { match name { diff --git a/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/props.rs/should_replace_static_props.js b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/props.rs/should_replace_static_props.js new file mode 100644 index 000000000000..546d26fd14ea --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/props.rs/should_replace_static_props.js @@ -0,0 +1,19 @@ +export default function Index() { + const list = [ + 1, + 2, + 3 + ]; + function renderA(listA) { + return {listA.map((item, index)=>{ + return {item} ; + })} ; + } + return + + { {list.map((item, index)=>{ + return {item} ; + })} } + + ; +} diff --git a/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/render.rs/should_not_render_with_circle_recursion.js b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/render.rs/should_not_render_with_circle_recursion.js new file mode 100644 index 000000000000..93c2eab03454 --- /dev/null +++ b/crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/render.rs/should_not_render_with_circle_recursion.js @@ -0,0 +1,71 @@ +export default function Index() { + function renderB() { + return + + ComponentB + + {renderA()} + + ; + } + function renderC() { + return + + ComponentC + + {renderA()} + + ; + } + function renderD() { + return + + ComponentD + + {renderC()} + + ; + } + function renderA() { + return + + ComponentA + + {renderB()} + + ; + } + return + + + + {renderA()} + + {renderB()} + + { + + ComponentC + + {renderA()} + + } + + { + + ComponentD + + { + + ComponentC + + {renderA()} + + } + + } + + + + ; +} From 96fabe32a98b89c0dfb662153144d4dce055f76e Mon Sep 17 00:00:00 2001 From: liuzejia Date: Tue, 24 Sep 2024 14:02:37 +0800 Subject: [PATCH 10/29] =?UTF-8?q?lint:=20=E4=BD=BF=E7=94=A8rustfmt=20?= =?UTF-8?q?=E7=BB=9F=E4=B8=80=E4=BB=A3=E7=A0=81=E9=A3=8E=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/swc_plugin_compile_mode/.editorconfig | 6 - crates/swc_plugin_compile_mode/src/lib.rs | 92 +- .../src/tests/attributes.rs | 26 +- .../src/tests/children.rs | 42 +- .../src/tests/condition.rs | 18 +- .../src/tests/entry.rs | 10 +- .../src/tests/harmony/attributes.rs | 18 +- .../src/tests/harmony/children.rs | 26 +- .../src/tests/harmony/condition.rs | 18 +- .../src/tests/harmony/entry.rs | 2 +- .../src/tests/harmony/looping.rs | 18 +- .../src/tests/harmony/mod.rs | 15 +- .../src/tests/looping.rs | 52 +- .../swc_plugin_compile_mode/src/tests/mod.rs | 43 +- .../src/tests/shake.rs | 10 +- .../swc_plugin_compile_mode/src/tests/wxs.rs | 34 +- .../swc_plugin_compile_mode/src/transform.rs | 1244 ++++++++-------- .../src/transform_harmony.rs | 1265 +++++++++-------- .../src/utils/constants.rs | 1 - .../src/utils/harmony/components.rs | 127 +- .../swc_plugin_compile_mode/src/utils/mod.rs | 740 +++++----- .../src/lib.rs | 34 +- .../src/tests/entry.rs | 50 +- .../src/tests/mod.rs | 37 +- .../src/tests/props.rs | 34 +- .../src/tests/render.rs | 24 +- .../src/visitors/collect_render_fn.rs | 236 +-- .../src/visitors/common.rs | 78 +- .../src/visitors/entry.rs | 272 ++-- .../src/visitors/find_react_component.rs | 125 +- .../src/visitors/generate_deps.rs | 60 +- .../src/visitors/is_compile_mode_component.rs | 79 +- .../src/visitors/mod.rs | 8 +- .../src/visitors/transform/component_entry.rs | 166 ++- .../src/visitors/transform/mod.rs | 2 +- .../src/visitors/transform/process.rs | 152 +- crates/swc_plugin_define_config/.editorconfig | 6 - crates/swc_plugin_define_config/src/lib.rs | 139 +- crates/taro_init/src/async_fs.rs | 2 +- crates/taro_init/src/constants.rs | 4 +- crates/taro_init/src/creator.rs | 5 +- crates/taro_init/src/plugin.rs | 5 +- crates/taro_init/src/project.rs | 5 +- crates/taro_init/src/rn/edit.rs | 2 +- crates/taro_init/src/utils.rs | 40 +- 45 files changed, 2827 insertions(+), 2545 deletions(-) delete mode 100644 crates/swc_plugin_compile_mode/.editorconfig delete mode 100644 crates/swc_plugin_define_config/.editorconfig diff --git a/crates/swc_plugin_compile_mode/.editorconfig b/crates/swc_plugin_compile_mode/.editorconfig deleted file mode 100644 index 7b227545b443..000000000000 --- a/crates/swc_plugin_compile_mode/.editorconfig +++ /dev/null @@ -1,6 +0,0 @@ -[*.rs] -indent_style = space -indent_size = 4 - -[*.js] -trim_trailing_whitespace = false diff --git a/crates/swc_plugin_compile_mode/src/lib.rs b/crates/swc_plugin_compile_mode/src/lib.rs index 593e7e5fdd59..cdaf22c3a63b 100644 --- a/crates/swc_plugin_compile_mode/src/lib.rs +++ b/crates/swc_plugin_compile_mode/src/lib.rs @@ -1,54 +1,50 @@ +use serde::Deserialize; +use std::collections::HashMap; use swc_core::{ - ecma::{ - ast::Program, - visit::{as_folder, FoldWith, VisitMut}, - }, - plugin::{ - plugin_transform, - proxies::TransformPluginProgramMetadata - } + ecma::{ + ast::Program, + visit::{as_folder, FoldWith, VisitMut}, + }, + plugin::{plugin_transform, proxies::TransformPluginProgramMetadata}, }; -use serde::{Deserialize}; -use std::collections::HashMap; -mod utils; -mod transform; -mod transform_harmony; #[cfg(test)] mod tests; +mod transform; +mod transform_harmony; +mod utils; struct SerdeDefault; impl SerdeDefault { - fn platform_default () -> String { - String::from("WEAPP") - } + fn platform_default() -> String { + String::from("WEAPP") + } } -#[derive(Deserialize, Debug)] +#[derive(Deserialize, Debug)] pub struct ComponentReplace { - pub current_init: String, - pub dependency_define: String, + pub current_init: String, + pub dependency_define: String, } #[derive(Deserialize, Debug)] pub struct PluginConfig { - pub tmpl_prefix: String, - #[serde(default = "SerdeDefault::platform_default")] - pub platform: String, - #[serde(default)] - pub is_harmony: bool, - #[serde(default)] - pub components: HashMap>, - #[serde(default)] - pub adapter: HashMap, - #[serde(default)] - pub support_events: Vec, - #[serde(default)] - pub support_components: Vec, - #[serde(default)] - pub event_adapter: HashMap, - #[serde(default)] - pub component_replace: HashMap, - + pub tmpl_prefix: String, + #[serde(default = "SerdeDefault::platform_default")] + pub platform: String, + #[serde(default)] + pub is_harmony: bool, + #[serde(default)] + pub components: HashMap>, + #[serde(default)] + pub adapter: HashMap, + #[serde(default)] + pub support_events: Vec, + #[serde(default)] + pub support_components: Vec, + #[serde(default)] + pub event_adapter: HashMap, + #[serde(default)] + pub component_replace: HashMap, } /// An example plugin function with macro support. @@ -68,19 +64,15 @@ pub struct PluginConfig { /// Refer swc_plugin_macro to see how does it work internally. #[plugin_transform] pub fn process_transform(program: Program, metadata: TransformPluginProgramMetadata) -> Program { - let config = serde_json::from_str::( - &metadata - .get_transform_plugin_config() - .unwrap() - ) - .unwrap(); + let config = + serde_json::from_str::(&metadata.get_transform_plugin_config().unwrap()).unwrap(); - // 如果 config 中的 is_harmony 字段为 true 则走 harmony_transform, 否则则走 transform - let visitor: Box = if config.is_harmony { - Box::new(transform_harmony::TransformVisitor::new(config)) - } else { - Box::new(transform::TransformVisitor::new(config)) - }; + // 如果 config 中的 is_harmony 字段为 true 则走 harmony_transform, 否则则走 transform + let visitor: Box = if config.is_harmony { + Box::new(transform_harmony::TransformVisitor::new(config)) + } else { + Box::new(transform::TransformVisitor::new(config)) + }; - program.fold_with(&mut as_folder(visitor)) + program.fold_with(&mut as_folder(visitor)) } diff --git a/crates/swc_plugin_compile_mode/src/tests/attributes.rs b/crates/swc_plugin_compile_mode/src/tests/attributes.rs index ddc9de82f4f8..891279df343b 100644 --- a/crates/swc_plugin_compile_mode/src/tests/attributes.rs +++ b/crates/swc_plugin_compile_mode/src/tests/attributes.rs @@ -1,11 +1,11 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( - get_syntax_config(), - |_| tr(), - should_keep_static_attrs_only_in_templates, - r#" + get_syntax_config(), + |_| tr(), + should_keep_static_attrs_only_in_templates, + r#" function Index () { return ( @@ -17,10 +17,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_turn_dynamic_attrs, - r#" + get_syntax_config(), + |_| tr(), + should_turn_dynamic_attrs, + r#" function Index () { return ( @@ -37,10 +37,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_handle_events, - r#" + get_syntax_config(), + |_| tr(), + should_handle_events, + r#" function Index () { return ( diff --git a/crates/swc_plugin_compile_mode/src/tests/children.rs b/crates/swc_plugin_compile_mode/src/tests/children.rs index dbc9cfa5e939..85207bbfa183 100644 --- a/crates/swc_plugin_compile_mode/src/tests/children.rs +++ b/crates/swc_plugin_compile_mode/src/tests/children.rs @@ -1,11 +1,11 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( - get_syntax_config(), - |_| tr(), - should_support_render_fn, - r#" + get_syntax_config(), + |_| tr(), + should_support_render_fn, + r#" function Index () { return ( @@ -19,10 +19,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_support_fragment, - r#" + get_syntax_config(), + |_| tr(), + should_support_fragment, + r#" function Index () { return ( @@ -54,10 +54,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_support_context_api, - r#" + get_syntax_config(), + |_| tr(), + should_support_context_api, + r#" function Index () { return ( @@ -77,10 +77,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_render_react_component, - r#" + get_syntax_config(), + |_| tr(), + should_render_react_component, + r#" function Index () { return ( @@ -94,10 +94,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_render_native_component, - r#" + get_syntax_config(), + |_| tr(), + should_render_native_component, + r#" function Index () { return ( diff --git a/crates/swc_plugin_compile_mode/src/tests/condition.rs b/crates/swc_plugin_compile_mode/src/tests/condition.rs index 07705eb37113..81b1de6d498d 100644 --- a/crates/swc_plugin_compile_mode/src/tests/condition.rs +++ b/crates/swc_plugin_compile_mode/src/tests/condition.rs @@ -1,11 +1,11 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( - get_syntax_config(), - |_| tr(), - should_support_and_expr, - r#" + get_syntax_config(), + |_| tr(), + should_support_and_expr, + r#" function Index () { return ( @@ -35,10 +35,10 @@ test!( "# ); test!( - get_syntax_config(), - |_| tr(), - should_support_conditional_expr, - r#" + get_syntax_config(), + |_| tr(), + should_support_conditional_expr, + r#" function Index () { const [list, setList] = useState([ 1, diff --git a/crates/swc_plugin_compile_mode/src/tests/entry.rs b/crates/swc_plugin_compile_mode/src/tests/entry.rs index de9f47355941..a588ccfd227a 100644 --- a/crates/swc_plugin_compile_mode/src/tests/entry.rs +++ b/crates/swc_plugin_compile_mode/src/tests/entry.rs @@ -1,11 +1,11 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( - get_syntax_config(), - |_| tr(), - should_support_multi_compile_mode, - r#" + get_syntax_config(), + |_| tr(), + should_support_multi_compile_mode, + r#" function Index () { return ( diff --git a/crates/swc_plugin_compile_mode/src/tests/harmony/attributes.rs b/crates/swc_plugin_compile_mode/src/tests/harmony/attributes.rs index 23952b0b8302..f6d974c59283 100644 --- a/crates/swc_plugin_compile_mode/src/tests/harmony/attributes.rs +++ b/crates/swc_plugin_compile_mode/src/tests/harmony/attributes.rs @@ -1,11 +1,11 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( - get_syntax_config(), - |_| tr(), - should_turn_dynamic_attrs, - r#" + get_syntax_config(), + |_| tr(), + should_turn_dynamic_attrs, + r#" function Index () { return ( @@ -25,10 +25,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_handle_events, - r#" + get_syntax_config(), + |_| tr(), + should_handle_events, + r#" function Index () { return ( diff --git a/crates/swc_plugin_compile_mode/src/tests/harmony/children.rs b/crates/swc_plugin_compile_mode/src/tests/harmony/children.rs index 341731a2aace..802f0e75f749 100644 --- a/crates/swc_plugin_compile_mode/src/tests/harmony/children.rs +++ b/crates/swc_plugin_compile_mode/src/tests/harmony/children.rs @@ -1,11 +1,11 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( - get_syntax_config(), - |_| tr(), - should_support_render_fn, - r#" + get_syntax_config(), + |_| tr(), + should_support_render_fn, + r#" function Index () { return ( @@ -23,10 +23,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_support_fragment, - r#" + get_syntax_config(), + |_| tr(), + should_support_fragment, + r#" function Index () { return ( @@ -58,10 +58,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_render_react_component, - r#" + get_syntax_config(), + |_| tr(), + should_render_react_component, + r#" function Index () { return ( diff --git a/crates/swc_plugin_compile_mode/src/tests/harmony/condition.rs b/crates/swc_plugin_compile_mode/src/tests/harmony/condition.rs index 97c264e49478..a06cd6e1993c 100644 --- a/crates/swc_plugin_compile_mode/src/tests/harmony/condition.rs +++ b/crates/swc_plugin_compile_mode/src/tests/harmony/condition.rs @@ -1,11 +1,11 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( - get_syntax_config(), - |_| tr(), - should_support_and_expr, - r#" + get_syntax_config(), + |_| tr(), + should_support_and_expr, + r#" function Index () { return ( @@ -22,10 +22,10 @@ test!( "# ); test!( - get_syntax_config(), - |_| tr(), - should_support_conditional_expr, - r#" + get_syntax_config(), + |_| tr(), + should_support_conditional_expr, + r#" function Index () { return ( diff --git a/crates/swc_plugin_compile_mode/src/tests/harmony/entry.rs b/crates/swc_plugin_compile_mode/src/tests/harmony/entry.rs index 340e6e6d59bd..ebe8fa4904d6 100644 --- a/crates/swc_plugin_compile_mode/src/tests/harmony/entry.rs +++ b/crates/swc_plugin_compile_mode/src/tests/harmony/entry.rs @@ -1,5 +1,5 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( get_syntax_config(), diff --git a/crates/swc_plugin_compile_mode/src/tests/harmony/looping.rs b/crates/swc_plugin_compile_mode/src/tests/harmony/looping.rs index c4362f0c7741..0d3c09a441ee 100644 --- a/crates/swc_plugin_compile_mode/src/tests/harmony/looping.rs +++ b/crates/swc_plugin_compile_mode/src/tests/harmony/looping.rs @@ -1,11 +1,11 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( - get_syntax_config(), - |_| tr(), - should_loop_with_function_expr, - r#" + get_syntax_config(), + |_| tr(), + should_loop_with_function_expr, + r#" function Index () { return ( @@ -26,10 +26,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_loop_with_arrow_function_with_blockstmt, - r#" + get_syntax_config(), + |_| tr(), + should_loop_with_arrow_function_with_blockstmt, + r#" function Index () { return ( diff --git a/crates/swc_plugin_compile_mode/src/tests/harmony/mod.rs b/crates/swc_plugin_compile_mode/src/tests/harmony/mod.rs index 858212721f97..f86994eb25d8 100644 --- a/crates/swc_plugin_compile_mode/src/tests/harmony/mod.rs +++ b/crates/swc_plugin_compile_mode/src/tests/harmony/mod.rs @@ -1,19 +1,16 @@ pub use super::get_syntax_config; +use crate::{transform_harmony::*, PluginConfig}; use swc_core::ecma::visit::{as_folder, Fold, VisitMut}; -use crate::{ - PluginConfig, - transform_harmony::*, -}; -mod entry; mod attributes; +mod children; mod condition; +mod entry; mod looping; -mod children; -pub fn tr () -> impl Fold + VisitMut { +pub fn tr() -> impl Fold + VisitMut { let config = serde_json::from_str::( - r#" + r#" { "is_harmony": true, "tmpl_prefix": "f0", @@ -37,7 +34,7 @@ pub fn tr () -> impl Fold + VisitMut { "onTouchCancel": "onTouch", "onLoad": "onComplete" } - }"# + }"#, ) .unwrap(); let visitor = TransformVisitor::new(config); diff --git a/crates/swc_plugin_compile_mode/src/tests/looping.rs b/crates/swc_plugin_compile_mode/src/tests/looping.rs index fbf9257ce957..1adc3acf43d5 100644 --- a/crates/swc_plugin_compile_mode/src/tests/looping.rs +++ b/crates/swc_plugin_compile_mode/src/tests/looping.rs @@ -1,11 +1,11 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( - get_syntax_config(), - |_| tr(), - should_loop_with_function_expr, - r#" + get_syntax_config(), + |_| tr(), + should_loop_with_function_expr, + r#" function Index () { return ( @@ -26,10 +26,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_loop_with_arrow_function_with_blockstmt, - r#" + get_syntax_config(), + |_| tr(), + should_loop_with_arrow_function_with_blockstmt, + r#" function Index () { return ( @@ -43,10 +43,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_loop_with_arrow_function_with_expr, - r#" + get_syntax_config(), + |_| tr(), + should_loop_with_arrow_function_with_expr, + r#" function Index () { return ( @@ -58,10 +58,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_support_nested_loop, - r#" + get_syntax_config(), + |_| tr(), + should_support_nested_loop, + r#" function Index () { return ( @@ -83,12 +83,11 @@ test!( "# ); - test!( - get_syntax_config(), - |_| tr(), - should_loop_with_fragment, - r#" + get_syntax_config(), + |_| tr(), + should_loop_with_fragment, + r#" function Index () { return ( @@ -104,12 +103,11 @@ test!( "# ); - test!( - get_syntax_config(), - |_| tr(), - should_loop_be_wrapped_when_its_not_the_only_child, - r#" + get_syntax_config(), + |_| tr(), + should_loop_be_wrapped_when_its_not_the_only_child, + r#" function Index () { return ( diff --git a/crates/swc_plugin_compile_mode/src/tests/mod.rs b/crates/swc_plugin_compile_mode/src/tests/mod.rs index 1675d69f25b7..b78d8af3416c 100644 --- a/crates/swc_plugin_compile_mode/src/tests/mod.rs +++ b/crates/swc_plugin_compile_mode/src/tests/mod.rs @@ -1,24 +1,21 @@ +use crate::{transform::*, PluginConfig}; use swc_core::ecma::{ - parser, - visit::{as_folder, Fold}, -}; -use crate::{ - PluginConfig, - transform::*, + parser, + visit::{as_folder, Fold}, }; -mod entry; mod attributes; -mod shake; -mod condition; -mod looping; mod children; +mod condition; +mod entry; mod harmony; +mod looping; +mod shake; mod wxs; -pub fn tr () -> impl Fold { - let config = serde_json::from_str::( - r#" +pub fn tr() -> impl Fold { + let config = serde_json::from_str::( + r#" { "tmpl_prefix": "f0", "components": { @@ -87,16 +84,16 @@ pub fn tr () -> impl Fold { "xs": "wxs", "type": "weapp" } - }"# - ) - .unwrap(); - let visitor = TransformVisitor::new(config); - as_folder(visitor) + }"#, + ) + .unwrap(); + let visitor = TransformVisitor::new(config); + as_folder(visitor) } -pub fn get_syntax_config () -> parser::Syntax { - parser::Syntax::Es(parser::EsConfig { - jsx: true, - ..Default::default() - }) +pub fn get_syntax_config() -> parser::Syntax { + parser::Syntax::Es(parser::EsConfig { + jsx: true, + ..Default::default() + }) } diff --git a/crates/swc_plugin_compile_mode/src/tests/shake.rs b/crates/swc_plugin_compile_mode/src/tests/shake.rs index 7910b49b9351..237635dcfce9 100644 --- a/crates/swc_plugin_compile_mode/src/tests/shake.rs +++ b/crates/swc_plugin_compile_mode/src/tests/shake.rs @@ -1,11 +1,11 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( - get_syntax_config(), - |_| tr(), - should_static_jsx_being_shaked, - r#" + get_syntax_config(), + |_| tr(), + should_static_jsx_being_shaked, + r#" function Index () { return ( diff --git a/crates/swc_plugin_compile_mode/src/tests/wxs.rs b/crates/swc_plugin_compile_mode/src/tests/wxs.rs index 489fc8fb9091..fe1accf0117c 100644 --- a/crates/swc_plugin_compile_mode/src/tests/wxs.rs +++ b/crates/swc_plugin_compile_mode/src/tests/wxs.rs @@ -1,11 +1,11 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( - get_syntax_config(), - |_| tr(), - should_support_wxs_children, - r#" + get_syntax_config(), + |_| tr(), + should_support_wxs_children, + r#" function Index () { return ( @@ -20,10 +20,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_support_wxs_attributes, - r#" + get_syntax_config(), + |_| tr(), + should_support_wxs_attributes, + r#" function Index () { return ( @@ -38,10 +38,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_wxs_work_in_multi_compile_mode, - r#" + get_syntax_config(), + |_| tr(), + should_wxs_work_in_multi_compile_mode, + r#" function Index () { return ( @@ -62,10 +62,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_support_wxs_events, - r#" + get_syntax_config(), + |_| tr(), + should_support_wxs_events, + r#" function Index () { return ( diff --git a/crates/swc_plugin_compile_mode/src/transform.rs b/crates/swc_plugin_compile_mode/src/transform.rs index 294dbc24a918..a55a86d427ae 100644 --- a/crates/swc_plugin_compile_mode/src/transform.rs +++ b/crates/swc_plugin_compile_mode/src/transform.rs @@ -1,483 +1,583 @@ - +use crate::utils::{self, constants::*}; +use crate::{utils::as_xscript_expr_string, PluginConfig}; +use std::collections::HashMap; use swc_core::{ - common::{ - iter::IdentifyLast, - util::take::Take, - DUMMY_SP as span, - Spanned, - }, - ecma::{ - self, - ast::*, - visit::{VisitMut, VisitMutWith}, - utils::{quote_ident, quote_str}, - }, - plugin::errors::HANDLER, - atoms::Atom, + atoms::Atom, + common::{iter::IdentifyLast, util::take::Take, Spanned, DUMMY_SP as span}, + ecma::{ + self, + ast::*, + utils::{quote_ident, quote_str}, + visit::{VisitMut, VisitMutWith}, + }, + plugin::errors::HANDLER, }; -use std::collections::HashMap; -use crate::{PluginConfig, utils::as_xscript_expr_string}; -use crate::utils::{self, constants::*}; struct PreVisitor; impl PreVisitor { - fn new () -> Self { - Self {} - } + fn new() -> Self { + Self {} + } } impl VisitMut for PreVisitor { - fn visit_mut_jsx_element_children(&mut self, children: &mut Vec) { - let len = children.len(); - - // 当 JSX 循环表达式存在兄弟节点,且这些兄弟节点中有动态节点(存在 JSX 表达式)时, - // 自动为该循环体外层包裹一个 。 - // 对应测试用例:should_loop_be_wrapped_when_its_not_the_only_child - if len > 1 { - let mut list: Vec = vec![]; - - // 收集 JSX 循环表达式到 list - children - .iter_mut() - .enumerate() - .for_each(|(i, child)| { - if let JSXElementChild::JSXExprContainer(JSXExprContainer { expr: JSXExpr::Expr(expr), .. }) = child { - if let Expr::Call(CallExpr { callee: Callee::Expr(callee_expr), args, .. }) = &mut **expr { - if utils::is_call_expr_of_loop(callee_expr, args) { - list.push(i); - } - } - } - }); - - // 遍历 list,为每个 child 的外层包裹 - fn wrap (list: Vec, children: &mut Vec) { - list.into_iter().for_each(|i| { - let child = &mut children[i]; - if let JSXElementChild::JSXExprContainer(JSXExprContainer { expr: JSXExpr::Expr(expr), .. }) = child { - let expr = expr.take(); - *child = JSXElementChild::JSXElement(Box::new(JSXElement { - span, - opening: JSXOpeningElement { - name: JSXElementName::Ident(quote_ident!("block")), - span, - attrs: vec![], - self_closing: false, - type_args: None - }, - children: vec![JSXElementChild::JSXExprContainer(JSXExprContainer { span, expr: JSXExpr::Expr(expr) })], - closing: Some(JSXClosingElement { span, name: JSXElementName::Ident(quote_ident!("block")) }) - })); - } - }); + fn visit_mut_jsx_element_children(&mut self, children: &mut Vec) { + let len = children.len(); + + // 当 JSX 循环表达式存在兄弟节点,且这些兄弟节点中有动态节点(存在 JSX 表达式)时, + // 自动为该循环体外层包裹一个 。 + // 对应测试用例:should_loop_be_wrapped_when_its_not_the_only_child + if len > 1 { + let mut list: Vec = vec![]; + + // 收集 JSX 循环表达式到 list + children.iter_mut().enumerate().for_each(|(i, child)| { + if let JSXElementChild::JSXExprContainer(JSXExprContainer { + expr: JSXExpr::Expr(expr), + .. + }) = child + { + if let Expr::Call(CallExpr { + callee: Callee::Expr(callee_expr), + args, + .. + }) = &mut **expr + { + if utils::is_call_expr_of_loop(callee_expr, args) { + list.push(i); } + } + } + }); + + // 遍历 list,为每个 child 的外层包裹 + fn wrap(list: Vec, children: &mut Vec) { + list.into_iter().for_each(|i| { + let child = &mut children[i]; + if let JSXElementChild::JSXExprContainer(JSXExprContainer { + expr: JSXExpr::Expr(expr), + .. + }) = child + { + let expr = expr.take(); + *child = JSXElementChild::JSXElement(Box::new(JSXElement { + span, + opening: JSXOpeningElement { + name: JSXElementName::Ident(quote_ident!("block")), + span, + attrs: vec![], + self_closing: false, + type_args: None, + }, + children: vec![JSXElementChild::JSXExprContainer(JSXExprContainer { + span, + expr: JSXExpr::Expr(expr), + })], + closing: Some(JSXClosingElement { + span, + name: JSXElementName::Ident(quote_ident!("block")), + }), + })); + } + }); + } + + if list.len() == 1 { + // 只有一个 JSX 循环表达式时,检查兄弟节点是否全是静态节点,如果不是则要包裹 + let mut pure = true; + let index = list[0]; + for i in 0..len { + if i != index && !utils::is_static_jsx_element_child(&children[i]) { + pure = false; + break; + } + } + if !pure { + wrap(list, children); + } + } else if list.len() > 1 { + // 有多个 JSX 循环表达式时一定要包裹 + wrap(list, children); + } + } - if list.len() == 1 { - // 只有一个 JSX 循环表达式时,检查兄弟节点是否全是静态节点,如果不是则要包裹 - let mut pure = true; - let index = list[0]; - for i in 0..len { - if i != index && !utils::is_static_jsx_element_child(&children[i]) { - pure = false; - break; - } - } - if !pure { - wrap(list, children); + children.visit_mut_children_with(self); + } + fn visit_mut_jsx_element_child(&mut self, child: &mut JSXElementChild) { + if let JSXElementChild::JSXExprContainer(JSXExprContainer { + expr: JSXExpr::Expr(expr), + .. + }) = child + { + if let Expr::Paren(ParenExpr { expr: e, .. }) = &mut **expr { + *expr = e.take(); + } + + match &mut **expr { + Expr::Bin(BinExpr { + op, left, right, .. + }) => { + // C&&A 替换为 C?A:A',原因是为了无论显示还是隐藏都保留一个元素,从而不影响兄弟节点的变量路径 + if *op == op!("&&") { + fn inject_compile_if(el: &mut Box, condition: &mut Box) -> () { + el.opening + .attrs + .push(utils::create_jsx_expr_attr(COMPILE_IF, condition.clone())); + } + fn get_element_double( + element_name: JSXElementName, + condition: &mut Box, + right: &mut Box, + ) -> Expr { + Expr::Cond(CondExpr { + span, + test: condition.take(), + cons: right.take(), + alt: Box::new(utils::create_self_closing_jsx_element_expr( + element_name, // element 替换为同类型的元素。在显示/隐藏切换时,让运行时 diff 只更新必要属性而不是整个节点刷新 + Some(vec![utils::create_jsx_bool_attr(COMPILE_IGNORE)]), + )), + }) + } + match &mut **right { + Expr::JSXElement(el) => { + let element_name = el.opening.name.clone(); + inject_compile_if(el, left); + **expr = get_element_double(element_name, left, right); + } + Expr::Paren(ParenExpr { + expr: paren_expr, .. + }) => { + if paren_expr.is_jsx_element() { + let el: &mut Box = paren_expr.as_mut_jsx_element().unwrap(); + let element_name = el.opening.name.clone(); + inject_compile_if(el, left); + **expr = get_element_double(element_name, left, paren_expr); } - } else if list.len() > 1 { - // 有多个 JSX 循环表达式时一定要包裹 - wrap(list, children); + } + Expr::Lit(_) => { + **expr = Expr::Cond(CondExpr { + span, + test: left.take(), + cons: right.take(), + alt: Box::new(Expr::Lit(Lit::Str(quote_str!(COMPILE_IGNORE)))), + }) + } + _ => { + let jsx_el_name = JSXElementName::Ident(quote_ident!("block")); + let mut block = Box::new(JSXElement { + span, + opening: JSXOpeningElement { + name: jsx_el_name.clone(), + span, + attrs: vec![], + self_closing: false, + type_args: None, + }, + children: vec![JSXElementChild::JSXExprContainer(JSXExprContainer { + span, + expr: JSXExpr::Expr(right.take()), + })], + closing: Some(JSXClosingElement { + span, + name: jsx_el_name.clone(), + }), + }); + inject_compile_if(&mut block, left); + **expr = + get_element_double(jsx_el_name, left, &mut Box::new(Expr::JSXElement(block))); + } } + } } - - children.visit_mut_children_with(self); - } - fn visit_mut_jsx_element_child (&mut self, child: &mut JSXElementChild) { - if let JSXElementChild::JSXExprContainer(JSXExprContainer { expr: JSXExpr::Expr(expr), .. }) = child { - if let Expr::Paren(ParenExpr { expr: e, .. }) = &mut **expr { - *expr = e.take(); + Expr::Cond(CondExpr { + test, cons, alt, .. + }) => { + let compile_if = utils::create_jsx_expr_attr(COMPILE_IF, test.clone()); + let compile_else = utils::create_jsx_bool_attr(COMPILE_ELSE); + let process_cond_arm = |arm: &mut Box, attr: JSXAttrOrSpread| match &mut **arm { + Expr::JSXElement(el) => { + el.opening.attrs.push(attr); } - - match &mut **expr { - Expr::Bin(BinExpr { op, left, right, ..}) => { - // C&&A 替换为 C?A:A',原因是为了无论显示还是隐藏都保留一个元素,从而不影响兄弟节点的变量路径 - if *op == op!("&&") { - fn inject_compile_if (el: &mut Box, condition: &mut Box) -> () { - el.opening.attrs.push(utils::create_jsx_expr_attr(COMPILE_IF, condition.clone())); - } - fn get_element_double (element_name: JSXElementName, condition: &mut Box, right: &mut Box) -> Expr { - Expr::Cond(CondExpr { - span, - test: condition.take(), - cons: right.take(), - alt: Box::new(utils::create_self_closing_jsx_element_expr( - element_name, // element 替换为同类型的元素。在显示/隐藏切换时,让运行时 diff 只更新必要属性而不是整个节点刷新 - Some(vec![utils::create_jsx_bool_attr(COMPILE_IGNORE)] - ))) - }) - } - match &mut **right { - Expr::JSXElement(el) => { - let element_name = el.opening.name.clone(); - inject_compile_if(el, left); - **expr = get_element_double(element_name, left, right); - }, - Expr::Paren(ParenExpr { expr: paren_expr, .. }) => { - if paren_expr.is_jsx_element() { - let el: &mut Box = paren_expr.as_mut_jsx_element().unwrap(); - let element_name = el.opening.name.clone(); - inject_compile_if(el, left); - **expr = get_element_double(element_name, left, paren_expr); - } - }, - Expr::Lit(_) => { - **expr = Expr::Cond(CondExpr { - span, - test: left.take(), - cons: right.take(), - alt: Box::new(Expr::Lit(Lit::Str(quote_str!(COMPILE_IGNORE)))) - }) - }, - _ => { - let jsx_el_name = JSXElementName::Ident(quote_ident!("block")); - let mut block = Box::new(JSXElement { - span, - opening: JSXOpeningElement { name: jsx_el_name.clone(), span, attrs: vec![], self_closing: false, type_args: None }, - children: vec![JSXElementChild::JSXExprContainer(JSXExprContainer { span, expr: JSXExpr::Expr(right.take()) })], - closing: Some(JSXClosingElement { span, name: jsx_el_name.clone() }) - }); - inject_compile_if(&mut block, left); - **expr = get_element_double(jsx_el_name, left, &mut Box::new(Expr::JSXElement(block))); - } - } - } - }, - Expr::Cond(CondExpr { test, cons, alt, ..}) => { - let compile_if = utils::create_jsx_expr_attr(COMPILE_IF, test.clone()); - let compile_else = utils::create_jsx_bool_attr(COMPILE_ELSE); - let process_cond_arm = |arm: &mut Box, attr: JSXAttrOrSpread| { - match &mut **arm { - Expr::JSXElement(el) => { - el.opening.attrs.push(attr); - }, - _ => { - let temp = arm.take(); - let jsx_el_name = JSXElementName::Ident(quote_ident!("block")); - **arm = Expr::JSXElement(Box::new(JSXElement { - span, - opening: JSXOpeningElement { name: jsx_el_name.clone(), span, attrs: vec![attr], self_closing: false, type_args: None }, - children: vec![JSXElementChild::JSXExprContainer(JSXExprContainer { span, expr: JSXExpr::Expr(temp)})], - closing: Some(JSXClosingElement { span, name: jsx_el_name }) - })) - } - } - }; - process_cond_arm(cons, compile_if); - process_cond_arm(alt, compile_else); + _ => { + let temp = arm.take(); + let jsx_el_name = JSXElementName::Ident(quote_ident!("block")); + **arm = Expr::JSXElement(Box::new(JSXElement { + span, + opening: JSXOpeningElement { + name: jsx_el_name.clone(), + span, + attrs: vec![attr], + self_closing: false, + type_args: None, }, - _ => (), + children: vec![JSXElementChild::JSXExprContainer(JSXExprContainer { + span, + expr: JSXExpr::Expr(temp), + })], + closing: Some(JSXClosingElement { + span, + name: jsx_el_name, + }), + })) } - - expr.visit_mut_children_with(self); - } else { - child.visit_mut_children_with(self); + }; + process_cond_arm(cons, compile_if); + process_cond_arm(alt, compile_else); } + _ => (), + } + + expr.visit_mut_children_with(self); + } else { + child.visit_mut_children_with(self); } + } } pub struct TransformVisitor { - pub config: PluginConfig, - pub is_compile_mode: bool, - pub node_stack: Vec, - pub templates: HashMap, - pub get_tmpl_name: Box String>, - pub xs_module_names: Vec, - pub xs_sources: Vec, + pub config: PluginConfig, + pub is_compile_mode: bool, + pub node_stack: Vec, + pub templates: HashMap, + pub get_tmpl_name: Box String>, + pub xs_module_names: Vec, + pub xs_sources: Vec, } impl TransformVisitor { - pub fn new (config: PluginConfig) -> Self { - let get_tmpl_name = Box::new(utils::named_iter( - format!("{}t", config.tmpl_prefix) - )); - Self { - config, - is_compile_mode: false, - node_stack: vec![], - templates: HashMap::new(), - get_tmpl_name, - xs_module_names: vec![], - xs_sources: vec![], - } + pub fn new(config: PluginConfig) -> Self { + let get_tmpl_name = Box::new(utils::named_iter(format!("{}t", config.tmpl_prefix))); + Self { + config, + is_compile_mode: false, + node_stack: vec![], + templates: HashMap::new(), + get_tmpl_name, + xs_module_names: vec![], + xs_sources: vec![], } - - fn build_xml_element (&mut self, el: &mut JSXElement) -> String { - let is_inner_component = utils::is_inner_component(&el, &self.config); - let opening_element = &mut el.opening; - - match &opening_element.name { - JSXElementName::Ident(ident) => { - if is_inner_component { - // 内置组件 - let mut name = utils::to_kebab_case(ident.as_ref()); - let attrs = self.build_xml_attrs(opening_element, &name); - if attrs.is_none() { return String::new() }; - let (children, ..) = self.build_xml_children(&mut el.children, None); - - if utils::is_xscript(&name) { - name = match self.config.adapter.get("xs") { - Some(xs) => { - xs.to_string() - }, - None => { - HANDLER.with(|handler| { - handler - .struct_span_err(el.span, "Taro CompileMode 语法错误") - .span_label(el.span, "当前小程序平台不支持 xs 语法") - .emit(); - panic!() - }) - } - }; - } - - format!("<{}{}>{}", name, attrs.unwrap_or_default(), children, name) - } else { - // 回退到旧的渲染模式(React 组件、原生自定义组件) - let node_path = self.get_current_node_path(); - format!(r#"