diff --git a/CHANGELOG.md b/CHANGELOG.md index d7cbde713ddf..d57a7523ee73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,10 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b ### Formatter +### Bug fixes + +- Fix [#4121](https://github.com/biomejs/biome/issues/4326), don't ident a CSS selector when has leading comments. Contributed by @fireairforce + ### JavaScript APIs ### Linter diff --git a/crates/biome_css_formatter/src/css/lists/relative_selector_list.rs b/crates/biome_css_formatter/src/css/lists/relative_selector_list.rs index 566e6e53982a..4f103d8f9b06 100644 --- a/crates/biome_css_formatter/src/css/lists/relative_selector_list.rs +++ b/crates/biome_css_formatter/src/css/lists/relative_selector_list.rs @@ -13,17 +13,37 @@ impl FormatRule for FormatCssRelativeSelectorList { let mut joiner = f.join_with(&separator); for formatted in node.format_separated(",") { - // Each selector gets `indent` added in case it breaks over multiple - // lines. The break is added here rather than in each selector both - // for simplicity and to avoid recursively adding indents when - // selectors are nested within other rules. The group is then added - // around the indent to ensure that it tries using a flat layout - // first and only expands when the single selector can't fit the line. - // - // For example, a selector like `div span a` is structured like - // `[div, [span, [a]]]`, so `a` would end up double-indented if it - // was handled by the selector rather than here. - joiner.entry(&group(&indent(&formatted))); + let has_leading_comments = formatted + .node()? + .as_css_relative_selector() + .and_then(|relative_selector| { + relative_selector + .selector() + .ok()? + .as_css_compound_selector() + .cloned() + }) + .and_then(|computed_selector| computed_selector.simple_selector()) + .and_then(|simple_selector| simple_selector.as_css_type_selector().cloned()) + .and_then(|type_selector| type_selector.ident().ok()?.value_token().ok()) + .is_some_and(|value_token| value_token.has_leading_comments()); + + if has_leading_comments { + // Computed Selector which contains a leading comments should be formatted without indent. + joiner.entry(&group(&formatted)); + } else { + // Each selector gets `indent` added in case it breaks over multiple + // lines. The break is added here rather than in each selector both + // for simplicity and to avoid recursively adding indents when + // selectors are nested within other rules. The group is then added + // around the indent to ensure that it tries using a flat layout + // first and only expands when the single selector can't fit the line. + // + // For example, a selector like `div span a` is structured like + // `[div, [span, [a]]]`, so `a` would end up double-indented if it + // was handled by the selector rather than here. + joiner.entry(&group(&indent(&formatted))); + } } joiner.finish() diff --git a/crates/biome_css_formatter/tests/specs/css/declaration_list.css b/crates/biome_css_formatter/tests/specs/css/declaration_list.css index 2d9252e42926..780622ef405b 100644 --- a/crates/biome_css_formatter/tests/specs/css/declaration_list.css +++ b/crates/biome_css_formatter/tests/specs/css/declaration_list.css @@ -34,4 +34,20 @@ a { a { color: red;;;; +} + +.with-comments { + /* hello */ + a, + /* world */ + button { + color: blue; + } +} + +.without-comments { + a, + button { + color: blue; + } } \ No newline at end of file diff --git a/crates/biome_css_formatter/tests/specs/css/declaration_list.css.snap b/crates/biome_css_formatter/tests/specs/css/declaration_list.css.snap index e168c99e2562..9db6650632b6 100644 --- a/crates/biome_css_formatter/tests/specs/css/declaration_list.css.snap +++ b/crates/biome_css_formatter/tests/specs/css/declaration_list.css.snap @@ -42,6 +42,22 @@ a { a { color: red;;;; } + +.with-comments { + /* hello */ + a, + /* world */ + button { + color: blue; + } +} + +.without-comments { + a, + button { + color: blue; + } +} ``` @@ -103,4 +119,20 @@ a { a { color: red; } + +.with-comments { + /* hello */ + a, + /* world */ + button { + color: blue; + } +} + +.without-comments { + a, + button { + color: blue; + } +} ```