@@ -20,11 +20,11 @@ use swc_core::{
2020 } ,
2121 ecma:: {
2222 ast:: {
23- ArrayLit , AssignExpr , AssignTarget , Bool , CallExpr , Callee , Expr , ExprOrSpread , Id ,
23+ ArrayLit , AssignExpr , AssignTarget , Bool , CallExpr , Callee , Expr , ExprOrSpread , Ident ,
2424 IdentName , JSXAttr , JSXAttrName , JSXAttrOrSpread , JSXAttrValue , JSXElementName ,
2525 JSXExpr , JSXExprContainer , JSXNamespacedName , JSXOpeningElement , KeyValueProp , Lit ,
26- MemberProp , ModuleItem , Number , ObjectLit , Pat , Prop , PropName , PropOrSpread ,
27- SimpleAssignTarget , Str , VarDeclarator ,
26+ MemberProp , ModuleItem , Number , ObjectLit , Prop , PropName , PropOrSpread ,
27+ SimpleAssignTarget , Str ,
2828 } ,
2929 visit:: { noop_visit_mut_type, VisitMut , VisitMutWith } ,
3030 } ,
@@ -48,7 +48,7 @@ pub struct FormatJSPluginOptions {
4848 pub additional_component_names : Vec < String > ,
4949}
5050
51- fn evaluate_expr ( evaluator : & mut Evaluator , expr : & Expr ) -> Option < String > {
51+ fn evaluate_expr ( expr : & Expr , evaluator : & mut Evaluator ) -> Option < String > {
5252 let result = match expr {
5353 Expr :: Tpl ( tpl) => evaluator. eval_tpl ( tpl) ,
5454 _ => evaluator. eval ( expr) ,
@@ -102,25 +102,22 @@ impl MessageDescriptorExtractor for JSXAttrOrSpread {
102102 if let JSXExpr :: Expr ( expr) = & container. expr {
103103 match & * * expr {
104104 Expr :: Ident ( ident) => {
105- let resolved = visitor. resolve_identifier ( ident) . cloned ( ) ;
105+ let resolved = visitor. resolve_identifier ( ident) ;
106106 if let Some ( resolved_expr) = resolved {
107107 match resolved_expr {
108108 Expr :: Object ( object_lit) => {
109109 Some ( MessageDescriptionValue :: Obj ( object_lit) )
110110 }
111- expr => evaluate_expression_with_visitor ( & expr, visitor)
111+ expr => evaluate_expr ( & expr, visitor. evaluator )
112112 . map ( MessageDescriptionValue :: Str ) ,
113113 }
114114 } else {
115115 None
116116 }
117117 }
118118 Expr :: Object ( obj) => Some ( MessageDescriptionValue :: Obj ( obj. clone ( ) ) ) ,
119- expr => {
120- // Evaluate the binary expression
121- evaluate_expression_with_visitor ( expr, visitor)
122- . map ( MessageDescriptionValue :: Str )
123- }
119+ expr => evaluate_expr ( expr, visitor. evaluator )
120+ . map ( MessageDescriptionValue :: Str ) ,
124121 }
125122 } else {
126123 None
@@ -153,7 +150,7 @@ impl MessageDescriptorExtractor for PropOrSpread {
153150 if let Prop :: KeyValue ( key_value) = & * * prop {
154151 let key = match & key_value. key {
155152 PropName :: Computed ( prop_name) => {
156- evaluate_expression_with_visitor ( & prop_name. expr , visitor)
153+ evaluate_expr ( & prop_name. expr , visitor. evaluator )
157154 }
158155 PropName :: Ident ( ident) => Some ( ident. sym . to_string ( ) ) ,
159156 PropName :: Str ( s) => {
@@ -166,8 +163,9 @@ impl MessageDescriptorExtractor for PropOrSpread {
166163 } ;
167164 let value = match & * key_value. value {
168165 Expr :: Object ( obj) => Some ( MessageDescriptionValue :: Obj ( obj. clone ( ) ) ) ,
169- expr => evaluate_expression_with_visitor ( expr, visitor)
170- . map ( MessageDescriptionValue :: Str ) ,
166+ expr => {
167+ evaluate_expr ( expr, visitor. evaluator ) . map ( MessageDescriptionValue :: Str )
168+ }
171169 } ;
172170 if let ( Some ( key) , Some ( value) ) = ( key, value) {
173171 Some ( ( key, value) )
@@ -233,95 +231,6 @@ fn get_message_descriptor_key_from_call_expr(name: &PropName) -> Option<&str> {
233231 // NOTE: Do not support evaluatePath()
234232}
235233
236- enum TraversalExpr {
237- Bin ,
238- Str ( String ) ,
239- }
240-
241- fn evaluate_expression_with_visitor (
242- root : & Expr ,
243- visitor : & mut FormatJSVisitor < impl Clone + Comments , impl SourceMapper > ,
244- ) -> Option < String > {
245- match root {
246- Expr :: Bin ( _) => { }
247- _ => {
248- return evaluate_expr ( visitor. evaluator , root) ;
249- }
250- }
251-
252- // Step 1: Create a post-order representation of the tree using a traversal
253- // stack. This process simulates recursion iteratively. The resulting
254- // `post_order_nodes` vector, when read in reverse, gives the correct order
255- // for evaluation.
256- let mut post_order_nodes: Vec < TraversalExpr > = Vec :: new ( ) ;
257- let mut traversal_stack: Vec < & Expr > = vec ! [ root] ;
258-
259- while let Some ( node) = traversal_stack. pop ( ) {
260- match node {
261- Expr :: Bin ( bin) => {
262- // Validate the operation. Only '+' is allowed.
263- if bin. op != swc_core:: ecma:: ast:: BinaryOp :: Add {
264- return None ;
265- }
266- // Traverse its left and right children.
267- post_order_nodes. push ( TraversalExpr :: Bin ) ;
268- traversal_stack. push ( & bin. left ) ;
269- traversal_stack. push ( & bin. right ) ;
270- }
271- Expr :: Tpl ( _) | Expr :: Ident ( _) | Expr :: Lit ( _) => {
272- if let Some ( res) = evaluate_expr ( visitor. evaluator , node) {
273- post_order_nodes. push ( TraversalExpr :: Str ( res) ) ;
274- } else {
275- return None ;
276- }
277- }
278- _ => {
279- // For all other expression types, we cannot evaluate them.
280- emit_non_evaluable_error ( root. span ( ) ) ;
281- }
282- }
283- }
284-
285- // Step 2: Evaluate the expression from the post-order list.
286- // We use a `result_stack` to hold intermediate string values.
287- let mut result_stack: Vec < String > = Vec :: new ( ) ;
288-
289- // We iterate through our collected nodes in reverse to get the correct
290- // post-order.
291- for node in post_order_nodes. iter ( ) . rev ( ) {
292- match & & node {
293- // If it's a literal, just push its value onto the result stack.
294- TraversalExpr :: Str ( s) => {
295- result_stack. push ( s. clone ( ) ) ;
296- }
297- // If it's a binary expression, evaluate it.
298- TraversalExpr :: Bin => {
299- // A binary operation requires two operands. If we don't have them,
300- // the tree is malformed (e.g., an operator with only one child).
301- if result_stack. len ( ) < 2 {
302- return None ;
303- }
304-
305- // Pop the operands, concatenate, and push the result.
306- // Note: The right value was processed last, so it's at the top of the stack.
307- let right_val = result_stack. pop ( ) . unwrap_or_default ( ) ;
308- let left_val = result_stack. pop ( ) . unwrap_or_default ( ) ;
309-
310- result_stack. push ( format ! ( "{left_val}{right_val}" ) ) ;
311- }
312- }
313- }
314-
315- // Step 3: Final validation and return.
316- // A correctly formed expression tree will result in exactly one value on the
317- // stack.
318- if result_stack. len ( ) == 1 {
319- Some ( result_stack. pop ( ) . unwrap ( ) )
320- } else {
321- None
322- }
323- }
324-
325234#[ derive( Debug , Clone , Deserialize ) ]
326235pub enum MessageDescriptionValue {
327236 Str ( String ) ,
@@ -615,8 +524,6 @@ pub struct FormatJSVisitor<'a, C: Clone + Comments, S: SourceMapper> {
615524 meta : HashMap < String , String > ,
616525 component_names : HashSet < String > ,
617526 function_names : HashSet < String > ,
618- // Variable tracking for React Compiler optimizations
619- variable_bindings : HashMap < Id , Expr > ,
620527 evaluator : & ' a mut Evaluator ,
621528}
622529
@@ -656,7 +563,6 @@ impl<'a, C: Clone + Comments, S: SourceMapper> FormatJSVisitor<'a, C, S> {
656563 meta : Default :: default ( ) ,
657564 component_names,
658565 function_names,
659- variable_bindings : Default :: default ( ) ,
660566 evaluator,
661567 }
662568 }
@@ -688,8 +594,11 @@ impl<'a, C: Clone + Comments, S: SourceMapper> FormatJSVisitor<'a, C, S> {
688594 }
689595 }
690596
691- fn resolve_identifier ( & self , ident : & swc_core:: ecma:: ast:: Ident ) -> Option < & Expr > {
692- self . variable_bindings . get ( & ident. to_id ( ) )
597+ fn resolve_identifier ( & mut self , ident : & Ident ) -> Option < Expr > {
598+ self . evaluator
599+ . eval_as_expr ( & Expr :: Ident ( ident. clone ( ) ) )
600+ . as_deref ( )
601+ . cloned ( )
693602 }
694603
695604 fn create_message_descriptor_from_extractor < T : MessageDescriptorExtractor > (
@@ -792,25 +701,19 @@ impl<'a, C: Clone + Comments, S: SourceMapper> FormatJSVisitor<'a, C, S> {
792701 ret
793702 }
794703
795- fn evaluate_message_descriptor (
796- & mut self ,
797- descriptor : & mut MessageDescriptor ,
798- // options: &FormatJSPluginOptions,
799- // filename: &str,
800- ) {
704+ fn evaluate_message_descriptor ( & mut self , descriptor : & mut MessageDescriptor ) {
801705 let id = & descriptor. id ;
802706 let default_message = descriptor. default_message . clone ( ) . unwrap_or_default ( ) ;
803707
804708 let description = descriptor. description . clone ( ) ;
805709
806710 // Note: do not support override fn
807711 let id = if id. is_none ( ) && !default_message. is_empty ( ) {
808- let interpolate_pattern =
809- if let Some ( interpolate_pattern) = & self . options . id_interpolation_pattern {
810- interpolate_pattern. as_str ( )
811- } else {
812- "[sha512:contenthash:base64:6]"
813- } ;
712+ let interpolate_pattern = self
713+ . options
714+ . id_interpolation_pattern
715+ . clone ( )
716+ . unwrap_or ( "[sha512:contenthash:base64:6]" . to_string ( ) ) ;
814717
815718 let content = match & description {
816719 Some ( MessageDescriptionValue :: Str ( description) ) => {
@@ -882,7 +785,7 @@ impl<'a, C: Clone + Comments, S: SourceMapper> FormatJSVisitor<'a, C, S> {
882785 _ => default_message. clone ( ) ,
883786 } ;
884787
885- interpolate_name ( & self . filename , interpolate_pattern, & content)
788+ interpolate_name ( & self . filename , & interpolate_pattern, & content)
886789 } else {
887790 id. clone ( )
888791 } ;
@@ -1042,18 +945,21 @@ fn emit_non_evaluable_error(span: Span) {
1042945impl < ' a , C : Clone + Comments , S : SourceMapper > VisitMut for FormatJSVisitor < ' a , C , S > {
1043946 noop_visit_mut_type ! ( fail) ;
1044947
1045- fn visit_mut_var_declarator ( & mut self , var_declarator : & mut VarDeclarator ) {
1046- var_declarator. visit_mut_children_with ( self ) ;
1047-
1048- // Track variable declarations for React Compiler optimizations
1049- if let ( Pat :: Ident ( binding_ident) , Some ( init) ) =
1050- ( & var_declarator. name , & var_declarator. init )
1051- {
1052- // Store the variable binding
1053- self . variable_bindings
1054- . insert ( binding_ident. id . to_id ( ) , * init. clone ( ) ) ;
1055- }
1056- }
948+ // fn visit_mut_var_declarator(&mut self, var_declarator: &mut VarDeclarator) {
949+ // var_declarator.visit_mut_children_with(self);
950+
951+ // // Track variable declarations for React Compiler optimizations
952+ // if let VarDeclarator {
953+ // name: Pat::Ident(binding_ident),
954+ // init: Some(init),
955+ // ..
956+ // } = &var_declarator
957+ // {
958+ // // Store the variable binding
959+ // self.evaluator
960+ // .store(binding_ident.id.to_id(), &init.clone());
961+ // }
962+ // }
1057963
1058964 fn visit_mut_assign_expr ( & mut self , assign_expr : & mut AssignExpr ) {
1059965 assign_expr. visit_mut_children_with ( self ) ;
@@ -1064,7 +970,7 @@ impl<'a, C: Clone + Comments, S: SourceMapper> VisitMut for FormatJSVisitor<'a,
1064970 let variable_id = ident. id . to_id ( ) ;
1065971
1066972 // Check if we already have a binding for this variable
1067- let should_update = match self . variable_bindings . get ( & variable_id ) {
973+ let should_update = match self . resolve_identifier ( ident ) {
1068974 Some ( existing_expr) => {
1069975 // Only overwrite if the new expression is an object literal
1070976 // and the existing one is not, or if both are object literals
@@ -1081,8 +987,7 @@ impl<'a, C: Clone + Comments, S: SourceMapper> VisitMut for FormatJSVisitor<'a,
1081987 } ;
1082988
1083989 if should_update {
1084- self . variable_bindings
1085- . insert ( variable_id, * assign_expr. right . clone ( ) ) ;
990+ self . evaluator . store ( variable_id, & assign_expr. right ) ;
1086991 }
1087992 }
1088993 }
0 commit comments