diff --git a/.changeset/friendly-needles-ring.md b/.changeset/friendly-needles-ring.md new file mode 100644 index 00000000..eb6eb016 --- /dev/null +++ b/.changeset/friendly-needles-ring.md @@ -0,0 +1,5 @@ +--- +"@devup-ui/wasm": patch +--- + +Extract nested styles diff --git a/libs/extractor/src/gen_class_name.rs b/libs/extractor/src/gen_class_name.rs index 7c30ffe0..740cef6a 100644 --- a/libs/extractor/src/gen_class_name.rs +++ b/libs/extractor/src/gen_class_name.rs @@ -1,8 +1,8 @@ use crate::{ExtractStyleProp, StyleProperty}; use oxc_allocator::CloneIn; use oxc_ast::ast::{ - Expression, JSXAttribute, JSXAttributeValue, JSXExpression, TemplateElement, - TemplateElementValue, + Expression, JSXAttribute, JSXAttributeValue, JSXExpression, ObjectPropertyKind, PropertyKey, + PropertyKind, TemplateElement, TemplateElementValue, }; use oxc_ast::AstBuilder; use oxc_span::SPAN; @@ -78,6 +78,34 @@ fn gen_class_name<'a>( ExtractStyleProp::Expression { expression, .. } => { Some(expression.clone_in(ast_builder.allocator)) } + ExtractStyleProp::MemberExpression { map, expression } => Some( + Expression::ComputedMemberExpression(ast_builder.alloc_computed_member_expression( + SPAN, + Expression::ObjectExpression(ast_builder.alloc_object_expression( + SPAN, + ast_builder.vec_from_iter(map.iter().filter_map(|(key, value)| { + gen_class_name(ast_builder, value).map(|expr| { + ObjectPropertyKind::ObjectProperty(ast_builder.alloc_object_property( + SPAN, + PropertyKind::Init, + PropertyKey::StringLiteral(ast_builder.alloc_string_literal( + SPAN, + key.as_str(), + None, + )), + expr, + false, + false, + false, + )) + }) + })), + None, + )), + expression.clone_in(ast_builder.allocator), + false, + )), + ), } } fn is_same_expression<'a>(a: &Expression<'a>, b: &Expression<'a>) -> bool { diff --git a/libs/extractor/src/gen_style.rs b/libs/extractor/src/gen_style.rs index 8dbff953..0499421b 100644 --- a/libs/extractor/src/gen_style.rs +++ b/libs/extractor/src/gen_style.rs @@ -6,6 +6,7 @@ use oxc_ast::ast::{ }; use oxc_ast::AstBuilder; use oxc_span::SPAN; +use std::collections::BTreeMap; pub fn gen_styles<'a>( ast_builder: &AstBuilder<'a>, style_props: &[ExtractStyleProp<'a>], @@ -198,6 +199,90 @@ fn gen_style<'a>( } } } + ExtractStyleProp::MemberExpression { map, expression } => { + let mut tmp_map = BTreeMap::>::new(); + for (key, value) in map.iter() { + for style in value.extract() { + match style.extract() { + StyleProperty::ClassName(_) => {} + StyleProperty::Variable { + variable_name, + identifier, + .. + } => { + tmp_map + .entry(variable_name) + .or_default() + .push((key.to_string(), identifier)); + } + } + } + } + + for (key, value) in tmp_map { + properties.push(ObjectPropertyKind::ObjectProperty( + ast_builder.alloc_object_property( + SPAN, + PropertyKind::Init, + PropertyKey::StringLiteral( + ast_builder.alloc_string_literal(SPAN, key, None), + ), + if value.len() == 1 { + // do not create object expression when property is single + Expression::Identifier( + ast_builder.alloc_identifier_reference(SPAN, &value[0].1), + ) + } else { + Expression::ComputedMemberExpression( + ast_builder.alloc_computed_member_expression( + SPAN, + Expression::ObjectExpression( + ast_builder.alloc_object_expression( + SPAN, + oxc_allocator::Vec::from_iter_in( + value + .into_iter() + .map(|(k, v)| { + ObjectPropertyKind::ObjectProperty( + ast_builder.alloc_object_property( + SPAN, + PropertyKind::Init, + PropertyKey::StaticIdentifier( + ast_builder + .alloc_identifier_name( + SPAN, k, + ), + ), + Expression::Identifier( + ast_builder + .alloc_identifier_reference( + SPAN, v, + ), + ), + false, + false, + false, + ), + ) + }) + .collect::>(), + ast_builder.allocator, + ), + None, + ), + ), + expression.clone_in(ast_builder.allocator), + false, + ), + ) + }, + false, + false, + false, + ), + )); + } + } } properties.sort_by_key(|p| { if let ObjectPropertyKind::ObjectProperty(p) = p { diff --git a/libs/extractor/src/lib.rs b/libs/extractor/src/lib.rs index 23790d85..f69431e9 100644 --- a/libs/extractor/src/lib.rs +++ b/libs/extractor/src/lib.rs @@ -8,6 +8,7 @@ mod utils; mod visit; use oxc_codegen::Codegen; +use std::collections::BTreeMap; use crate::extract_style::ExtractStyleValue; use crate::visit::DevupVisitor; @@ -36,6 +37,10 @@ pub enum ExtractStyleProp<'a> { styles: Vec, expression: Expression<'a>, }, + MemberExpression { + map: BTreeMap>>, + expression: Expression<'a>, + }, } impl ExtractStyleProp<'_> { pub fn extract(&self) -> Vec { @@ -59,6 +64,9 @@ impl ExtractStyleProp<'_> { array.iter().flat_map(|s| s.extract()).collect() } ExtractStyleProp::Expression { styles, .. } => styles.to_vec(), + ExtractStyleProp::MemberExpression { ref map, .. } => { + map.values().flat_map(|s| s.extract()).collect() + } } } } @@ -1314,7 +1322,20 @@ export { #[test] #[serial] - fn props_direct_select() { + fn props_wrong_direct_array_select() { + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Flex} from '@devup-ui/core' + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + reset_class_map(); assert_debug_snapshot!(extract( "test.js", @@ -1327,10 +1348,12 @@ export { } ) .unwrap()); + + reset_class_map(); assert_debug_snapshot!(extract( "test.js", r#"import {Flex} from '@devup-ui/core' - + "#, ExtractOption { package: "@devup-ui/core".to_string(), @@ -1338,10 +1361,29 @@ export { } ) .unwrap()); + + reset_class_map(); assert_debug_snapshot!(extract( "test.js", r#"import {Flex} from '@devup-ui/core' - + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + } + + #[test] + #[serial] + fn props_wrong_direct_object_select() { + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Box} from '@devup-ui/core' + "#, ExtractOption { package: "@devup-ui/core".to_string(), @@ -1354,7 +1396,7 @@ export { assert_debug_snapshot!(extract( "test.js", r#"import {Flex} from '@devup-ui/core' - + "#, ExtractOption { package: "@devup-ui/core".to_string(), @@ -1367,7 +1409,7 @@ export { assert_debug_snapshot!(extract( "test.js", r#"import {Flex} from '@devup-ui/core' - + "#, ExtractOption { package: "@devup-ui/core".to_string(), @@ -1380,7 +1422,7 @@ export { assert_debug_snapshot!(extract( "test.js", r#"import {Flex} from '@devup-ui/core' - + "#, ExtractOption { package: "@devup-ui/core".to_string(), @@ -1388,12 +1430,16 @@ export { } ) .unwrap()); + } + #[test] + #[serial] + fn props_direct_array_select() { reset_class_map(); assert_debug_snapshot!(extract( "test.js", r#"import {Flex} from '@devup-ui/core' - + "#, ExtractOption { package: "@devup-ui/core".to_string(), @@ -1406,7 +1452,7 @@ export { assert_debug_snapshot!(extract( "test.js", r#"import {Flex} from '@devup-ui/core' - + "#, ExtractOption { package: "@devup-ui/core".to_string(), @@ -1460,9 +1506,64 @@ export { reset_class_map(); assert_debug_snapshot!(extract( "test.js", - r#"import {Center} from '@devup-ui/core' -
-
+ r#"import {Flex} from '@devup-ui/core' + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Flex} from '@devup-ui/core' + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + } + + #[test] + #[serial] + fn props_direct_object_select() { + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Flex} from '@devup-ui/core' + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Flex} from '@devup-ui/core' + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Flex} from '@devup-ui/core' + "#, ExtractOption { package: "@devup-ui/core".to_string(), @@ -1485,6 +1586,143 @@ export { .unwrap()); } + #[test] + #[serial] + fn props_direct_variable_object_select() { + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Flex} from '@devup-ui/core' + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Box} from '@devup-ui/core' + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + } + + #[test] + #[serial] + fn props_direct_object_responsive_select() { + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Flex} from '@devup-ui/core' +; + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Flex} from '@devup-ui/core' +; + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + } + #[test] + #[serial] + fn props_direct_variable_object_responsive_select() { + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Flex} from '@devup-ui/core' +; + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + } + + #[test] + #[serial] + fn props_direct_array_responsive_select() { + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Flex} from '@devup-ui/core' +; + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Flex} from '@devup-ui/core' +; + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + } + #[test] + #[serial] + fn props_direct_variable_array_responsive_select() { + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Flex} from '@devup-ui/core' +; + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + } + + #[test] + #[serial] + fn props_direct_hybrid_responsive_select() { + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Flex} from '@devup-ui/core' +; + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + } #[test] #[serial] fn test_component_in_func() { diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_array_responsive_select-2.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_array_responsive_select-2.snap new file mode 100644 index 00000000..a660a996 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_array_responsive_select-2.snap @@ -0,0 +1,72 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n;\n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "4px", + level: 0, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "8px", + level: 1, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "12px", + level: 2, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "16px", + level: 0, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "20px", + level: 1, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "24px", + level: 2, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_array_responsive_select.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_array_responsive_select.snap new file mode 100644 index 00000000..3838fba9 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_array_responsive_select.snap @@ -0,0 +1,72 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n;\n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "4px", + level: 0, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "8px", + level: 1, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "12px", + level: 2, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "16px", + level: 0, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "20px", + level: 1, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "24px", + level: 2, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_array_select-2.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_array_select-2.snap new file mode 100644 index 00000000..4b129208 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_array_select-2.snap @@ -0,0 +1,36 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Static( + ExtractStaticStyle { + property: "opacity", + value: "1", + level: 0, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "opacity", + value: "0.5", + level: 0, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_array_select-3.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_array_select-3.snap new file mode 100644 index 00000000..3b835fe1 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_array_select-3.snap @@ -0,0 +1,36 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Static( + ExtractStaticStyle { + property: "background", + value: "$red", + level: 0, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "background", + value: "$blue", + level: 0, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_array_select-4.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_array_select-4.snap new file mode 100644 index 00000000..19f4a82c --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_array_select-4.snap @@ -0,0 +1,35 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Static( + ExtractStaticStyle { + property: "background", + value: "$red", + level: 0, + selector: None, + basic: false, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "background", + level: 0, + identifier: "`${variable}`", + selector: None, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_array_select-5.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_array_select-5.snap new file mode 100644 index 00000000..9c351e4c --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_array_select-5.snap @@ -0,0 +1,63 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Center} from '@devup-ui/core'\n\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Static( + ExtractStaticStyle { + property: "justifyContent", + value: "center", + level: 0, + selector: None, + basic: true, + }, + ), + Static( + ExtractStaticStyle { + property: "alignItems", + value: "center", + level: 0, + selector: None, + basic: true, + }, + ), + Static( + ExtractStaticStyle { + property: "background", + value: "$webBg", + level: 0, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "background", + value: "$appBg", + level: 0, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "background", + value: "$solutionBg", + level: 0, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_array_select-6.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_array_select-6.snap new file mode 100644 index 00000000..b52e23e8 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_array_select-6.snap @@ -0,0 +1,26 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "opacity", + level: 0, + identifier: "some[100]", + selector: None, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_array_select-7.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_array_select-7.snap new file mode 100644 index 00000000..bf41a9fd --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_array_select-7.snap @@ -0,0 +1,44 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Static( + ExtractStaticStyle { + property: "opacity", + value: "1", + level: 0, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "opacity", + value: "0.5", + level: 0, + selector: None, + basic: false, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "opacity", + level: 0, + identifier: "some[a]", + selector: None, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_array_select.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_array_select.snap new file mode 100644 index 00000000..1d157256 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_array_select.snap @@ -0,0 +1,27 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Static( + ExtractStaticStyle { + property: "opacity", + value: "1", + level: 0, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_hybrid_responsive_select.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_hybrid_responsive_select.snap new file mode 100644 index 00000000..0e20fd77 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_hybrid_responsive_select.snap @@ -0,0 +1,68 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n;\n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "gap", + level: 0, + identifier: "a", + selector: None, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "4px", + level: 1, + selector: None, + basic: false, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "gap", + level: 2, + identifier: "c", + selector: None, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "gap", + level: 0, + identifier: "d", + selector: None, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "gap", + level: 1, + identifier: "e", + selector: None, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "8px", + level: 2, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_object_responsive_select-2.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_object_responsive_select-2.snap new file mode 100644 index 00000000..de7fd6bc --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_object_responsive_select-2.snap @@ -0,0 +1,72 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n;\n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "4px", + level: 0, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "8px", + level: 1, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "12px", + level: 2, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "16px", + level: 0, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "20px", + level: 1, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "24px", + level: 2, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_object_responsive_select.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_object_responsive_select.snap new file mode 100644 index 00000000..de05bc96 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_object_responsive_select.snap @@ -0,0 +1,72 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n;\n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "4px", + level: 0, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "8px", + level: 1, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "12px", + level: 2, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "16px", + level: 0, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "20px", + level: 1, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "24px", + level: 2, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_object_select-2.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_object_select-2.snap new file mode 100644 index 00000000..c94f5cc5 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_object_select-2.snap @@ -0,0 +1,27 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Static( + ExtractStaticStyle { + property: "opacity", + value: "0.5", + level: 0, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_object_select-3.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_object_select-3.snap new file mode 100644 index 00000000..3d5d52c4 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_object_select-3.snap @@ -0,0 +1,44 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "opacity", + level: 0, + identifier: "any[\"some\"]", + selector: None, + }, + ), + Static( + ExtractStaticStyle { + property: "opacity", + value: "1", + level: 0, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "opacity", + value: "0.5", + level: 0, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_object_select-4.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_object_select-4.snap new file mode 100644 index 00000000..20f49b4b --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_object_select-4.snap @@ -0,0 +1,36 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Static( + ExtractStaticStyle { + property: "background", + value: "$red", + level: 0, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "background", + value: "$blue", + level: 0, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_object_select.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_object_select.snap new file mode 100644 index 00000000..9de962c5 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_object_select.snap @@ -0,0 +1,27 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Static( + ExtractStaticStyle { + property: "opacity", + value: "1", + level: 0, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_responsive_select-2.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_responsive_select-2.snap new file mode 100644 index 00000000..de7fd6bc --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_responsive_select-2.snap @@ -0,0 +1,72 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n;\n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "4px", + level: 0, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "8px", + level: 1, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "12px", + level: 2, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "16px", + level: 0, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "20px", + level: 1, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "24px", + level: 2, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_responsive_select.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_responsive_select.snap new file mode 100644 index 00000000..de05bc96 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_responsive_select.snap @@ -0,0 +1,72 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n;\n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "4px", + level: 0, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "8px", + level: 1, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "12px", + level: 2, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "16px", + level: 0, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "20px", + level: 1, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "gap", + value: "24px", + level: 2, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_variable_array_responsive_select.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_variable_array_responsive_select.snap new file mode 100644 index 00000000..b2a0b222 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_variable_array_responsive_select.snap @@ -0,0 +1,66 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n;\n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "gap", + level: 0, + identifier: "a", + selector: None, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "gap", + level: 1, + identifier: "b", + selector: None, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "gap", + level: 2, + identifier: "c", + selector: None, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "gap", + level: 0, + identifier: "d", + selector: None, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "gap", + level: 1, + identifier: "e", + selector: None, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "gap", + level: 2, + identifier: "f", + selector: None, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_variable_object_responsive_select.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_variable_object_responsive_select.snap new file mode 100644 index 00000000..ec4d52cd --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_variable_object_responsive_select.snap @@ -0,0 +1,66 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n;\n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "gap", + level: 0, + identifier: "a", + selector: None, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "gap", + level: 1, + identifier: "b", + selector: None, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "gap", + level: 2, + identifier: "c", + selector: None, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "gap", + level: 0, + identifier: "d", + selector: None, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "gap", + level: 1, + identifier: "e", + selector: None, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "gap", + level: 2, + identifier: "f", + selector: None, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_variable_object_select-2.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_variable_object_select-2.snap new file mode 100644 index 00000000..9023e94d --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_variable_object_select-2.snap @@ -0,0 +1,17 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Box} from '@devup-ui/core'\n\n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Dynamic( + ExtractDynamicStyle { + property: "background", + level: 0, + identifier: "SOME_VAR[idx]", + selector: None, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_variable_object_select.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_variable_object_select.snap new file mode 100644 index 00000000..e2aa1dcf --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_variable_object_select.snap @@ -0,0 +1,36 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Static( + ExtractStaticStyle { + property: "opacity", + value: "1", + level: 0, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "opacity", + value: "0.5", + level: 0, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_direct_variable_responsive_select.snap b/libs/extractor/src/snapshots/extractor__tests__props_direct_variable_responsive_select.snap new file mode 100644 index 00000000..ec4d52cd --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_direct_variable_responsive_select.snap @@ -0,0 +1,66 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n;\n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "gap", + level: 0, + identifier: "a", + selector: None, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "gap", + level: 1, + identifier: "b", + selector: None, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "gap", + level: 2, + identifier: "c", + selector: None, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "gap", + level: 0, + identifier: "d", + selector: None, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "gap", + level: 1, + identifier: "e", + selector: None, + }, + ), + Dynamic( + ExtractDynamicStyle { + property: "gap", + level: 2, + identifier: "f", + selector: None, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_array_select-2.snap b/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_array_select-2.snap new file mode 100644 index 00000000..adfc95fa --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_array_select-2.snap @@ -0,0 +1,18 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_array_select-3.snap b/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_array_select-3.snap new file mode 100644 index 00000000..2b861412 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_array_select-3.snap @@ -0,0 +1,18 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_array_select-4.snap b/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_array_select-4.snap new file mode 100644 index 00000000..9dace631 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_array_select-4.snap @@ -0,0 +1,18 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_array_select.snap b/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_array_select.snap new file mode 100644 index 00000000..c0b9e9be --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_array_select.snap @@ -0,0 +1,18 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_object_select-2.snap b/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_object_select-2.snap new file mode 100644 index 00000000..898d5585 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_object_select-2.snap @@ -0,0 +1,18 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_object_select-3.snap b/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_object_select-3.snap new file mode 100644 index 00000000..974babf0 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_object_select-3.snap @@ -0,0 +1,18 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_object_select-4.snap b/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_object_select-4.snap new file mode 100644 index 00000000..5a622301 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_object_select-4.snap @@ -0,0 +1,18 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Flex} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_object_select.snap b/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_object_select.snap new file mode 100644 index 00000000..775282ad --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__props_wrong_direct_object_select.snap @@ -0,0 +1,8 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Box} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [], + code: "
;\n", +} diff --git a/libs/extractor/src/style_extractor.rs b/libs/extractor/src/style_extractor.rs index 33f5b8b0..a876ceb9 100644 --- a/libs/extractor/src/style_extractor.rs +++ b/libs/extractor/src/style_extractor.rs @@ -2,14 +2,16 @@ use crate::utils::{expression_to_code, is_special_property}; use crate::ExtractStyleProp; use oxc_allocator::CloneIn; use oxc_ast::ast::{ - Expression, JSXAttributeValue, ObjectPropertyKind, PropertyKey, TemplateElementValue, + ArrayExpressionElement, ComputedMemberExpression, Expression, JSXAttributeValue, + ObjectPropertyKind, PropertyKey, TemplateElementValue, }; +use std::collections::BTreeMap; use crate::extract_style::ExtractStyleValue::{Dynamic, Static, Typography}; use crate::extract_style::{ExtractDynamicStyle, ExtractStaticStyle}; use oxc_ast::AstBuilder; use oxc_span::SPAN; -use oxc_syntax::operator::{BinaryOperator, LogicalOperator}; +use oxc_syntax::operator::{BinaryOperator, LogicalOperator, UnaryOperator}; const IGNORED_IDENTIFIERS: [&str; 3] = ["undefined", "NaN", "Infinity"]; @@ -251,152 +253,7 @@ pub fn extract_style_from_expression<'a>( } match expression { Expression::ComputedMemberExpression(mem) => { - let mem_expression = &mem.expression.clone_in(ast_builder.allocator); - match &mut mem.object { - Expression::ArrayExpression(array) => { - for element in array.elements.iter_mut() { - if let Expression::StringLiteral(str) = element.to_expression_mut() { - if let Some(rest) = str.value.strip_prefix("$") { - str.value = ast_builder.atom(&format!("var(--{})", rest)); - } - } else if let Expression::TemplateLiteral(tmp) = element.to_expression_mut() - { - if tmp.quasis.len() == 1 { - if let Some(rest) = tmp.quasis[0].value.raw.strip_prefix("$") { - tmp.quasis[0].value.raw = - ast_builder.atom(&format!("var(--{})", rest)); - } - } - } - } - - match mem_expression { - Expression::NumericLiteral(v) => { - if array.elements.len() < v.value as usize { - // wrong indexing case - ExtractResult::Remove - } else { - extract_style_from_expression( - ast_builder, - name, - array.elements[v.value as usize] - .clone_in(ast_builder.allocator) - .to_expression_mut(), - level, - selector, - ) - } - } - // wrong indexing case - Expression::UnaryExpression(unary) => { - if let Expression::NumericLiteral(_) = &unary.argument { - ExtractResult::Remove - } else { - ExtractResult::Maintain - } - } - _ => name - .map(|name| { - ExtractResult::ExtractStyle(vec![ExtractStyleProp::Static( - Dynamic(ExtractDynamicStyle::new( - name, - level, - expression_to_code(expression).as_str(), - selector.map(|s| s.into()), - )), - )]) - }) - .unwrap_or_else(|| ExtractResult::Maintain), - } - } - Expression::ObjectExpression(obj) => { - for p in obj.properties.iter_mut() { - if let ObjectPropertyKind::ObjectProperty(ref mut o) = p { - if let PropertyKey::StaticIdentifier(_) = o.key { - if let Expression::StringLiteral(str) = &mut o.value { - if let Some(rest) = str.value.strip_prefix("$") { - str.value = ast_builder.atom(&format!("var(--{})", rest)); - } - } else if let Expression::TemplateLiteral(tmp) = &mut o.value { - if tmp.quasis.len() == 1 { - if let Some(rest) = - tmp.quasis[0].value.raw.strip_prefix("$") - { - tmp.quasis[0].value.raw = - ast_builder.atom(&format!("var(--{})", rest)); - } - } - } - } - } - } - match mem_expression { - Expression::StringLiteral(str) => { - let key = str.value.as_str(); - for p in obj.properties.iter() { - match p { - ObjectPropertyKind::ObjectProperty(o) => { - if let PropertyKey::StaticIdentifier(ident) = &o.key { - if ident.name == key { - return extract_style_from_expression( - ast_builder, - name, - &mut o.value.clone_in(ast_builder.allocator), - level, - selector, - ); - } - } - } - ObjectPropertyKind::SpreadProperty(_) => { - if let Some(name) = name { - return ExtractResult::ExtractStyle(vec![ - ExtractStyleProp::Static(Dynamic( - ExtractDynamicStyle::new( - name, - level, - expression_to_code(expression).as_str(), - selector.map(|s| s.into()), - ), - )), - ]); - } - } - } - } - ExtractResult::Remove - } - Expression::Identifier(_) => { - if let Some(name) = name { - ExtractResult::ExtractStyle(vec![ExtractStyleProp::Static( - Dynamic(ExtractDynamicStyle::new( - name, - level, - expression_to_code(expression).as_str(), - selector.map(|s| s.into()), - )), - )]) - } else { - ExtractResult::Maintain - } - } - _ => ExtractResult::Maintain, - } - } - Expression::Identifier(_) => name - .map(|name| { - ExtractResult::ExtractStyle(vec![ExtractStyleProp::Static(Dynamic( - ExtractDynamicStyle::new( - name, - level, - expression_to_code(expression).as_str(), - selector.map(|s| s.into()), - ), - ))]) - }) - .unwrap_or(ExtractResult::Maintain), - _ => ExtractResult::Maintain, - } + extract_style_from_member_expression(ast_builder, name, mem, level, selector) } Expression::NumericLiteral(v) => name .map(|name| { @@ -423,44 +280,42 @@ pub fn extract_style_from_expression<'a>( selector.map(|s| s.into()), )) })]) + } else if typo { + ExtractResult::ExtractStyle(vec![ExtractStyleProp::Expression { + expression: ast_builder.expression_template_literal( + SPAN, + ast_builder.vec_from_array([ + ast_builder.template_element( + SPAN, + false, + TemplateElementValue { + raw: ast_builder.atom("typo-"), + cooked: None, + }, + ), + ast_builder.template_element( + SPAN, + true, + TemplateElementValue { + raw: ast_builder.atom(""), + cooked: None, + }, + ), + ]), + ast_builder + .vec_from_array([expression.clone_in(ast_builder.allocator)]), + ), + styles: vec![], + }]) } else { - if typo { - ExtractResult::ExtractStyle(vec![ExtractStyleProp::Expression { - expression: ast_builder.expression_template_literal( - SPAN, - ast_builder.vec_from_array([ - ast_builder.template_element( - SPAN, - false, - TemplateElementValue { - raw: ast_builder.atom("typo-"), - cooked: None, - }, - ), - ast_builder.template_element( - SPAN, - true, - TemplateElementValue { - raw: ast_builder.atom(""), - cooked: None, - }, - ), - ]), - ast_builder - .vec_from_array([expression.clone_in(ast_builder.allocator)]), - ), - styles: vec![], - }]) - } else { - ExtractResult::ExtractStyle(vec![ExtractStyleProp::Static(Dynamic( - ExtractDynamicStyle::new( - name, - level, - expression_to_code(expression).as_str(), - selector.map(|s| s.into()), - ), - ))]) - } + ExtractResult::ExtractStyle(vec![ExtractStyleProp::Static(Dynamic( + ExtractDynamicStyle::new( + name, + level, + expression_to_code(expression).as_str(), + selector.map(|s| s.into()), + ), + ))]) } } else { ExtractResult::Maintain @@ -664,3 +519,234 @@ pub fn extract_style_from_expression<'a>( _ => ExtractResult::Maintain, } } + +fn extract_style_from_member_expression<'a>( + ast_builder: &AstBuilder<'a>, + name: Option<&str>, + mem: &mut ComputedMemberExpression<'a>, + level: u8, + selector: Option<&str>, +) -> ExtractResult<'a> { + let mem_expression = &mem.expression.clone_in(ast_builder.allocator); + let mut ret: Vec = vec![]; + + match &mut mem.object { + Expression::ArrayExpression(array) => { + if array.elements.is_empty() { + return ExtractResult::Remove; + } + + if let Some(num) = get_number_by_literal_expression(mem_expression) { + if num < 0f64 { + return ExtractResult::Remove; + } + let mut etc = None; + for (idx, p) in array.elements.iter_mut().enumerate() { + if let ArrayExpressionElement::SpreadElement(sp) = p { + etc = Some(sp.argument.clone_in(ast_builder.allocator)); + continue; + } + if idx as f64 == num { + if let ExtractResult::ExtractStyle(styles) = extract_style_from_expression( + ast_builder, + name, + p.to_expression_mut(), + level, + selector, + ) { + return ExtractResult::ExtractStyle(styles); + } + } + } + return match etc { + None => ExtractResult::Remove, + Some(etc) => ExtractResult::ExtractStyle(vec![ExtractStyleProp::Static( + Dynamic(ExtractDynamicStyle::new( + name.unwrap(), + level, + expression_to_code(&Expression::ComputedMemberExpression( + ast_builder.alloc_computed_member_expression( + SPAN, + etc, + mem_expression.clone_in(ast_builder.allocator), + false, + ), + )) + .as_str(), + selector.map(|s| s.into()), + )), + )]), + }; + } + + let mut map = BTreeMap::new(); + for (idx, p) in array.elements.iter_mut().enumerate() { + if let ArrayExpressionElement::SpreadElement(ref sp) = p { + map.insert( + idx.to_string(), + Box::new(ExtractStyleProp::Static(Dynamic(ExtractDynamicStyle::new( + name.unwrap(), + level, + expression_to_code(&Expression::ComputedMemberExpression( + ast_builder.alloc_computed_member_expression( + SPAN, + sp.argument.clone_in(ast_builder.allocator), + mem_expression.clone_in(ast_builder.allocator), + false, + ), + )) + .as_str(), + selector.map(|s| s.into()), + )))), + ); + } else if let ExtractResult::ExtractStyle(styles) = extract_style_from_expression( + ast_builder, + name, + p.to_expression_mut(), + level, + selector, + ) { + map.insert( + idx.to_string(), + Box::new(ExtractStyleProp::StaticArray(styles)), + ); + } + } + + ret.push(ExtractStyleProp::MemberExpression { + expression: mem_expression.clone_in(ast_builder.allocator), + map, + }); + } + Expression::ObjectExpression(obj) => { + if obj.properties.is_empty() { + return ExtractResult::Remove; + } + + let mut map = BTreeMap::new(); + if let Some(k) = get_string_by_literal_expression(mem_expression) { + let mut etc = None; + for p in obj.properties.iter_mut() { + if let ObjectPropertyKind::ObjectProperty(ref mut o) = p { + if let PropertyKey::StaticIdentifier(ref pk) = o.key { + if pk.name == k { + if let ExtractResult::ExtractStyle(styles) = + extract_style_from_expression( + ast_builder, + name, + &mut o.value, + level, + selector, + ) + { + return ExtractResult::ExtractStyle(styles); + } + } + } + } else if let ObjectPropertyKind::SpreadProperty(ref sp) = p { + etc = Some(sp.argument.clone_in(ast_builder.allocator)); + } + } + match etc { + None => return ExtractResult::Remove, + Some(etc) => { + ret.push(ExtractStyleProp::Static(Dynamic(ExtractDynamicStyle::new( + name.unwrap(), + level, + expression_to_code(&Expression::ComputedMemberExpression( + ast_builder.alloc_computed_member_expression( + SPAN, + etc, + mem_expression.clone_in(ast_builder.allocator), + false, + ), + )) + .as_str(), + selector.map(|s| s.into()), + )))) + } + } + } + + for p in obj.properties.iter_mut() { + if let ObjectPropertyKind::ObjectProperty(ref mut o) = p { + if let PropertyKey::StaticIdentifier(_) + | PropertyKey::NumericLiteral(_) + | PropertyKey::StringLiteral(_) = o.key + { + if let ExtractResult::ExtractStyle(styles) = extract_style_from_expression( + ast_builder, + name, + &mut o.value, + level, + selector, + ) { + map.insert( + o.key.name().unwrap().to_string(), + Box::new(ExtractStyleProp::StaticArray(styles)), + ); + } + } + } + } + ret.push(ExtractStyleProp::MemberExpression { + expression: mem_expression.clone_in(ast_builder.allocator), + map, + }); + } + Expression::Identifier(_) => { + if let Some(name) = name { + ret.push(ExtractStyleProp::Static(Dynamic(ExtractDynamicStyle::new( + name, + level, + expression_to_code(&Expression::ComputedMemberExpression( + ast_builder.alloc_computed_member_expression( + SPAN, + mem.object.clone_in(ast_builder.allocator), + mem_expression.clone_in(ast_builder.allocator), + false, + ), + )) + .as_str(), + selector.map(|s| s.into()), + )))) + } + } + _ => {} + }; + + ExtractResult::ExtractStyle(ret) +} + +fn get_number_by_literal_expression(expr: &Expression) -> Option { + match expr { + Expression::NumericLiteral(num) => Some(num.value), + Expression::UnaryExpression(unary) => { + if let Expression::NumericLiteral(ref num) = unary.argument { + match unary.operator { + UnaryOperator::UnaryNegation => Some(-num.value), + UnaryOperator::UnaryPlus => Some(num.value), + _ => None, + } + } else { + None + } + } + _ => None, + } +} + +fn get_string_by_literal_expression(expr: &Expression) -> Option { + match expr { + Expression::StringLiteral(str) => Some(str.value.as_str().to_string()), + Expression::TemplateLiteral(tmp) => { + if tmp.quasis.len() == 1 { + Some(tmp.quasis[0].value.raw.as_str().to_string()) + } else { + None + } + } + Expression::NumericLiteral(num) => Some(num.value.to_string()), + _ => None, + } +}