1+ use std:: fmt:: { Debug , Formatter } ;
2+
13use css:: {
24 optimize_value:: optimize_value,
35 sheet_to_classname, sheet_to_variable_name,
@@ -6,7 +8,7 @@ use css::{
68
79use crate :: extract_style:: { ExtractStyleProperty , style_property:: StyleProperty } ;
810
9- #[ derive( Debug , PartialEq , Clone , Eq , Hash , Ord , PartialOrd ) ]
11+ #[ derive( PartialEq , Clone , Eq , Hash , Ord , PartialOrd ) ]
1012pub struct ExtractDynamicStyle {
1113 /// property
1214 property : String ,
@@ -18,6 +20,41 @@ pub struct ExtractDynamicStyle {
1820 selector : Option < StyleSelector > ,
1921
2022 pub ( super ) style_order : Option < u8 > ,
23+
24+ /// Whether the value had `!important` that was stripped from the identifier
25+ important : bool ,
26+ }
27+
28+ impl Debug for ExtractDynamicStyle {
29+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
30+ let mut s = f. debug_struct ( "ExtractDynamicStyle" ) ;
31+ s. field ( "property" , & self . property )
32+ . field ( "level" , & self . level )
33+ . field ( "identifier" , & self . identifier )
34+ . field ( "selector" , & self . selector )
35+ . field ( "style_order" , & self . style_order ) ;
36+ if self . important {
37+ s. field ( "important" , & self . important ) ;
38+ }
39+ s. finish ( )
40+ }
41+ }
42+
43+ /// Strip ` !important` from a dynamic style identifier, returning the cleaned
44+ /// identifier and whether `!important` was found.
45+ ///
46+ /// Handles JS expression code produced by `expression_to_code`, where the
47+ /// `!important` text appears before a closing delimiter (backtick, quote) or
48+ /// at the very end of the string.
49+ fn strip_important ( identifier : & str ) -> ( String , bool ) {
50+ for str_symbol in [ "" , "`" , "\" " , "'" ] {
51+ let suffix = format ! ( " !important{str_symbol}" ) ;
52+ if identifier. ends_with ( & suffix) {
53+ let base = & identifier[ ..identifier. len ( ) - suffix. len ( ) ] ;
54+ return ( format ! ( "{base}{str_symbol}" ) , true ) ;
55+ }
56+ }
57+ ( identifier. to_string ( ) , false )
2158}
2259
2360impl ExtractDynamicStyle {
@@ -28,12 +65,15 @@ impl ExtractDynamicStyle {
2865 identifier : & str ,
2966 selector : Option < StyleSelector > ,
3067 ) -> Self {
68+ let optimized = optimize_value ( identifier) ;
69+ let ( identifier, important) = strip_important ( & optimized) ;
3170 Self {
3271 property : property. to_string ( ) ,
3372 level,
34- identifier : optimize_value ( identifier ) ,
73+ identifier,
3574 selector : selector. map ( optimize_selector) ,
3675 style_order : None ,
76+ important,
3777 }
3878 }
3979
@@ -56,6 +96,10 @@ impl ExtractDynamicStyle {
5696 pub fn style_order ( & self ) -> Option < u8 > {
5797 self . style_order
5898 }
99+
100+ pub fn important ( & self ) -> bool {
101+ self . important
102+ }
59103}
60104
61105impl ExtractStyleProperty for ExtractDynamicStyle {
@@ -92,5 +136,50 @@ mod tests {
92136 assert_eq ! ( style. selector( ) , None ) ;
93137 assert_eq ! ( style. identifier( ) , "primary" ) ;
94138 assert_eq ! ( style. style_order( ) , None ) ;
139+ assert ! ( !style. important( ) ) ;
140+ }
141+
142+ #[ test]
143+ fn test_strip_important_plain ( ) {
144+ let ( id, important) = strip_important ( "color" ) ;
145+ assert_eq ! ( id, "color" ) ;
146+ assert ! ( !important) ;
147+ }
148+
149+ #[ test]
150+ fn test_strip_important_template_literal ( ) {
151+ // Template literal: `${color} !important`
152+ let ( id, important) = strip_important ( "`${color} !important`" ) ;
153+ assert_eq ! ( id, "`${color}`" ) ;
154+ assert ! ( important) ;
155+ }
156+
157+ #[ test]
158+ fn test_strip_important_double_quote ( ) {
159+ let ( id, important) = strip_important ( "\" red !important\" " ) ;
160+ assert_eq ! ( id, "\" red\" " ) ;
161+ assert ! ( important) ;
162+ }
163+
164+ #[ test]
165+ fn test_strip_important_single_quote ( ) {
166+ let ( id, important) = strip_important ( "'red !important'" ) ;
167+ assert_eq ! ( id, "'red'" ) ;
168+ assert ! ( important) ;
169+ }
170+
171+ #[ test]
172+ fn test_strip_important_bare ( ) {
173+ let ( id, important) = strip_important ( "something !important" ) ;
174+ assert_eq ! ( id, "something" ) ;
175+ assert ! ( important) ;
176+ }
177+
178+ #[ test]
179+ fn test_dynamic_style_with_important ( ) {
180+ let style = ExtractDynamicStyle :: new ( "background" , 0 , "`${color} !important`" , None ) ;
181+ assert_eq ! ( style. property( ) , "background" ) ;
182+ assert_eq ! ( style. identifier( ) , "`${color}`" ) ;
183+ assert ! ( style. important( ) ) ;
95184 }
96185}
0 commit comments