@@ -15,7 +15,7 @@ mod visit;
1515use crate :: extract_style:: extract_style_value:: ExtractStyleValue ;
1616use crate :: visit:: DevupVisitor ;
1717use css:: file_map:: get_file_num_by_filename;
18- use oxc_allocator:: Allocator ;
18+ use oxc_allocator:: { Allocator , CloneIn } ;
1919use oxc_ast:: ast:: Expression ;
2020use oxc_ast_visit:: VisitMut ;
2121use oxc_codegen:: { Codegen , CodegenOptions } ;
@@ -57,7 +57,45 @@ pub enum ExtractStyleProp<'a> {
5757 } ,
5858}
5959
60- impl ExtractStyleProp < ' _ > {
60+ impl < ' a > ExtractStyleProp < ' a > {
61+ pub fn clone_in ( & self , alloc : & ' a Allocator ) -> Self {
62+ match self {
63+ ExtractStyleProp :: Static ( v) => ExtractStyleProp :: Static ( v. clone ( ) ) ,
64+ ExtractStyleProp :: StaticArray ( arr) => {
65+ ExtractStyleProp :: StaticArray ( arr. iter ( ) . map ( |s| s. clone_in ( alloc) ) . collect ( ) )
66+ }
67+ ExtractStyleProp :: Conditional {
68+ condition,
69+ consequent,
70+ alternate,
71+ } => ExtractStyleProp :: Conditional {
72+ condition : condition. clone_in ( alloc) ,
73+ consequent : consequent. as_ref ( ) . map ( |c| Box :: new ( c. clone_in ( alloc) ) ) ,
74+ alternate : alternate. as_ref ( ) . map ( |a| Box :: new ( a. clone_in ( alloc) ) ) ,
75+ } ,
76+ ExtractStyleProp :: Enum { condition, map } => ExtractStyleProp :: Enum {
77+ condition : condition. clone_in ( alloc) ,
78+ map : map
79+ . iter ( )
80+ . map ( |( k, v) | ( k. clone ( ) , v. iter ( ) . map ( |s| s. clone_in ( alloc) ) . collect ( ) ) )
81+ . collect ( ) ,
82+ } ,
83+ ExtractStyleProp :: Expression { styles, expression } => ExtractStyleProp :: Expression {
84+ styles : styles. clone ( ) ,
85+ expression : expression. clone_in ( alloc) ,
86+ } ,
87+ ExtractStyleProp :: MemberExpression { map, expression } => {
88+ ExtractStyleProp :: MemberExpression {
89+ map : map
90+ . iter ( )
91+ . map ( |( k, v) | ( k. clone ( ) , Box :: new ( v. clone_in ( alloc) ) ) )
92+ . collect ( ) ,
93+ expression : expression. clone_in ( alloc) ,
94+ }
95+ }
96+ }
97+ }
98+
6199 pub fn extract ( & self ) -> Vec < ExtractStyleValue > {
62100 match self {
63101 ExtractStyleProp :: Static ( style) => vec ! [ style. clone( ) ] ,
@@ -6202,6 +6240,254 @@ export {
62026240 ) ) ;
62036241 }
62046242
6243+ #[ test]
6244+ #[ serial]
6245+ fn style_order_conditional ( ) {
6246+ // Test 1: styleOrder={condition ? 5 : 10} — ternary with two static numbers
6247+ // Since jsx_expression_to_number doesn't handle ConditionalExpression,
6248+ // styleOrder should be None (not applied)
6249+ reset_class_map ( ) ;
6250+ reset_file_map ( ) ;
6251+ assert_debug_snapshot ! ( ToBTreeSet :: from(
6252+ extract(
6253+ "test.jsx" ,
6254+ r#"import {Box} from '@devup-ui/core'
6255+ <Box styleOrder={isActive ? 5 : 10} bg="red" p="4" />
6256+ "# ,
6257+ ExtractOption {
6258+ package: "@devup-ui/core" . to_string( ) ,
6259+ css_dir: "@devup-ui/core" . to_string( ) ,
6260+ single_css: true ,
6261+ import_main_css: false ,
6262+ import_aliases: HashMap :: new( )
6263+ }
6264+ )
6265+ . unwrap( )
6266+ ) ) ;
6267+
6268+ // Test 2: styleOrder={condition ? 5 : variable} — ternary with mixed static/dynamic
6269+ reset_class_map ( ) ;
6270+ reset_file_map ( ) ;
6271+ assert_debug_snapshot ! ( ToBTreeSet :: from(
6272+ extract(
6273+ "test.jsx" ,
6274+ r#"import {Box} from '@devup-ui/core'
6275+ <Box styleOrder={isActive ? 5 : order} bg="red" p="4" />
6276+ "# ,
6277+ ExtractOption {
6278+ package: "@devup-ui/core" . to_string( ) ,
6279+ css_dir: "@devup-ui/core" . to_string( ) ,
6280+ single_css: true ,
6281+ import_main_css: false ,
6282+ import_aliases: HashMap :: new( )
6283+ }
6284+ )
6285+ . unwrap( )
6286+ ) ) ;
6287+
6288+ // Test 3: styleOrder={variable} — fully dynamic styleOrder
6289+ reset_class_map ( ) ;
6290+ reset_file_map ( ) ;
6291+ assert_debug_snapshot ! ( ToBTreeSet :: from(
6292+ extract(
6293+ "test.jsx" ,
6294+ r#"import {Box} from '@devup-ui/core'
6295+ <Box styleOrder={order} bg="red" p="4" />
6296+ "# ,
6297+ ExtractOption {
6298+ package: "@devup-ui/core" . to_string( ) ,
6299+ css_dir: "@devup-ui/core" . to_string( ) ,
6300+ single_css: true ,
6301+ import_main_css: false ,
6302+ import_aliases: HashMap :: new( )
6303+ }
6304+ )
6305+ . unwrap( )
6306+ ) ) ;
6307+
6308+ // Test 4: styleOrder={condition ? 5 : 10} with conditional style props
6309+ // Verifies interaction between conditional styleOrder and conditional style values
6310+ reset_class_map ( ) ;
6311+ reset_file_map ( ) ;
6312+ assert_debug_snapshot ! ( ToBTreeSet :: from(
6313+ extract(
6314+ "test.jsx" ,
6315+ r#"import {Box} from '@devup-ui/core'
6316+ <Box styleOrder={isActive ? 5 : 10} bg={isActive ? "red" : "blue"} />
6317+ "# ,
6318+ ExtractOption {
6319+ package: "@devup-ui/core" . to_string( ) ,
6320+ css_dir: "@devup-ui/core" . to_string( ) ,
6321+ single_css: true ,
6322+ import_main_css: false ,
6323+ import_aliases: HashMap :: new( )
6324+ }
6325+ )
6326+ . unwrap( )
6327+ ) ) ;
6328+
6329+ // Test 5: styleOrder={condition ? 5 : 10} with css() className
6330+ reset_class_map ( ) ;
6331+ reset_file_map ( ) ;
6332+ assert_debug_snapshot ! ( ToBTreeSet :: from(
6333+ extract(
6334+ "test.jsx" ,
6335+ r#"import {Box, css} from '@devup-ui/core'
6336+ <Box styleOrder={isActive ? 5 : 10} className={css({color:"white"})} bg="red" />
6337+ "# ,
6338+ ExtractOption {
6339+ package: "@devup-ui/core" . to_string( ) ,
6340+ css_dir: "@devup-ui/core" . to_string( ) ,
6341+ single_css: true ,
6342+ import_main_css: false ,
6343+ import_aliases: HashMap :: new( )
6344+ }
6345+ )
6346+ . unwrap( )
6347+ ) ) ;
6348+ }
6349+
6350+ #[ test]
6351+ #[ serial]
6352+ fn style_order_logical_and ( ) {
6353+ // Test 1: JSX path — styleOrder={a === 1 && 5}
6354+ // truthy → styleOrder=5, falsy → no styleOrder (None)
6355+ reset_class_map ( ) ;
6356+ reset_file_map ( ) ;
6357+ assert_debug_snapshot ! ( ToBTreeSet :: from(
6358+ extract(
6359+ "test.jsx" ,
6360+ r#"import {Box} from '@devup-ui/core'
6361+ <Box styleOrder={a === 1 && 5} bg="red" p="4" />
6362+ "# ,
6363+ ExtractOption {
6364+ package: "@devup-ui/core" . to_string( ) ,
6365+ css_dir: "@devup-ui/core" . to_string( ) ,
6366+ single_css: true ,
6367+ import_main_css: false ,
6368+ import_aliases: HashMap :: new( )
6369+ }
6370+ )
6371+ . unwrap( )
6372+ ) ) ;
6373+
6374+ // Test 2: JSX path — styleOrder={a === 1 && 5} with conditional style props
6375+ reset_class_map ( ) ;
6376+ reset_file_map ( ) ;
6377+ assert_debug_snapshot ! ( ToBTreeSet :: from(
6378+ extract(
6379+ "test.jsx" ,
6380+ r#"import {Box} from '@devup-ui/core'
6381+ <Box styleOrder={a === 1 && 5} bg={isActive ? "red" : "blue"} />
6382+ "# ,
6383+ ExtractOption {
6384+ package: "@devup-ui/core" . to_string( ) ,
6385+ css_dir: "@devup-ui/core" . to_string( ) ,
6386+ single_css: true ,
6387+ import_main_css: false ,
6388+ import_aliases: HashMap :: new( )
6389+ }
6390+ )
6391+ . unwrap( )
6392+ ) ) ;
6393+
6394+ // Test 3: Call expression path — styleOrder: a === 1 && 5
6395+ reset_class_map ( ) ;
6396+ reset_file_map ( ) ;
6397+ assert_debug_snapshot ! ( ToBTreeSet :: from(
6398+ extract(
6399+ "test.mjs" ,
6400+ r#"import { jsx as e } from "react/jsx-runtime";
6401+ import { Box as o } from "@devup-ui/react";
6402+ function c() {
6403+ return e(o, { styleOrder: a === 1 && 5, bg: "red", p: "4" });
6404+ }
6405+ export { c as Lib };"# ,
6406+ ExtractOption {
6407+ package: "@devup-ui/react" . to_string( ) ,
6408+ css_dir: "@devup-ui/react" . to_string( ) ,
6409+ single_css: true ,
6410+ import_main_css: false ,
6411+ import_aliases: HashMap :: new( )
6412+ }
6413+ )
6414+ . unwrap( )
6415+ ) ) ;
6416+ }
6417+
6418+ #[ test]
6419+ #[ serial]
6420+ fn style_order_conditional_call_expression ( ) {
6421+ // Test 1: styleOrder: isActive ? 5 : 10 — ternary with two static numbers via call expression
6422+ reset_class_map ( ) ;
6423+ reset_file_map ( ) ;
6424+ assert_debug_snapshot ! ( ToBTreeSet :: from(
6425+ extract(
6426+ "test.mjs" ,
6427+ r#"import { jsx as e } from "react/jsx-runtime";
6428+ import { Box as o } from "@devup-ui/react";
6429+ function c() {
6430+ return e(o, { styleOrder: isActive ? 5 : 10, bg: "red", p: "4" });
6431+ }
6432+ export { c as Lib };"# ,
6433+ ExtractOption {
6434+ package: "@devup-ui/react" . to_string( ) ,
6435+ css_dir: "@devup-ui/react" . to_string( ) ,
6436+ single_css: true ,
6437+ import_main_css: false ,
6438+ import_aliases: HashMap :: new( )
6439+ }
6440+ )
6441+ . unwrap( )
6442+ ) ) ;
6443+
6444+ // Test 2: styleOrder: isActive ? 5 : 10 with conditional style props via call expression
6445+ reset_class_map ( ) ;
6446+ reset_file_map ( ) ;
6447+ assert_debug_snapshot ! ( ToBTreeSet :: from(
6448+ extract(
6449+ "test.mjs" ,
6450+ r#"import { jsx as e } from "react/jsx-runtime";
6451+ import { Box as o } from "@devup-ui/react";
6452+ function c() {
6453+ return e(o, { styleOrder: isActive ? 5 : 10, bg: isActive ? "red" : "blue" });
6454+ }
6455+ export { c as Lib };"# ,
6456+ ExtractOption {
6457+ package: "@devup-ui/react" . to_string( ) ,
6458+ css_dir: "@devup-ui/react" . to_string( ) ,
6459+ single_css: true ,
6460+ import_main_css: false ,
6461+ import_aliases: HashMap :: new( )
6462+ }
6463+ )
6464+ . unwrap( )
6465+ ) ) ;
6466+
6467+ // Test 3: static styleOrder via call expression (backward compat)
6468+ reset_class_map ( ) ;
6469+ reset_file_map ( ) ;
6470+ assert_debug_snapshot ! ( ToBTreeSet :: from(
6471+ extract(
6472+ "test.mjs" ,
6473+ r#"import { jsx as e } from "react/jsx-runtime";
6474+ import { Box as o } from "@devup-ui/react";
6475+ function c() {
6476+ return e(o, { styleOrder: 5, bg: "red", p: "4" });
6477+ }
6478+ export { c as Lib };"# ,
6479+ ExtractOption {
6480+ package: "@devup-ui/react" . to_string( ) ,
6481+ css_dir: "@devup-ui/react" . to_string( ) ,
6482+ single_css: true ,
6483+ import_main_css: false ,
6484+ import_aliases: HashMap :: new( )
6485+ }
6486+ )
6487+ . unwrap( )
6488+ ) ) ;
6489+ }
6490+
62056491 #[ test]
62066492 #[ serial]
62076493 fn style_order2 ( ) {
0 commit comments