Skip to content

Commit

Permalink
fix(css_formatter): keep @charset double quote in single quote config (
Browse files Browse the repository at this point in the history
  • Loading branch information
fireairforce authored Oct 30, 2024
1 parent fe792ed commit 044baf4
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 28 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b
#### Bug fixes
- Fix [#4121](https://github.com/biomejs/biome/issues/4121). Respect line width when printing multiline strings. Contributed by @ah-yu
- Fix [#4384](https://github.com/biomejs/biome/issues/4384). Keep `@charset` dobule quote under any situation for css syntax rule. Contributed by @fireairforce
### JavaScript APIs
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::{prelude::*, utils::string_utils::FormatLiteralStringToken};
use crate::{
prelude::*,
utils::string_utils::{FormatLiteralStringToken, StringLiteralParentKind},
};
use biome_css_syntax::{
AnyCssAttributeMatcherValue, CssAttributeMatcherValue, CssAttributeMatcherValueFields,
};
Expand Down Expand Up @@ -35,7 +38,10 @@ impl FormatNodeRule<CssAttributeMatcherValue> for FormatCssAttributeMatcherValue
// does not get converted to lowercase. Once it's quoted, it
// will be parsed as a CssString on the next pass, at which
// point casing is preserved no matter what.
FormatLiteralStringToken::new(&ident.value_token()?),
FormatLiteralStringToken::new(
&ident.value_token()?,
StringLiteralParentKind::Others
),
format_trailing_comments(ident.syntax()),
format_dangling_comments(ident.syntax())
]
Expand Down
30 changes: 26 additions & 4 deletions crates/biome_css_formatter/src/css/value/string.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,35 @@
use crate::{prelude::*, utils::string_utils::FormatLiteralStringToken};
use biome_css_syntax::{CssString, CssStringFields};
use crate::{
prelude::*,
utils::string_utils::{FormatLiteralStringToken, StringLiteralParentKind},
};
use biome_css_syntax::{CssString, CssStringFields, CssSyntaxKind};
use biome_formatter::write;
use biome_rowan::SyntaxNodeOptionExt;

#[derive(Debug, Clone, Default)]
pub(crate) struct FormatCssString;
impl FormatNodeRule<CssString> for FormatCssString {
fn fmt_fields(&self, node: &CssString, f: &mut CssFormatter) -> FormatResult<()> {
let CssStringFields { value_token } = node.as_fields();

write!(f, [FormatLiteralStringToken::new(&value_token?)])
if matches!(
node.syntax().parent().kind(),
Some(CssSyntaxKind::CSS_CHARSET_AT_RULE)
) {
write!(
f,
[FormatLiteralStringToken::new(
&value_token?,
StringLiteralParentKind::CharsetAtRule
)]
)
} else {
write!(
f,
[FormatLiteralStringToken::new(
&value_token?,
StringLiteralParentKind::Others
)]
)
}
}
}
50 changes: 36 additions & 14 deletions crates/biome_css_formatter/src/utils/string_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,29 @@ impl Format<CssFormatContext> for FormatTokenAsLowercase {
}
}

#[derive(Eq, PartialEq, Debug)]
pub(crate) enum StringLiteralParentKind {
/// Variants to track tokens that are inside a CssCharasetRule
/// @charset must always have double quotes: https://www.w3.org/TR/css-syntax-3/#determine-the-fallback-encoding
CharsetAtRule,
/// other types, will add more later
Others,
}

/// Data structure of convenience to format string literals. This is copied
/// from the JS formatter, but should eventually have the logic made generic
/// and reusable since many languages will have the same needs.
pub(crate) struct FormatLiteralStringToken<'token> {
/// The current token
token: &'token CssSyntaxToken,

// The parent that holds the token
parent_kind: StringLiteralParentKind,
}

impl<'token> FormatLiteralStringToken<'token> {
pub fn new(token: &'token CssSyntaxToken) -> Self {
Self { token }
pub fn new(token: &'token CssSyntaxToken, parent_kind: StringLiteralParentKind) -> Self {
Self { token, parent_kind }
}

fn token(&self) -> &'token CssSyntaxToken {
Expand Down Expand Up @@ -204,18 +216,28 @@ impl<'token> LiteralStringNormaliser<'token> {
}

fn normalise_text(&mut self) -> Cow<'token, str> {
let string_information = self
.token
.compute_string_information(self.chosen_quote_style);

// Normalize string token and non-string token.
//
// Add the chosen quotes to any non-string tokensto normalize them into strings.
//
// CSS has various places where "string-like" tokens can be used without quotes, but the
// semantics aren't affected by whether they are present or not. This function lets those
// tokens become string literals by safely adding quotes around them.
self.normalise_tokens(string_information)
match self.token.parent_kind {
StringLiteralParentKind::CharsetAtRule => {
let string_information = StringInformation {
preferred_quote: QuoteStyle::Double,
};
self.normalise_tokens(string_information)
}
StringLiteralParentKind::Others => {
let string_information = self
.token
.compute_string_information(self.chosen_quote_style);

// Normalize string token and non-string token.
//
// Add the chosen quotes to any non-string tokensto normalize them into strings.
//
// CSS has various places where "string-like" tokens can be used without quotes, but the
// semantics aren't affected by whether they are present or not. This function lets those
// tokens become string literals by safely adding quotes around them.
self.normalise_tokens(string_information)
}
}
}

fn get_token(&self) -> &'token CssSyntaxToken {
Expand Down
11 changes: 4 additions & 7 deletions crates/biome_css_formatter/tests/quick_test.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use biome_css_formatter::format_node;
use biome_css_formatter::{context::CssFormatOptions, CssFormatLanguage};
use biome_css_parser::{parse_css, CssParserOptions};
use biome_formatter::{IndentStyle, LineWidth};
use biome_formatter::{IndentStyle, LineWidth, QuoteStyle};
use biome_formatter_test::check_reformat::CheckReformat;

mod language {
Expand All @@ -13,18 +13,15 @@ mod language {
// use this test check if your snippet prints as you wish, without using a snapshot
fn quick_test() {
let src = r#"
.container {
&:has(.child) {
color: blue;
}
}
@charset "UTF-8";
"#;
let parse = parse_css(src, CssParserOptions::default());
println!("{parse:#?}");

let options = CssFormatOptions::default()
.with_line_width(LineWidth::try_from(80).unwrap())
.with_indent_style(IndentStyle::Space);
.with_indent_style(IndentStyle::Space)
.with_quote_style(QuoteStyle::Single);
let doc = format_node(options.clone(), &parse.syntax()).unwrap();
let result = doc.print().unwrap();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@ div {
width: 0\eestays-unquoted;
--\eeunquoted: green;
color: var(--\eeunquoted);
}
}

@charset·"UTF-8";
@charset "iso-8859-15";
@charset "any-string-is-okay";
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ div {
--\eeunquoted: green;
color: var(--\eeunquoted);
}

@charset·"UTF-8";
@charset "iso-8859-15";
@charset "any-string-is-okay";
```


Expand Down Expand Up @@ -65,6 +69,10 @@ div {
--\eeunquoted: green;
color: var(--\eeunquoted);
}

@charset· "UTF-8";
@charset "iso-8859-15";
@charset "any-string-is-okay";
```

## Output 1
Expand Down Expand Up @@ -99,4 +107,8 @@ div {
--\eeunquoted: green;
color: var(--\eeunquoted);
}

@charset· "UTF-8";
@charset "iso-8859-15";
@charset "any-string-is-okay";
```

0 comments on commit 044baf4

Please sign in to comment.