From 011a709cdf6044580a9e57c7ecb6362e4df0fdbe Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Fri, 27 Sep 2024 13:42:03 +0100 Subject: [PATCH] fix(formatter): trim CSS raw values (#4108) Co-authored-by: Carson McManus --- CHANGELOG.md | 13 +++++++++ .../src/css/value/url_value_raw.rs | 11 ++++++-- .../src/utils/component_value_list.rs | 6 +++-- .../tests/specs/css/atrule/import.css.snap | 17 ++++++------ .../tests/specs/css/url.css.snap | 2 +- .../css/inline-url/inline_url.css.snap | 27 ++++++------------- .../tests/specs/prettier/css/url/url.css.snap | 25 +++++++++-------- 7 files changed, 55 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99d9ffdf165c..42dd50991f6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,18 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b #### Bug fixes - Fix [#3924](https://github.com/biomejs/biome/issues/3924) where GraphQL formatter panics in block comments with empty line. Contributed by @vohoanglong0107 + +- Fix a case where raw values inside `url()` functions weren't properly trimmed. + ```diff + .value { + - background: url( + - whitespace-around-string + - ); + + background: url(whitespace-around-string); + } + ``` + Contributed by @ematipico + - Fixed [#4076](https://github.com/biomejs/biome/issues/4076), where a media query wasn't correctly formatted: ```diff .class { @@ -54,6 +66,7 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b } ``` Contributed by @blaze-d83 + ### JavaScript API ### Linter diff --git a/crates/biome_css_formatter/src/css/value/url_value_raw.rs b/crates/biome_css_formatter/src/css/value/url_value_raw.rs index 11c158017144..333dad79a519 100644 --- a/crates/biome_css_formatter/src/css/value/url_value_raw.rs +++ b/crates/biome_css_formatter/src/css/value/url_value_raw.rs @@ -7,7 +7,14 @@ pub(crate) struct FormatCssUrlValueRaw; impl FormatNodeRule for FormatCssUrlValueRaw { fn fmt_fields(&self, node: &CssUrlValueRaw, f: &mut CssFormatter) -> FormatResult<()> { let CssUrlValueRawFields { value_token } = node.as_fields(); - - write!(f, [value_token.format()]) + let value_token = value_token?; + let text = value_token.token_text(); + write!( + f, + [format_replaced( + &value_token, + &dynamic_text(text.trim(), value_token.text_trimmed_range().start()) + )] + ) } } diff --git a/crates/biome_css_formatter/src/utils/component_value_list.rs b/crates/biome_css_formatter/src/utils/component_value_list.rs index 9e9eeaf2ff77..854a298e5d20 100644 --- a/crates/biome_css_formatter/src/utils/component_value_list.rs +++ b/crates/biome_css_formatter/src/utils/component_value_list.rs @@ -39,9 +39,11 @@ where // Consider the CSS example: `font: first , second;` // The desired format is: `font: first, second;` // A separator should not be added before the comma because the comma acts as a `CssGenericDelimiter`. - let is_comma = CssGenericDelimiter::cast_ref(element.syntax()) + let token_kind = CssGenericDelimiter::cast_ref(element.syntax()) .and_then(|node| node.value().ok()) - .map_or(false, |node| node.kind() == CssSyntaxKind::COMMA); + .map(|token| token.kind()); + + let is_comma = matches!(token_kind, Some(CssSyntaxKind::COMMA)); if !is_comma { if matches!( diff --git a/crates/biome_css_formatter/tests/specs/css/atrule/import.css.snap b/crates/biome_css_formatter/tests/specs/css/atrule/import.css.snap index 44df6d935496..6c739b374ed9 100644 --- a/crates/biome_css_formatter/tests/specs/css/atrule/import.css.snap +++ b/crates/biome_css_formatter/tests/specs/css/atrule/import.css.snap @@ -218,11 +218,10 @@ Quote style: Double Quotes @import url("test.css"); @import url(test.css); @import url(test.css); -@import url(test.css ); @import url(test.css); -@import url(test.css ); -@import url(test.css -); +@import url(test.css); +@import url(test.css); +@import url(test.css); @import url(); @import url(""); @import url(""); @@ -287,7 +286,7 @@ st.css"); @import url("./t\65st%20test.css"); @import "./t\65st%20test.css"; @import "./t\65st%20test.css"; -@import url(test.css ); +@import url(test.css); @import "\ \ \ @@ -304,7 +303,7 @@ st.css"); @import " ./test.css "; @import url(" ./test.css "); -@import url(./test.css ); +@import url(./test.css); @import "./my.scss"; @@ -378,7 +377,7 @@ st.css"); # Lines exceeding max width of 80 characters ``` - 103: @import url("!!../../helpers/string-loader.js?esModule=false!~package/tilde.css"); - 121: @import url(" !!../../helpers/string-loader.js?esModule=false!~package/tilde.css "); - 122: @import url(data:text/css;charset=utf-8,a%20%7B%0D%0A%20%20color%3A%20red%3B%0D%0A%7D); + 102: @import url("!!../../helpers/string-loader.js?esModule=false!~package/tilde.css"); + 120: @import url(" !!../../helpers/string-loader.js?esModule=false!~package/tilde.css "); + 121: @import url(data:text/css;charset=utf-8,a%20%7B%0D%0A%20%20color%3A%20red%3B%0D%0A%7D); ``` diff --git a/crates/biome_css_formatter/tests/specs/css/url.css.snap b/crates/biome_css_formatter/tests/specs/css/url.css.snap index e63018ae6aaf..201bfb3acc12 100644 --- a/crates/biome_css_formatter/tests/specs/css/url.css.snap +++ b/crates/biome_css_formatter/tests/specs/css/url.css.snap @@ -51,7 +51,7 @@ div { a { content: url(https://example.com/a.jpg); - content: url(https://example.com/f.jpg ); + content: url(https://example.com/f.jpg); background: no-repeat url(RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf); diff --git a/crates/biome_css_formatter/tests/specs/prettier/css/inline-url/inline_url.css.snap b/crates/biome_css_formatter/tests/specs/prettier/css/inline-url/inline_url.css.snap index 39b826df7018..2d3c979dbb28 100644 --- a/crates/biome_css_formatter/tests/specs/prettier/css/inline-url/inline_url.css.snap +++ b/crates/biome_css_formatter/tests/specs/prettier/css/inline-url/inline_url.css.snap @@ -65,17 +65,7 @@ info: css/inline-url/inline_url.css ```diff --- Prettier +++ Biome -@@ -7,7 +7,8 @@ - } - - .validUnquotedUrls { -- background: url(whitespace-around-string); -+ background: url(whitespace-around-string -+ ); - background-image: url(/images/product/simple_product_manager/breadcrumb/chevron_right.png); - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mO4/B8AAqgB0yr7dJgAAAAASUVORK5CYII=); - background-image: url(data:application/font-woff;charset=utf-8;base64,ThisIsNormalBut/+0ThisIsLowerCased); -@@ -42,7 +43,7 @@ +@@ -42,7 +42,7 @@ background-image: url(http://123.com); background: url(path/to/123.jpg); background: url(#123.foo); @@ -100,8 +90,7 @@ info: css/inline-url/inline_url.css } .validUnquotedUrls { - background: url(whitespace-around-string - ); + background: url(whitespace-around-string); background-image: url(/images/product/simple_product_manager/breadcrumb/chevron_right.png); background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mO4/B8AAqgB0yr7dJgAAAAASUVORK5CYII=); background-image: url(data:application/font-woff;charset=utf-8;base64,ThisIsNormalBut/+0ThisIsLowerCased); @@ -164,10 +153,10 @@ inline_url.css:29:19 parse ━━━━━━━━━━━━━━━━━ # Lines exceeding max width of 80 characters ``` - 12: background-image: url(/images/product/simple_product_manager/breadcrumb/chevron_right.png); - 13: background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mO4/B8AAqgB0yr7dJgAAAAASUVORK5CYII=); - 14: background-image: url(data:application/font-woff;charset=utf-8;base64,ThisIsNormalBut/+0ThisIsLowerCased); - 15: background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mO4/B8AAqgB0yr7dJgAAAAASUVORK5CYII=) - 17: background: url(data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%229%22%20height=%229%22%3E%3Cpath%20d=%22M0%203h3%22%20stroke=%22red%22/%3E%3C/svg%3E); - 24: @import url(https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900&display=swap); + 11: background-image: url(/images/product/simple_product_manager/breadcrumb/chevron_right.png); + 12: background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mO4/B8AAqgB0yr7dJgAAAAASUVORK5CYII=); + 13: background-image: url(data:application/font-woff;charset=utf-8;base64,ThisIsNormalBut/+0ThisIsLowerCased); + 14: background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mO4/B8AAqgB0yr7dJgAAAAASUVORK5CYII=) + 16: background: url(data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%229%22%20height=%229%22%3E%3Cpath%20d=%22M0%203h3%22%20stroke=%22red%22/%3E%3C/svg%3E); + 23: @import url(https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900&display=swap); ``` diff --git a/crates/biome_css_formatter/tests/specs/prettier/css/url/url.css.snap b/crates/biome_css_formatter/tests/specs/prettier/css/url/url.css.snap index 726db567279c..ea933ab459c5 100644 --- a/crates/biome_css_formatter/tests/specs/prettier/css/url/url.css.snap +++ b/crates/biome_css_formatter/tests/specs/prettier/css/url/url.css.snap @@ -51,22 +51,21 @@ a { content: url(https://example.com/\ \ .jpg); - content: url( https://example.com/\)\).jpg ); - content: url( https://example.com/\(\(.jpg ); -- content: url(https://example.com/\ \ .jpg); -+ content: url(https://example.com/\)\).jpg ); -+ content: url(https://example.com/\(\(.jpg ); -+ content: url(https://example.com/\ \ .jpg ); ++ content: url(https://example.com/\)\).jpg); ++ content: url(https://example.com/\(\(.jpg); + content: url(https://example.com/\ \ .jpg); - background: no-repeat url(https://example.com/\)\).jpg), + background: ++ no-repeat url(https://example.com/\)\).jpg), ++ no-repeat url(https://example.com/\(\(.jpg), ++ no-repeat url(https://example.com/\ \ .jpg), + no-repeat url(https://example.com/\)\).jpg), no-repeat url(https://example.com/\(\(.jpg), no-repeat url(https://example.com/\ \ .jpg), - no-repeat url( https://example.com/\)\).jpg ), - no-repeat url( https://example.com/\(\(.jpg ), - no-repeat url( https://example.com/\ \ .jpg ), -+ no-repeat url(https://example.com/\)\).jpg ), -+ no-repeat url(https://example.com/\(\(.jpg ), -+ no-repeat url(https://example.com/\ \ .jpg ), no-repeat url(foo.ttf?query=foo,bar,), no-repeat url(foo.woff2?foo=rgb\(255,255,0\)) no-repeat url(RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf); @@ -92,17 +91,17 @@ a { content: url(https://example.com/\)\).jpg); content: url(https://example.com/\(\(.jpg); content: url(https://example.com/\ \ .jpg); - content: url(https://example.com/\)\).jpg ); - content: url(https://example.com/\(\(.jpg ); - content: url(https://example.com/\ \ .jpg ); + content: url(https://example.com/\)\).jpg); + content: url(https://example.com/\(\(.jpg); + content: url(https://example.com/\ \ .jpg); background: no-repeat url(https://example.com/\)\).jpg), no-repeat url(https://example.com/\(\(.jpg), no-repeat url(https://example.com/\ \ .jpg), - no-repeat url(https://example.com/\)\).jpg ), - no-repeat url(https://example.com/\(\(.jpg ), - no-repeat url(https://example.com/\ \ .jpg ), + no-repeat url(https://example.com/\)\).jpg), + no-repeat url(https://example.com/\(\(.jpg), + no-repeat url(https://example.com/\ \ .jpg), no-repeat url(foo.ttf?query=foo,bar,), no-repeat url(foo.woff2?foo=rgb\(255,255,0\)) no-repeat url(RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf);