1- use crate :: utils:: { self , constants:: * } ;
1+ use crate :: utils:: { self , constants:: * , transform_taro_components } ;
22use crate :: { utils:: as_xscript_expr_string, PluginConfig } ;
33use std:: collections:: HashMap ;
4+ use std:: vec;
45use swc_core:: {
56 atoms:: Atom ,
67 common:: { iter:: IdentifyLast , util:: take:: Take , Spanned , DUMMY_SP as span} ,
@@ -13,10 +14,23 @@ use swc_core::{
1314 plugin:: errors:: HANDLER ,
1415} ;
1516
16- struct PreVisitor ;
17+ struct PreVisitor {
18+ // HashMap<导出名, 模块标识符>
19+ pub import_specifiers : HashMap < String , String > ,
20+ // HashMap<导出名, 别名>
21+ // import { x as y } from 'pkg'; import_aliases: [[x -> y]]
22+ pub import_aliases : HashMap < String , String > ,
23+ }
24+
1725impl PreVisitor {
18- fn new ( ) -> Self {
19- Self { }
26+ fn new (
27+ import_specifiers : HashMap < String , String > ,
28+ import_aliases : HashMap < String , String > ,
29+ ) -> Self {
30+ Self {
31+ import_specifiers,
32+ import_aliases,
33+ }
2034 }
2135}
2236impl VisitMut for PreVisitor {
@@ -232,6 +246,12 @@ impl VisitMut for PreVisitor {
232246 child. visit_mut_children_with ( self ) ;
233247 }
234248 }
249+
250+ fn visit_mut_jsx_element ( & mut self , el : & mut JSXElement ) {
251+ // 处理 @tarojs/components 的 List,ListItem 组件
252+ transform_taro_components ( el, & self . import_specifiers , & self . import_aliases ) ;
253+ el. visit_mut_children_with ( self ) ;
254+ }
235255}
236256
237257pub struct TransformVisitor {
@@ -242,6 +262,11 @@ pub struct TransformVisitor {
242262 pub get_tmpl_name : Box < dyn FnMut ( ) -> String > ,
243263 pub xs_module_names : Vec < String > ,
244264 pub xs_sources : Vec < String > ,
265+ // HashMap<导出名, 模块标识符>
266+ pub import_specifiers : HashMap < String , String > ,
267+ // HashMap<导出名, 别名>
268+ // import { x as y } from 'pkg'; import_aliases: [[x -> y]]
269+ pub import_aliases : HashMap < String , String > ,
245270}
246271
247272impl TransformVisitor {
@@ -255,15 +280,72 @@ impl TransformVisitor {
255280 get_tmpl_name,
256281 xs_module_names : vec ! [ ] ,
257282 xs_sources : vec ! [ ] ,
283+ import_specifiers : HashMap :: new ( ) ,
284+ import_aliases : HashMap :: new ( ) ,
258285 }
259286 }
260287
288+ fn collect_import_info ( & mut self , body_stmts : & mut Vec < ModuleItem > ) {
289+ body_stmts. iter ( ) . for_each ( |item| match item {
290+ ModuleItem :: ModuleDecl ( ModuleDecl :: Import ( import_decl) ) => {
291+ import_decl. specifiers . iter ( ) . for_each ( |import_specifier| {
292+ let src = import_decl. src . value . to_string ( ) ;
293+ match import_specifier {
294+ ImportSpecifier :: Named ( import_named_specifier) => {
295+ let specifier = import_named_specifier. local . sym . to_string ( ) ;
296+ // origin: 原始导出名
297+ // import { X as Y } from 'pkg', origin = X;
298+ // import { X } from 'pkg', origin = X;
299+ let mut origin = specifier. clone ( ) ;
300+ self . import_specifiers . insert ( specifier. clone ( ) , src) ;
301+
302+ if let Some ( ModuleExportName :: Ident ( imported) ) =
303+ import_named_specifier. clone ( ) . imported
304+ {
305+ origin = imported. sym . to_string ( ) ;
306+ }
307+ self
308+ . import_aliases
309+ . insert ( origin. clone ( ) , specifier. clone ( ) ) ;
310+ }
311+ ImportSpecifier :: Default ( import_default_specifier) => {
312+ let specifier = import_default_specifier. local . sym . to_string ( ) ;
313+ self . import_specifiers . insert ( specifier, src) ;
314+ }
315+ ImportSpecifier :: Namespace ( import_star_as_specifier) => {
316+ let specifier = import_star_as_specifier. local . sym . to_string ( ) ;
317+ self . import_specifiers . insert ( specifier, src) ;
318+ }
319+ }
320+ } ) ;
321+ }
322+ _ => ( ) ,
323+ } ) ;
324+ }
325+
261326 fn build_xml_element ( & mut self , el : & mut JSXElement ) -> String {
262327 let is_inner_component = utils:: is_inner_component ( & el, & self . config ) ;
263328 let opening_element = & mut el. opening ;
264329
330+ let has_slot_item_attr = opening_element. clone ( ) . attrs . iter ( ) . any ( |attr| {
331+ if let JSXAttrOrSpread :: JSXAttr ( attr) = attr {
332+ if let JSXAttrName :: Ident ( Ident { sym : name, .. } ) = & attr. name {
333+ return name. to_string ( ) == SLOT_ITEM ;
334+ }
335+ }
336+ false
337+ } ) ;
265338 match & opening_element. name {
266339 JSXElementName :: Ident ( ident) => {
340+ // 先特殊处理有 slotItem 属性的组件,避免进入回退逻辑添加 wx:for 造成干扰
341+ if has_slot_item_attr {
342+ let node_path = self . get_current_node_path ( ) ;
343+ return format ! (
344+ "<block slot:item slot:index>{}</block>" ,
345+ self . generate_template( node_path, "" . to_string( ) )
346+ ) ;
347+ }
348+
267349 if is_inner_component {
268350 // 内置组件
269351 let mut name = utils:: to_kebab_case ( ident. as_ref ( ) ) ;
@@ -295,8 +377,23 @@ impl TransformVisitor {
295377 )
296378 } else {
297379 // 回退到旧的渲染模式(React 组件、原生自定义组件)
380+ // 如果是 map React组件,那么组件经过 extract_jsx_loop 的处理后会有 compileFor 属性,可以检测这个属性判断当前组件是否是循环里的组件
381+ let is_loop = el. opening . attrs . iter ( ) . any ( |attr| {
382+ if let JSXAttrOrSpread :: JSXAttr ( attr) = attr {
383+ if let JSXAttrName :: Ident ( attr) = & attr. name {
384+ return attr. sym == COMPILE_FOR ;
385+ }
386+ }
387+ false
388+ } ) ;
298389 let node_path = self . get_current_node_path ( ) ;
299- self . generate_template ( node_path)
390+ // 循环的组件需要添加 wx:for 指令,否则生成的 template 里的 item 找不到
391+ let attrs = if is_loop {
392+ "wx:for=\" {{i.cn}}\" wx:key=\" {{sid}}\" "
393+ } else {
394+ ""
395+ } ;
396+ self . generate_template ( node_path, attrs. to_string ( ) )
300397 }
301398 }
302399 JSXElementName :: JSXMemberExpr ( JSXMemberExpr { prop, .. } ) => {
@@ -307,7 +404,7 @@ impl TransformVisitor {
307404 } else {
308405 // 回退到旧的渲染模式
309406 let node_path = self . get_current_node_path ( ) ;
310- self . generate_template ( node_path)
407+ self . generate_template ( node_path, "" . to_string ( ) )
311408 }
312409 }
313410 _ => String :: new ( ) ,
@@ -325,7 +422,6 @@ impl TransformVisitor {
325422 let is_xscript = utils:: is_xscript ( element_name) ;
326423 let mut attrs_wait_for_inserting: Vec < JSXAttrOrSpread > = vec ! [ ] ;
327424 let mut get_xs_attrs_name = utils:: named_iter ( "xs" . into ( ) ) ;
328-
329425 opening_element. attrs . retain_mut ( |attr| {
330426 if let JSXAttrOrSpread :: JSXAttr ( jsx_attr) = attr {
331427 if let JSXAttrName :: Ident ( Ident { sym : name, .. } ) = & jsx_attr. name {
@@ -471,7 +567,16 @@ impl TransformVisitor {
471567 // 小程序组件标准属性 -> 取 @tarojs/shared 传递过来的属性值;非标准属性 -> 取属性名
472568 let value: & str = attrs_map
473569 . get ( & miniapp_attr_name)
474- . map ( |res| res. as_str ( ) )
570+ . map ( |res| {
571+ // list-builder这种场景下需要把原 list 换成 taro vdom 的 list
572+ if utils:: to_kebab_case ( element_name) == "list-builder"
573+ && miniapp_attr_name == "list"
574+ {
575+ "cn"
576+ } else {
577+ res. as_str ( )
578+ }
579+ } )
475580 . unwrap_or ( if miniapp_attr_name == "id" {
476581 "uid"
477582 } else {
@@ -496,6 +601,7 @@ impl TransformVisitor {
496601 if jsx_attr_name == COMPILE_ELSE || jsx_attr_name == COMPILE_IGNORE {
497602 props. insert ( miniapp_attr_name, String :: from ( jsx_attr_name) ) ;
498603 } else if jsx_attr_name == COMPILE_FOR {
604+ // 构造 wx:for 表达式
499605 let current_path = self . get_current_loop_path ( ) ;
500606 let miniapp_attr_value = format ! ( "{{{{{}}}}}" , current_path) ;
501607 props. insert ( miniapp_attr_name, miniapp_attr_value) ;
@@ -643,7 +749,7 @@ impl TransformVisitor {
643749 let child_string = self . build_xml_element ( & mut * return_value) ;
644750 children_string. push_str ( & child_string) ;
645751 } else if utils:: is_render_fn ( callee_expr) {
646- let tmpl = self . generate_template ( node_path) ;
752+ let tmpl = self . generate_template ( node_path, "" . to_string ( ) ) ;
647753 children_string. push_str ( & tmpl)
648754 } else {
649755 let mut xscript_expr_string: Option < String > = None ;
@@ -786,19 +892,20 @@ impl TransformVisitor {
786892 ( children_string, retain_child_counter - start)
787893 }
788894
789- fn generate_template ( & mut self , node_path : String ) -> String {
895+ fn generate_template ( & mut self , node_path : String , attrs : String ) -> String {
790896 if self . config . is_use_xs {
791897 format ! (
792- r#"<template is="{{{{xs.a(c, {}.nn, l)}}}}" data="{{{{i:{},c:c+1,l:xs.f(l,{}.nn)}}}}" />"# ,
793- node_path, node_path, node_path
898+ r#"<template is="{{{{xs.a(c, {}.nn, l)}}}}" data="{{{{i:{},c:c+1,l:xs.f(l,{}.nn)}}}}" {} />"# ,
899+ node_path, node_path, node_path, attrs
794900 )
795901 } else {
796902 format ! (
797- r#"<template is="{{{{'tmpl_' + ({}.nn[0] === '{}' ? 0 : c) + '_' + {}.nn }}}}" data="{{{{i:{},c:c+1}}}}" />"# ,
903+ r#"<template is="{{{{'tmpl_' + ({}.nn[0] === '{}' ? 0 : c) + '_' + {}.nn }}}}" data="{{{{i:{},c:c+1}}}}" {} />"# ,
798904 node_path,
799905 self . config. tmpl_prefix. chars( ) . next( ) . unwrap( ) ,
800906 node_path,
801- node_path
907+ node_path,
908+ attrs
802909 )
803910 }
804911 }
@@ -864,9 +971,14 @@ impl VisitMut for TransformVisitor {
864971 }
865972 }
866973 }
974+
867975 if self . is_compile_mode {
868976 self . reset_states ( ) ;
869- el. visit_mut_children_with ( & mut PreVisitor :: new ( ) ) ;
977+ transform_taro_components ( el, & self . import_specifiers , & self . import_aliases ) ;
978+ el. visit_mut_children_with ( & mut PreVisitor :: new (
979+ self . import_specifiers . clone ( ) ,
980+ self . import_aliases . clone ( ) ,
981+ ) ) ;
870982
871983 let tmpl_contents = format ! (
872984 r#"{}<template name="tmpl_0_{}">{}</template>{}"# ,
@@ -883,6 +995,8 @@ impl VisitMut for TransformVisitor {
883995 }
884996
885997 fn visit_mut_module_items ( & mut self , body_stmts : & mut Vec < ModuleItem > ) {
998+ // 收集模块导入信息
999+ self . collect_import_info ( body_stmts) ;
8861000 body_stmts. visit_mut_children_with ( self ) ;
8871001
8881002 let mut keys: Vec < & String > = self . templates . keys ( ) . collect ( ) ;
0 commit comments