From 469edf831e0723f57259106b42b5cf9d94666054 Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Sat, 19 Jul 2025 21:48:44 +0900 Subject: [PATCH 1/2] Fix optimize value --- .changeset/great-shrimps-melt.md | 5 ++ libs/css/src/constant.rs | 13 ++++ libs/css/src/optimize_value.rs | 67 ++++++++++++++++++- libs/css/src/property_type.rs | 1 - libs/css/src/style_selector.rs | 6 +- libs/extractor/src/css_utils.rs | 11 ++- .../src/extract_style/extract_style_value.rs | 4 +- .../src/extract_style/style_property.rs | 10 +-- .../extract_style_from_expression.rs | 4 +- libs/extractor/src/visit.rs | 8 +-- libs/sheet/src/lib.rs | 6 +- pnpm-workspace.yaml | 13 ++-- 12 files changed, 118 insertions(+), 30 deletions(-) create mode 100644 .changeset/great-shrimps-melt.md diff --git a/.changeset/great-shrimps-melt.md b/.changeset/great-shrimps-melt.md new file mode 100644 index 00000000..5e912f17 --- /dev/null +++ b/.changeset/great-shrimps-melt.md @@ -0,0 +1,5 @@ +--- +"@devup-ui/wasm": patch +--- + +Fix optimize value diff --git a/libs/css/src/constant.rs b/libs/css/src/constant.rs index 7a0de2ae..3c02ca70 100644 --- a/libs/css/src/constant.rs +++ b/libs/css/src/constant.rs @@ -76,11 +76,24 @@ pub(super) static DOUBLE_SEPARATOR: phf::Set<&str> = phf_set! { "view-transition-old", }; +pub(super) static ZERO_PERCENT_FUNCTION: phf::Set<&str> = phf_set! { + "min(", + "max(", + "clamp(", + "calc(", + "MIN(", + "MAX(", + "CLAMP(", + "CALC(", +}; + pub(super) static F_SPACE_RE: Lazy = Lazy::new(|| Regex::new(r"\s*,\s*").unwrap()); pub(super) static F_DOT_RE: Lazy = Lazy::new(|| Regex::new(r"(\b|,)0\.(\d+)").unwrap()); pub(super) static DOT_ZERO_RE: Lazy = Lazy::new(|| Regex::new(r"(\b|,)-?0\.0+([^\d])").unwrap()); pub(super) static COLOR_HASH: Lazy = Lazy::new(|| Regex::new(r"#([0-9a-zA-Z]+)").unwrap()); +pub(super) static INNER_TRIM_RE: Lazy = + Lazy::new(|| Regex::new(r"\(\s*([^)]*?)\s*\)").unwrap()); pub(super) static ZERO_RE: Lazy = Lazy::new(|| Regex::new(r"(^|\s|\(|,)-?0(px|em|rem|vh|vw|%|dvh|dvw)").unwrap()); diff --git a/libs/css/src/optimize_value.rs b/libs/css/src/optimize_value.rs index 0d863160..7765bd4e 100644 --- a/libs/css/src/optimize_value.rs +++ b/libs/css/src/optimize_value.rs @@ -1,10 +1,11 @@ use crate::{ COLOR_HASH, F_SPACE_RE, ZERO_RE, - constant::{DOT_ZERO_RE, F_DOT_RE}, + constant::{DOT_ZERO_RE, F_DOT_RE, INNER_TRIM_RE, ZERO_PERCENT_FUNCTION}, }; pub fn optimize_value(value: &str) -> String { let mut ret = value.trim().to_string(); + ret = INNER_TRIM_RE.replace_all(&ret, "(${1})").to_string(); if ret.contains(",") { ret = F_SPACE_RE.replace_all(&ret, ",").trim().to_string(); } @@ -17,6 +18,31 @@ pub fn optimize_value(value: &str) -> String { ret = DOT_ZERO_RE.replace_all(&ret, "${1}0${2}").to_string(); ret = F_DOT_RE.replace_all(&ret, "${1}.${2}").to_string(); ret = ZERO_RE.replace_all(&ret, "${1}0").to_string(); + + for f in ZERO_PERCENT_FUNCTION.iter() { + if ret.contains(f) { + let index = ret.find(f).unwrap() + f.len(); + let mut zero_idx = vec![]; + let mut depth = 0; + for i in index..ret.len() { + if ret[i..i + 1].eq("(") { + depth += 1; + } else if ret[i..i + 1].eq(")") { + depth -= 1; + } else if ret[i..i + 1].eq("0") + && !ret[i - 1..i].chars().next().unwrap().is_ascii_digit() + && (ret.len() == i + 1 + || !ret[i + 1..i + 2].chars().next().unwrap().is_ascii_digit()) + && depth == 0 + { + zero_idx.push(i); + } + } + for i in zero_idx.iter().rev() { + ret = ret[..*i].to_string() + "0%" + &ret[*i + 1..]; + } + } + } } // remove ; from dynamic value for str_symbol in ["", "`", "\"", "'"] { @@ -34,6 +60,27 @@ pub fn optimize_value(value: &str) -> String { ); } } + + if ret.contains("(") || ret.contains(")") { + let mut depth = 0; + for i in 0..ret.len() { + if ret[i..i + 1].eq("(") { + depth += 1; + } else if ret[i..i + 1].eq(")") { + depth -= 1; + } + } + if depth < 0 { + for _ in 0..(-depth) { + ret.insert(0, '('); + } + } + if depth > 0 { + for _ in 0..depth { + ret.push(')'); + } + } + } ret } @@ -99,6 +146,19 @@ mod tests { #[case("translate(-0px, 0px)", "translate(0,0)")] #[case("translate(0px, 0px)", "translate(0,0)")] #[case("translate(10px, 0px)", "translate(10px,0)")] + #[case("translate( 10px , 0px )", "translate(10px,0)")] + #[case("translate( 0px , 0px )", "translate(0,0)")] + #[case(" translate( 0px , 0px ) ", "translate(0,0)")] + #[case("clamp(0, 10px, 10px)", "clamp(0%,10px,10px)")] + #[case("clamp(10px, 0, 10px)", "clamp(10px,0%,10px)")] + #[case("clamp(10px, 10px, 0)", "clamp(10px,10px,0%)")] + #[case("clamp(0px, 10px, 0px)", "clamp(0%,10px,0%)")] + #[case("min(0, 10px)", "min(0%,10px)")] + #[case("max(0, 10px)", "max(0%,10px)")] + #[case("min(10px, 0)", "min(10px,0%)")] + #[case("max(10px, 0)", "max(10px,0%)")] + #[case("max(some(0), 0)", "max(some(0),0%)")] + #[case("translate(0, min(0, 10px))", "translate(0,min(0%,10px))")] #[case("\"red\"", "\"red\"")] #[case("'red'", "'red'")] #[case("`red`", "`red`")] @@ -110,6 +170,11 @@ mod tests { #[case("('red;')", "('red')")] #[case("('red') + 'blue;'", "('red') + 'blue'")] #[case("translateX(0px) translateY(0px)", "translateX(0) translateY(0)")] + // recovery case + #[case("max(10px, 0", "max(10px,0%)")] + #[case("max(10px, calc(0", "max(10px,calc(0%))")] + #[case("max(10px, any(0", "max(10px,any(0))")] + #[case("10px, any(0))", "(10px,any(0))")] fn test_optimize_value(#[case] input: &str, #[case] expected: &str) { assert_eq!(optimize_value(input), expected); } diff --git a/libs/css/src/property_type.rs b/libs/css/src/property_type.rs index 5d1827dc..d695957a 100644 --- a/libs/css/src/property_type.rs +++ b/libs/css/src/property_type.rs @@ -41,7 +41,6 @@ impl From<[&str; 2]> for PropertyType { } #[cfg(test)] - mod tests { use super::*; diff --git a/libs/css/src/style_selector.rs b/libs/css/src/style_selector.rs index 132e144c..4ffc9fd5 100644 --- a/libs/css/src/style_selector.rs +++ b/libs/css/src/style_selector.rs @@ -171,7 +171,7 @@ impl Display for StyleSelector { format!("@{query}") } } - StyleSelector::Global(value, _) => format!("{value}"), + StyleSelector::Global(value, _) => value.to_string(), } ) } @@ -296,7 +296,7 @@ mod tests { #[case( StyleSelector::Global("div:hover".to_string(), "file2.rs".to_string()), StyleSelector::Global("span:hover".to_string(), "file1.rs".to_string()), - "div".cmp(&"span") + "div".cmp("span") )] #[case( StyleSelector::Global("div:hover".to_string(), "file2.rs".to_string()), @@ -306,7 +306,7 @@ mod tests { #[case( StyleSelector::Global("div:".to_string(), "file2.rs".to_string()), StyleSelector::Global("span:".to_string(), "file1.rs".to_string()), - "div".cmp(&"span") + "div".cmp("span") )] // global selector always less than selector #[case( diff --git a/libs/extractor/src/css_utils.rs b/libs/extractor/src/css_utils.rs index 65862fdb..b4f422fc 100644 --- a/libs/extractor/src/css_utils.rs +++ b/libs/extractor/src/css_utils.rs @@ -25,7 +25,7 @@ pub fn css_to_style<'a>( if s.is_empty() { return None; } - Some(format!("@media{}", s)) + Some(format!("@media{s}")) }) .collect::>(); if media_inputs.len() > 1 { @@ -69,9 +69,9 @@ pub fn css_to_style<'a>( } }; let block = if block.contains('{') { - css_to_style(block, level, &sel) + css_to_style(block, level, sel) } else { - css_to_style_block(block, level, &sel) + css_to_style_block(block, level, sel) }; let input_end = input.rfind('}').unwrap() + 1; @@ -98,7 +98,7 @@ fn css_to_style_block<'a>( selector: &Option, ) -> Vec> { css.split(";") - .map(|s| { + .filter_map(|s| { let s = s.trim(); if s.is_empty() { None @@ -111,7 +111,6 @@ fn css_to_style_block<'a>( ))) } }) - .flatten() .collect() } @@ -163,7 +162,7 @@ pub fn optimize_css_block(css: &str) -> String { let mut iter = s.split(":"); let property = iter.next().unwrap().trim(); let value = iter.next().unwrap().trim(); - format!("{}:{}", property, value) + format!("{property}:{value}") } }) .collect::>() diff --git a/libs/extractor/src/extract_style/extract_style_value.rs b/libs/extractor/src/extract_style/extract_style_value.rs index bfecf41c..20c45805 100644 --- a/libs/extractor/src/extract_style/extract_style_value.rs +++ b/libs/extractor/src/extract_style/extract_style_value.rs @@ -85,12 +85,12 @@ mod tests { css: "".to_string(), file: "".to_string(), }); - assert!(matches!(value.extract(), None)); + assert!(value.extract().is_none()); let value = ExtractStyleValue::Import(ExtractImport { url: "".to_string(), file: "".to_string(), }); - assert!(matches!(value.extract(), None)); + assert!(value.extract().is_none()); } } diff --git a/libs/extractor/src/extract_style/style_property.rs b/libs/extractor/src/extract_style/style_property.rs index 4c04eed4..6d508906 100644 --- a/libs/extractor/src/extract_style/style_property.rs +++ b/libs/extractor/src/extract_style/style_property.rs @@ -1,3 +1,5 @@ +use std::fmt::{Display, Error, Formatter}; + pub enum StyleProperty { ClassName(String), Variable { @@ -6,11 +8,11 @@ pub enum StyleProperty { identifier: String, }, } -impl StyleProperty { - pub fn to_string(&self) -> String { +impl Display for StyleProperty { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { match self { - StyleProperty::ClassName(name) => name.clone(), - StyleProperty::Variable { variable_name, .. } => format!("var({})", variable_name), + StyleProperty::ClassName(name) => write!(f, "{name}"), + StyleProperty::Variable { variable_name, .. } => write!(f, "var({variable_name})"), } } } diff --git a/libs/extractor/src/extractor/extract_style_from_expression.rs b/libs/extractor/src/extractor/extract_style_from_expression.rs index cc3faa13..95ecf5e4 100644 --- a/libs/extractor/src/extractor/extract_style_from_expression.rs +++ b/libs/extractor/src/extractor/extract_style_from_expression.rs @@ -144,7 +144,7 @@ pub fn extract_style_from_expression<'a>( .collect::>() .join(""), level, - &selector, + selector, ), ..ExtractResult::default() }, @@ -228,7 +228,7 @@ pub fn extract_style_from_expression<'a>( } } else { ExtractResult { - styles: css_to_style(&value, level, &selector), + styles: css_to_style(&value, level, selector), ..ExtractResult::default() } } diff --git a/libs/extractor/src/visit.rs b/libs/extractor/src/visit.rs index 8d5a22df..ef9dff71 100644 --- a/libs/extractor/src/visit.rs +++ b/libs/extractor/src/visit.rs @@ -255,8 +255,8 @@ impl<'a> VisitMut<'a> for DevupVisitor<'a> { let keyframes = ExtractKeyframes { keyframes: keyframes_to_keyframes_style(&css_str) .into_iter() - .filter_map(|(k, v)| { - Some(( + .map(|(k, v)| { + ( k, v.into_iter() .filter_map(|ex| { @@ -270,7 +270,7 @@ impl<'a> VisitMut<'a> for DevupVisitor<'a> { } }) .collect(), - )) + ) }) .collect(), }; @@ -354,7 +354,7 @@ impl<'a> VisitMut<'a> for DevupVisitor<'a> { kind.extract() .into_iter() .rev() - .map(|ex| ExtractStyleProp::Static(ex)), + .map(ExtractStyleProp::Static), ); props_styles.iter().rev().for_each(|style| { self.styles.extend(style.extract().into_iter().map(|mut s| { diff --git a/libs/sheet/src/lib.rs b/libs/sheet/src/lib.rs index 4c5de0e5..fe0d0e46 100644 --- a/libs/sheet/src/lib.rs +++ b/libs/sheet/src/lib.rs @@ -265,7 +265,7 @@ impl StyleSheet { color_interface_name, color_keys .into_iter() - .map(|key| format!("{}:null;", convert_interface_key(&format!("${}", key)))) + .map(|key| format!("{}:null;", convert_interface_key(&format!("${key}")))) .collect::>() .join(""), typography_interface_name, @@ -288,8 +288,8 @@ impl StyleSheet { pub fn create_css(&self) -> String { let mut css = self .imports - .iter() - .map(|(_, import)| format!("@import \"{}\";", import)) + .values() + .map(|import| format!("@import \"{import}\";")) .collect::>() .join(""); css.push_str(&self.theme.to_css()); diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 49b960ca..347a9a9b 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,5 +1,10 @@ packages: - - 'packages/*' - - 'apps/*' - - 'bindings/*' - - 'benchmark/*' + - packages/* + - apps/* + - bindings/* + - benchmark/* + +onlyBuiltDependencies: + - core-js + - esbuild + - sharp From b285d7fc97ae6c9f70fe41aa6f47686f160a0cec Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Sat, 19 Jul 2025 22:02:15 +0900 Subject: [PATCH 2/2] Fix optimize value --- libs/sheet/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/sheet/src/lib.rs b/libs/sheet/src/lib.rs index fe0d0e46..42039d6b 100644 --- a/libs/sheet/src/lib.rs +++ b/libs/sheet/src/lib.rs @@ -215,8 +215,8 @@ impl StyleSheet { } self.global_css_files.remove(file); self.css.remove(file); - for (_, map) in self.properties.iter_mut() { - for (_, props) in map.iter_mut() { + for map in self.properties.values_mut() { + for props in map.values_mut() { props.retain(|prop| { if let Some(StyleSelector::Global(_, f)) = prop.selector.as_ref() { f != file