Skip to content

Commit a23235a

Browse files
committed
fix(stylex_css_parser): fix color parser
1 parent f9bf318 commit a23235a

3 files changed

Lines changed: 273 additions & 53 deletions

File tree

crates/stylex-css-parser/src/css_types/color.rs

Lines changed: 60 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -712,7 +712,7 @@ impl Rgb {
712712
})?;
713713

714714
if let SimpleToken::Function(name) = function_token {
715-
if name != "rgb" {
715+
if name.to_lowercase() != "rgb" {
716716
return Err(CssParseError::ParseError {
717717
message: format!("Expected 'rgb' function, got '{}'", name),
718718
});
@@ -723,6 +723,11 @@ impl Rgb {
723723
});
724724
}
725725

726+
// Skip optional whitespace before first value
727+
while let Ok(Some(SimpleToken::Whitespace)) = tokens.peek() {
728+
tokens.consume_next_token()?;
729+
}
730+
726731
// Parse r value
727732
let r = Self::parse_rgb_number_token(tokens)?;
728733

@@ -738,6 +743,11 @@ impl Rgb {
738743
// Parse b value
739744
let b = Self::parse_rgb_number_token(tokens)?;
740745

746+
// Skip optional whitespace before closing paren
747+
while let Ok(Some(SimpleToken::Whitespace)) = tokens.peek() {
748+
tokens.consume_next_token()?;
749+
}
750+
741751
// Expect closing paren
742752
let close_token = tokens
743753
.consume_next_token()?
@@ -769,7 +779,7 @@ impl Rgb {
769779
})?;
770780

771781
if let SimpleToken::Function(name) = function_token {
772-
if name != "rgb" {
782+
if name.to_lowercase() != "rgb" {
773783
return Err(CssParseError::ParseError {
774784
message: format!("Expected 'rgb' function, got '{}'", name),
775785
});
@@ -885,7 +895,7 @@ impl Rgb {
885895

886896
impl Display for Rgb {
887897
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
888-
write!(f, "rgb({},{},{})", self.r, self.g, self.b)
898+
write!(f, "rgb({}, {}, {})", self.r, self.g, self.b)
889899
}
890900
}
891901

@@ -919,7 +929,7 @@ impl Rgba {
919929
})?;
920930

921931
if let SimpleToken::Function(name) = function_token {
922-
if name != "rgba" {
932+
if name.to_lowercase() != "rgba" {
923933
return Err(CssParseError::ParseError {
924934
message: format!("Expected 'rgba' function, got '{}'", name),
925935
});
@@ -930,6 +940,11 @@ impl Rgba {
930940
});
931941
}
932942

943+
// Skip optional whitespace before first value
944+
while let Ok(Some(SimpleToken::Whitespace)) = tokens.peek() {
945+
tokens.consume_next_token()?;
946+
}
947+
933948
// Parse r value
934949
let r = Self::parse_rgba_number_token(tokens)?;
935950

@@ -951,6 +966,11 @@ impl Rgba {
951966
// Parse alpha value
952967
let a = Self::parse_alpha_value_token(tokens)?;
953968

969+
// Skip optional whitespace before closing paren
970+
while let Ok(Some(SimpleToken::Whitespace)) = tokens.peek() {
971+
tokens.consume_next_token()?;
972+
}
973+
954974
// Expect closing paren
955975
let close_token = tokens
956976
.consume_next_token()?
@@ -970,21 +990,21 @@ impl Rgba {
970990
)
971991
}
972992

973-
/// Parse space-separated RGBA with slash: rgb(255 0 0 / 0.5)
993+
/// Parse space-separated RGBA with slash: rgb(255 0 0 / 0.5) or rgba(255 0 0 / 0.5)
974994
fn space_slash_parser() -> TokenParser<Rgba> {
975995
TokenParser::new(
976996
|tokens| {
977-
// Expect Function("rgb") - note: uses rgb, not rgba!
997+
// Expect Function("rgb" or "rgba")
978998
let function_token = tokens
979999
.consume_next_token()?
9801000
.ok_or(CssParseError::ParseError {
981-
message: "Expected RGB function".to_string(),
1001+
message: "Expected RGB/RGBA function".to_string(),
9821002
})?;
9831003

9841004
if let SimpleToken::Function(name) = function_token {
985-
if name != "rgb" {
1005+
if name.to_lowercase() != "rgb" && name.to_lowercase() != "rgba" {
9861006
return Err(CssParseError::ParseError {
987-
message: format!("Expected 'rgb' function, got '{}'", name),
1007+
message: format!("Expected 'rgb' or 'rgba' function, got '{}'", name),
9881008
});
9891009
}
9901010
} else {
@@ -1164,7 +1184,7 @@ impl Rgba {
11641184

11651185
impl Display for Rgba {
11661186
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1167-
write!(f, "rgba({},{},{},{})", self.r, self.g, self.b, self.a)
1187+
write!(f, "rgba({}, {}, {}, {})", self.r, self.g, self.b, self.a)
11681188
}
11691189
}
11701190

@@ -1207,7 +1227,7 @@ impl Hsl {
12071227
})?;
12081228

12091229
if let SimpleToken::Function(name) = function_token {
1210-
if name != "hsl" {
1230+
if name.to_lowercase() != "hsl" {
12111231
return Err(CssParseError::ParseError {
12121232
message: format!("Expected 'hsl' function, got '{}'", name),
12131233
});
@@ -1218,6 +1238,11 @@ impl Hsl {
12181238
});
12191239
}
12201240

1241+
// Skip optional whitespace before first value
1242+
while let Ok(Some(SimpleToken::Whitespace)) = tokens.peek() {
1243+
tokens.consume_next_token()?;
1244+
}
1245+
12211246
// Parse hue value (angle or number)
12221247
let h = Self::parse_hsl_hue_token(tokens)?;
12231248

@@ -1233,6 +1258,11 @@ impl Hsl {
12331258
// Parse lightness percentage
12341259
let l = Self::parse_hsl_percentage_token(tokens)?;
12351260

1261+
// Skip optional whitespace before closing paren
1262+
while let Ok(Some(SimpleToken::Whitespace)) = tokens.peek() {
1263+
tokens.consume_next_token()?;
1264+
}
1265+
12361266
// Expect closing paren
12371267
let close_token = tokens
12381268
.consume_next_token()?
@@ -1264,7 +1294,7 @@ impl Hsl {
12641294
})?;
12651295

12661296
if let SimpleToken::Function(name) = function_token {
1267-
if name != "hsl" {
1297+
if name.to_lowercase() != "hsl" {
12681298
return Err(CssParseError::ParseError {
12691299
message: format!("Expected 'hsl' function, got '{}'", name),
12701300
});
@@ -1408,8 +1438,7 @@ impl Hsl {
14081438

14091439
impl Display for Hsl {
14101440
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1411-
let h_value = self.h.value; // Extract the numeric value without unit
1412-
write!(f, "hsl({},{},{})", h_value, self.s, self.l)
1441+
write!(f, "hsl({}, {}, {})", self.h, self.s, self.l)
14131442
}
14141443
}
14151444

@@ -1454,7 +1483,7 @@ impl Hsla {
14541483
})?;
14551484

14561485
if let SimpleToken::Function(name) = function_token {
1457-
if name != "hsla" {
1486+
if name.to_lowercase() != "hsla" {
14581487
return Err(CssParseError::ParseError {
14591488
message: format!("Expected 'hsla' function, got '{}'", name),
14601489
});
@@ -1517,7 +1546,7 @@ impl Hsla {
15171546
})?;
15181547

15191548
if let SimpleToken::Function(name) = function_token {
1520-
if name != "hsl" {
1549+
if name.to_lowercase() != "hsl" {
15211550
return Err(CssParseError::ParseError {
15221551
message: format!("Expected 'hsl' function, got '{}'", name),
15231552
});
@@ -1726,8 +1755,7 @@ impl Hsla {
17261755

17271756
impl Display for Hsla {
17281757
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1729-
let h_value = self.h.value; // Extract the numeric value without unit
1730-
write!(f, "hsla({},{},{},{})", h_value, self.s, self.l, self.a)
1758+
write!(f, "hsla({}, {}, {}, {})", self.h, self.s, self.l, self.a)
17311759
}
17321760
}
17331761

@@ -1790,7 +1818,7 @@ impl Lch {
17901818
})?;
17911819

17921820
if let SimpleToken::Function(name) = function_token {
1793-
if name != "lch" {
1821+
if name.to_lowercase() != "lch" {
17941822
return Err(CssParseError::ParseError {
17951823
message: format!("Expected 'lch' function, got '{}'", name),
17961824
});
@@ -1998,7 +2026,7 @@ impl Oklch {
19982026
move |input| {
19992027
// Parse 'oklch(' function start
20002028
match input.consume_next_token()? {
2001-
Some(SimpleToken::Function(fn_name)) if fn_name == "oklch" => {}
2029+
Some(SimpleToken::Function(fn_name)) if fn_name.to_lowercase() == "oklch" => {}
20022030
_ => {
20032031
return Err(CssParseError::ParseError {
20042032
message: "Expected oklch() function".to_string(),
@@ -2065,7 +2093,7 @@ impl Oklch {
20652093
}
20662094
}
20672095

2068-
/// Parse OKLCH hue: angle | number (number * 360 -> angle conversion)
2096+
/// Parse OKLCH hue: angle | number (interpreted as degrees) | 'none'
20692097
fn parse_oklch_hue(input: &mut crate::token_types::TokenList) -> Result<Angle, CssParseError> {
20702098
match input.consume_next_token()? {
20712099
Some(SimpleToken::Dimension { value, unit }) => {
@@ -2078,9 +2106,12 @@ impl Oklch {
20782106
})
20792107
}
20802108
}
2081-
Some(SimpleToken::Number(n)) => Ok(Angle::new((n as f32) * 360.0, "deg".to_string())),
2109+
Some(SimpleToken::Number(n)) => Ok(Angle::new(n as f32, "deg".to_string())),
2110+
Some(SimpleToken::Ident(keyword)) if keyword == "none" => {
2111+
Ok(Angle::new(0.0, "deg".to_string()))
2112+
}
20822113
_ => Err(CssParseError::ParseError {
2083-
message: "Expected hue: angle or number".to_string(),
2114+
message: "Expected hue: angle, number, or 'none'".to_string(),
20842115
}),
20852116
}
20862117
}
@@ -2153,7 +2184,7 @@ impl Oklab {
21532184
move |input| {
21542185
// Parse 'oklab(' function start
21552186
match input.consume_next_token()? {
2156-
Some(SimpleToken::Function(fn_name)) if fn_name == "oklab" => {}
2187+
Some(SimpleToken::Function(fn_name)) if fn_name.to_lowercase() == "oklab" => {}
21572188
_ => {
21582189
return Err(CssParseError::ParseError {
21592190
message: "Expected oklab() function".to_string(),
@@ -2337,25 +2368,25 @@ mod tests {
23372368
#[test]
23382369
fn test_rgb_color_display() {
23392370
let color = Rgb::new(255, 0, 0);
2340-
assert_eq!(color.to_string(), "rgb(255,0,0)");
2371+
assert_eq!(color.to_string(), "rgb(255, 0, 0)");
23412372
}
23422373

23432374
#[test]
23442375
fn test_rgba_color_display() {
23452376
let color = Rgba::new(255, 0, 0, 0.5);
2346-
assert_eq!(color.to_string(), "rgba(255,0,0,0.5)");
2377+
assert_eq!(color.to_string(), "rgba(255, 0, 0, 0.5)");
23472378
}
23482379

23492380
#[test]
23502381
fn test_hsl_color_display() {
23512382
let color = Hsl::from_primitives(360.0, 100.0, 50.0);
2352-
assert_eq!(color.to_string(), "hsl(360,100%,50%)");
2383+
assert_eq!(color.to_string(), "hsl(360deg, 100%, 50%)");
23532384
}
23542385

23552386
#[test]
23562387
fn test_hsla_color_display() {
23572388
let color = Hsla::from_primitives(360.0, 100.0, 50.0, 0.8);
2358-
assert_eq!(color.to_string(), "hsla(360,100%,50%,0.8)");
2389+
assert_eq!(color.to_string(), "hsla(360deg, 100%, 50%, 0.8)");
23592390
}
23602391

23612392
#[test]
@@ -2367,7 +2398,7 @@ mod tests {
23672398
assert_eq!(hash.to_string(), "#FF0000");
23682399

23692400
let rgb = Color::Rgb(Rgb::new(255, 0, 0));
2370-
assert_eq!(rgb.to_string(), "rgb(255,0,0)");
2401+
assert_eq!(rgb.to_string(), "rgb(255, 0, 0)");
23712402
}
23722403

23732404
#[test]

0 commit comments

Comments
 (0)