fix(css): updating formatting of non-lowercase CSS dimension units (#8175)
Some checks failed
CI on main / Format Rust Files (push) Waiting to run
CI on main / Lint Rust Files (push) Waiting to run
CI on main / Check Dependencies (push) Waiting to run
CI on main / Test (push) Waiting to run
CI on main / Test262 Coverage (push) Waiting to run
Release / Release (push) Waiting to run
Release / version (push) Blocked by required conditions
Release / Package darwin-arm64 (push) Blocked by required conditions
Release / Package darwin-x64 (push) Blocked by required conditions
Release / Package linux-arm64-musl (push) Blocked by required conditions
Release / Package linux-x64-musl (push) Blocked by required conditions
Release / Package win32-arm64 (push) Blocked by required conditions
Release / Package win32-x64 (push) Blocked by required conditions
Release / Package linux-arm64 (push) Blocked by required conditions
Release / Package linux-x64 (push) Blocked by required conditions
Release / Build WASM (push) Blocked by required conditions
Release / Package JavaScript APIs (push) Blocked by required conditions
Release / Publish CLI (push) Blocked by required conditions
Release / Publish JS API (push) Blocked by required conditions
Repository dispatch on main / Build @biomejs/wasm-web (push) Waiting to run
Repository dispatch on main / Repository dispatch (push) Blocked by required conditions
Benchmarks CSS / Bench (push) Has been cancelled

Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>
This commit is contained in:
Ryan Walker 2025-11-20 00:08:58 -07:00 committed by GitHub
parent fb1458b33c
commit 0c8349e686
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 104 additions and 11 deletions

View file

@ -0,0 +1,25 @@
---
"@biomejs/biome": patch
---
Fixed CSS formatting of dimension units to use correct casing for `Q`, `Hz` and `kHz`.
**Before:**
``` css
.cssUnits {
a: 1q;
b: 1hz;
c: 1khz;
}
```
**After:**
``` css
.cssUnits {
a: 1Q;
b: 1Hz;
c: 1kHz;
}
```

View file

@ -1,4 +1,4 @@
use crate::{prelude::*, utils::string_utils::FormatTokenAsLowercase};
use crate::{prelude::*, utils::string_utils::FormatDimensionUnit};
use biome_css_syntax::{CssRegularDimension, CssRegularDimensionFields};
use biome_formatter::{token::number::NumberFormatOptions, write};
@ -15,7 +15,7 @@ impl FormatNodeRule<CssRegularDimension> for FormatCssRegularDimension {
f,
[
format_number_token(&value_token?, NumberFormatOptions::default()),
FormatTokenAsLowercase::from(unit_token?),
FormatDimensionUnit::from(unit_token?),
]
)
}

View file

@ -1,4 +1,7 @@
use crate::{prelude::*, utils::string_utils::FormatTokenAsLowercase};
use crate::{
prelude::*,
utils::string_utils::{FormatDimensionUnit, FormatTokenAsLowercase},
};
use biome_css_syntax::{CssUnknownDimension, CssUnknownDimensionFields};
use biome_formatter::write;
@ -15,7 +18,7 @@ impl FormatNodeRule<CssUnknownDimension> for FormatCssUnknownDimension {
f,
[
FormatTokenAsLowercase::from(value_token?),
FormatTokenAsLowercase::from(unit_token?),
FormatDimensionUnit::from(unit_token?),
]
);
var_name

View file

@ -296,3 +296,61 @@ impl<'token> LiteralStringNormaliser<'token> {
}
}
}
pub(crate) struct FormatDimensionUnit {
token: SyntaxToken<CssLanguage>,
}
impl From<SyntaxToken<CssLanguage>> for FormatDimensionUnit {
fn from(value: SyntaxToken<CssLanguage>) -> Self {
Self { token: value }
}
}
impl Format<CssFormatContext> for FormatDimensionUnit {
fn fmt(&self, f: &mut CssFormatter) -> FormatResult<()> {
let original = self.token.text_trimmed();
match original.to_ascii_lowercase_cow() {
Cow::Borrowed(lowercase) => {
if let Some(uppercase) = map_dimension_unit(lowercase) {
write!(
f,
[format_replaced(
&self.token,
&text(&uppercase, self.token.text_trimmed_range().start()),
)]
)
} else {
write!(f, [self.token.format()])
}
}
Cow::Owned(lowercase) => {
write!(
f,
[format_replaced(
&self.token,
&text(
&map_dimension_unit(lowercase.as_str()).unwrap_or(lowercase),
self.token.text_trimmed_range().start()
),
)]
)
}
}
}
}
/// Most CSS dimension units can be formatted as lower case, but there are
/// a few that are more commonly formatted with some uppercase characters.
/// This maps those few cases to the correct casing. This matches the
/// behavior of the Prettier formatter.
fn map_dimension_unit(unit: &str) -> Option<String> {
match unit {
"hz" => Some(String::from("Hz")),
"khz" => Some(String::from("kHz")),
"q" => Some(String::from("Q")),
_ => None,
}
}

View file

@ -20,6 +20,7 @@
a: 5CM;
a: 5MM;
a: 5Q;
a: 5q;
a: 5IN;
a: 5PT;
a: 5PC;
@ -30,7 +31,9 @@
a: 5S;
a: 5MS;
a: 5HZ;
a: 5hz;
a: 5KHZ;
a: 5kHz;
a: 5DPI;
a: 5DPCM;
a: 5DPPX;
@ -41,4 +44,4 @@
a: 5Unknown;
/* http://browserbu.gs/css-hacks/media-min-width-0-backslash-0/ */
a: 0\0;
}
}

View file

@ -2,7 +2,6 @@
source: crates/biome_formatter_test/src/snapshot_builder.rs
info: css/units.css
---
# Input
```css
@ -28,6 +27,7 @@ info: css/units.css
a: 5CM;
a: 5MM;
a: 5Q;
a: 5q;
a: 5IN;
a: 5PT;
a: 5PC;
@ -38,7 +38,9 @@ info: css/units.css
a: 5S;
a: 5MS;
a: 5HZ;
a: 5hz;
a: 5KHZ;
a: 5kHz;
a: 5DPI;
a: 5DPCM;
a: 5DPPX;
@ -50,6 +52,7 @@ info: css/units.css
/* http://browserbu.gs/css-hacks/media-min-width-0-backslash-0/ */
a: 0\0;
}
```
@ -89,7 +92,8 @@ Quote style: Double Quotes
a: 5vmax;
a: 5cm;
a: 5mm;
a: 5q;
a: 5Q;
a: 5Q;
a: 5in;
a: 5pt;
a: 5pc;
@ -99,8 +103,10 @@ Quote style: Double Quotes
a: 5rad;
a: 5s;
a: 5ms;
a: 5hz;
a: 5khz;
a: 5Hz;
a: 5Hz;
a: 5kHz;
a: 5kHz;
a: 5dpi;
a: 5dpcm;
a: 5dppx;
@ -113,5 +119,3 @@ Quote style: Double Quotes
a: 0\0;
}
```