@@ -6,8 +6,8 @@ use oxc_ast::AstBuilder;
66use oxc_ast:: ast:: JSXAttributeItem :: Attribute ;
77use oxc_ast:: ast:: JSXAttributeName :: Identifier ;
88use oxc_ast:: ast:: {
9- Expression , JSXAttributeItem , JSXAttributeValue , JSXExpression , ObjectPropertyKind ,
10- PropertyKey , PropertyKind , TemplateElementValue ,
9+ Expression , JSXAttributeItem , JSXAttributeValue , JSXExpression , LogicalOperator ,
10+ ObjectPropertyKind , PropertyKey , PropertyKind , TemplateElementValue ,
1111} ;
1212use oxc_span:: SPAN ;
1313
@@ -21,6 +21,7 @@ pub fn modify_prop_object<'a>(
2121) {
2222 let mut class_name_prop = None ;
2323 let mut style_prop = None ;
24+ let mut spread_props = vec ! [ ] ;
2425 for idx in ( 0 ..props. len ( ) ) . rev ( ) {
2526 let prop = props. remove ( idx) ;
2627 match prop {
@@ -40,14 +41,20 @@ pub fn modify_prop_object<'a>(
4041 }
4142 props. insert ( idx, ObjectPropertyKind :: ObjectProperty ( attr) ) ;
4243 }
43- _ => {
44- props. insert ( idx, prop) ;
44+ ObjectPropertyKind :: SpreadProperty ( spread) => {
45+ spread_props. push ( spread. argument . clone_in ( ast_builder. allocator ) ) ;
46+ props. insert ( idx, ObjectPropertyKind :: SpreadProperty ( spread) ) ;
4547 }
4648 }
4749 }
4850
49- if let Some ( ex) = get_class_name_expression ( ast_builder, & class_name_prop, styles, style_order)
50- {
51+ if let Some ( ex) = get_class_name_expression (
52+ ast_builder,
53+ & class_name_prop,
54+ styles,
55+ style_order,
56+ & spread_props,
57+ ) {
5158 props. push ( ObjectPropertyKind :: ObjectProperty (
5259 ast_builder. alloc_object_property (
5360 SPAN ,
@@ -60,7 +67,9 @@ pub fn modify_prop_object<'a>(
6067 ) ,
6168 ) ) ;
6269 }
63- if let Some ( ex) = get_style_expression ( ast_builder, & style_prop, styles, & style_vars) {
70+ if let Some ( ex) =
71+ get_style_expression ( ast_builder, & style_prop, styles, & style_vars, & spread_props)
72+ {
6473 props. push ( ObjectPropertyKind :: ObjectProperty (
6574 ast_builder. alloc_object_property (
6675 SPAN ,
@@ -84,6 +93,7 @@ pub fn modify_props<'a>(
8493) {
8594 let mut class_name_prop = None ;
8695 let mut style_prop = None ;
96+ let mut spread_props = vec ! [ ] ;
8797 for idx in ( 0 ..props. len ( ) ) . rev ( ) {
8898 let prop = props. remove ( idx) ;
8999 match prop {
@@ -125,13 +135,19 @@ pub fn modify_props<'a>(
125135 }
126136 props. insert ( idx, Attribute ( attr) ) ;
127137 }
128- _ => {
129- props. insert ( idx, prop) ;
138+ JSXAttributeItem :: SpreadAttribute ( spread) => {
139+ spread_props. push ( spread. argument . clone_in ( ast_builder. allocator ) ) ;
140+ props. insert ( idx, JSXAttributeItem :: SpreadAttribute ( spread) ) ;
130141 }
131142 }
132143 }
133- if let Some ( ex) = get_class_name_expression ( ast_builder, & class_name_prop, styles, style_order)
134- {
144+ if let Some ( ex) = get_class_name_expression (
145+ ast_builder,
146+ & class_name_prop,
147+ styles,
148+ style_order,
149+ & spread_props,
150+ ) {
135151 props. push ( Attribute ( ast_builder. alloc_jsx_attribute (
136152 SPAN ,
137153 Identifier ( ast_builder. alloc_jsx_identifier ( SPAN , "className" ) ) ,
@@ -144,7 +160,9 @@ pub fn modify_props<'a>(
144160 } ) ,
145161 ) ) ) ;
146162 }
147- if let Some ( ex) = get_style_expression ( ast_builder, & style_prop, styles, & style_vars) {
163+ if let Some ( ex) =
164+ get_style_expression ( ast_builder, & style_prop, styles, & style_vars, & spread_props)
165+ {
148166 props. push ( Attribute ( ast_builder. alloc_jsx_attribute (
149167 SPAN ,
150168 Identifier ( ast_builder. alloc_jsx_identifier ( SPAN , "style" ) ) ,
@@ -160,16 +178,30 @@ pub fn get_class_name_expression<'a>(
160178 class_name_prop : & Option < Expression < ' a > > ,
161179 styles : & mut [ ExtractStyleProp < ' a > ] ,
162180 style_order : Option < u8 > ,
181+ spread_props : & [ Expression < ' a > ] ,
163182) -> Option < Expression < ' a > > {
164183 // should modify class name prop
165184 merge_string_expressions (
166185 ast_builder,
167186 [
168- class_name_prop. clone_in ( ast_builder. allocator ) ,
187+ class_name_prop
188+ . as_ref ( )
189+ . map ( |class_name| convert_class_name ( ast_builder, class_name) ) ,
169190 gen_class_names ( ast_builder, styles, style_order) ,
170191 ]
171192 . into_iter ( )
172193 . flatten ( )
194+ . chain ( spread_props. iter ( ) . map ( |ex| {
195+ convert_class_name (
196+ ast_builder,
197+ & Expression :: StaticMemberExpression ( ast_builder. alloc_static_member_expression (
198+ SPAN ,
199+ ex. clone_in ( ast_builder. allocator ) ,
200+ ast_builder. identifier_name ( SPAN , ast_builder. atom ( "className" ) ) ,
201+ true ,
202+ ) ) ,
203+ )
204+ } ) )
173205 . collect :: < Vec < _ > > ( )
174206 . as_slice ( ) ,
175207 )
@@ -180,6 +212,7 @@ pub fn get_style_expression<'a>(
180212 style_prop : & Option < Expression < ' a > > ,
181213 styles : & [ ExtractStyleProp < ' a > ] ,
182214 style_vars : & Option < Expression < ' a > > ,
215+ spread_props : & [ Expression < ' a > ] ,
183216) -> Option < Expression < ' a > > {
184217 merge_object_expressions (
185218 ast_builder,
@@ -192,6 +225,14 @@ pub fn get_style_expression<'a>(
192225 ]
193226 . into_iter ( )
194227 . flatten ( )
228+ . chain ( spread_props. iter ( ) . map ( |ex| {
229+ Expression :: StaticMemberExpression ( ast_builder. alloc_static_member_expression (
230+ SPAN ,
231+ ex. clone_in ( ast_builder. allocator ) ,
232+ ast_builder. identifier_name ( SPAN , ast_builder. atom ( "style" ) ) ,
233+ true ,
234+ ) )
235+ } ) )
195236 . collect :: < Vec < _ > > ( )
196237 . as_slice ( ) ,
197238 )
@@ -333,6 +374,35 @@ fn merge_object_expressions<'a>(
333374 ) )
334375}
335376
377+ pub fn convert_class_name < ' a > (
378+ ast_builder : & AstBuilder < ' a > ,
379+ class_name : & Expression < ' a > ,
380+ ) -> Expression < ' a > {
381+ if matches ! (
382+ class_name,
383+ Expression :: StringLiteral ( _)
384+ | Expression :: TemplateLiteral ( _)
385+ | Expression :: NumericLiteral ( _)
386+ ) {
387+ return class_name. clone_in ( ast_builder. allocator ) ;
388+ }
389+
390+ // wrap ( and ?? ''
391+ Expression :: LogicalExpression (
392+ ast_builder. alloc_logical_expression (
393+ SPAN ,
394+ Expression :: ParenthesizedExpression (
395+ ast_builder. alloc_parenthesized_expression (
396+ SPAN ,
397+ class_name. clone_in ( ast_builder. allocator ) ,
398+ ) ,
399+ ) ,
400+ LogicalOperator :: Coalesce ,
401+ Expression :: StringLiteral ( ast_builder. alloc_string_literal ( SPAN , "" , None ) ) ,
402+ ) ,
403+ )
404+ }
405+
336406pub fn convert_style_vars < ' a > (
337407 ast_builder : & AstBuilder < ' a > ,
338408 style_vars : & Expression < ' a > ,
0 commit comments