From 12405071d0e8c2145419f867bad1388e1215200d Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Wed, 2 Jul 2025 14:59:09 +0900 Subject: [PATCH 1/4] Fix classname order issue --- .changeset/tame-berries-jam.md | 5 + apps/vite/src/App.tsx | 5 + apps/vite/src/Button.tsx | 49 ++++++++++ libs/extractor/src/lib.rs | 34 +++++++ libs/extractor/src/prop_modify_utils.rs | 98 +++++++++++++++---- ...ts__extract_class_name_from_component.snap | 2 +- ...xtract_class_name_from_component2.snap.new | 45 +++++++++ ...extract_style_props_with_class_name-5.snap | 2 +- ...extract_style_props_with_class_name-6.snap | 2 +- ...extract_style_props_with_class_name-7.snap | 27 +++++ ...extract_style_props_with_class_name-8.snap | 44 +++++++++ ..._extract_style_props_with_class_name1.snap | 29 ------ 12 files changed, 290 insertions(+), 52 deletions(-) create mode 100644 .changeset/tame-berries-jam.md create mode 100644 apps/vite/src/Button.tsx create mode 100644 libs/extractor/src/snapshots/extractor__tests__extract_class_name_from_component2.snap.new create mode 100644 libs/extractor/src/snapshots/extractor__tests__extract_style_props_with_class_name-7.snap create mode 100644 libs/extractor/src/snapshots/extractor__tests__extract_style_props_with_class_name-8.snap delete mode 100644 libs/extractor/src/snapshots/extractor__tests__extract_style_props_with_class_name1.snap diff --git a/.changeset/tame-berries-jam.md b/.changeset/tame-berries-jam.md new file mode 100644 index 00000000..8080213f --- /dev/null +++ b/.changeset/tame-berries-jam.md @@ -0,0 +1,5 @@ +--- +"@devup-ui/wasm": patch +--- + +Fix classname order issue diff --git a/apps/vite/src/App.tsx b/apps/vite/src/App.tsx index 88f55b93..033f881f 100644 --- a/apps/vite/src/App.tsx +++ b/apps/vite/src/App.tsx @@ -1,6 +1,8 @@ import { Box, Text } from '@devup-ui/react' import { Lib } from 'vite-lib-example' +import { Button } from './Button' + export default function App() { return (
@@ -18,6 +20,9 @@ export default function App() { typo +
) } diff --git a/apps/vite/src/Button.tsx b/apps/vite/src/Button.tsx new file mode 100644 index 00000000..9dfd0def --- /dev/null +++ b/apps/vite/src/Button.tsx @@ -0,0 +1,49 @@ +import { Button as DevupButton } from '@devup-ui/react' + +type ButtonProps = React.ButtonHTMLAttributes & { + variant?: 'primary' | 'default' + colors?: { + primary?: string + error?: string + } + isError?: boolean + size?: 's' | 'm' +} + +/** + * Button + * ## Design Token + * ### Color + * - inputDisabledBackground + * - inputDisabled + * - inputBackground + * - primaryHover + * - text + * - border + * + * @constructor + */ +export function Button({ + variant = 'default', + className = '', + type = 'button', + colors, + isError = false, + children, + size = 'm', + ...props +}: ButtonProps): React.ReactElement { + const isPrimary = variant === 'primary' + + return ( + + {children} + + ) +} diff --git a/libs/extractor/src/lib.rs b/libs/extractor/src/lib.rs index 2a2eae77..74b53a4f 100644 --- a/libs/extractor/src/lib.rs +++ b/libs/extractor/src/lib.rs @@ -570,6 +570,40 @@ mod tests { ) .unwrap() )); + + reset_class_map(); + assert_debug_snapshot!(ToBTreeSet::from( + extract( + "test.tsx", + r#"import {Box as C} from '@devup-ui/core' + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap() + )); + + reset_class_map(); + assert_debug_snapshot!(ToBTreeSet::from( + extract( + "test.tsx", + r#"import {Box as C} from '@devup-ui/core' + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap() + )); } #[test] diff --git a/libs/extractor/src/prop_modify_utils.rs b/libs/extractor/src/prop_modify_utils.rs index 94a060b7..b41e105d 100644 --- a/libs/extractor/src/prop_modify_utils.rs +++ b/libs/extractor/src/prop_modify_utils.rs @@ -205,40 +205,98 @@ fn merge_string_expressions<'a>( return None; } if expressions.len() == 1 { - return Some(expressions[0].clone_in(ast_builder.allocator)); + return Some(expressions.first().unwrap().clone_in(ast_builder.allocator)); } - let mut string_literals = vec![]; + let mut string_literals: std::vec::Vec = vec![]; let mut other_expressions = vec![]; for ex in expressions { + string_literals.push("".to_string()); if let Expression::StringLiteral(literal) = ex { - string_literals.push(literal.value.trim()); + if !string_literals.is_empty() { + string_literals + .last_mut() + .unwrap() + .push_str(&format!(" {}", literal.value.trim())); + } else { + string_literals.push(literal.value.trim().to_string()); + } + } else if let Expression::TemplateLiteral(template) = ex { + if !string_literals.is_empty() { + string_literals.last_mut().unwrap().push_str(&format!( + " {}", + template + .quasis + .iter() + .map(|q| q.value.raw.trim()) + .filter(|q| !q.is_empty()) + .collect::>() + .join(" ") + )); + } else { + string_literals.push( + template + .quasis + .iter() + .map(|q| q.value.raw.as_str()) + .collect::>() + .join(" "), + ); + } + other_expressions.extend(template.expressions.clone_in(ast_builder.allocator)); } else { - other_expressions.push(ex); + other_expressions.push(ex.clone_in(ast_builder.allocator)); } } if other_expressions.is_empty() { - return Some(Expression::StringLiteral(ast_builder.alloc_string_literal( - SPAN, - ast_builder.atom(&string_literals.join(" ")), - None, - ))); + return Some(Expression::StringLiteral( + ast_builder.alloc_string_literal( + SPAN, + ast_builder.atom( + &string_literals + .iter() + .map(|s| s.trim()) + .filter(|s| !s.is_empty()) + .collect::>() + .join(" "), + ), + None, + ), + )); } + let literals = oxc_allocator::Vec::from_iter_in( + string_literals.iter().enumerate().map(|(idx, s)| { + ast_builder.template_element( + SPAN, + TemplateElementValue { + raw: ast_builder.atom(&{ + let trimmed = s.trim(); + if trimmed.is_empty() { + "".to_string() + } else if idx > 0 && idx == string_literals.len() - 1 { + if string_literals.len() == other_expressions.len() { + format!(" {} ", trimmed) + } else { + format!(" {}", trimmed) + } + } else if idx == string_literals.len() - 1 { + trimmed.to_string() + } else { + format!("{} ", trimmed) + } + }), + cooked: None, + }, + false, + ) + }), + ast_builder.allocator, + ); Some(Expression::TemplateLiteral( ast_builder.alloc_template_literal( SPAN, - oxc_allocator::Vec::from_iter_in( - [ast_builder.template_element( - SPAN, - TemplateElementValue { - raw: ast_builder.atom(&format!("{} ", string_literals.join(" "))), - cooked: None, - }, - false, - )], - ast_builder.allocator, - ), + literals, oxc_allocator::Vec::from_iter_in( other_expressions .into_iter() diff --git a/libs/extractor/src/snapshots/extractor__tests__extract_class_name_from_component.snap b/libs/extractor/src/snapshots/extractor__tests__extract_class_name_from_component.snap index ad580656..2f5a8a07 100644 --- a/libs/extractor/src/snapshots/extractor__tests__extract_class_name_from_component.snap +++ b/libs/extractor/src/snapshots/extractor__tests__extract_class_name_from_component.snap @@ -45,5 +45,5 @@ ToBTreeSet { }, ), }, - code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", } diff --git a/libs/extractor/src/snapshots/extractor__tests__extract_class_name_from_component2.snap.new b/libs/extractor/src/snapshots/extractor__tests__extract_class_name_from_component2.snap.new new file mode 100644 index 00000000..8d2dcfdc --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__extract_class_name_from_component2.snap.new @@ -0,0 +1,45 @@ +--- +source: libs/extractor/src/lib.rs +assertion_line: 613 +expression: "ToBTreeSet::from(extract(\"test.tsx\",\nr#\"import {Box as C} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap())" +--- +ToBTreeSet { + styles: { + Static( + ExtractStaticStyle { + property: "borderColor", + value: "", + level: 0, + selector: Some( + Selector( + "&:hover", + ), + ), + style_order: None, + }, + ), + Static( + ExtractStaticStyle { + property: "borderColor", + value: "blue", + level: 0, + selector: Some( + Selector( + "&:hover", + ), + ), + style_order: None, + }, + ), + Static( + ExtractStaticStyle { + property: "padding", + value: "4px", + level: 0, + selector: None, + style_order: None, + }, + ), + }, + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__extract_style_props_with_class_name-5.snap b/libs/extractor/src/snapshots/extractor__tests__extract_style_props_with_class_name-5.snap index 580a9aac..39471513 100644 --- a/libs/extractor/src/snapshots/extractor__tests__extract_style_props_with_class_name-5.snap +++ b/libs/extractor/src/snapshots/extractor__tests__extract_style_props_with_class_name-5.snap @@ -23,5 +23,5 @@ ToBTreeSet { }, ), }, - code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", } diff --git a/libs/extractor/src/snapshots/extractor__tests__extract_style_props_with_class_name-6.snap b/libs/extractor/src/snapshots/extractor__tests__extract_style_props_with_class_name-6.snap index fdbb4357..a946c166 100644 --- a/libs/extractor/src/snapshots/extractor__tests__extract_style_props_with_class_name-6.snap +++ b/libs/extractor/src/snapshots/extractor__tests__extract_style_props_with_class_name-6.snap @@ -23,5 +23,5 @@ ToBTreeSet { }, ), }, - code: "import \"@devup-ui/core/devup-ui.css\";\n\"Next.js;\n", + code: "import \"@devup-ui/core/devup-ui.css\";\n\"Next.js;\n", } diff --git a/libs/extractor/src/snapshots/extractor__tests__extract_style_props_with_class_name-7.snap b/libs/extractor/src/snapshots/extractor__tests__extract_style_props_with_class_name-7.snap new file mode 100644 index 00000000..39660de1 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__extract_style_props_with_class_name-7.snap @@ -0,0 +1,27 @@ +--- +source: libs/extractor/src/lib.rs +expression: "ToBTreeSet::from(extract(\"test.tsx\",\nr#\"import {Box as C} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap())" +--- +ToBTreeSet { + styles: { + Static( + ExtractStaticStyle { + property: "margin", + value: "8px", + level: 0, + selector: None, + style_order: None, + }, + ), + Static( + ExtractStaticStyle { + property: "padding", + value: "4px", + level: 0, + selector: None, + style_order: None, + }, + ), + }, + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__extract_style_props_with_class_name-8.snap b/libs/extractor/src/snapshots/extractor__tests__extract_style_props_with_class_name-8.snap new file mode 100644 index 00000000..6bbe6ff7 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__extract_style_props_with_class_name-8.snap @@ -0,0 +1,44 @@ +--- +source: libs/extractor/src/lib.rs +expression: "ToBTreeSet::from(extract(\"test.tsx\",\nr#\"import {Box as C} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap())" +--- +ToBTreeSet { + styles: { + Static( + ExtractStaticStyle { + property: "borderColor", + value: "", + level: 0, + selector: Some( + Selector( + "&:hover", + ), + ), + style_order: None, + }, + ), + Static( + ExtractStaticStyle { + property: "borderColor", + value: "blue", + level: 0, + selector: Some( + Selector( + "&:hover", + ), + ), + style_order: None, + }, + ), + Static( + ExtractStaticStyle { + property: "padding", + value: "4px", + level: 0, + selector: None, + style_order: None, + }, + ), + }, + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__extract_style_props_with_class_name1.snap b/libs/extractor/src/snapshots/extractor__tests__extract_style_props_with_class_name1.snap deleted file mode 100644 index defb72b9..00000000 --- a/libs/extractor/src/snapshots/extractor__tests__extract_style_props_with_class_name1.snap +++ /dev/null @@ -1,29 +0,0 @@ ---- -source: libs/extractor/src/lib.rs -expression: "ToBTreeSet::from(extract(\"test.tsx\",\nr\"import * as B from '@devup-ui/core'\n \n \",\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap())" ---- -ToBTreeSet { - styles: { - Static( - ExtractStaticStyle { - property: "display", - value: "flex", - level: 0, - selector: None, - style_order: Some( - 0, - ), - }, - ), - Static( - ExtractStaticStyle { - property: "padding", - value: "-4px", - level: 0, - selector: None, - style_order: None, - }, - ), - }, - code: "import \"@devup-ui/core/devup-ui.css\";\nimport * as B from \"@devup-ui/core\";\n
;\n", -} From 1a203d6a2d34f48fcc27b938a1078dd87edcca0a Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Wed, 2 Jul 2025 15:00:35 +0900 Subject: [PATCH 2/4] Fix classname order issue --- libs/extractor/src/prop_modify_utils.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/extractor/src/prop_modify_utils.rs b/libs/extractor/src/prop_modify_utils.rs index b41e105d..a01866f7 100644 --- a/libs/extractor/src/prop_modify_utils.rs +++ b/libs/extractor/src/prop_modify_utils.rs @@ -275,14 +275,14 @@ fn merge_string_expressions<'a>( "".to_string() } else if idx > 0 && idx == string_literals.len() - 1 { if string_literals.len() == other_expressions.len() { - format!(" {} ", trimmed) + format!(" {trimmed} ") } else { - format!(" {}", trimmed) + format!(" {trimmed}") } } else if idx == string_literals.len() - 1 { trimmed.to_string() } else { - format!("{} ", trimmed) + format!("{trimmed} ") } }), cooked: None, @@ -322,7 +322,7 @@ fn merge_object_expressions<'a>( ast_builder.alloc_object_expression( SPAN, oxc_allocator::Vec::from_iter_in( - expressions.into_iter().map(|ex| { + expressions.iter().map(|ex| { ObjectPropertyKind::SpreadProperty( ast_builder.alloc_spread_element(SPAN, ex.clone_in(ast_builder.allocator)), ) From e002e0bb771e80dd6e4208cd855fe73de95c1083 Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Wed, 2 Jul 2025 15:01:07 +0900 Subject: [PATCH 3/4] Fix classname order issue --- apps/vite/src/App.tsx | 5 ---- apps/vite/src/Button.tsx | 49 ---------------------------------------- 2 files changed, 54 deletions(-) delete mode 100644 apps/vite/src/Button.tsx diff --git a/apps/vite/src/App.tsx b/apps/vite/src/App.tsx index 033f881f..88f55b93 100644 --- a/apps/vite/src/App.tsx +++ b/apps/vite/src/App.tsx @@ -1,8 +1,6 @@ import { Box, Text } from '@devup-ui/react' import { Lib } from 'vite-lib-example' -import { Button } from './Button' - export default function App() { return (
@@ -20,9 +18,6 @@ export default function App() { typo -
) } diff --git a/apps/vite/src/Button.tsx b/apps/vite/src/Button.tsx deleted file mode 100644 index 9dfd0def..00000000 --- a/apps/vite/src/Button.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { Button as DevupButton } from '@devup-ui/react' - -type ButtonProps = React.ButtonHTMLAttributes & { - variant?: 'primary' | 'default' - colors?: { - primary?: string - error?: string - } - isError?: boolean - size?: 's' | 'm' -} - -/** - * Button - * ## Design Token - * ### Color - * - inputDisabledBackground - * - inputDisabled - * - inputBackground - * - primaryHover - * - text - * - border - * - * @constructor - */ -export function Button({ - variant = 'default', - className = '', - type = 'button', - colors, - isError = false, - children, - size = 'm', - ...props -}: ButtonProps): React.ReactElement { - const isPrimary = variant === 'primary' - - return ( - - {children} - - ) -} From 2ab9a9e680c38172f9e310238ae13fb805c52125 Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Wed, 2 Jul 2025 15:03:45 +0900 Subject: [PATCH 4/4] Fix classname order issue --- ...xtract_class_name_from_component2.snap.new | 45 ------------------- 1 file changed, 45 deletions(-) delete mode 100644 libs/extractor/src/snapshots/extractor__tests__extract_class_name_from_component2.snap.new diff --git a/libs/extractor/src/snapshots/extractor__tests__extract_class_name_from_component2.snap.new b/libs/extractor/src/snapshots/extractor__tests__extract_class_name_from_component2.snap.new deleted file mode 100644 index 8d2dcfdc..00000000 --- a/libs/extractor/src/snapshots/extractor__tests__extract_class_name_from_component2.snap.new +++ /dev/null @@ -1,45 +0,0 @@ ---- -source: libs/extractor/src/lib.rs -assertion_line: 613 -expression: "ToBTreeSet::from(extract(\"test.tsx\",\nr#\"import {Box as C} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap())" ---- -ToBTreeSet { - styles: { - Static( - ExtractStaticStyle { - property: "borderColor", - value: "", - level: 0, - selector: Some( - Selector( - "&:hover", - ), - ), - style_order: None, - }, - ), - Static( - ExtractStaticStyle { - property: "borderColor", - value: "blue", - level: 0, - selector: Some( - Selector( - "&:hover", - ), - ), - style_order: None, - }, - ), - Static( - ExtractStaticStyle { - property: "padding", - value: "4px", - level: 0, - selector: None, - style_order: None, - }, - ), - }, - code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", -}