diff --git a/crates/biome_css_formatter/src/css/auxiliary/supports_and_condition.rs b/crates/biome_css_formatter/src/css/auxiliary/supports_and_condition.rs index 7681f00e36ef..07d64ecc9c82 100644 --- a/crates/biome_css_formatter/src/css/auxiliary/supports_and_condition.rs +++ b/crates/biome_css_formatter/src/css/auxiliary/supports_and_condition.rs @@ -1,10 +1,26 @@ use crate::prelude::*; -use biome_css_syntax::CssSupportsAndCondition; -use biome_rowan::AstNode; +use biome_css_syntax::{CssSupportsAndCondition, CssSupportsAndConditionFields}; +use biome_formatter::write; + #[derive(Debug, Clone, Default)] pub(crate) struct FormatCssSupportsAndCondition; impl FormatNodeRule for FormatCssSupportsAndCondition { fn fmt_fields(&self, node: &CssSupportsAndCondition, f: &mut CssFormatter) -> FormatResult<()> { - format_verbatim_node(node.syntax()).fmt(f) + let CssSupportsAndConditionFields { + left, + and_token, + right, + } = node.as_fields(); + + write!( + f, + [ + left.format(), + space(), + and_token.format(), + soft_line_break_or_space(), + right.format() + ] + ) } } diff --git a/crates/biome_css_formatter/src/css/auxiliary/supports_condition_in_parens.rs b/crates/biome_css_formatter/src/css/auxiliary/supports_condition_in_parens.rs index cdbb7d964341..a473e04223d1 100644 --- a/crates/biome_css_formatter/src/css/auxiliary/supports_condition_in_parens.rs +++ b/crates/biome_css_formatter/src/css/auxiliary/supports_condition_in_parens.rs @@ -1,6 +1,7 @@ use crate::prelude::*; -use biome_css_syntax::CssSupportsConditionInParens; -use biome_rowan::AstNode; +use biome_css_syntax::{CssSupportsConditionInParens, CssSupportsConditionInParensFields}; +use biome_formatter::{format_args, write}; + #[derive(Debug, Clone, Default)] pub(crate) struct FormatCssSupportsConditionInParens; impl FormatNodeRule for FormatCssSupportsConditionInParens { @@ -9,6 +10,19 @@ impl FormatNodeRule for FormatCssSupportsCondition node: &CssSupportsConditionInParens, f: &mut CssFormatter, ) -> FormatResult<()> { - format_verbatim_node(node.syntax()).fmt(f) + let CssSupportsConditionInParensFields { + l_paren_token, + condition, + r_paren_token, + } = node.as_fields(); + + write!( + f, + [group(&format_args![ + l_paren_token.format(), + soft_block_indent(&condition.format()), + r_paren_token.format() + ])] + ) } } diff --git a/crates/biome_css_formatter/src/css/auxiliary/supports_feature_declaration.rs b/crates/biome_css_formatter/src/css/auxiliary/supports_feature_declaration.rs index b04f4836a1ec..195c2c38b7d9 100644 --- a/crates/biome_css_formatter/src/css/auxiliary/supports_feature_declaration.rs +++ b/crates/biome_css_formatter/src/css/auxiliary/supports_feature_declaration.rs @@ -1,6 +1,7 @@ use crate::prelude::*; -use biome_css_syntax::CssSupportsFeatureDeclaration; -use biome_rowan::AstNode; +use biome_css_syntax::{CssSupportsFeatureDeclaration, CssSupportsFeatureDeclarationFields}; +use biome_formatter::{format_args, write}; + #[derive(Debug, Clone, Default)] pub(crate) struct FormatCssSupportsFeatureDeclaration; impl FormatNodeRule for FormatCssSupportsFeatureDeclaration { @@ -9,6 +10,19 @@ impl FormatNodeRule for FormatCssSupportsFeatureD node: &CssSupportsFeatureDeclaration, f: &mut CssFormatter, ) -> FormatResult<()> { - format_verbatim_node(node.syntax()).fmt(f) + let CssSupportsFeatureDeclarationFields { + l_paren_token, + declaration, + r_paren_token, + } = node.as_fields(); + + write!( + f, + [group(&format_args![ + l_paren_token.format(), + soft_block_indent(&declaration.format()), + r_paren_token.format() + ])] + ) } } diff --git a/crates/biome_css_formatter/src/css/auxiliary/supports_not_condition.rs b/crates/biome_css_formatter/src/css/auxiliary/supports_not_condition.rs index 13721dba9580..a174c8d4a616 100644 --- a/crates/biome_css_formatter/src/css/auxiliary/supports_not_condition.rs +++ b/crates/biome_css_formatter/src/css/auxiliary/supports_not_condition.rs @@ -1,10 +1,13 @@ use crate::prelude::*; -use biome_css_syntax::CssSupportsNotCondition; -use biome_rowan::AstNode; +use biome_css_syntax::{CssSupportsNotCondition, CssSupportsNotConditionFields}; +use biome_formatter::write; + #[derive(Debug, Clone, Default)] pub(crate) struct FormatCssSupportsNotCondition; impl FormatNodeRule for FormatCssSupportsNotCondition { fn fmt_fields(&self, node: &CssSupportsNotCondition, f: &mut CssFormatter) -> FormatResult<()> { - format_verbatim_node(node.syntax()).fmt(f) + let CssSupportsNotConditionFields { not_token, query } = node.as_fields(); + + write!(f, [not_token.format(), space(), query.format()]) } } diff --git a/crates/biome_css_formatter/src/css/auxiliary/supports_or_condition.rs b/crates/biome_css_formatter/src/css/auxiliary/supports_or_condition.rs index 7313a46f37fc..21f366f60e17 100644 --- a/crates/biome_css_formatter/src/css/auxiliary/supports_or_condition.rs +++ b/crates/biome_css_formatter/src/css/auxiliary/supports_or_condition.rs @@ -1,10 +1,26 @@ use crate::prelude::*; -use biome_css_syntax::CssSupportsOrCondition; -use biome_rowan::AstNode; +use biome_css_syntax::{CssSupportsOrCondition, CssSupportsOrConditionFields}; +use biome_formatter::write; + #[derive(Debug, Clone, Default)] pub(crate) struct FormatCssSupportsOrCondition; impl FormatNodeRule for FormatCssSupportsOrCondition { fn fmt_fields(&self, node: &CssSupportsOrCondition, f: &mut CssFormatter) -> FormatResult<()> { - format_verbatim_node(node.syntax()).fmt(f) + let CssSupportsOrConditionFields { + left, + or_token, + right, + } = node.as_fields(); + + write!( + f, + [ + left.format(), + space(), + or_token.format(), + soft_line_break_or_space(), + right.format() + ] + ) } } diff --git a/crates/biome_css_formatter/src/css/selectors/supports_feature_selector.rs b/crates/biome_css_formatter/src/css/selectors/supports_feature_selector.rs index fda06a30eb2f..9ad589fdf90b 100644 --- a/crates/biome_css_formatter/src/css/selectors/supports_feature_selector.rs +++ b/crates/biome_css_formatter/src/css/selectors/supports_feature_selector.rs @@ -1,6 +1,7 @@ use crate::prelude::*; -use biome_css_syntax::CssSupportsFeatureSelector; -use biome_rowan::AstNode; +use biome_css_syntax::{CssSupportsFeatureSelector, CssSupportsFeatureSelectorFields}; +use biome_formatter::{format_args, write}; + #[derive(Debug, Clone, Default)] pub(crate) struct FormatCssSupportsFeatureSelector; impl FormatNodeRule for FormatCssSupportsFeatureSelector { @@ -9,6 +10,21 @@ impl FormatNodeRule for FormatCssSupportsFeatureSele node: &CssSupportsFeatureSelector, f: &mut CssFormatter, ) -> FormatResult<()> { - format_verbatim_node(node.syntax()).fmt(f) + let CssSupportsFeatureSelectorFields { + selector_token, + l_paren_token, + selector, + r_paren_token, + } = node.as_fields(); + + write!( + f, + [group(&format_args![ + selector_token.format(), + l_paren_token.format(), + soft_block_indent(&selector.format()), + r_paren_token.format() + ])] + ) } } diff --git a/crates/biome_css_formatter/src/css/statements/supports_at_rule.rs b/crates/biome_css_formatter/src/css/statements/supports_at_rule.rs index 5280962ceb7f..bc6d4e10ba9e 100644 --- a/crates/biome_css_formatter/src/css/statements/supports_at_rule.rs +++ b/crates/biome_css_formatter/src/css/statements/supports_at_rule.rs @@ -1,10 +1,26 @@ use crate::prelude::*; -use biome_css_syntax::CssSupportsAtRule; -use biome_rowan::AstNode; +use biome_css_syntax::{CssSupportsAtRule, CssSupportsAtRuleFields}; +use biome_formatter::write; + #[derive(Debug, Clone, Default)] pub(crate) struct FormatCssSupportsAtRule; impl FormatNodeRule for FormatCssSupportsAtRule { fn fmt_fields(&self, node: &CssSupportsAtRule, f: &mut CssFormatter) -> FormatResult<()> { - format_verbatim_node(node.syntax()).fmt(f) + let CssSupportsAtRuleFields { + supports_token, + condition, + block, + } = node.as_fields(); + + write!( + f, + [ + supports_token.format(), + space(), + group(&indent(&condition.format())), + space(), + block.format() + ] + ) } } diff --git a/crates/biome_css_formatter/tests/specs/css/atrule/supports.css b/crates/biome_css_formatter/tests/specs/css/atrule/supports.css new file mode 100644 index 000000000000..bcad2e72c4fd --- /dev/null +++ b/crates/biome_css_formatter/tests/specs/css/atrule/supports.css @@ -0,0 +1,178 @@ +@supports (display: grid) { + div { + display: grid; + } +} + +@supports (display: flex) { + body { + color: blue; + } + + @media screen and (min-width: 900px) { + article { + display: flex; + } + } +} +@supports ( display : flex ) {} +@supports not (display: flex) {} +@SUPPORTS not (display: flex) {} +@supports (box-shadow: 0 0 2px black inset ) or (-moz-box-shadow: 0 0 2px black inset ) or (-webkit-box-shadow: 0 0 2px black inset ) or (-o-box-shadow: 0 0 2px black inset ) {} +@supports ( box-shadow: 0 0 2px black inset ) + +or + ( -moz-box-shadow: 0 0 2px black inset ) or + + ( -webkit-box-shadow: 0 0 2px black inset ) or + ( + -o-box-shadow: 0 0 2px black inset ) { + +} +@supports ( transition-property : color ) or ( ( animation-name : foo ) and ( transform : rotate(10deg) ) ) {} +@supports(transition-property:color)or ((animation-name:foo)and (transform:rotate(10deg))){} +@supports (( + display: flex)) {} +@supports (display: flex !important) {} +@supports NOT (display: flex) {} +@supports ((transition-property: color) OR (animation-name: foo)) AND (transform: rotate(10deg)) {} +@supports (transition-property: color) OR ((animation-name: foo) AND (transform: rotate(10deg)) + +) {} +@supports (NOT (display: flex)) {} + +@supports selector(col || td) { + col.selected || td { + background: tan; + } +} + +@supports selector( + :focus-visible + ) { + a:focus-visible { + background: yellow; + } +} + +@supports ( + --element(".minwidth")) { + +} + +@supports (ident: 1) { + * { background: red; } +} + +@supports ((ident: 1)) { + * { background: red; } +} + +@supports (ident: "str") { + * { background: red; } +} + +@supports ((ident: "str")) { + * { background: red; } +} + +@supports func(10, 20, 40) { + * { background: red; } +} + +@supports (func(10, 20, 40)) { + * { background: red; } +} + +@supports ( func( 10 , 20 , 40 ) ) { + * { background: red; } +} + +@supports (animation-name: test) { + @keyframes anim { + from { + color: black; + } + to { + color: white + } + } +} + +@supports (--foo: green) { + body { + color: var(--varName); + } +} + +@supports not selector(:is(a, b)) { + ul > li, + ol > li { + color: red; + } +} + +@supports selector( + :nth-child( + 1n of a + + , + b)) { + :is( + :nth-child(1n of ul, ol) a, + details > summary + ) { + color: red + } +} + +@supports (animation-name: test) { + @keyframes anim { + from { + color: black; + } + to { + color: white + } + } +} + +@supports selector(:focus-visible) { + a:focus-visible { + background: yellow; + } +} + +@supports (width: calc(100px)) { + div { + background: red; + } +} + +@supports (func(1)) { + * { background: red; } +} + +@supports ( selector( col || td ) ) { + col.selected || td { + background: tan; + } +} + +@supports ( func("example") ) { + * { background: red; } +} + +@supports ( --var: "test" ) { + * { background: red; } +} + +@supports (--var) { + * { background: red; } +} + +@supports (--element(".minwidth")) { + [--self] { + background: greenyellow; + } +} diff --git a/crates/biome_css_formatter/tests/specs/css/atrule/supports.css.snap b/crates/biome_css_formatter/tests/specs/css/atrule/supports.css.snap new file mode 100644 index 000000000000..c324868ed8e7 --- /dev/null +++ b/crates/biome_css_formatter/tests/specs/css/atrule/supports.css.snap @@ -0,0 +1,429 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: css/atrule/supports.css +--- + +# Input + +```css +@supports (display: grid) { + div { + display: grid; + } +} + +@supports (display: flex) { + body { + color: blue; + } + + @media screen and (min-width: 900px) { + article { + display: flex; + } + } +} +@supports ( display : flex ) {} +@supports not (display: flex) {} +@SUPPORTS not (display: flex) {} +@supports (box-shadow: 0 0 2px black inset ) or (-moz-box-shadow: 0 0 2px black inset ) or (-webkit-box-shadow: 0 0 2px black inset ) or (-o-box-shadow: 0 0 2px black inset ) {} +@supports ( box-shadow: 0 0 2px black inset ) + +or + ( -moz-box-shadow: 0 0 2px black inset ) or + + ( -webkit-box-shadow: 0 0 2px black inset ) or + ( + -o-box-shadow: 0 0 2px black inset ) { + +} +@supports ( transition-property : color ) or ( ( animation-name : foo ) and ( transform : rotate(10deg) ) ) {} +@supports(transition-property:color)or ((animation-name:foo)and (transform:rotate(10deg))){} +@supports (( + display: flex)) {} +@supports (display: flex !important) {} +@supports NOT (display: flex) {} +@supports ((transition-property: color) OR (animation-name: foo)) AND (transform: rotate(10deg)) {} +@supports (transition-property: color) OR ((animation-name: foo) AND (transform: rotate(10deg)) + +) {} +@supports (NOT (display: flex)) {} + +@supports selector(col || td) { + col.selected || td { + background: tan; + } +} + +@supports selector( + :focus-visible + ) { + a:focus-visible { + background: yellow; + } +} + +@supports ( + --element(".minwidth")) { + +} + +@supports (ident: 1) { + * { background: red; } +} + +@supports ((ident: 1)) { + * { background: red; } +} + +@supports (ident: "str") { + * { background: red; } +} + +@supports ((ident: "str")) { + * { background: red; } +} + +@supports func(10, 20, 40) { + * { background: red; } +} + +@supports (func(10, 20, 40)) { + * { background: red; } +} + +@supports ( func( 10 , 20 , 40 ) ) { + * { background: red; } +} + +@supports (animation-name: test) { + @keyframes anim { + from { + color: black; + } + to { + color: white + } + } +} + +@supports (--foo: green) { + body { + color: var(--varName); + } +} + +@supports not selector(:is(a, b)) { + ul > li, + ol > li { + color: red; + } +} + +@supports selector( + :nth-child( + 1n of a + + , + b)) { + :is( + :nth-child(1n of ul, ol) a, + details > summary + ) { + color: red + } +} + +@supports (animation-name: test) { + @keyframes anim { + from { + color: black; + } + to { + color: white + } + } +} + +@supports selector(:focus-visible) { + a:focus-visible { + background: yellow; + } +} + +@supports (width: calc(100px)) { + div { + background: red; + } +} + +@supports (func(1)) { + * { background: red; } +} + +@supports ( selector( col || td ) ) { + col.selected || td { + background: tan; + } +} + +@supports ( func("example") ) { + * { background: red; } +} + +@supports ( --var: "test" ) { + * { background: red; } +} + +@supports (--var) { + * { background: red; } +} + +@supports (--element(".minwidth")) { + [--self] { + background: greenyellow; + } +} + +``` + + +============================= + +# Outputs + +## Output 1 + +----- +Indent style: Tab +Indent width: 2 +Line ending: LF +Line width: 80 +----- + +```css +@supports (display: grid) { + div { + display: grid; + } +} + +@supports (display: flex) { + body { + color: blue; + } + + @media screen and (min-width: 900px) { + article { + display: flex; + } + } +} +@supports (display: flex) { +} +@supports not (display: flex) { +} +@SUPPORTS not (display: flex) { +} +@supports (box-shadow: 0 0 2px black inset) or + (-moz-box-shadow: 0 0 2px black inset) or + (-webkit-box-shadow: 0 0 2px black inset) or + (-o-box-shadow: 0 0 2px black inset) { +} +@supports (box-shadow: 0 0 2px black inset) or + (-moz-box-shadow: 0 0 2px black inset) or + (-webkit-box-shadow: 0 0 2px black inset) or + (-o-box-shadow: 0 0 2px black inset) { +} +@supports (transition-property: color) or + ((animation-name: foo) and (transform: rotate(10deg))) { +} +@supports (transition-property: color) or + ((animation-name: foo) and (transform: rotate(10deg))) { +} +@supports ((display: flex)) { +} +@supports (display: flex !important) { +} +@supports NOT (display: flex) { +} +@supports ((transition-property: color) OR (animation-name: foo)) AND + (transform: rotate(10deg)) { +} +@supports (transition-property: color) OR + ((animation-name: foo) AND (transform: rotate(10deg))) { +} +@supports (NOT (display: flex)) { +} + +@supports selector(col || td) { + col.selected || td { + background: tan; + } +} + +@supports selector(:focus-visible) { + a:focus-visible { + background: yellow; + } +} + +@supports (--element(".minwidth")) { +} + +@supports (ident: 1) { + * { + background: red; + } +} + +@supports ((ident: 1)) { + * { + background: red; + } +} + +@supports (ident: "str") { + * { + background: red; + } +} + +@supports ((ident: "str")) { + * { + background: red; + } +} + +@supports func(10, 20, 40) { + * { + background: red; + } +} + +@supports (func(10, 20, 40)) { + * { + background: red; + } +} + +@supports (func(10, 20, 40)) { + * { + background: red; + } +} + +@supports (animation-name: test) { + @keyframes anim { + from { + color: black; + } + to { + color: white; + } + } +} + +@supports (--foo: green) { + body { + color: var(--varName); + } +} + +@supports not selector(:is(a, b)) { + ul > li, + ol > li { + color: red; + } +} + +@supports selector(:nth-child(1n of a, b)) { + :is(:nth-child(1n of ul, ol) a, details > summary) { + color: red; + } +} + +@supports (animation-name: test) { + @keyframes anim { + from { + color: black; + } + to { + color: white; + } + } +} + +@supports selector(:focus-visible) { + a:focus-visible { + background: yellow; + } +} + +@supports (width: calc(100px)) { + div { + background: red; + } +} + +@supports (func(1)) { + * { + background: red; + } +} + +@supports (selector(col || td)) { + col.selected || td { + background: tan; + } +} + +@supports (func("example")) { + * { + background: red; + } +} + +@supports (--var: "test") { + * { + background: red; + } +} + +@supports (--var) { + * { + background: red; + } +} + +@supports (--element(".minwidth")) { + [--self] { + background: greenyellow; + } +} +``` + + + +## Unimplemented nodes/tokens + +"10deg" => 735..740 +"10deg" => 837..842 +"10deg" => 1047..1052 +"10deg" => 1148..1153 +"\".minwidth\"" => 1382..1393 +"10" => 1640..1642 +" 2" => 1643..1645 +" 4" => 1647..1649 +"10" => 1700..1702 +" 2" => 1703..1705 +" 4" => 1707..1709 +"10, 2" => 1761..1766 +" 20, " => 1764..1769 +" 40))" => 1768..1773 +"--varName" => 1972..1981 +"100px" => 2411..2416 +"1" => 2469..2470 +"\"example\"" => 2602..2611 +"\".minwidth\"" => 2775..2786 + diff --git a/crates/biome_css_formatter/tests/specs/css/atrule/supports_complex.css b/crates/biome_css_formatter/tests/specs/css/atrule/supports_complex.css new file mode 100644 index 000000000000..cec0e3f5248d --- /dev/null +++ b/crates/biome_css_formatter/tests/specs/css/atrule/supports_complex.css @@ -0,0 +1,43 @@ +@supports ( + display: flex + ) { } +@supports ( + display: flex + + ) + or + ( +display : +flex ) or (display: flex +) or (display: flex) { } +@supports (display: flex) +and (display: flex) +and (display: flex) +and (display: flex) { } + +@supports (display: flex) and +(selector( + :focus-visible +) or (( + animation-name: + test))) { } + +@supports (display: flex +) and (selector(:focus-visible + +) or ( +not +( +(animation-name: test) +)) + +) { } + +@supports (display: flex) + +and (selector(:focus-visible ) or ( + +not ((animation-name: test)) ) + +) and (display: flex +) { } diff --git a/crates/biome_css_formatter/tests/specs/css/atrule/supports_complex.css.snap b/crates/biome_css_formatter/tests/specs/css/atrule/supports_complex.css.snap new file mode 100644 index 000000000000..4ab0f09d9e0f --- /dev/null +++ b/crates/biome_css_formatter/tests/specs/css/atrule/supports_complex.css.snap @@ -0,0 +1,97 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: css/atrule/supports_complex.css +--- + +# Input + +```css +@supports ( + display: flex + ) { } +@supports ( + display: flex + + ) + or + ( +display : +flex ) or (display: flex +) or (display: flex) { } +@supports (display: flex) +and (display: flex) +and (display: flex) +and (display: flex) { } + +@supports (display: flex) and +(selector( + :focus-visible +) or (( + animation-name: + test))) { } + +@supports (display: flex +) and (selector(:focus-visible + +) or ( +not +( +(animation-name: test) +)) + +) { } + +@supports (display: flex) + +and (selector(:focus-visible ) or ( + +not ((animation-name: test)) ) + +) and (display: flex +) { } + +``` + + +============================= + +# Outputs + +## Output 1 + +----- +Indent style: Tab +Indent width: 2 +Line ending: LF +Line width: 80 +----- + +```css +@supports (display: flex) { +} +@supports (display: flex) or + (display: flex) or + (display: flex) or + (display: flex) { +} +@supports (display: flex) and + (display: flex) and + (display: flex) and + (display: flex) { +} + +@supports (display: flex) and + (selector(:focus-visible) or ((animation-name: test))) { +} + +@supports (display: flex) and + (selector(:focus-visible) or (not ((animation-name: test)))) { +} + +@supports (display: flex) and + (selector(:focus-visible) or (not ((animation-name: test)))) and + (display: flex) { +} +``` + +