diff --git a/crates/biome_css_factory/src/generated/node_factory.rs b/crates/biome_css_factory/src/generated/node_factory.rs index afba70a30c36..c6adb91d6d50 100644 --- a/crates/biome_css_factory/src/generated/node_factory.rs +++ b/crates/biome_css_factory/src/generated/node_factory.rs @@ -2976,10 +2976,24 @@ pub fn css_view_transition_at_rule_declarator( [Some(SyntaxElement::Token(view_transition_token))], )) } +pub fn scss_binary_expression( + left: AnyScssExpression, + operator_token: SyntaxToken, + right: AnyScssExpression, +) -> ScssBinaryExpression { + ScssBinaryExpression::unwrap_cast(SyntaxNode::new_detached( + CssSyntaxKind::SCSS_BINARY_EXPRESSION, + [ + Some(SyntaxElement::Node(left.into_syntax())), + Some(SyntaxElement::Token(operator_token)), + Some(SyntaxElement::Node(right.into_syntax())), + ], + )) +} pub fn scss_declaration( name: AnyScssDeclarationName, colon_token: SyntaxToken, - value: CssGenericComponentValueList, + value: ScssExpression, modifiers: ScssVariableModifierList, ) -> ScssDeclarationBuilder { ScssDeclarationBuilder { @@ -2993,7 +3007,7 @@ pub fn scss_declaration( pub struct ScssDeclarationBuilder { name: AnyScssDeclarationName, colon_token: SyntaxToken, - value: CssGenericComponentValueList, + value: ScssExpression, modifiers: ScssVariableModifierList, semicolon_token: Option, } @@ -3135,6 +3149,18 @@ pub fn scss_qualified_name( ], )) } +pub fn scss_unary_expression( + operator_token: SyntaxToken, + expression: AnyScssExpression, +) -> ScssUnaryExpression { + ScssUnaryExpression::unwrap_cast(SyntaxNode::new_detached( + CssSyntaxKind::SCSS_UNARY_EXPRESSION, + [ + Some(SyntaxElement::Token(operator_token)), + Some(SyntaxElement::Node(expression.into_syntax())), + ], + )) +} pub fn scss_variable_modifier( excl_token: SyntaxToken, value_token: SyntaxToken, diff --git a/crates/biome_css_factory/src/generated/syntax_factory.rs b/crates/biome_css_factory/src/generated/syntax_factory.rs index 98be14b18214..e8192ee0367e 100644 --- a/crates/biome_css_factory/src/generated/syntax_factory.rs +++ b/crates/biome_css_factory/src/generated/syntax_factory.rs @@ -6120,6 +6120,54 @@ impl SyntaxFactory for CssSyntaxFactory { } slots.into_node(CSS_VIEW_TRANSITION_AT_RULE_DECLARATOR, children) } + SCSS_BINARY_EXPRESSION => { + let mut elements = (&children).into_iter(); + let mut slots: RawNodeSlots<3usize> = RawNodeSlots::default(); + let mut current_element = elements.next(); + if let Some(element) = ¤t_element + && AnyScssExpression::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && matches!( + element.kind(), + T ! [*] + | T ! [/] + | T ! [%] + | T ! [+] + | T ! [-] + | T ! [>] + | T ! [>=] + | T ! [<] + | T ! [<=] + | T ! [==] + | T ! [!=] + | T![and] + | T![or] + ) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && AnyScssExpression::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + SCSS_BINARY_EXPRESSION.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(SCSS_BINARY_EXPRESSION, children) + } SCSS_DECLARATION => { let mut elements = (&children).into_iter(); let mut slots: RawNodeSlots<5usize> = RawNodeSlots::default(); @@ -6139,7 +6187,7 @@ impl SyntaxFactory for CssSyntaxFactory { } slots.next_slot(); if let Some(element) = ¤t_element - && CssGenericComponentValueList::can_cast(element.kind()) + && ScssExpression::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); @@ -6474,6 +6522,32 @@ impl SyntaxFactory for CssSyntaxFactory { } slots.into_node(SCSS_QUALIFIED_NAME, children) } + SCSS_UNARY_EXPRESSION => { + let mut elements = (&children).into_iter(); + let mut slots: RawNodeSlots<2usize> = RawNodeSlots::default(); + let mut current_element = elements.next(); + if let Some(element) = ¤t_element + && matches!(element.kind(), T ! [+] | T ! [-] | T![not]) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && AnyScssExpression::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + SCSS_UNARY_EXPRESSION.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(SCSS_UNARY_EXPRESSION, children) + } SCSS_VARIABLE_MODIFIER => { let mut elements = (&children).into_iter(); let mut slots: RawNodeSlots<2usize> = RawNodeSlots::default(); diff --git a/crates/biome_css_formatter/src/generated.rs b/crates/biome_css_formatter/src/generated.rs index 71cc1ba426e2..1588fcdd7de2 100644 --- a/crates/biome_css_formatter/src/generated.rs +++ b/crates/biome_css_formatter/src/generated.rs @@ -6996,6 +6996,44 @@ impl IntoFormat for biome_css_syntax::CssViewTransitionAtRuleD FormatOwnedWithRule :: new (self , crate :: css :: auxiliary :: view_transition_at_rule_declarator :: FormatCssViewTransitionAtRuleDeclarator :: default ()) } } +impl FormatRule + for crate::scss::auxiliary::binary_expression::FormatScssBinaryExpression +{ + type Context = CssFormatContext; + #[inline(always)] + fn fmt( + &self, + node: &biome_css_syntax::ScssBinaryExpression, + f: &mut CssFormatter, + ) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl AsFormat for biome_css_syntax::ScssBinaryExpression { + type Format<'a> = FormatRefWithRule< + 'a, + biome_css_syntax::ScssBinaryExpression, + crate::scss::auxiliary::binary_expression::FormatScssBinaryExpression, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::scss::auxiliary::binary_expression::FormatScssBinaryExpression::default(), + ) + } +} +impl IntoFormat for biome_css_syntax::ScssBinaryExpression { + type Format = FormatOwnedWithRule< + biome_css_syntax::ScssBinaryExpression, + crate::scss::auxiliary::binary_expression::FormatScssBinaryExpression, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::scss::auxiliary::binary_expression::FormatScssBinaryExpression::default(), + ) + } +} impl FormatRule for crate::scss::auxiliary::declaration::FormatScssDeclaration { @@ -7440,6 +7478,44 @@ impl IntoFormat for biome_css_syntax::ScssQualifiedName { ) } } +impl FormatRule + for crate::scss::auxiliary::unary_expression::FormatScssUnaryExpression +{ + type Context = CssFormatContext; + #[inline(always)] + fn fmt( + &self, + node: &biome_css_syntax::ScssUnaryExpression, + f: &mut CssFormatter, + ) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl AsFormat for biome_css_syntax::ScssUnaryExpression { + type Format<'a> = FormatRefWithRule< + 'a, + biome_css_syntax::ScssUnaryExpression, + crate::scss::auxiliary::unary_expression::FormatScssUnaryExpression, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::scss::auxiliary::unary_expression::FormatScssUnaryExpression::default(), + ) + } +} +impl IntoFormat for biome_css_syntax::ScssUnaryExpression { + type Format = FormatOwnedWithRule< + biome_css_syntax::ScssUnaryExpression, + crate::scss::auxiliary::unary_expression::FormatScssUnaryExpression, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::scss::auxiliary::unary_expression::FormatScssUnaryExpression::default(), + ) + } +} impl FormatRule for crate::scss::auxiliary::variable_modifier::FormatScssVariableModifier { diff --git a/crates/biome_css_formatter/src/scss/any/expression.rs b/crates/biome_css_formatter/src/scss/any/expression.rs index 006148e1f049..5dcec8550e51 100644 --- a/crates/biome_css_formatter/src/scss/any/expression.rs +++ b/crates/biome_css_formatter/src/scss/any/expression.rs @@ -9,10 +9,12 @@ impl FormatRule for FormatAnyScssExpression { fn fmt(&self, node: &AnyScssExpression, f: &mut CssFormatter) -> FormatResult<()> { match node { AnyScssExpression::AnyCssValue(node) => node.format().fmt(f), + AnyScssExpression::ScssBinaryExpression(node) => node.format().fmt(f), AnyScssExpression::ScssExpression(node) => node.format().fmt(f), AnyScssExpression::ScssListExpression(node) => node.format().fmt(f), AnyScssExpression::ScssMapExpression(node) => node.format().fmt(f), AnyScssExpression::ScssParenthesizedExpression(node) => node.format().fmt(f), + AnyScssExpression::ScssUnaryExpression(node) => node.format().fmt(f), } } } diff --git a/crates/biome_css_formatter/src/scss/any/expression_item.rs b/crates/biome_css_formatter/src/scss/any/expression_item.rs index ca1cb81ca393..06d7021cdea4 100644 --- a/crates/biome_css_formatter/src/scss/any/expression_item.rs +++ b/crates/biome_css_formatter/src/scss/any/expression_item.rs @@ -10,9 +10,11 @@ impl FormatRule for FormatAnyScssExpressionItem { match node { AnyScssExpressionItem::AnyCssValue(node) => node.format().fmt(f), AnyScssExpressionItem::CssGenericDelimiter(node) => node.format().fmt(f), + AnyScssExpressionItem::ScssBinaryExpression(node) => node.format().fmt(f), AnyScssExpressionItem::ScssListExpression(node) => node.format().fmt(f), AnyScssExpressionItem::ScssMapExpression(node) => node.format().fmt(f), AnyScssExpressionItem::ScssParenthesizedExpression(node) => node.format().fmt(f), + AnyScssExpressionItem::ScssUnaryExpression(node) => node.format().fmt(f), } } } diff --git a/crates/biome_css_formatter/src/scss/auxiliary/binary_expression.rs b/crates/biome_css_formatter/src/scss/auxiliary/binary_expression.rs new file mode 100644 index 000000000000..700960f77c3f --- /dev/null +++ b/crates/biome_css_formatter/src/scss/auxiliary/binary_expression.rs @@ -0,0 +1,27 @@ +use crate::prelude::*; +use biome_css_syntax::{ScssBinaryExpression, ScssBinaryExpressionFields}; +use biome_formatter::{format_args, write}; + +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatScssBinaryExpression; + +impl FormatNodeRule for FormatScssBinaryExpression { + fn fmt_fields(&self, node: &ScssBinaryExpression, f: &mut CssFormatter) -> FormatResult<()> { + let ScssBinaryExpressionFields { + left, + operator, + right, + } = node.as_fields(); + + write!( + f, + [group(&format_args![ + left.format(), + space(), + operator.format(), + soft_line_break_or_space(), + right.format() + ])] + ) + } +} diff --git a/crates/biome_css_formatter/src/scss/auxiliary/mod.rs b/crates/biome_css_formatter/src/scss/auxiliary/mod.rs index 29017cb09662..3c752cc56747 100644 --- a/crates/biome_css_formatter/src/scss/auxiliary/mod.rs +++ b/crates/biome_css_formatter/src/scss/auxiliary/mod.rs @@ -1,5 +1,6 @@ //! This is a generated file. Don't modify it by hand! Run 'cargo codegen formatter' to re-generate the file. +pub(crate) mod binary_expression; pub(crate) mod declaration; pub(crate) mod expression; pub(crate) mod list_expression; @@ -10,4 +11,5 @@ pub(crate) mod nesting_declaration; pub(crate) mod parent_selector_value; pub(crate) mod parenthesized_expression; pub(crate) mod qualified_name; +pub(crate) mod unary_expression; pub(crate) mod variable_modifier; diff --git a/crates/biome_css_formatter/src/scss/auxiliary/unary_expression.rs b/crates/biome_css_formatter/src/scss/auxiliary/unary_expression.rs new file mode 100644 index 000000000000..cc98907794be --- /dev/null +++ b/crates/biome_css_formatter/src/scss/auxiliary/unary_expression.rs @@ -0,0 +1,29 @@ +use crate::prelude::*; +use biome_css_syntax::CssSyntaxKind; +use biome_css_syntax::{ScssUnaryExpression, ScssUnaryExpressionFields, T}; +use biome_formatter::write; + +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatScssUnaryExpression; +impl FormatNodeRule for FormatScssUnaryExpression { + fn fmt_fields(&self, node: &ScssUnaryExpression, f: &mut CssFormatter) -> FormatResult<()> { + let ScssUnaryExpressionFields { + operator, + expression, + } = node.as_fields(); + let operator = operator?; + let expression = expression?; + + let is_parenthesized = matches!( + expression.syntax().kind(), + CssSyntaxKind::SCSS_PARENTHESIZED_EXPRESSION + ); + let needs_space = matches!(operator.kind(), T![not]) && !is_parenthesized; + + if needs_space { + write!(f, [operator.format(), space(), expression.format()]) + } else { + write!(f, [operator.format(), expression.format()]) + } + } +} diff --git a/crates/biome_css_formatter/tests/specs/css/scss/expression/precedence.scss b/crates/biome_css_formatter/tests/specs/css/scss/expression/precedence.scss new file mode 100644 index 000000000000..d10360237fb1 --- /dev/null +++ b/crates/biome_css_formatter/tests/specs/css/scss/expression/precedence.scss @@ -0,0 +1,103 @@ +$expr1:$a+$b*$c; + +$expr2:( +$a + +$b )*$c; + + +$expr3:-$a +$b; + $expr4:not $a and $b; + + $expr5:$a== + $b +or $c!= + +$d; + + $expr6:$a>= $b + and not( $c<=$d); + $expr7:$a+$b+$c*$d/$e%$f; + + $expr8:( $a ++ $b )*( $c + - + +$d)/$e; + +$expr9:not + -$a + or $b and + +$c; + $expr10:$a + < +$b + == $c; + $expr11:$a +$b*($c + ++ $d ) - +$e; + + $expr12:($a + ++ + +$b ) * +$c + $d/( $e +- + $f); + + +$expr13:-( $a ++ + +$b) + +* + +$c; + $expr14:$a + +and $b or $c + +and $d; + + $expr15:$a!=( $b ++ $c* $d); + + $expr16:$a + ++ + $b/$c +- +$d*$e + ++ $f; + + $expr17:1+2*3-4/5; + $expr18:-1+2; + $expr19:( $a+ +$b )*( $c+ +$d )/( $e + -$f); + +$expr20:$a== $b and + $c== $d +or $e; + + $expr21:not( $a +== $b or +$c== $d); + +$expr22:$a +or $b +and $c or +$d; + + $expr23:( $a + +$b ) * -( + $c - $d); + +$expr24:$a/ + $b * $c +% $d; diff --git a/crates/biome_css_formatter/tests/specs/css/scss/expression/precedence.scss.snap b/crates/biome_css_formatter/tests/specs/css/scss/expression/precedence.scss.snap new file mode 100644 index 000000000000..57a93be8b456 --- /dev/null +++ b/crates/biome_css_formatter/tests/specs/css/scss/expression/precedence.scss.snap @@ -0,0 +1,173 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +assertion_line: 212 +info: css/scss/expression/precedence.scss +--- +# Input + +```scss +$expr1:$a+$b*$c; + +$expr2:( +$a + +$b )*$c; + + +$expr3:-$a +$b; + $expr4:not $a and $b; + + $expr5:$a== + $b +or $c!= + +$d; + + $expr6:$a>= $b + and not( $c<=$d); + $expr7:$a+$b+$c*$d/$e%$f; + + $expr8:( $a ++ $b )*( $c + - + +$d)/$e; + +$expr9:not + -$a + or $b and + +$c; + $expr10:$a + < +$b + == $c; + $expr11:$a +$b*($c + ++ $d ) - +$e; + + $expr12:($a + ++ + +$b ) * +$c + $d/( $e +- + $f); + + +$expr13:-( $a ++ + +$b) + +* + +$c; + $expr14:$a + +and $b or $c + +and $d; + + $expr15:$a!=( $b ++ $c* $d); + + $expr16:$a + ++ + $b/$c +- +$d*$e + ++ $f; + + $expr17:1+2*3-4/5; + $expr18:-1+2; + $expr19:( $a+ +$b )*( $c+ +$d )/( $e + -$f); + +$expr20:$a== $b and + $c== $d +or $e; + + $expr21:not( $a +== $b or +$c== $d); + +$expr22:$a +or $b +and $c or +$d; + + $expr23:( $a + +$b ) * -( + $c - $d); + +$expr24:$a/ + $b * $c +% $d; + +``` + + +============================= + +# Outputs + +## Output 1 + +----- +Indent style: Tab +Indent width: 2 +Line ending: LF +Line width: 80 +Quote style: Double Quotes +Trailing newline: true +----- + +```scss +$expr1: $a + $b * $c; + +$expr2: ($a + $b) * $c; + +$expr3: -$a + $b; +$expr4: not $a and $b; + +$expr5: $a == $b or $c != $d; + +$expr6: $a >= $b and not($c <= $d); +$expr7: $a + $b + $c * $d / $e % $f; + +$expr8: ($a + $b) * ($c - $d) / $e; + +$expr9: not -$a or $b and $c; +$expr10: $a < $b == $c; +$expr11: $a + $b * ($c + $d) - $e; + +$expr12: ($a + $b) * $c + $d / ($e - $f); + +$expr13: -($a + $b) * $c; +$expr14: $a and $b or $c and $d; + +$expr15: $a != ($b + $c * $d); + +$expr16: $a + $b / $c - $d * $e + $f; + +$expr17: 1 +2 * 3 -4 / 5; +$expr18: -1 +2; +$expr19: ($a + $b) * ($c + $d) / ($e - $f); + +$expr20: $a == $b and $c == $d or $e; + +$expr21: not($a == $b or $c == $d); + +$expr22: $a or $b and $c or $d; + +$expr23: ($a + $b) * -($c - $d); + +$expr24: $a / $b * $c % $d; + +``` diff --git a/crates/biome_css_formatter/tests/specs/prettier/css/parens/empty-lines.css.snap b/crates/biome_css_formatter/tests/specs/prettier/css/parens/empty-lines.css.snap index 4b064ff4f577..8f055489edb2 100644 --- a/crates/biome_css_formatter/tests/specs/prettier/css/parens/empty-lines.css.snap +++ b/crates/biome_css_formatter/tests/specs/prettier/css/parens/empty-lines.css.snap @@ -77,29 +77,11 @@ empty-lines.css:1:1 parse ━━━━━━━━━━━━━━━━━━ ... > 10 │ "background-secondary": $dark-200, > 11 │ "background-tertiary": $dark-100 - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 12 │ ); - 13 │ - - i SCSS only syntax - -empty-lines.css:12:1 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a qualified rule, or an at rule but instead found ');'. - - 10 │ "background-secondary": $dark-200, - 11 │ "background-tertiary": $dark-100 > 12 │ ); │ ^^ 13 │ - i Expected a qualified rule, or an at rule here. - - 10 │ "background-secondary": $dark-200, - 11 │ "background-tertiary": $dark-100 - > 12 │ ); - │ ^^ - 13 │ + i SCSS only syntax ``` diff --git a/crates/biome_css_parser/src/lexer/mod.rs b/crates/biome_css_parser/src/lexer/mod.rs index e6f08c22b613..a381cf8868d1 100644 --- a/crates/biome_css_parser/src/lexer/mod.rs +++ b/crates/biome_css_parser/src/lexer/mod.rs @@ -343,7 +343,7 @@ impl<'src> CssLexer<'src> { LSS => self.consume_lss(), - IDT | DOL if self.peek_byte() == Some(b'=') => { + DOL if self.peek_byte() == Some(b'=') => { self.advance(1); self.consume_byte(T!["$="]) } @@ -369,8 +369,8 @@ impl<'src> CssLexer<'src> { MOR => self.consume_mor(), TLD => self.consume_tilde(), PIP => self.consume_pipe(), - EQL => self.consume_byte(T![=]), - EXL => self.consume_byte(T![!]), + EQL => self.consume_eql(), + EXL => self.consume_exl(), PRC => self.consume_byte(T![%]), Dispatch::AMP => self.consume_byte(T![&]), @@ -1195,6 +1195,26 @@ impl<'src> CssLexer<'src> { } } + #[inline] + fn consume_eql(&mut self) -> CssSyntaxKind { + self.assert_byte(b'='); + + match self.next_byte() { + Some(b'=') if self.source_type.is_scss() => self.consume_byte(T![==]), + _ => T![=], + } + } + + #[inline] + fn consume_exl(&mut self) -> CssSyntaxKind { + self.assert_byte(b'!'); + + match self.next_byte() { + Some(b'=') if self.source_type.is_scss() => self.consume_byte(T![!=]), + _ => T![!], + } + } + #[inline] fn consume_mor(&mut self) -> CssSyntaxKind { self.assert_byte(b'>'); diff --git a/crates/biome_css_parser/src/syntax/scss/declaration/variable.rs b/crates/biome_css_parser/src/syntax/scss/declaration/variable.rs index 4dd9c08baec4..9b04bb09295f 100644 --- a/crates/biome_css_parser/src/syntax/scss/declaration/variable.rs +++ b/crates/biome_css_parser/src/syntax/scss/declaration/variable.rs @@ -1,6 +1,7 @@ use super::super::{is_at_scss_identifier, parse_scss_identifier}; use crate::parser::CssParser; -use crate::syntax::property::GenericComponentValueList; +use crate::syntax::parse_error::expected_scss_expression; +use crate::syntax::scss::parse_scss_expression_until; use crate::syntax::{is_at_identifier, is_nth_at_identifier, parse_regular_identifier}; use biome_css_syntax::CssSyntaxKind::{ EOF, SCSS_DECLARATION, SCSS_NAMESPACED_IDENTIFIER, SCSS_VARIABLE_MODIFIER, @@ -53,7 +54,8 @@ pub(crate) fn parse_scss_declaration(p: &mut CssParser) -> ParsedSyntax { parse_scss_declaration_name(p).ok(); p.expect(T![:]); - GenericComponentValueList.parse_list(p); + parse_scss_expression_until(p, token_set![T![!], T![;], T!['}']]) + .or_add_diagnostic(p, expected_scss_expression); ScssVariableModifierList.parse_list(p); if !p.at(T!['}']) && !p.at(EOF) { diff --git a/crates/biome_css_parser/src/syntax/scss/expression/mod.rs b/crates/biome_css_parser/src/syntax/scss/expression/mod.rs index 7e47b6cf61e5..9b9655a298cf 100644 --- a/crates/biome_css_parser/src/syntax/scss/expression/mod.rs +++ b/crates/biome_css_parser/src/syntax/scss/expression/mod.rs @@ -1,11 +1,11 @@ use crate::parser::CssParser; -use crate::syntax::parse_error::expected_scss_expression; +use crate::syntax::parse_error::{expected_component_value, expected_scss_expression}; use crate::syntax::property::parse_generic_component_value; use biome_css_syntax::CssSyntaxKind::{ - CSS_BOGUS_PROPERTY_VALUE, EOF, SCSS_EXPRESSION, SCSS_EXPRESSION_ITEM_LIST, - SCSS_LIST_EXPRESSION, SCSS_LIST_EXPRESSION_ELEMENT, SCSS_LIST_EXPRESSION_ELEMENT_LIST, - SCSS_MAP_EXPRESSION, SCSS_MAP_EXPRESSION_PAIR, SCSS_MAP_EXPRESSION_PAIR_LIST, - SCSS_PARENTHESIZED_EXPRESSION, + CSS_BOGUS_PROPERTY_VALUE, EOF, SCSS_BINARY_EXPRESSION, SCSS_EXPRESSION, + SCSS_EXPRESSION_ITEM_LIST, SCSS_LIST_EXPRESSION, SCSS_LIST_EXPRESSION_ELEMENT, + SCSS_LIST_EXPRESSION_ELEMENT_LIST, SCSS_MAP_EXPRESSION, SCSS_MAP_EXPRESSION_PAIR, + SCSS_MAP_EXPRESSION_PAIR_LIST, SCSS_PARENTHESIZED_EXPRESSION, SCSS_UNARY_EXPRESSION, }; use biome_css_syntax::{CssSyntaxKind, T}; use biome_parser::parse_recovery::ParseRecoveryTokenSet; @@ -13,8 +13,23 @@ use biome_parser::prelude::ParsedSyntax; use biome_parser::prelude::ParsedSyntax::{Absent, Present}; use biome_parser::{CompletedMarker, Parser, ParserProgress, TokenSet, token_set}; -const SCSS_BINARY_OPERATOR_TOKEN_SET: TokenSet = - token_set![T![+], T![-], T![*], T![/]]; +const SCSS_BINARY_OPERATOR_TOKEN_SET: TokenSet = token_set![ + T![*], + T![/], + T![%], + T![+], + T![-], + T![>], + T![>=], + T![<], + T![<=], + T![==], + T![!=], + T![and], + T![or], +]; +pub(crate) const SCSS_UNARY_OPERATOR_TOKEN_SET: TokenSet = + token_set![T![+], T![-], T![not]]; const SCSS_MAP_EXPRESSION_KEY_END_TOKEN_SET: TokenSet = token_set![T![,], T![:], T![')']]; @@ -23,7 +38,7 @@ const SCSS_LIST_EXPRESSION_ELEMENT_END_TOKEN_SET: TokenSet = token_set![T![,], T![')']]; pub(crate) const END_OF_SCSS_EXPRESSION_TOKEN_SET: TokenSet = - token_set![T![,], T![')'], T![;], T!['}']].union(SCSS_BINARY_OPERATOR_TOKEN_SET); + token_set![T![,], T![')'], T![;], T!['}']]; #[inline] pub(crate) fn parse_scss_expression(p: &mut CssParser) -> ParsedSyntax { @@ -31,8 +46,11 @@ pub(crate) fn parse_scss_expression(p: &mut CssParser) -> ParsedSyntax { } #[inline] -fn parse_scss_expression_until(p: &mut CssParser, end_ts: TokenSet) -> ParsedSyntax { - parse_scss_expression_with_options(p, end_ts.union(SCSS_BINARY_OPERATOR_TOKEN_SET), false) +pub(crate) fn parse_scss_expression_until( + p: &mut CssParser, + end_ts: TokenSet, +) -> ParsedSyntax { + parse_scss_expression_with_options(p, end_ts, false) } #[inline] @@ -79,6 +97,50 @@ fn parse_scss_expression_with_options( #[inline] fn parse_scss_expression_item(p: &mut CssParser) -> ParsedSyntax { + parse_scss_binary_expression(p, 0) +} + +#[inline] +fn parse_scss_binary_expression(p: &mut CssParser, min_prec: u8) -> ParsedSyntax { + let mut left = match parse_scss_unary_expression(p) { + Present(left) => left, + Absent => return Absent, + }; + + loop { + let Some(prec) = scss_binary_precedence(p) else { + break; + }; + + if prec < min_prec { + break; + } + + let m = left.precede(p); + p.bump_ts(SCSS_BINARY_OPERATOR_TOKEN_SET); + + parse_scss_binary_expression(p, prec + 1).or_add_diagnostic(p, expected_component_value); + + left = m.complete(p, SCSS_BINARY_EXPRESSION); + } + + Present(left) +} + +#[inline] +fn parse_scss_unary_expression(p: &mut CssParser) -> ParsedSyntax { + if is_at_scss_unary_operator(p) { + let m = p.start(); + p.bump_ts(SCSS_UNARY_OPERATOR_TOKEN_SET); + parse_scss_unary_expression(p).or_add_diagnostic(p, expected_component_value); + return Present(m.complete(p, SCSS_UNARY_EXPRESSION)); + } + + parse_scss_primary_expression(p) +} + +#[inline] +fn parse_scss_primary_expression(p: &mut CssParser) -> ParsedSyntax { if p.at(T!['(']) { parse_scss_parenthesized_or_map_expression(p) } else { @@ -86,6 +148,31 @@ fn parse_scss_expression_item(p: &mut CssParser) -> ParsedSyntax { } } +/// Returns the precedence level for the current SCSS binary operator token. +/// +/// Docs: https://sass-lang.com/documentation/operators/#order-of-operations +#[inline] +fn scss_binary_precedence(p: &mut CssParser) -> Option { + if !p.at_ts(SCSS_BINARY_OPERATOR_TOKEN_SET) { + return None; + } + + Some(match p.cur() { + T![or] => 1, + T![and] => 2, + T![==] | T![!=] => 3, + T![<] | T![<=] | T![>] | T![>=] => 4, + T![+] | T![-] => 5, + T![*] | T![/] | T![%] => 6, + _ => return None, + }) +} + +#[inline] +fn is_at_scss_unary_operator(p: &mut CssParser) -> bool { + p.at_ts(SCSS_UNARY_OPERATOR_TOKEN_SET) +} + #[inline] fn parse_scss_parenthesized_or_map_expression(p: &mut CssParser) -> ParsedSyntax { if !p.at(T!['(']) { diff --git a/crates/biome_css_parser/src/syntax/scss/mod.rs b/crates/biome_css_parser/src/syntax/scss/mod.rs index a9b39a3d0974..9ee3ce89e144 100644 --- a/crates/biome_css_parser/src/syntax/scss/mod.rs +++ b/crates/biome_css_parser/src/syntax/scss/mod.rs @@ -16,7 +16,9 @@ pub(crate) use declaration::{ is_at_scss_declaration, is_at_scss_nesting_declaration, parse_scss_declaration, parse_scss_nesting_declaration, }; -pub(crate) use expression::parse_scss_expression; +pub(crate) use expression::{ + SCSS_UNARY_OPERATOR_TOKEN_SET, parse_scss_expression, parse_scss_expression_until, +}; #[inline] pub(crate) fn is_at_scss_identifier(p: &mut CssParser) -> bool { diff --git a/crates/biome_css_parser/src/syntax/value/function.rs b/crates/biome_css_parser/src/syntax/value/function.rs index a0ef82238287..07e90e00bbce 100644 --- a/crates/biome_css_parser/src/syntax/value/function.rs +++ b/crates/biome_css_parser/src/syntax/value/function.rs @@ -9,8 +9,8 @@ use crate::syntax::parse_error::{ }; use crate::syntax::property::parse_generic_component_value; use crate::syntax::scss::{ - is_at_scss_qualified_name, is_nth_at_scss_qualified_name, parse_scss_expression, - parse_scss_function_name, + SCSS_UNARY_OPERATOR_TOKEN_SET, is_at_scss_qualified_name, is_nth_at_scss_qualified_name, + parse_scss_expression, parse_scss_function_name, }; use crate::syntax::value::attr::{is_at_attr_function, parse_attr_function}; use crate::syntax::value::r#if::parse_if_function; @@ -232,7 +232,13 @@ pub(crate) fn parse_any_expression(p: &mut CssParser) -> ParsedSyntax { return Absent; } - let param = parse_unary_expression_operand(p); + let param = if CssSyntaxFeatures::Scss.is_supported(p) + && (is_at_parenthesized(p) || is_at_any_value(p) || p.at_ts(SCSS_UNARY_OPERATOR_TOKEN_SET)) + { + return parse_scss_expression(p); + } else { + parse_unary_expression_operand(p) + }; if is_at_binary_operator(p) { let binary_expression = param.precede(p); @@ -279,14 +285,9 @@ pub(crate) fn parse_unary_expression(p: &mut CssParser) -> ParsedSyntax { #[inline] fn parse_unary_expression_operand(p: &mut CssParser) -> ParsedSyntax { - let scss_enabled = CssSyntaxFeatures::Scss.is_supported(p); - if is_at_unary_operator(p) { parse_unary_expression(p) - } else if scss_enabled && (is_at_parenthesized(p) || is_at_any_value(p)) { - parse_scss_expression(p) - } else if !scss_enabled && is_at_parenthesized(p) { - // In SCSS mode, parenthesized values are consumed as SCSS expressions above. + } else if is_at_parenthesized(p) { parse_parenthesized_expression(p) } else if is_at_comma_separated_value(p) { parse_comma_separated_value(p) diff --git a/crates/biome_css_parser/tests/css_test_suite/error/scss/declaration/invalid-modifier.scss.snap b/crates/biome_css_parser/tests/css_test_suite/error/scss/declaration/invalid-modifier.scss.snap index 583cf1cb5d20..56207c9e3ee7 100644 --- a/crates/biome_css_parser/tests/css_test_suite/error/scss/declaration/invalid-modifier.scss.snap +++ b/crates/biome_css_parser/tests/css_test_suite/error/scss/declaration/invalid-modifier.scss.snap @@ -39,11 +39,13 @@ CssRoot { }, }, COLON@84..86 ":" [] [Whitespace(" ")], - CssGenericComponentValueList [ - CssIdentifier { - value_token: IDENT@86..90 "red" [] [Whitespace(" ")], - }, - ], + ScssExpression { + items: ScssExpressionItemList [ + CssIdentifier { + value_token: IDENT@86..90 "red" [] [Whitespace(" ")], + }, + ], + }, CssBogus { items: [ CssBogus { @@ -66,12 +68,14 @@ CssRoot { }, }, COLON@150..152 ":" [] [Whitespace(" ")], - CssGenericComponentValueList [ - CssRegularDimension { - value_token: CSS_NUMBER_LITERAL@152..155 "100" [] [], - unit_token: IDENT@155..158 "px" [] [Whitespace(" ")], - }, - ], + ScssExpression { + items: ScssExpressionItemList [ + CssRegularDimension { + value_token: CSS_NUMBER_LITERAL@152..155 "100" [] [], + unit_token: IDENT@155..158 "px" [] [Whitespace(" ")], + }, + ], + }, CssBogus { items: [ CssBogus { @@ -94,12 +98,14 @@ CssRoot { }, }, COLON@213..215 ":" [] [Whitespace(" ")], - CssGenericComponentValueList [ - CssRegularDimension { - value_token: CSS_NUMBER_LITERAL@215..217 "50" [] [], - unit_token: IDENT@217..220 "vh" [] [Whitespace(" ")], - }, - ], + ScssExpression { + items: ScssExpressionItemList [ + CssRegularDimension { + value_token: CSS_NUMBER_LITERAL@215..217 "50" [] [], + unit_token: IDENT@217..220 "vh" [] [Whitespace(" ")], + }, + ], + }, CssBogus { items: [ CssBogus { @@ -122,12 +128,14 @@ CssRoot { }, }, COLON@277..279 ":" [] [Whitespace(" ")], - CssGenericComponentValueList [ - CssRegularDimension { - value_token: CSS_NUMBER_LITERAL@279..281 "16" [] [], - unit_token: IDENT@281..284 "px" [] [Whitespace(" ")], - }, - ], + ScssExpression { + items: ScssExpressionItemList [ + CssRegularDimension { + value_token: CSS_NUMBER_LITERAL@279..281 "16" [] [], + unit_token: IDENT@281..284 "px" [] [Whitespace(" ")], + }, + ], + }, CssBogus { items: [ CssBogus { @@ -150,12 +158,14 @@ CssRoot { }, }, COLON@330..332 ":" [] [Whitespace(" ")], - CssGenericComponentValueList [ - CssRegularDimension { - value_token: CSS_NUMBER_LITERAL@332..334 "10" [] [], - unit_token: IDENT@334..337 "px" [] [Whitespace(" ")], - }, - ], + ScssExpression { + items: ScssExpressionItemList [ + CssRegularDimension { + value_token: CSS_NUMBER_LITERAL@332..334 "10" [] [], + unit_token: IDENT@334..337 "px" [] [Whitespace(" ")], + }, + ], + }, CssBogus { items: [ CssBogus { @@ -192,9 +202,10 @@ CssRoot { 1: CSS_IDENTIFIER@79..84 0: IDENT@79..84 "color" [] [] 1: COLON@84..86 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@86..90 - 0: CSS_IDENTIFIER@86..90 - 0: IDENT@86..90 "red" [] [Whitespace(" ")] + 2: SCSS_EXPRESSION@86..90 + 0: SCSS_EXPRESSION_ITEM_LIST@86..90 + 0: CSS_IDENTIFIER@86..90 + 0: IDENT@86..90 "red" [] [Whitespace(" ")] 3: CSS_BOGUS@90..100 0: CSS_BOGUS@90..100 0: BANG@90..91 "!" [] [] @@ -206,10 +217,11 @@ CssRoot { 1: CSS_IDENTIFIER@145..150 0: IDENT@145..150 "width" [] [] 1: COLON@150..152 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@152..158 - 0: CSS_REGULAR_DIMENSION@152..158 - 0: CSS_NUMBER_LITERAL@152..155 "100" [] [] - 1: IDENT@155..158 "px" [] [Whitespace(" ")] + 2: SCSS_EXPRESSION@152..158 + 0: SCSS_EXPRESSION_ITEM_LIST@152..158 + 0: CSS_REGULAR_DIMENSION@152..158 + 0: CSS_NUMBER_LITERAL@152..155 "100" [] [] + 1: IDENT@155..158 "px" [] [Whitespace(" ")] 3: CSS_BOGUS@158..165 0: CSS_BOGUS@158..165 0: BANG@158..159 "!" [] [] @@ -221,10 +233,11 @@ CssRoot { 1: CSS_IDENTIFIER@207..213 0: IDENT@207..213 "height" [] [] 1: COLON@213..215 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@215..220 - 0: CSS_REGULAR_DIMENSION@215..220 - 0: CSS_NUMBER_LITERAL@215..217 "50" [] [] - 1: IDENT@217..220 "vh" [] [Whitespace(" ")] + 2: SCSS_EXPRESSION@215..220 + 0: SCSS_EXPRESSION_ITEM_LIST@215..220 + 0: CSS_REGULAR_DIMENSION@215..220 + 0: CSS_NUMBER_LITERAL@215..217 "50" [] [] + 1: IDENT@217..220 "vh" [] [Whitespace(" ")] 3: CSS_BOGUS@220..227 0: CSS_BOGUS@220..227 0: BANG@220..221 "!" [] [] @@ -236,10 +249,11 @@ CssRoot { 1: CSS_IDENTIFIER@268..277 0: IDENT@268..277 "font-size" [] [] 1: COLON@277..279 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@279..284 - 0: CSS_REGULAR_DIMENSION@279..284 - 0: CSS_NUMBER_LITERAL@279..281 "16" [] [] - 1: IDENT@281..284 "px" [] [Whitespace(" ")] + 2: SCSS_EXPRESSION@279..284 + 0: SCSS_EXPRESSION_ITEM_LIST@279..284 + 0: CSS_REGULAR_DIMENSION@279..284 + 0: CSS_NUMBER_LITERAL@279..281 "16" [] [] + 1: IDENT@281..284 "px" [] [Whitespace(" ")] 3: CSS_BOGUS@284..290 0: CSS_BOGUS@284..290 0: BANG@284..285 "!" [] [] @@ -251,10 +265,11 @@ CssRoot { 1: CSS_IDENTIFIER@324..330 0: IDENT@324..330 "margin" [] [] 1: COLON@330..332 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@332..337 - 0: CSS_REGULAR_DIMENSION@332..337 - 0: CSS_NUMBER_LITERAL@332..334 "10" [] [] - 1: IDENT@334..337 "px" [] [Whitespace(" ")] + 2: SCSS_EXPRESSION@332..337 + 0: SCSS_EXPRESSION_ITEM_LIST@332..337 + 0: CSS_REGULAR_DIMENSION@332..337 + 0: CSS_NUMBER_LITERAL@332..334 "10" [] [] + 1: IDENT@334..337 "px" [] [Whitespace(" ")] 3: CSS_BOGUS@337..352 0: CSS_BOGUS@337..344 0: BANG@337..338 "!" [] [] diff --git a/crates/biome_css_parser/tests/css_test_suite/error/scss/declaration/missing-modifier.scss.snap b/crates/biome_css_parser/tests/css_test_suite/error/scss/declaration/missing-modifier.scss.snap index d390e8a0b856..97aab5fe59b2 100644 --- a/crates/biome_css_parser/tests/css_test_suite/error/scss/declaration/missing-modifier.scss.snap +++ b/crates/biome_css_parser/tests/css_test_suite/error/scss/declaration/missing-modifier.scss.snap @@ -32,11 +32,13 @@ CssRoot { }, }, colon_token: COLON@42..44 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssIdentifier { - value_token: IDENT@44..48 "red" [] [Whitespace(" ")], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssIdentifier { + value_token: IDENT@44..48 "red" [] [Whitespace(" ")], + }, + ], + }, modifiers: ScssVariableModifierList [ ScssVariableModifier { excl_token: BANG@48..49 "!" [] [], @@ -53,12 +55,14 @@ CssRoot { }, }, colon_token: COLON@105..107 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssRegularDimension { - value_token: CSS_NUMBER_LITERAL@107..110 "100" [] [], - unit_token: IDENT@110..113 "px" [] [Whitespace(" ")], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssRegularDimension { + value_token: CSS_NUMBER_LITERAL@107..110 "100" [] [], + unit_token: IDENT@110..113 "px" [] [Whitespace(" ")], + }, + ], + }, modifiers: ScssVariableModifierList [ ScssVariableModifier { excl_token: BANG@113..115 "!" [] [Whitespace(" ")], @@ -75,12 +79,14 @@ CssRoot { }, }, colon_token: COLON@156..158 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssRegularDimension { - value_token: CSS_NUMBER_LITERAL@158..160 "50" [] [], - unit_token: IDENT@160..163 "vh" [] [Whitespace(" ")], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssRegularDimension { + value_token: CSS_NUMBER_LITERAL@158..160 "50" [] [], + unit_token: IDENT@160..163 "vh" [] [Whitespace(" ")], + }, + ], + }, modifiers: ScssVariableModifierList [ ScssVariableModifier { excl_token: BANG@163..164 "!" [] [], @@ -106,9 +112,10 @@ CssRoot { 1: CSS_IDENTIFIER@37..42 0: IDENT@37..42 "color" [] [] 1: COLON@42..44 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@44..48 - 0: CSS_IDENTIFIER@44..48 - 0: IDENT@44..48 "red" [] [Whitespace(" ")] + 2: SCSS_EXPRESSION@44..48 + 0: SCSS_EXPRESSION_ITEM_LIST@44..48 + 0: CSS_IDENTIFIER@44..48 + 0: IDENT@44..48 "red" [] [Whitespace(" ")] 3: SCSS_VARIABLE_MODIFIER_LIST@48..49 0: SCSS_VARIABLE_MODIFIER@48..49 0: BANG@48..49 "!" [] [] @@ -120,10 +127,11 @@ CssRoot { 1: CSS_IDENTIFIER@100..105 0: IDENT@100..105 "width" [] [] 1: COLON@105..107 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@107..113 - 0: CSS_REGULAR_DIMENSION@107..113 - 0: CSS_NUMBER_LITERAL@107..110 "100" [] [] - 1: IDENT@110..113 "px" [] [Whitespace(" ")] + 2: SCSS_EXPRESSION@107..113 + 0: SCSS_EXPRESSION_ITEM_LIST@107..113 + 0: CSS_REGULAR_DIMENSION@107..113 + 0: CSS_NUMBER_LITERAL@107..110 "100" [] [] + 1: IDENT@110..113 "px" [] [Whitespace(" ")] 3: SCSS_VARIABLE_MODIFIER_LIST@113..115 0: SCSS_VARIABLE_MODIFIER@113..115 0: BANG@113..115 "!" [] [Whitespace(" ")] @@ -135,10 +143,11 @@ CssRoot { 1: CSS_IDENTIFIER@150..156 0: IDENT@150..156 "height" [] [] 1: COLON@156..158 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@158..163 - 0: CSS_REGULAR_DIMENSION@158..163 - 0: CSS_NUMBER_LITERAL@158..160 "50" [] [] - 1: IDENT@160..163 "vh" [] [Whitespace(" ")] + 2: SCSS_EXPRESSION@158..163 + 0: SCSS_EXPRESSION_ITEM_LIST@158..163 + 0: CSS_REGULAR_DIMENSION@158..163 + 0: CSS_NUMBER_LITERAL@158..160 "50" [] [] + 1: IDENT@160..163 "vh" [] [Whitespace(" ")] 3: SCSS_VARIABLE_MODIFIER_LIST@163..164 0: SCSS_VARIABLE_MODIFIER@163..164 0: BANG@163..164 "!" [] [] diff --git a/crates/biome_css_parser/tests/css_test_suite/error/scss/value/bracketed-mixed-separators.scss.snap b/crates/biome_css_parser/tests/css_test_suite/error/scss/value/bracketed-mixed-separators.scss.snap index e3b36e9da1c8..577a984446e7 100644 --- a/crates/biome_css_parser/tests/css_test_suite/error/scss/value/bracketed-mixed-separators.scss.snap +++ b/crates/biome_css_parser/tests/css_test_suite/error/scss/value/bracketed-mixed-separators.scss.snap @@ -26,29 +26,31 @@ CssRoot { }, }, colon_token: COLON@5..7 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssBracketedValue { - l_brack_token: L_BRACK@7..8 "[" [] [], - items: CssBracketedValueList [ - CssCustomIdentifier { - value_token: IDENT@8..9 "a" [] [], - }, - CssGenericDelimiter { - value: COMMA@9..11 "," [] [Whitespace(" ")], - }, - CssCustomIdentifier { - value_token: IDENT@11..13 "b" [] [Whitespace(" ")], - }, - CssGenericDelimiter { - value: SLASH@13..15 "/" [] [Whitespace(" ")], - }, - CssCustomIdentifier { - value_token: IDENT@15..16 "c" [] [], - }, - ], - r_brack_token: R_BRACK@16..17 "]" [] [], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssBracketedValue { + l_brack_token: L_BRACK@7..8 "[" [] [], + items: CssBracketedValueList [ + CssCustomIdentifier { + value_token: IDENT@8..9 "a" [] [], + }, + CssGenericDelimiter { + value: COMMA@9..11 "," [] [Whitespace(" ")], + }, + CssCustomIdentifier { + value_token: IDENT@11..13 "b" [] [Whitespace(" ")], + }, + CssGenericDelimiter { + value: SLASH@13..15 "/" [] [Whitespace(" ")], + }, + CssCustomIdentifier { + value_token: IDENT@15..16 "c" [] [], + }, + ], + r_brack_token: R_BRACK@16..17 "]" [] [], + }, + ], + }, modifiers: ScssVariableModifierList [], semicolon_token: SEMICOLON@17..18 ";" [] [], }, @@ -60,29 +62,31 @@ CssRoot { }, }, colon_token: COLON@30..32 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssBracketedValue { - l_brack_token: L_BRACK@32..33 "[" [] [], - items: CssBracketedValueList [ - CssCustomIdentifier { - value_token: IDENT@33..35 "x" [] [Whitespace(" ")], - }, - CssGenericDelimiter { - value: SLASH@35..37 "/" [] [Whitespace(" ")], - }, - CssCustomIdentifier { - value_token: IDENT@37..38 "y" [] [], - }, - CssGenericDelimiter { - value: COMMA@38..40 "," [] [Whitespace(" ")], - }, - CssCustomIdentifier { - value_token: IDENT@40..41 "z" [] [], - }, - ], - r_brack_token: R_BRACK@41..42 "]" [] [], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssBracketedValue { + l_brack_token: L_BRACK@32..33 "[" [] [], + items: CssBracketedValueList [ + CssCustomIdentifier { + value_token: IDENT@33..35 "x" [] [Whitespace(" ")], + }, + CssGenericDelimiter { + value: SLASH@35..37 "/" [] [Whitespace(" ")], + }, + CssCustomIdentifier { + value_token: IDENT@37..38 "y" [] [], + }, + CssGenericDelimiter { + value: COMMA@38..40 "," [] [Whitespace(" ")], + }, + CssCustomIdentifier { + value_token: IDENT@40..41 "z" [] [], + }, + ], + r_brack_token: R_BRACK@41..42 "]" [] [], + }, + ], + }, modifiers: ScssVariableModifierList [], semicolon_token: SEMICOLON@42..43 ";" [] [], }, @@ -103,21 +107,22 @@ CssRoot { 1: CSS_IDENTIFIER@1..5 0: IDENT@1..5 "list" [] [] 1: COLON@5..7 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@7..17 - 0: CSS_BRACKETED_VALUE@7..17 - 0: L_BRACK@7..8 "[" [] [] - 1: CSS_BRACKETED_VALUE_LIST@8..16 - 0: CSS_CUSTOM_IDENTIFIER@8..9 - 0: IDENT@8..9 "a" [] [] - 1: CSS_GENERIC_DELIMITER@9..11 - 0: COMMA@9..11 "," [] [Whitespace(" ")] - 2: CSS_CUSTOM_IDENTIFIER@11..13 - 0: IDENT@11..13 "b" [] [Whitespace(" ")] - 3: CSS_GENERIC_DELIMITER@13..15 - 0: SLASH@13..15 "/" [] [Whitespace(" ")] - 4: CSS_CUSTOM_IDENTIFIER@15..16 - 0: IDENT@15..16 "c" [] [] - 2: R_BRACK@16..17 "]" [] [] + 2: SCSS_EXPRESSION@7..17 + 0: SCSS_EXPRESSION_ITEM_LIST@7..17 + 0: CSS_BRACKETED_VALUE@7..17 + 0: L_BRACK@7..8 "[" [] [] + 1: CSS_BRACKETED_VALUE_LIST@8..16 + 0: CSS_CUSTOM_IDENTIFIER@8..9 + 0: IDENT@8..9 "a" [] [] + 1: CSS_GENERIC_DELIMITER@9..11 + 0: COMMA@9..11 "," [] [Whitespace(" ")] + 2: CSS_CUSTOM_IDENTIFIER@11..13 + 0: IDENT@11..13 "b" [] [Whitespace(" ")] + 3: CSS_GENERIC_DELIMITER@13..15 + 0: SLASH@13..15 "/" [] [Whitespace(" ")] + 4: CSS_CUSTOM_IDENTIFIER@15..16 + 0: IDENT@15..16 "c" [] [] + 2: R_BRACK@16..17 "]" [] [] 3: SCSS_VARIABLE_MODIFIER_LIST@17..17 4: SEMICOLON@17..18 ";" [] [] 1: SCSS_DECLARATION@18..43 @@ -126,21 +131,22 @@ CssRoot { 1: CSS_IDENTIFIER@20..30 0: IDENT@20..30 "also_mixed" [] [] 1: COLON@30..32 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@32..42 - 0: CSS_BRACKETED_VALUE@32..42 - 0: L_BRACK@32..33 "[" [] [] - 1: CSS_BRACKETED_VALUE_LIST@33..41 - 0: CSS_CUSTOM_IDENTIFIER@33..35 - 0: IDENT@33..35 "x" [] [Whitespace(" ")] - 1: CSS_GENERIC_DELIMITER@35..37 - 0: SLASH@35..37 "/" [] [Whitespace(" ")] - 2: CSS_CUSTOM_IDENTIFIER@37..38 - 0: IDENT@37..38 "y" [] [] - 3: CSS_GENERIC_DELIMITER@38..40 - 0: COMMA@38..40 "," [] [Whitespace(" ")] - 4: CSS_CUSTOM_IDENTIFIER@40..41 - 0: IDENT@40..41 "z" [] [] - 2: R_BRACK@41..42 "]" [] [] + 2: SCSS_EXPRESSION@32..42 + 0: SCSS_EXPRESSION_ITEM_LIST@32..42 + 0: CSS_BRACKETED_VALUE@32..42 + 0: L_BRACK@32..33 "[" [] [] + 1: CSS_BRACKETED_VALUE_LIST@33..41 + 0: CSS_CUSTOM_IDENTIFIER@33..35 + 0: IDENT@33..35 "x" [] [Whitespace(" ")] + 1: CSS_GENERIC_DELIMITER@35..37 + 0: SLASH@35..37 "/" [] [Whitespace(" ")] + 2: CSS_CUSTOM_IDENTIFIER@37..38 + 0: IDENT@37..38 "y" [] [] + 3: CSS_GENERIC_DELIMITER@38..40 + 0: COMMA@38..40 "," [] [Whitespace(" ")] + 4: CSS_CUSTOM_IDENTIFIER@40..41 + 0: IDENT@40..41 "z" [] [] + 2: R_BRACK@41..42 "]" [] [] 3: SCSS_VARIABLE_MODIFIER_LIST@42..42 4: SEMICOLON@42..43 ";" [] [] 2: EOF@43..44 "" [Newline("\n")] [] diff --git a/crates/biome_css_parser/tests/css_test_suite/error/scss/value/bracketed-recovery-separators.scss.snap b/crates/biome_css_parser/tests/css_test_suite/error/scss/value/bracketed-recovery-separators.scss.snap index dcd582bfeb69..0d5486d8abba 100644 --- a/crates/biome_css_parser/tests/css_test_suite/error/scss/value/bracketed-recovery-separators.scss.snap +++ b/crates/biome_css_parser/tests/css_test_suite/error/scss/value/bracketed-recovery-separators.scss.snap @@ -26,37 +26,39 @@ CssRoot { }, }, colon_token: COLON@11..13 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssBracketedValue { - l_brack_token: L_BRACK@13..14 "[" [] [], - items: CssBracketedValueList [ - CssCustomIdentifier { - value_token: IDENT@14..15 "a" [] [], - }, - CssGenericDelimiter { - value: COMMA@15..17 "," [] [Whitespace(" ")], - }, - CssBogusCustomIdentifier { - items: [ - CSS_NUMBER_LITERAL@17..18 "1" [] [], - ], - }, - CssGenericDelimiter { - value: COMMA@18..20 "," [] [Whitespace(" ")], - }, - CssCustomIdentifier { - value_token: IDENT@20..21 "b" [] [], - }, - CssGenericDelimiter { - value: COMMA@21..23 "," [] [Whitespace(" ")], - }, - CssCustomIdentifier { - value_token: IDENT@23..24 "c" [] [], - }, - ], - r_brack_token: R_BRACK@24..25 "]" [] [], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssBracketedValue { + l_brack_token: L_BRACK@13..14 "[" [] [], + items: CssBracketedValueList [ + CssCustomIdentifier { + value_token: IDENT@14..15 "a" [] [], + }, + CssGenericDelimiter { + value: COMMA@15..17 "," [] [Whitespace(" ")], + }, + CssBogusCustomIdentifier { + items: [ + CSS_NUMBER_LITERAL@17..18 "1" [] [], + ], + }, + CssGenericDelimiter { + value: COMMA@18..20 "," [] [Whitespace(" ")], + }, + CssCustomIdentifier { + value_token: IDENT@20..21 "b" [] [], + }, + CssGenericDelimiter { + value: COMMA@21..23 "," [] [Whitespace(" ")], + }, + CssCustomIdentifier { + value_token: IDENT@23..24 "c" [] [], + }, + ], + r_brack_token: R_BRACK@24..25 "]" [] [], + }, + ], + }, modifiers: ScssVariableModifierList [], semicolon_token: SEMICOLON@25..26 ";" [] [], }, @@ -68,37 +70,39 @@ CssRoot { }, }, colon_token: COLON@38..40 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssBracketedValue { - l_brack_token: L_BRACK@40..41 "[" [] [], - items: CssBracketedValueList [ - CssCustomIdentifier { - value_token: IDENT@41..43 "x" [] [Whitespace(" ")], - }, - CssGenericDelimiter { - value: SLASH@43..45 "/" [] [Whitespace(" ")], - }, - CssBogusCustomIdentifier { - items: [ - CSS_NUMBER_LITERAL@45..47 "2" [] [Whitespace(" ")], - ], - }, - CssGenericDelimiter { - value: SLASH@47..49 "/" [] [Whitespace(" ")], - }, - CssCustomIdentifier { - value_token: IDENT@49..51 "y" [] [Whitespace(" ")], - }, - CssGenericDelimiter { - value: SLASH@51..53 "/" [] [Whitespace(" ")], - }, - CssCustomIdentifier { - value_token: IDENT@53..54 "z" [] [], - }, - ], - r_brack_token: R_BRACK@54..55 "]" [] [], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssBracketedValue { + l_brack_token: L_BRACK@40..41 "[" [] [], + items: CssBracketedValueList [ + CssCustomIdentifier { + value_token: IDENT@41..43 "x" [] [Whitespace(" ")], + }, + CssGenericDelimiter { + value: SLASH@43..45 "/" [] [Whitespace(" ")], + }, + CssBogusCustomIdentifier { + items: [ + CSS_NUMBER_LITERAL@45..47 "2" [] [Whitespace(" ")], + ], + }, + CssGenericDelimiter { + value: SLASH@47..49 "/" [] [Whitespace(" ")], + }, + CssCustomIdentifier { + value_token: IDENT@49..51 "y" [] [Whitespace(" ")], + }, + CssGenericDelimiter { + value: SLASH@51..53 "/" [] [Whitespace(" ")], + }, + CssCustomIdentifier { + value_token: IDENT@53..54 "z" [] [], + }, + ], + r_brack_token: R_BRACK@54..55 "]" [] [], + }, + ], + }, modifiers: ScssVariableModifierList [], semicolon_token: SEMICOLON@55..56 ";" [] [], }, @@ -119,25 +123,26 @@ CssRoot { 1: CSS_IDENTIFIER@1..11 0: IDENT@1..11 "comma_list" [] [] 1: COLON@11..13 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@13..25 - 0: CSS_BRACKETED_VALUE@13..25 - 0: L_BRACK@13..14 "[" [] [] - 1: CSS_BRACKETED_VALUE_LIST@14..24 - 0: CSS_CUSTOM_IDENTIFIER@14..15 - 0: IDENT@14..15 "a" [] [] - 1: CSS_GENERIC_DELIMITER@15..17 - 0: COMMA@15..17 "," [] [Whitespace(" ")] - 2: CSS_BOGUS_CUSTOM_IDENTIFIER@17..18 - 0: CSS_NUMBER_LITERAL@17..18 "1" [] [] - 3: CSS_GENERIC_DELIMITER@18..20 - 0: COMMA@18..20 "," [] [Whitespace(" ")] - 4: CSS_CUSTOM_IDENTIFIER@20..21 - 0: IDENT@20..21 "b" [] [] - 5: CSS_GENERIC_DELIMITER@21..23 - 0: COMMA@21..23 "," [] [Whitespace(" ")] - 6: CSS_CUSTOM_IDENTIFIER@23..24 - 0: IDENT@23..24 "c" [] [] - 2: R_BRACK@24..25 "]" [] [] + 2: SCSS_EXPRESSION@13..25 + 0: SCSS_EXPRESSION_ITEM_LIST@13..25 + 0: CSS_BRACKETED_VALUE@13..25 + 0: L_BRACK@13..14 "[" [] [] + 1: CSS_BRACKETED_VALUE_LIST@14..24 + 0: CSS_CUSTOM_IDENTIFIER@14..15 + 0: IDENT@14..15 "a" [] [] + 1: CSS_GENERIC_DELIMITER@15..17 + 0: COMMA@15..17 "," [] [Whitespace(" ")] + 2: CSS_BOGUS_CUSTOM_IDENTIFIER@17..18 + 0: CSS_NUMBER_LITERAL@17..18 "1" [] [] + 3: CSS_GENERIC_DELIMITER@18..20 + 0: COMMA@18..20 "," [] [Whitespace(" ")] + 4: CSS_CUSTOM_IDENTIFIER@20..21 + 0: IDENT@20..21 "b" [] [] + 5: CSS_GENERIC_DELIMITER@21..23 + 0: COMMA@21..23 "," [] [Whitespace(" ")] + 6: CSS_CUSTOM_IDENTIFIER@23..24 + 0: IDENT@23..24 "c" [] [] + 2: R_BRACK@24..25 "]" [] [] 3: SCSS_VARIABLE_MODIFIER_LIST@25..25 4: SEMICOLON@25..26 ";" [] [] 1: SCSS_DECLARATION@26..56 @@ -146,25 +151,26 @@ CssRoot { 1: CSS_IDENTIFIER@28..38 0: IDENT@28..38 "slash_list" [] [] 1: COLON@38..40 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@40..55 - 0: CSS_BRACKETED_VALUE@40..55 - 0: L_BRACK@40..41 "[" [] [] - 1: CSS_BRACKETED_VALUE_LIST@41..54 - 0: CSS_CUSTOM_IDENTIFIER@41..43 - 0: IDENT@41..43 "x" [] [Whitespace(" ")] - 1: CSS_GENERIC_DELIMITER@43..45 - 0: SLASH@43..45 "/" [] [Whitespace(" ")] - 2: CSS_BOGUS_CUSTOM_IDENTIFIER@45..47 - 0: CSS_NUMBER_LITERAL@45..47 "2" [] [Whitespace(" ")] - 3: CSS_GENERIC_DELIMITER@47..49 - 0: SLASH@47..49 "/" [] [Whitespace(" ")] - 4: CSS_CUSTOM_IDENTIFIER@49..51 - 0: IDENT@49..51 "y" [] [Whitespace(" ")] - 5: CSS_GENERIC_DELIMITER@51..53 - 0: SLASH@51..53 "/" [] [Whitespace(" ")] - 6: CSS_CUSTOM_IDENTIFIER@53..54 - 0: IDENT@53..54 "z" [] [] - 2: R_BRACK@54..55 "]" [] [] + 2: SCSS_EXPRESSION@40..55 + 0: SCSS_EXPRESSION_ITEM_LIST@40..55 + 0: CSS_BRACKETED_VALUE@40..55 + 0: L_BRACK@40..41 "[" [] [] + 1: CSS_BRACKETED_VALUE_LIST@41..54 + 0: CSS_CUSTOM_IDENTIFIER@41..43 + 0: IDENT@41..43 "x" [] [Whitespace(" ")] + 1: CSS_GENERIC_DELIMITER@43..45 + 0: SLASH@43..45 "/" [] [Whitespace(" ")] + 2: CSS_BOGUS_CUSTOM_IDENTIFIER@45..47 + 0: CSS_NUMBER_LITERAL@45..47 "2" [] [Whitespace(" ")] + 3: CSS_GENERIC_DELIMITER@47..49 + 0: SLASH@47..49 "/" [] [Whitespace(" ")] + 4: CSS_CUSTOM_IDENTIFIER@49..51 + 0: IDENT@49..51 "y" [] [Whitespace(" ")] + 5: CSS_GENERIC_DELIMITER@51..53 + 0: SLASH@51..53 "/" [] [Whitespace(" ")] + 6: CSS_CUSTOM_IDENTIFIER@53..54 + 0: IDENT@53..54 "z" [] [] + 2: R_BRACK@54..55 "]" [] [] 3: SCSS_VARIABLE_MODIFIER_LIST@55..55 4: SEMICOLON@55..56 ";" [] [] 2: EOF@56..57 "" [Newline("\n")] [] diff --git a/crates/biome_css_parser/tests/css_test_suite/error/scss/value/colon-value.scss.snap b/crates/biome_css_parser/tests/css_test_suite/error/scss/value/colon-value.scss.snap index 3d8a764c989f..94f4c31536b7 100644 --- a/crates/biome_css_parser/tests/css_test_suite/error/scss/value/colon-value.scss.snap +++ b/crates/biome_css_parser/tests/css_test_suite/error/scss/value/colon-value.scss.snap @@ -1,6 +1,5 @@ --- source: crates/biome_css_parser/tests/spec_test.rs -assertion_line: 208 expression: snapshot --- @@ -29,9 +28,13 @@ CssRoot { COLON@4..6 ":" [] [Whitespace(" ")], CssBogus { items: [ - CssBogusPropertyValue { + CssBogus { items: [ - COLON@6..7 ":" [] [], + CssBogusPropertyValue { + items: [ + COLON@6..7 ":" [] [], + ], + }, ], }, ], @@ -58,8 +61,9 @@ CssRoot { 0: IDENT@1..4 "sep" [] [] 1: COLON@4..6 ":" [] [Whitespace(" ")] 2: CSS_BOGUS@6..7 - 0: CSS_BOGUS_PROPERTY_VALUE@6..7 - 0: COLON@6..7 ":" [] [] + 0: CSS_BOGUS@6..7 + 0: CSS_BOGUS_PROPERTY_VALUE@6..7 + 0: COLON@6..7 ":" [] [] 3: SCSS_VARIABLE_MODIFIER_LIST@7..7 4: SEMICOLON@7..8 ";" [] [] 2: EOF@8..9 "" [Newline("\n")] [] @@ -71,20 +75,16 @@ CssRoot { ``` colon-value.scss:1:7 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - × Unexpected value or character. + × Expected a SCSS expression but instead found ':'. > 1 │ $sep: :; │ ^ 2 │ - i Expected one of: + i Expected a SCSS expression here. - - identifier - - string - - number - - dimension - - ratio - - custom property - - function + > 1 │ $sep: :; + │ ^ + 2 │ ``` diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/page.scss.snap b/crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/page.scss.snap index 1f5e484fe0d0..012eb2dc3c00 100644 --- a/crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/page.scss.snap +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/page.scss.snap @@ -1,8 +1,8 @@ --- source: crates/biome_css_parser/tests/spec_test.rs -assertion_line: 208 expression: snapshot --- + ## Input ```css @@ -57,12 +57,14 @@ CssRoot { }, }, colon_token: COLON@24..26 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssRegularDimension { - value_token: CSS_NUMBER_LITERAL@26..28 "12" [] [], - unit_token: IDENT@28..31 "px" [] [Whitespace(" ")], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssRegularDimension { + value_token: CSS_NUMBER_LITERAL@26..28 "12" [] [], + unit_token: IDENT@28..31 "px" [] [Whitespace(" ")], + }, + ], + }, modifiers: ScssVariableModifierList [ ScssVariableModifier { excl_token: BANG@31..32 "!" [] [], @@ -136,12 +138,14 @@ CssRoot { }, }, colon_token: COLON@119..121 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssRegularDimension { - value_token: CSS_NUMBER_LITERAL@121..122 "4" [] [], - unit_token: IDENT@122..125 "px" [] [Whitespace(" ")], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssRegularDimension { + value_token: CSS_NUMBER_LITERAL@121..122 "4" [] [], + unit_token: IDENT@122..125 "px" [] [Whitespace(" ")], + }, + ], + }, modifiers: ScssVariableModifierList [ ScssVariableModifier { excl_token: BANG@125..126 "!" [] [], @@ -211,10 +215,11 @@ CssRoot { 1: CSS_IDENTIFIER@17..24 0: IDENT@17..24 "padding" [] [] 1: COLON@24..26 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@26..31 - 0: CSS_REGULAR_DIMENSION@26..31 - 0: CSS_NUMBER_LITERAL@26..28 "12" [] [] - 1: IDENT@28..31 "px" [] [Whitespace(" ")] + 2: SCSS_EXPRESSION@26..31 + 0: SCSS_EXPRESSION_ITEM_LIST@26..31 + 0: CSS_REGULAR_DIMENSION@26..31 + 0: CSS_NUMBER_LITERAL@26..28 "12" [] [] + 1: IDENT@28..31 "px" [] [Whitespace(" ")] 3: SCSS_VARIABLE_MODIFIER_LIST@31..39 0: SCSS_VARIABLE_MODIFIER@31..39 0: BANG@31..32 "!" [] [] @@ -266,10 +271,11 @@ CssRoot { 1: CSS_IDENTIFIER@113..119 0: IDENT@113..119 "margin" [] [] 1: COLON@119..121 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@121..125 - 0: CSS_REGULAR_DIMENSION@121..125 - 0: CSS_NUMBER_LITERAL@121..122 "4" [] [] - 1: IDENT@122..125 "px" [] [Whitespace(" ")] + 2: SCSS_EXPRESSION@121..125 + 0: SCSS_EXPRESSION_ITEM_LIST@121..125 + 0: CSS_REGULAR_DIMENSION@121..125 + 0: CSS_NUMBER_LITERAL@121..122 "4" [] [] + 1: IDENT@122..125 "px" [] [Whitespace(" ")] 3: SCSS_VARIABLE_MODIFIER_LIST@125..132 0: SCSS_VARIABLE_MODIFIER@125..132 0: BANG@125..126 "!" [] [] diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/comment/multiline.scss.snap b/crates/biome_css_parser/tests/css_test_suite/ok/scss/comment/multiline.scss.snap index 25c91e85afb9..e3038d134379 100644 --- a/crates/biome_css_parser/tests/css_test_suite/ok/scss/comment/multiline.scss.snap +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/comment/multiline.scss.snap @@ -62,11 +62,13 @@ CssRoot { }, }, colon_token: COLON@60..62 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssIdentifier { - value_token: IDENT@62..67 "value" [] [], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssIdentifier { + value_token: IDENT@62..67 "value" [] [], + }, + ], + }, modifiers: ScssVariableModifierList [], semicolon_token: SEMICOLON@67..68 ";" [] [], }, @@ -117,11 +119,13 @@ CssRoot { }, }, colon_token: COLON@204..206 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssIdentifier { - value_token: IDENT@206..210 "blue" [] [], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssIdentifier { + value_token: IDENT@206..210 "blue" [] [], + }, + ], + }, modifiers: ScssVariableModifierList [], semicolon_token: SEMICOLON@210..211 ";" [] [], }, @@ -133,11 +137,13 @@ CssRoot { }, }, colon_token: COLON@247..249 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssIdentifier { - value_token: IDENT@249..253 "true" [] [], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssIdentifier { + value_token: IDENT@249..253 "true" [] [], + }, + ], + }, modifiers: ScssVariableModifierList [], semicolon_token: SEMICOLON@253..254 ";" [] [], }, @@ -188,12 +194,14 @@ CssRoot { }, }, colon_token: COLON@405..407 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssRegularDimension { - value_token: CSS_NUMBER_LITERAL@407..409 "10" [] [], - unit_token: IDENT@409..411 "px" [] [], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssRegularDimension { + value_token: CSS_NUMBER_LITERAL@407..409 "10" [] [], + unit_token: IDENT@409..411 "px" [] [], + }, + ], + }, modifiers: ScssVariableModifierList [], semicolon_token: SEMICOLON@411..412 ";" [] [], }, @@ -250,9 +258,10 @@ CssRoot { 1: CSS_IDENTIFIER@57..60 0: IDENT@57..60 "var" [] [] 1: COLON@60..62 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@62..67 - 0: CSS_IDENTIFIER@62..67 - 0: IDENT@62..67 "value" [] [] + 2: SCSS_EXPRESSION@62..67 + 0: SCSS_EXPRESSION_ITEM_LIST@62..67 + 0: CSS_IDENTIFIER@62..67 + 0: IDENT@62..67 "value" [] [] 3: SCSS_VARIABLE_MODIFIER_LIST@67..67 4: SEMICOLON@67..68 ";" [] [] 1: CSS_QUALIFIED_RULE@68..122 @@ -286,9 +295,10 @@ CssRoot { 1: CSS_IDENTIFIER@193..204 0: IDENT@193..204 "another-var" [] [] 1: COLON@204..206 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@206..210 - 0: CSS_IDENTIFIER@206..210 - 0: IDENT@206..210 "blue" [] [] + 2: SCSS_EXPRESSION@206..210 + 0: SCSS_EXPRESSION_ITEM_LIST@206..210 + 0: CSS_IDENTIFIER@206..210 + 0: IDENT@206..210 "blue" [] [] 3: SCSS_VARIABLE_MODIFIER_LIST@210..210 4: SEMICOLON@210..211 ";" [] [] 3: SCSS_DECLARATION@211..254 @@ -297,9 +307,10 @@ CssRoot { 1: CSS_IDENTIFIER@235..247 0: IDENT@235..247 "line-comment" [] [] 1: COLON@247..249 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@249..253 - 0: CSS_IDENTIFIER@249..253 - 0: IDENT@249..253 "true" [] [] + 2: SCSS_EXPRESSION@249..253 + 0: SCSS_EXPRESSION_ITEM_LIST@249..253 + 0: CSS_IDENTIFIER@249..253 + 0: IDENT@249..253 "true" [] [] 3: SCSS_VARIABLE_MODIFIER_LIST@253..253 4: SEMICOLON@253..254 ";" [] [] 4: CSS_QUALIFIED_RULE@254..351 @@ -333,10 +344,11 @@ CssRoot { 1: CSS_IDENTIFIER@398..405 0: IDENT@398..405 "special" [] [] 1: COLON@405..407 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@407..411 - 0: CSS_REGULAR_DIMENSION@407..411 - 0: CSS_NUMBER_LITERAL@407..409 "10" [] [] - 1: IDENT@409..411 "px" [] [] + 2: SCSS_EXPRESSION@407..411 + 0: SCSS_EXPRESSION_ITEM_LIST@407..411 + 0: CSS_REGULAR_DIMENSION@407..411 + 0: CSS_NUMBER_LITERAL@407..409 "10" [] [] + 1: IDENT@409..411 "px" [] [] 3: SCSS_VARIABLE_MODIFIER_LIST@411..411 4: SEMICOLON@411..412 ";" [] [] 6: CSS_AT_RULE@412..508 diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/comment/nested.scss.snap b/crates/biome_css_parser/tests/css_test_suite/ok/scss/comment/nested.scss.snap index 70eee8da1562..d44e90c3e8a7 100644 --- a/crates/biome_css_parser/tests/css_test_suite/ok/scss/comment/nested.scss.snap +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/comment/nested.scss.snap @@ -127,11 +127,13 @@ CssRoot { }, }, colon_token: COLON@237..239 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssIdentifier { - value_token: IDENT@239..244 "value" [] [], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssIdentifier { + value_token: IDENT@239..244 "value" [] [], + }, + ], + }, modifiers: ScssVariableModifierList [], semicolon_token: SEMICOLON@244..245 ";" [] [], }, @@ -241,9 +243,10 @@ CssRoot { 1: CSS_IDENTIFIER@234..237 0: IDENT@234..237 "var" [] [] 1: COLON@237..239 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@239..244 - 0: CSS_IDENTIFIER@239..244 - 0: IDENT@239..244 "value" [] [] + 2: SCSS_EXPRESSION@239..244 + 0: SCSS_EXPRESSION_ITEM_LIST@239..244 + 0: CSS_IDENTIFIER@239..244 + 0: IDENT@239..244 "value" [] [] 3: SCSS_VARIABLE_MODIFIER_LIST@244..244 4: SEMICOLON@244..245 ";" [] [] 3: CSS_QUALIFIED_RULE@245..327 diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/global-flag.scss.snap b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/global-flag.scss.snap index 1d844ac398ac..ed4d85ded24d 100644 --- a/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/global-flag.scss.snap +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/global-flag.scss.snap @@ -43,11 +43,13 @@ CssRoot { }, }, colon_token: COLON@32..34 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssIdentifier { - value_token: IDENT@34..41 "initial" [] [], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssIdentifier { + value_token: IDENT@34..41 "initial" [] [], + }, + ], + }, modifiers: ScssVariableModifierList [], semicolon_token: SEMICOLON@41..42 ";" [] [], }, @@ -77,11 +79,13 @@ CssRoot { }, }, colon_token: COLON@100..102 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssIdentifier { - value_token: IDENT@102..111 "modified" [] [Whitespace(" ")], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssIdentifier { + value_token: IDENT@102..111 "modified" [] [Whitespace(" ")], + }, + ], + }, modifiers: ScssVariableModifierList [ ScssVariableModifier { excl_token: BANG@111..112 "!" [] [], @@ -98,11 +102,13 @@ CssRoot { }, }, colon_token: COLON@155..157 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssIdentifier { - value_token: IDENT@157..163 "value" [] [Whitespace(" ")], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssIdentifier { + value_token: IDENT@157..163 "value" [] [Whitespace(" ")], + }, + ], + }, modifiers: ScssVariableModifierList [ ScssVariableModifier { excl_token: BANG@163..164 "!" [] [], @@ -123,11 +129,13 @@ CssRoot { }, }, colon_token: COLON@193..195 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssIdentifier { - value_token: IDENT@195..201 "value" [] [Whitespace(" ")], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssIdentifier { + value_token: IDENT@195..201 "value" [] [Whitespace(" ")], + }, + ], + }, modifiers: ScssVariableModifierList [ ScssVariableModifier { excl_token: BANG@201..202 "!" [] [], @@ -190,11 +198,13 @@ CssRoot { }, }, colon_token: COLON@328..330 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssIdentifier { - value_token: IDENT@330..334 "red" [] [Whitespace(" ")], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssIdentifier { + value_token: IDENT@330..334 "red" [] [Whitespace(" ")], + }, + ], + }, modifiers: ScssVariableModifierList [ ScssVariableModifier { excl_token: BANG@334..335 "!" [] [], @@ -247,9 +257,10 @@ CssRoot { 1: CSS_IDENTIFIER@22..32 0: IDENT@22..32 "global-var" [] [] 1: COLON@32..34 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@34..41 - 0: CSS_IDENTIFIER@34..41 - 0: IDENT@34..41 "initial" [] [] + 2: SCSS_EXPRESSION@34..41 + 0: SCSS_EXPRESSION_ITEM_LIST@34..41 + 0: CSS_IDENTIFIER@34..41 + 0: IDENT@34..41 "initial" [] [] 3: SCSS_VARIABLE_MODIFIER_LIST@41..41 4: SEMICOLON@41..42 ";" [] [] 1: CSS_QUALIFIED_RULE@42..243 @@ -271,9 +282,10 @@ CssRoot { 1: CSS_IDENTIFIER@90..100 0: IDENT@90..100 "global-var" [] [] 1: COLON@100..102 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@102..111 - 0: CSS_IDENTIFIER@102..111 - 0: IDENT@102..111 "modified" [] [Whitespace(" ")] + 2: SCSS_EXPRESSION@102..111 + 0: SCSS_EXPRESSION_ITEM_LIST@102..111 + 0: CSS_IDENTIFIER@102..111 + 0: IDENT@102..111 "modified" [] [Whitespace(" ")] 3: SCSS_VARIABLE_MODIFIER_LIST@111..118 0: SCSS_VARIABLE_MODIFIER@111..118 0: BANG@111..112 "!" [] [] @@ -285,9 +297,10 @@ CssRoot { 1: CSS_IDENTIFIER@144..155 0: IDENT@144..155 "another-var" [] [] 1: COLON@155..157 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@157..163 - 0: CSS_IDENTIFIER@157..163 - 0: IDENT@157..163 "value" [] [Whitespace(" ")] + 2: SCSS_EXPRESSION@157..163 + 0: SCSS_EXPRESSION_ITEM_LIST@157..163 + 0: CSS_IDENTIFIER@157..163 + 0: IDENT@157..163 "value" [] [Whitespace(" ")] 3: SCSS_VARIABLE_MODIFIER_LIST@163..179 0: SCSS_VARIABLE_MODIFIER@163..172 0: BANG@163..164 "!" [] [] @@ -302,9 +315,10 @@ CssRoot { 1: CSS_IDENTIFIER@184..193 0: IDENT@184..193 "third-var" [] [] 1: COLON@193..195 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@195..201 - 0: CSS_IDENTIFIER@195..201 - 0: IDENT@195..201 "value" [] [Whitespace(" ")] + 2: SCSS_EXPRESSION@195..201 + 0: SCSS_EXPRESSION_ITEM_LIST@195..201 + 0: CSS_IDENTIFIER@195..201 + 0: IDENT@195..201 "value" [] [Whitespace(" ")] 3: SCSS_VARIABLE_MODIFIER_LIST@201..217 0: SCSS_VARIABLE_MODIFIER@201..209 0: BANG@201..202 "!" [] [] @@ -346,9 +360,10 @@ CssRoot { 1: CSS_IDENTIFIER@315..328 0: IDENT@315..328 "important-var" [] [] 1: COLON@328..330 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@330..334 - 0: CSS_IDENTIFIER@330..334 - 0: IDENT@330..334 "red" [] [Whitespace(" ")] + 2: SCSS_EXPRESSION@330..334 + 0: SCSS_EXPRESSION_ITEM_LIST@330..334 + 0: CSS_IDENTIFIER@330..334 + 0: IDENT@330..334 "red" [] [Whitespace(" ")] 3: SCSS_VARIABLE_MODIFIER_LIST@334..341 0: SCSS_VARIABLE_MODIFIER@334..341 0: BANG@334..335 "!" [] [] diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/namespace-properties.scss.snap b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/namespace-properties.scss.snap index 58eba46ad976..da2f5da724a9 100644 --- a/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/namespace-properties.scss.snap +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/namespace-properties.scss.snap @@ -32,11 +32,13 @@ CssRoot { }, }, colon_token: COLON@7..9 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssIdentifier { - value_token: IDENT@9..14 "value" [] [], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssIdentifier { + value_token: IDENT@9..14 "value" [] [], + }, + ], + }, modifiers: ScssVariableModifierList [], semicolon_token: SEMICOLON@14..15 ";" [] [], }, @@ -61,9 +63,10 @@ CssRoot { 1: CSS_IDENTIFIER@4..7 0: IDENT@4..7 "var" [] [] 1: COLON@7..9 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@9..14 - 0: CSS_IDENTIFIER@9..14 - 0: IDENT@9..14 "value" [] [] + 2: SCSS_EXPRESSION@9..14 + 0: SCSS_EXPRESSION_ITEM_LIST@9..14 + 0: CSS_IDENTIFIER@9..14 + 0: IDENT@9..14 "value" [] [] 3: SCSS_VARIABLE_MODIFIER_LIST@14..14 4: SEMICOLON@14..15 ";" [] [] 2: EOF@15..17 "" [Newline("\n"), Newline("\n")] [] diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/namespaced-function.scss.snap b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/namespaced-function.scss.snap index 93cd5b8e6c37..9b79e0ef0325 100644 --- a/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/namespaced-function.scss.snap +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/namespaced-function.scss.snap @@ -1,6 +1,5 @@ --- source: crates/biome_css_parser/tests/spec_test.rs -assertion_line: 208 expression: snapshot --- @@ -27,42 +26,44 @@ CssRoot { }, }, colon_token: COLON@10..12 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssFunction { - name: ScssQualifiedName { - module: CssIdentifier { - value_token: IDENT@12..15 "mod" [] [], - }, - dot_token: DOT@15..16 "." [] [], - member: CssIdentifier { - value_token: IDENT@16..18 "fn" [] [], - }, - }, - l_paren_token: L_PAREN@18..19 "(" [] [], - items: CssParameterList [ - CssParameter { - any_css_expression: ScssExpression { - items: ScssExpressionItemList [ - CssNumber { - value_token: CSS_NUMBER_LITERAL@19..20 "1" [] [], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssFunction { + name: ScssQualifiedName { + module: CssIdentifier { + value_token: IDENT@12..15 "mod" [] [], }, - }, - COMMA@20..22 "," [] [Whitespace(" ")], - CssParameter { - any_css_expression: ScssExpression { - items: ScssExpressionItemList [ - CssNumber { - value_token: CSS_NUMBER_LITERAL@22..23 "2" [] [], - }, - ], + dot_token: DOT@15..16 "." [] [], + member: CssIdentifier { + value_token: IDENT@16..18 "fn" [] [], }, }, - ], - r_paren_token: R_PAREN@23..24 ")" [] [], - }, - ], + l_paren_token: L_PAREN@18..19 "(" [] [], + items: CssParameterList [ + CssParameter { + any_css_expression: ScssExpression { + items: ScssExpressionItemList [ + CssNumber { + value_token: CSS_NUMBER_LITERAL@19..20 "1" [] [], + }, + ], + }, + }, + COMMA@20..22 "," [] [Whitespace(" ")], + CssParameter { + any_css_expression: ScssExpression { + items: ScssExpressionItemList [ + CssNumber { + value_token: CSS_NUMBER_LITERAL@22..23 "2" [] [], + }, + ], + }, + }, + ], + r_paren_token: R_PAREN@23..24 ")" [] [], + }, + ], + }, modifiers: ScssVariableModifierList [], semicolon_token: SEMICOLON@24..25 ";" [] [], }, @@ -74,47 +75,49 @@ CssRoot { }, }, colon_token: COLON@39..41 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssFunction { - name: ScssQualifiedName { - module: CssIdentifier { - value_token: IDENT@41..44 "mod" [] [], - }, - dot_token: DOT@44..45 "." [] [], - member: CssIdentifier { - value_token: IDENT@45..47 "fn" [] [], + value: ScssExpression { + items: ScssExpressionItemList [ + CssFunction { + name: ScssQualifiedName { + module: CssIdentifier { + value_token: IDENT@41..44 "mod" [] [], + }, + dot_token: DOT@44..45 "." [] [], + member: CssIdentifier { + value_token: IDENT@45..47 "fn" [] [], + }, }, - }, - l_paren_token: L_PAREN@47..48 "(" [] [], - items: CssParameterList [ - CssParameter { - any_css_expression: ScssExpression { - items: ScssExpressionItemList [ - CssFunction { - name: CssIdentifier { - value_token: IDENT@48..51 "var" [] [], - }, - l_paren_token: L_PAREN@51..52 "(" [] [], - items: CssParameterList [ - CssParameter { - any_css_expression: ScssExpression { - items: ScssExpressionItemList [ - CssDashedIdentifier { - value_token: IDENT@52..59 "--token" [] [], - }, - ], - }, + l_paren_token: L_PAREN@47..48 "(" [] [], + items: CssParameterList [ + CssParameter { + any_css_expression: ScssExpression { + items: ScssExpressionItemList [ + CssFunction { + name: CssIdentifier { + value_token: IDENT@48..51 "var" [] [], }, - ], - r_paren_token: R_PAREN@59..60 ")" [] [], - }, - ], + l_paren_token: L_PAREN@51..52 "(" [] [], + items: CssParameterList [ + CssParameter { + any_css_expression: ScssExpression { + items: ScssExpressionItemList [ + CssDashedIdentifier { + value_token: IDENT@52..59 "--token" [] [], + }, + ], + }, + }, + ], + r_paren_token: R_PAREN@59..60 ")" [] [], + }, + ], + }, }, - }, - ], - r_paren_token: R_PAREN@60..61 ")" [] [], - }, - ], + ], + r_paren_token: R_PAREN@60..61 ")" [] [], + }, + ], + }, modifiers: ScssVariableModifierList [], semicolon_token: SEMICOLON@61..62 ";" [] [], }, @@ -135,28 +138,29 @@ CssRoot { 1: CSS_IDENTIFIER@1..10 0: IDENT@1..10 "scoped-fn" [] [] 1: COLON@10..12 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@12..24 - 0: CSS_FUNCTION@12..24 - 0: SCSS_QUALIFIED_NAME@12..18 - 0: CSS_IDENTIFIER@12..15 - 0: IDENT@12..15 "mod" [] [] - 1: DOT@15..16 "." [] [] - 2: CSS_IDENTIFIER@16..18 - 0: IDENT@16..18 "fn" [] [] - 1: L_PAREN@18..19 "(" [] [] - 2: CSS_PARAMETER_LIST@19..23 - 0: CSS_PARAMETER@19..20 - 0: SCSS_EXPRESSION@19..20 - 0: SCSS_EXPRESSION_ITEM_LIST@19..20 - 0: CSS_NUMBER@19..20 - 0: CSS_NUMBER_LITERAL@19..20 "1" [] [] - 1: COMMA@20..22 "," [] [Whitespace(" ")] - 2: CSS_PARAMETER@22..23 - 0: SCSS_EXPRESSION@22..23 - 0: SCSS_EXPRESSION_ITEM_LIST@22..23 - 0: CSS_NUMBER@22..23 - 0: CSS_NUMBER_LITERAL@22..23 "2" [] [] - 3: R_PAREN@23..24 ")" [] [] + 2: SCSS_EXPRESSION@12..24 + 0: SCSS_EXPRESSION_ITEM_LIST@12..24 + 0: CSS_FUNCTION@12..24 + 0: SCSS_QUALIFIED_NAME@12..18 + 0: CSS_IDENTIFIER@12..15 + 0: IDENT@12..15 "mod" [] [] + 1: DOT@15..16 "." [] [] + 2: CSS_IDENTIFIER@16..18 + 0: IDENT@16..18 "fn" [] [] + 1: L_PAREN@18..19 "(" [] [] + 2: CSS_PARAMETER_LIST@19..23 + 0: CSS_PARAMETER@19..20 + 0: SCSS_EXPRESSION@19..20 + 0: SCSS_EXPRESSION_ITEM_LIST@19..20 + 0: CSS_NUMBER@19..20 + 0: CSS_NUMBER_LITERAL@19..20 "1" [] [] + 1: COMMA@20..22 "," [] [Whitespace(" ")] + 2: CSS_PARAMETER@22..23 + 0: SCSS_EXPRESSION@22..23 + 0: SCSS_EXPRESSION_ITEM_LIST@22..23 + 0: CSS_NUMBER@22..23 + 0: CSS_NUMBER_LITERAL@22..23 "2" [] [] + 3: R_PAREN@23..24 ")" [] [] 3: SCSS_VARIABLE_MODIFIER_LIST@24..24 4: SEMICOLON@24..25 ";" [] [] 1: SCSS_DECLARATION@25..62 @@ -165,31 +169,32 @@ CssRoot { 1: CSS_IDENTIFIER@27..39 0: IDENT@27..39 "scoped-ident" [] [] 1: COLON@39..41 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@41..61 - 0: CSS_FUNCTION@41..61 - 0: SCSS_QUALIFIED_NAME@41..47 - 0: CSS_IDENTIFIER@41..44 - 0: IDENT@41..44 "mod" [] [] - 1: DOT@44..45 "." [] [] - 2: CSS_IDENTIFIER@45..47 - 0: IDENT@45..47 "fn" [] [] - 1: L_PAREN@47..48 "(" [] [] - 2: CSS_PARAMETER_LIST@48..60 - 0: CSS_PARAMETER@48..60 - 0: SCSS_EXPRESSION@48..60 - 0: SCSS_EXPRESSION_ITEM_LIST@48..60 - 0: CSS_FUNCTION@48..60 - 0: CSS_IDENTIFIER@48..51 - 0: IDENT@48..51 "var" [] [] - 1: L_PAREN@51..52 "(" [] [] - 2: CSS_PARAMETER_LIST@52..59 - 0: CSS_PARAMETER@52..59 - 0: SCSS_EXPRESSION@52..59 - 0: SCSS_EXPRESSION_ITEM_LIST@52..59 - 0: CSS_DASHED_IDENTIFIER@52..59 - 0: IDENT@52..59 "--token" [] [] - 3: R_PAREN@59..60 ")" [] [] - 3: R_PAREN@60..61 ")" [] [] + 2: SCSS_EXPRESSION@41..61 + 0: SCSS_EXPRESSION_ITEM_LIST@41..61 + 0: CSS_FUNCTION@41..61 + 0: SCSS_QUALIFIED_NAME@41..47 + 0: CSS_IDENTIFIER@41..44 + 0: IDENT@41..44 "mod" [] [] + 1: DOT@44..45 "." [] [] + 2: CSS_IDENTIFIER@45..47 + 0: IDENT@45..47 "fn" [] [] + 1: L_PAREN@47..48 "(" [] [] + 2: CSS_PARAMETER_LIST@48..60 + 0: CSS_PARAMETER@48..60 + 0: SCSS_EXPRESSION@48..60 + 0: SCSS_EXPRESSION_ITEM_LIST@48..60 + 0: CSS_FUNCTION@48..60 + 0: CSS_IDENTIFIER@48..51 + 0: IDENT@48..51 "var" [] [] + 1: L_PAREN@51..52 "(" [] [] + 2: CSS_PARAMETER_LIST@52..59 + 0: CSS_PARAMETER@52..59 + 0: SCSS_EXPRESSION@52..59 + 0: SCSS_EXPRESSION_ITEM_LIST@52..59 + 0: CSS_DASHED_IDENTIFIER@52..59 + 0: IDENT@52..59 "--token" [] [] + 3: R_PAREN@59..60 ")" [] [] + 3: R_PAREN@60..61 ")" [] [] 3: SCSS_VARIABLE_MODIFIER_LIST@61..61 4: SEMICOLON@61..62 ";" [] [] 2: EOF@62..63 "" [Newline("\n")] [] diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/namespaced-variable.scss.snap b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/namespaced-variable.scss.snap index b71e942b0985..cf254ac9f023 100644 --- a/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/namespaced-variable.scss.snap +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/namespaced-variable.scss.snap @@ -1,6 +1,5 @@ --- source: crates/biome_css_parser/tests/spec_test.rs -assertion_line: 208 expression: snapshot --- @@ -32,11 +31,13 @@ CssRoot { }, }, colon_token: COLON@8..10 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssNumber { - value_token: CSS_NUMBER_LITERAL@10..11 "1" [] [], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssNumber { + value_token: CSS_NUMBER_LITERAL@10..11 "1" [] [], + }, + ], + }, modifiers: ScssVariableModifierList [], semicolon_token: SEMICOLON@11..12 ";" [] [], }, @@ -61,9 +62,10 @@ CssRoot { 1: CSS_IDENTIFIER@5..8 0: IDENT@5..8 "var" [] [] 1: COLON@8..10 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@10..11 - 0: CSS_NUMBER@10..11 - 0: CSS_NUMBER_LITERAL@10..11 "1" [] [] + 2: SCSS_EXPRESSION@10..11 + 0: SCSS_EXPRESSION_ITEM_LIST@10..11 + 0: CSS_NUMBER@10..11 + 0: CSS_NUMBER_LITERAL@10..11 "1" [] [] 3: SCSS_VARIABLE_MODIFIER_LIST@11..11 4: SEMICOLON@11..12 ";" [] [] 2: EOF@12..13 "" [Newline("\n")] [] diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/nested-variables.scss.snap b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/nested-variables.scss.snap index 4d812bf9415d..ff759945a4de 100644 --- a/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/nested-variables.scss.snap +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/nested-variables.scss.snap @@ -46,12 +46,14 @@ CssRoot { }, }, colon_token: COLON@20..22 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssRegularDimension { - value_token: CSS_NUMBER_LITERAL@22..24 "12" [] [], - unit_token: IDENT@24..26 "px" [] [], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssRegularDimension { + value_token: CSS_NUMBER_LITERAL@22..24 "12" [] [], + unit_token: IDENT@24..26 "px" [] [], + }, + ], + }, modifiers: ScssVariableModifierList [], semicolon_token: SEMICOLON@26..27 ";" [] [], }, @@ -109,10 +111,11 @@ CssRoot { 1: CSS_IDENTIFIER@13..20 0: IDENT@13..20 "padding" [] [] 1: COLON@20..22 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@22..26 - 0: CSS_REGULAR_DIMENSION@22..26 - 0: CSS_NUMBER_LITERAL@22..24 "12" [] [] - 1: IDENT@24..26 "px" [] [] + 2: SCSS_EXPRESSION@22..26 + 0: SCSS_EXPRESSION_ITEM_LIST@22..26 + 0: CSS_REGULAR_DIMENSION@22..26 + 0: CSS_NUMBER_LITERAL@22..24 "12" [] [] + 1: IDENT@24..26 "px" [] [] 3: SCSS_VARIABLE_MODIFIER_LIST@26..26 4: SEMICOLON@26..27 ";" [] [] 1: CSS_DECLARATION_WITH_SEMICOLON@27..48 diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/semicolon-eof.scss.snap b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/semicolon-eof.scss.snap index 98949f650050..61ceaf941b52 100644 --- a/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/semicolon-eof.scss.snap +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/semicolon-eof.scss.snap @@ -26,11 +26,13 @@ CssRoot { }, }, colon_token: COLON@6..8 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssIdentifier { - value_token: IDENT@8..11 "red" [] [], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssIdentifier { + value_token: IDENT@8..11 "red" [] [], + }, + ], + }, modifiers: ScssVariableModifierList [], semicolon_token: SEMICOLON@11..12 ";" [] [], }, @@ -42,12 +44,14 @@ CssRoot { }, }, colon_token: COLON@18..20 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssRegularDimension { - value_token: CSS_NUMBER_LITERAL@20..22 "10" [] [], - unit_token: IDENT@22..24 "px" [] [], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssRegularDimension { + value_token: CSS_NUMBER_LITERAL@20..22 "10" [] [], + unit_token: IDENT@22..24 "px" [] [], + }, + ], + }, modifiers: ScssVariableModifierList [], semicolon_token: missing (optional), }, @@ -68,9 +72,10 @@ CssRoot { 1: CSS_IDENTIFIER@1..6 0: IDENT@1..6 "color" [] [] 1: COLON@6..8 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@8..11 - 0: CSS_IDENTIFIER@8..11 - 0: IDENT@8..11 "red" [] [] + 2: SCSS_EXPRESSION@8..11 + 0: SCSS_EXPRESSION_ITEM_LIST@8..11 + 0: CSS_IDENTIFIER@8..11 + 0: IDENT@8..11 "red" [] [] 3: SCSS_VARIABLE_MODIFIER_LIST@11..11 4: SEMICOLON@11..12 ";" [] [] 1: SCSS_DECLARATION@12..24 @@ -79,10 +84,11 @@ CssRoot { 1: CSS_IDENTIFIER@14..18 0: IDENT@14..18 "size" [] [] 1: COLON@18..20 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@20..24 - 0: CSS_REGULAR_DIMENSION@20..24 - 0: CSS_NUMBER_LITERAL@20..22 "10" [] [] - 1: IDENT@22..24 "px" [] [] + 2: SCSS_EXPRESSION@20..24 + 0: SCSS_EXPRESSION_ITEM_LIST@20..24 + 0: CSS_REGULAR_DIMENSION@20..24 + 0: CSS_NUMBER_LITERAL@20..22 "10" [] [] + 1: IDENT@22..24 "px" [] [] 3: SCSS_VARIABLE_MODIFIER_LIST@24..24 4: (empty) 2: EOF@24..25 "" [Newline("\n")] [] diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/expression/precedence.scss b/crates/biome_css_parser/tests/css_test_suite/ok/scss/expression/precedence.scss new file mode 100644 index 000000000000..a0d952236e56 --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/expression/precedence.scss @@ -0,0 +1,10 @@ +$expr1: $a + $b * $c; +$expr2: ($a + $b) * $c; +$expr3: $a * $b + $c; +$expr4: -$a + $b; +$expr5: not $a and $b; +$expr6: $a == $b or $c != $d; + + + + diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/expression/precedence.scss.snap b/crates/biome_css_parser/tests/css_test_suite/ok/scss/expression/precedence.scss.snap new file mode 100644 index 000000000000..791b038f0f8e --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/expression/precedence.scss.snap @@ -0,0 +1,440 @@ +--- +source: crates/biome_css_parser/tests/spec_test.rs +expression: snapshot +--- + +## Input + +```css +$expr1: $a + $b * $c; +$expr2: ($a + $b) * $c; +$expr3: $a * $b + $c; +$expr4: -$a + $b; +$expr5: not $a and $b; +$expr6: $a == $b or $c != $d; + + + + + +``` + + +## AST + +``` +CssRoot { + bom_token: missing (optional), + items: CssRootItemList [ + ScssDeclaration { + name: ScssIdentifier { + dollar_token: DOLLAR@0..1 "$" [] [], + name: CssIdentifier { + value_token: IDENT@1..6 "expr1" [] [], + }, + }, + colon_token: COLON@6..8 ":" [] [Whitespace(" ")], + value: ScssExpression { + items: ScssExpressionItemList [ + ScssBinaryExpression { + left: ScssIdentifier { + dollar_token: DOLLAR@8..9 "$" [] [], + name: CssIdentifier { + value_token: IDENT@9..11 "a" [] [Whitespace(" ")], + }, + }, + operator: PLUS@11..13 "+" [] [Whitespace(" ")], + right: ScssBinaryExpression { + left: ScssIdentifier { + dollar_token: DOLLAR@13..14 "$" [] [], + name: CssIdentifier { + value_token: IDENT@14..16 "b" [] [Whitespace(" ")], + }, + }, + operator: STAR@16..18 "*" [] [Whitespace(" ")], + right: ScssIdentifier { + dollar_token: DOLLAR@18..19 "$" [] [], + name: CssIdentifier { + value_token: IDENT@19..20 "c" [] [], + }, + }, + }, + }, + ], + }, + modifiers: ScssVariableModifierList [], + semicolon_token: SEMICOLON@20..21 ";" [] [], + }, + ScssDeclaration { + name: ScssIdentifier { + dollar_token: DOLLAR@21..23 "$" [Newline("\n")] [], + name: CssIdentifier { + value_token: IDENT@23..28 "expr2" [] [], + }, + }, + colon_token: COLON@28..30 ":" [] [Whitespace(" ")], + value: ScssExpression { + items: ScssExpressionItemList [ + ScssBinaryExpression { + left: ScssParenthesizedExpression { + l_paren_token: L_PAREN@30..31 "(" [] [], + expression: ScssExpression { + items: ScssExpressionItemList [ + ScssBinaryExpression { + left: ScssIdentifier { + dollar_token: DOLLAR@31..32 "$" [] [], + name: CssIdentifier { + value_token: IDENT@32..34 "a" [] [Whitespace(" ")], + }, + }, + operator: PLUS@34..36 "+" [] [Whitespace(" ")], + right: ScssIdentifier { + dollar_token: DOLLAR@36..37 "$" [] [], + name: CssIdentifier { + value_token: IDENT@37..38 "b" [] [], + }, + }, + }, + ], + }, + r_paren_token: R_PAREN@38..40 ")" [] [Whitespace(" ")], + }, + operator: STAR@40..42 "*" [] [Whitespace(" ")], + right: ScssIdentifier { + dollar_token: DOLLAR@42..43 "$" [] [], + name: CssIdentifier { + value_token: IDENT@43..44 "c" [] [], + }, + }, + }, + ], + }, + modifiers: ScssVariableModifierList [], + semicolon_token: SEMICOLON@44..45 ";" [] [], + }, + ScssDeclaration { + name: ScssIdentifier { + dollar_token: DOLLAR@45..47 "$" [Newline("\n")] [], + name: CssIdentifier { + value_token: IDENT@47..52 "expr3" [] [], + }, + }, + colon_token: COLON@52..54 ":" [] [Whitespace(" ")], + value: ScssExpression { + items: ScssExpressionItemList [ + ScssBinaryExpression { + left: ScssBinaryExpression { + left: ScssIdentifier { + dollar_token: DOLLAR@54..55 "$" [] [], + name: CssIdentifier { + value_token: IDENT@55..57 "a" [] [Whitespace(" ")], + }, + }, + operator: STAR@57..59 "*" [] [Whitespace(" ")], + right: ScssIdentifier { + dollar_token: DOLLAR@59..60 "$" [] [], + name: CssIdentifier { + value_token: IDENT@60..62 "b" [] [Whitespace(" ")], + }, + }, + }, + operator: PLUS@62..64 "+" [] [Whitespace(" ")], + right: ScssIdentifier { + dollar_token: DOLLAR@64..65 "$" [] [], + name: CssIdentifier { + value_token: IDENT@65..66 "c" [] [], + }, + }, + }, + ], + }, + modifiers: ScssVariableModifierList [], + semicolon_token: SEMICOLON@66..67 ";" [] [], + }, + ScssDeclaration { + name: ScssIdentifier { + dollar_token: DOLLAR@67..69 "$" [Newline("\n")] [], + name: CssIdentifier { + value_token: IDENT@69..74 "expr4" [] [], + }, + }, + colon_token: COLON@74..76 ":" [] [Whitespace(" ")], + value: ScssExpression { + items: ScssExpressionItemList [ + ScssBinaryExpression { + left: ScssUnaryExpression { + operator: MINUS@76..77 "-" [] [], + expression: ScssIdentifier { + dollar_token: DOLLAR@77..78 "$" [] [], + name: CssIdentifier { + value_token: IDENT@78..80 "a" [] [Whitespace(" ")], + }, + }, + }, + operator: PLUS@80..82 "+" [] [Whitespace(" ")], + right: ScssIdentifier { + dollar_token: DOLLAR@82..83 "$" [] [], + name: CssIdentifier { + value_token: IDENT@83..84 "b" [] [], + }, + }, + }, + ], + }, + modifiers: ScssVariableModifierList [], + semicolon_token: SEMICOLON@84..85 ";" [] [], + }, + ScssDeclaration { + name: ScssIdentifier { + dollar_token: DOLLAR@85..87 "$" [Newline("\n")] [], + name: CssIdentifier { + value_token: IDENT@87..92 "expr5" [] [], + }, + }, + colon_token: COLON@92..94 ":" [] [Whitespace(" ")], + value: ScssExpression { + items: ScssExpressionItemList [ + ScssBinaryExpression { + left: ScssUnaryExpression { + operator: NOT_KW@94..98 "not" [] [Whitespace(" ")], + expression: ScssIdentifier { + dollar_token: DOLLAR@98..99 "$" [] [], + name: CssIdentifier { + value_token: IDENT@99..101 "a" [] [Whitespace(" ")], + }, + }, + }, + operator: AND_KW@101..105 "and" [] [Whitespace(" ")], + right: ScssIdentifier { + dollar_token: DOLLAR@105..106 "$" [] [], + name: CssIdentifier { + value_token: IDENT@106..107 "b" [] [], + }, + }, + }, + ], + }, + modifiers: ScssVariableModifierList [], + semicolon_token: SEMICOLON@107..108 ";" [] [], + }, + ScssDeclaration { + name: ScssIdentifier { + dollar_token: DOLLAR@108..110 "$" [Newline("\n")] [], + name: CssIdentifier { + value_token: IDENT@110..115 "expr6" [] [], + }, + }, + colon_token: COLON@115..117 ":" [] [Whitespace(" ")], + value: ScssExpression { + items: ScssExpressionItemList [ + ScssBinaryExpression { + left: ScssBinaryExpression { + left: ScssIdentifier { + dollar_token: DOLLAR@117..118 "$" [] [], + name: CssIdentifier { + value_token: IDENT@118..120 "a" [] [Whitespace(" ")], + }, + }, + operator: EQ2@120..123 "==" [] [Whitespace(" ")], + right: ScssIdentifier { + dollar_token: DOLLAR@123..124 "$" [] [], + name: CssIdentifier { + value_token: IDENT@124..126 "b" [] [Whitespace(" ")], + }, + }, + }, + operator: OR_KW@126..129 "or" [] [Whitespace(" ")], + right: ScssBinaryExpression { + left: ScssIdentifier { + dollar_token: DOLLAR@129..130 "$" [] [], + name: CssIdentifier { + value_token: IDENT@130..132 "c" [] [Whitespace(" ")], + }, + }, + operator: NEQ@132..135 "!=" [] [Whitespace(" ")], + right: ScssIdentifier { + dollar_token: DOLLAR@135..136 "$" [] [], + name: CssIdentifier { + value_token: IDENT@136..137 "d" [] [], + }, + }, + }, + }, + ], + }, + modifiers: ScssVariableModifierList [], + semicolon_token: SEMICOLON@137..138 ";" [] [], + }, + ], + eof_token: EOF@138..143 "" [Newline("\n"), Newline("\n"), Newline("\n"), Newline("\n"), Newline("\n")] [], +} +``` + +## CST + +``` +0: CSS_ROOT@0..143 + 0: (empty) + 1: CSS_ROOT_ITEM_LIST@0..138 + 0: SCSS_DECLARATION@0..21 + 0: SCSS_IDENTIFIER@0..6 + 0: DOLLAR@0..1 "$" [] [] + 1: CSS_IDENTIFIER@1..6 + 0: IDENT@1..6 "expr1" [] [] + 1: COLON@6..8 ":" [] [Whitespace(" ")] + 2: SCSS_EXPRESSION@8..20 + 0: SCSS_EXPRESSION_ITEM_LIST@8..20 + 0: SCSS_BINARY_EXPRESSION@8..20 + 0: SCSS_IDENTIFIER@8..11 + 0: DOLLAR@8..9 "$" [] [] + 1: CSS_IDENTIFIER@9..11 + 0: IDENT@9..11 "a" [] [Whitespace(" ")] + 1: PLUS@11..13 "+" [] [Whitespace(" ")] + 2: SCSS_BINARY_EXPRESSION@13..20 + 0: SCSS_IDENTIFIER@13..16 + 0: DOLLAR@13..14 "$" [] [] + 1: CSS_IDENTIFIER@14..16 + 0: IDENT@14..16 "b" [] [Whitespace(" ")] + 1: STAR@16..18 "*" [] [Whitespace(" ")] + 2: SCSS_IDENTIFIER@18..20 + 0: DOLLAR@18..19 "$" [] [] + 1: CSS_IDENTIFIER@19..20 + 0: IDENT@19..20 "c" [] [] + 3: SCSS_VARIABLE_MODIFIER_LIST@20..20 + 4: SEMICOLON@20..21 ";" [] [] + 1: SCSS_DECLARATION@21..45 + 0: SCSS_IDENTIFIER@21..28 + 0: DOLLAR@21..23 "$" [Newline("\n")] [] + 1: CSS_IDENTIFIER@23..28 + 0: IDENT@23..28 "expr2" [] [] + 1: COLON@28..30 ":" [] [Whitespace(" ")] + 2: SCSS_EXPRESSION@30..44 + 0: SCSS_EXPRESSION_ITEM_LIST@30..44 + 0: SCSS_BINARY_EXPRESSION@30..44 + 0: SCSS_PARENTHESIZED_EXPRESSION@30..40 + 0: L_PAREN@30..31 "(" [] [] + 1: SCSS_EXPRESSION@31..38 + 0: SCSS_EXPRESSION_ITEM_LIST@31..38 + 0: SCSS_BINARY_EXPRESSION@31..38 + 0: SCSS_IDENTIFIER@31..34 + 0: DOLLAR@31..32 "$" [] [] + 1: CSS_IDENTIFIER@32..34 + 0: IDENT@32..34 "a" [] [Whitespace(" ")] + 1: PLUS@34..36 "+" [] [Whitespace(" ")] + 2: SCSS_IDENTIFIER@36..38 + 0: DOLLAR@36..37 "$" [] [] + 1: CSS_IDENTIFIER@37..38 + 0: IDENT@37..38 "b" [] [] + 2: R_PAREN@38..40 ")" [] [Whitespace(" ")] + 1: STAR@40..42 "*" [] [Whitespace(" ")] + 2: SCSS_IDENTIFIER@42..44 + 0: DOLLAR@42..43 "$" [] [] + 1: CSS_IDENTIFIER@43..44 + 0: IDENT@43..44 "c" [] [] + 3: SCSS_VARIABLE_MODIFIER_LIST@44..44 + 4: SEMICOLON@44..45 ";" [] [] + 2: SCSS_DECLARATION@45..67 + 0: SCSS_IDENTIFIER@45..52 + 0: DOLLAR@45..47 "$" [Newline("\n")] [] + 1: CSS_IDENTIFIER@47..52 + 0: IDENT@47..52 "expr3" [] [] + 1: COLON@52..54 ":" [] [Whitespace(" ")] + 2: SCSS_EXPRESSION@54..66 + 0: SCSS_EXPRESSION_ITEM_LIST@54..66 + 0: SCSS_BINARY_EXPRESSION@54..66 + 0: SCSS_BINARY_EXPRESSION@54..62 + 0: SCSS_IDENTIFIER@54..57 + 0: DOLLAR@54..55 "$" [] [] + 1: CSS_IDENTIFIER@55..57 + 0: IDENT@55..57 "a" [] [Whitespace(" ")] + 1: STAR@57..59 "*" [] [Whitespace(" ")] + 2: SCSS_IDENTIFIER@59..62 + 0: DOLLAR@59..60 "$" [] [] + 1: CSS_IDENTIFIER@60..62 + 0: IDENT@60..62 "b" [] [Whitespace(" ")] + 1: PLUS@62..64 "+" [] [Whitespace(" ")] + 2: SCSS_IDENTIFIER@64..66 + 0: DOLLAR@64..65 "$" [] [] + 1: CSS_IDENTIFIER@65..66 + 0: IDENT@65..66 "c" [] [] + 3: SCSS_VARIABLE_MODIFIER_LIST@66..66 + 4: SEMICOLON@66..67 ";" [] [] + 3: SCSS_DECLARATION@67..85 + 0: SCSS_IDENTIFIER@67..74 + 0: DOLLAR@67..69 "$" [Newline("\n")] [] + 1: CSS_IDENTIFIER@69..74 + 0: IDENT@69..74 "expr4" [] [] + 1: COLON@74..76 ":" [] [Whitespace(" ")] + 2: SCSS_EXPRESSION@76..84 + 0: SCSS_EXPRESSION_ITEM_LIST@76..84 + 0: SCSS_BINARY_EXPRESSION@76..84 + 0: SCSS_UNARY_EXPRESSION@76..80 + 0: MINUS@76..77 "-" [] [] + 1: SCSS_IDENTIFIER@77..80 + 0: DOLLAR@77..78 "$" [] [] + 1: CSS_IDENTIFIER@78..80 + 0: IDENT@78..80 "a" [] [Whitespace(" ")] + 1: PLUS@80..82 "+" [] [Whitespace(" ")] + 2: SCSS_IDENTIFIER@82..84 + 0: DOLLAR@82..83 "$" [] [] + 1: CSS_IDENTIFIER@83..84 + 0: IDENT@83..84 "b" [] [] + 3: SCSS_VARIABLE_MODIFIER_LIST@84..84 + 4: SEMICOLON@84..85 ";" [] [] + 4: SCSS_DECLARATION@85..108 + 0: SCSS_IDENTIFIER@85..92 + 0: DOLLAR@85..87 "$" [Newline("\n")] [] + 1: CSS_IDENTIFIER@87..92 + 0: IDENT@87..92 "expr5" [] [] + 1: COLON@92..94 ":" [] [Whitespace(" ")] + 2: SCSS_EXPRESSION@94..107 + 0: SCSS_EXPRESSION_ITEM_LIST@94..107 + 0: SCSS_BINARY_EXPRESSION@94..107 + 0: SCSS_UNARY_EXPRESSION@94..101 + 0: NOT_KW@94..98 "not" [] [Whitespace(" ")] + 1: SCSS_IDENTIFIER@98..101 + 0: DOLLAR@98..99 "$" [] [] + 1: CSS_IDENTIFIER@99..101 + 0: IDENT@99..101 "a" [] [Whitespace(" ")] + 1: AND_KW@101..105 "and" [] [Whitespace(" ")] + 2: SCSS_IDENTIFIER@105..107 + 0: DOLLAR@105..106 "$" [] [] + 1: CSS_IDENTIFIER@106..107 + 0: IDENT@106..107 "b" [] [] + 3: SCSS_VARIABLE_MODIFIER_LIST@107..107 + 4: SEMICOLON@107..108 ";" [] [] + 5: SCSS_DECLARATION@108..138 + 0: SCSS_IDENTIFIER@108..115 + 0: DOLLAR@108..110 "$" [Newline("\n")] [] + 1: CSS_IDENTIFIER@110..115 + 0: IDENT@110..115 "expr6" [] [] + 1: COLON@115..117 ":" [] [Whitespace(" ")] + 2: SCSS_EXPRESSION@117..137 + 0: SCSS_EXPRESSION_ITEM_LIST@117..137 + 0: SCSS_BINARY_EXPRESSION@117..137 + 0: SCSS_BINARY_EXPRESSION@117..126 + 0: SCSS_IDENTIFIER@117..120 + 0: DOLLAR@117..118 "$" [] [] + 1: CSS_IDENTIFIER@118..120 + 0: IDENT@118..120 "a" [] [Whitespace(" ")] + 1: EQ2@120..123 "==" [] [Whitespace(" ")] + 2: SCSS_IDENTIFIER@123..126 + 0: DOLLAR@123..124 "$" [] [] + 1: CSS_IDENTIFIER@124..126 + 0: IDENT@124..126 "b" [] [Whitespace(" ")] + 1: OR_KW@126..129 "or" [] [Whitespace(" ")] + 2: SCSS_BINARY_EXPRESSION@129..137 + 0: SCSS_IDENTIFIER@129..132 + 0: DOLLAR@129..130 "$" [] [] + 1: CSS_IDENTIFIER@130..132 + 0: IDENT@130..132 "c" [] [Whitespace(" ")] + 1: NEQ@132..135 "!=" [] [Whitespace(" ")] + 2: SCSS_IDENTIFIER@135..137 + 0: DOLLAR@135..136 "$" [] [] + 1: CSS_IDENTIFIER@136..137 + 0: IDENT@136..137 "d" [] [] + 3: SCSS_VARIABLE_MODIFIER_LIST@137..137 + 4: SEMICOLON@137..138 ";" [] [] + 2: EOF@138..143 "" [Newline("\n"), Newline("\n"), Newline("\n"), Newline("\n"), Newline("\n")] [] + +``` diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/expression/unary-parenthesized.scss.snap b/crates/biome_css_parser/tests/css_test_suite/ok/scss/expression/unary-parenthesized.scss.snap index 04191365ab80..f377e59f4749 100644 --- a/crates/biome_css_parser/tests/css_test_suite/ok/scss/expression/unary-parenthesized.scss.snap +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/expression/unary-parenthesized.scss.snap @@ -1,6 +1,5 @@ --- source: crates/biome_css_parser/tests/spec_test.rs -assertion_line: 208 expression: snapshot --- @@ -54,11 +53,11 @@ CssRoot { l_paren_token: L_PAREN@18..19 "(" [] [], items: CssParameterList [ CssParameter { - any_css_expression: CssUnaryExpression { - operator: MINUS@19..20 "-" [] [], - expression: ScssExpression { - items: ScssExpressionItemList [ - ScssParenthesizedExpression { + any_css_expression: ScssExpression { + items: ScssExpressionItemList [ + ScssUnaryExpression { + operator: MINUS@19..20 "-" [] [], + expression: ScssParenthesizedExpression { l_paren_token: L_PAREN@20..21 "(" [] [], expression: ScssExpression { items: ScssExpressionItemList [ @@ -72,8 +71,8 @@ CssRoot { }, r_paren_token: R_PAREN@24..25 ")" [] [], }, - ], - }, + }, + ], }, }, ], @@ -100,11 +99,11 @@ CssRoot { l_paren_token: L_PAREN@37..38 "(" [] [], items: CssParameterList [ CssParameter { - any_css_expression: CssUnaryExpression { - operator: MINUS@38..39 "-" [] [], - expression: ScssExpression { - items: ScssExpressionItemList [ - ScssMapExpression { + any_css_expression: ScssExpression { + items: ScssExpressionItemList [ + ScssUnaryExpression { + operator: MINUS@38..39 "-" [] [], + expression: ScssMapExpression { l_paren_token: L_PAREN@39..40 "(" [] [], pairs: ScssMapExpressionPairList [ ScssMapExpressionPair { @@ -127,8 +126,8 @@ CssRoot { ], r_paren_token: R_PAREN@52..53 ")" [] [], }, - ], - }, + }, + ], }, }, ], @@ -181,11 +180,11 @@ CssRoot { 1: L_PAREN@18..19 "(" [] [] 2: CSS_PARAMETER_LIST@19..25 0: CSS_PARAMETER@19..25 - 0: CSS_UNARY_EXPRESSION@19..25 - 0: MINUS@19..20 "-" [] [] - 1: SCSS_EXPRESSION@20..25 - 0: SCSS_EXPRESSION_ITEM_LIST@20..25 - 0: SCSS_PARENTHESIZED_EXPRESSION@20..25 + 0: SCSS_EXPRESSION@19..25 + 0: SCSS_EXPRESSION_ITEM_LIST@19..25 + 0: SCSS_UNARY_EXPRESSION@19..25 + 0: MINUS@19..20 "-" [] [] + 1: SCSS_PARENTHESIZED_EXPRESSION@20..25 0: L_PAREN@20..21 "(" [] [] 1: SCSS_EXPRESSION@21..24 0: SCSS_EXPRESSION_ITEM_LIST@21..24 @@ -210,11 +209,11 @@ CssRoot { 1: L_PAREN@37..38 "(" [] [] 2: CSS_PARAMETER_LIST@38..53 0: CSS_PARAMETER@38..53 - 0: CSS_UNARY_EXPRESSION@38..53 - 0: MINUS@38..39 "-" [] [] - 1: SCSS_EXPRESSION@39..53 - 0: SCSS_EXPRESSION_ITEM_LIST@39..53 - 0: SCSS_MAP_EXPRESSION@39..53 + 0: SCSS_EXPRESSION@38..53 + 0: SCSS_EXPRESSION_ITEM_LIST@38..53 + 0: SCSS_UNARY_EXPRESSION@38..53 + 0: MINUS@38..39 "-" [] [] + 1: SCSS_MAP_EXPRESSION@39..53 0: L_PAREN@39..40 "(" [] [] 1: SCSS_MAP_EXPRESSION_PAIR_LIST@40..52 0: SCSS_MAP_EXPRESSION_PAIR@40..52 diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/value/bracketed-values.scss.snap b/crates/biome_css_parser/tests/css_test_suite/ok/scss/value/bracketed-values.scss.snap index bd7be0419e8d..ef70edc692ff 100644 --- a/crates/biome_css_parser/tests/css_test_suite/ok/scss/value/bracketed-values.scss.snap +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/value/bracketed-values.scss.snap @@ -30,29 +30,31 @@ CssRoot { }, }, colon_token: COLON@9..11 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssBracketedValue { - l_brack_token: L_BRACK@11..12 "[" [] [], - items: CssBracketedValueList [ - CssCustomIdentifier { - value_token: IDENT@12..13 "a" [] [], - }, - CssGenericDelimiter { - value: COMMA@13..15 "," [] [Whitespace(" ")], - }, - CssCustomIdentifier { - value_token: IDENT@15..16 "b" [] [], - }, - CssGenericDelimiter { - value: COMMA@16..18 "," [] [Whitespace(" ")], - }, - CssCustomIdentifier { - value_token: IDENT@18..19 "c" [] [], - }, - ], - r_brack_token: R_BRACK@19..20 "]" [] [], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssBracketedValue { + l_brack_token: L_BRACK@11..12 "[" [] [], + items: CssBracketedValueList [ + CssCustomIdentifier { + value_token: IDENT@12..13 "a" [] [], + }, + CssGenericDelimiter { + value: COMMA@13..15 "," [] [Whitespace(" ")], + }, + CssCustomIdentifier { + value_token: IDENT@15..16 "b" [] [], + }, + CssGenericDelimiter { + value: COMMA@16..18 "," [] [Whitespace(" ")], + }, + CssCustomIdentifier { + value_token: IDENT@18..19 "c" [] [], + }, + ], + r_brack_token: R_BRACK@19..20 "]" [] [], + }, + ], + }, modifiers: ScssVariableModifierList [], semicolon_token: SEMICOLON@20..21 ";" [] [], }, @@ -64,35 +66,37 @@ CssRoot { }, }, colon_token: COLON@28..30 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - CssBracketedValue { - l_brack_token: L_BRACK@30..31 "[" [] [], - items: CssBracketedValueList [ - CssCustomIdentifier { - value_token: IDENT@31..41 "full-start" [] [], - }, - CssGenericDelimiter { - value: COMMA@41..43 "," [] [Whitespace(" ")], - }, - CssCustomIdentifier { - value_token: IDENT@43..53 "main-start" [] [], - }, - CssGenericDelimiter { - value: COMMA@53..55 "," [] [Whitespace(" ")], - }, - CssCustomIdentifier { - value_token: IDENT@55..63 "main-end" [] [], - }, - CssGenericDelimiter { - value: COMMA@63..65 "," [] [Whitespace(" ")], - }, - CssCustomIdentifier { - value_token: IDENT@65..73 "full-end" [] [], - }, - ], - r_brack_token: R_BRACK@73..74 "]" [] [], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + CssBracketedValue { + l_brack_token: L_BRACK@30..31 "[" [] [], + items: CssBracketedValueList [ + CssCustomIdentifier { + value_token: IDENT@31..41 "full-start" [] [], + }, + CssGenericDelimiter { + value: COMMA@41..43 "," [] [Whitespace(" ")], + }, + CssCustomIdentifier { + value_token: IDENT@43..53 "main-start" [] [], + }, + CssGenericDelimiter { + value: COMMA@53..55 "," [] [Whitespace(" ")], + }, + CssCustomIdentifier { + value_token: IDENT@55..63 "main-end" [] [], + }, + CssGenericDelimiter { + value: COMMA@63..65 "," [] [Whitespace(" ")], + }, + CssCustomIdentifier { + value_token: IDENT@65..73 "full-end" [] [], + }, + ], + r_brack_token: R_BRACK@73..74 "]" [] [], + }, + ], + }, modifiers: ScssVariableModifierList [], semicolon_token: SEMICOLON@74..75 ";" [] [], }, @@ -170,21 +174,22 @@ CssRoot { 1: CSS_IDENTIFIER@1..9 0: IDENT@1..9 "brackets" [] [] 1: COLON@9..11 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@11..20 - 0: CSS_BRACKETED_VALUE@11..20 - 0: L_BRACK@11..12 "[" [] [] - 1: CSS_BRACKETED_VALUE_LIST@12..19 - 0: CSS_CUSTOM_IDENTIFIER@12..13 - 0: IDENT@12..13 "a" [] [] - 1: CSS_GENERIC_DELIMITER@13..15 - 0: COMMA@13..15 "," [] [Whitespace(" ")] - 2: CSS_CUSTOM_IDENTIFIER@15..16 - 0: IDENT@15..16 "b" [] [] - 3: CSS_GENERIC_DELIMITER@16..18 - 0: COMMA@16..18 "," [] [Whitespace(" ")] - 4: CSS_CUSTOM_IDENTIFIER@18..19 - 0: IDENT@18..19 "c" [] [] - 2: R_BRACK@19..20 "]" [] [] + 2: SCSS_EXPRESSION@11..20 + 0: SCSS_EXPRESSION_ITEM_LIST@11..20 + 0: CSS_BRACKETED_VALUE@11..20 + 0: L_BRACK@11..12 "[" [] [] + 1: CSS_BRACKETED_VALUE_LIST@12..19 + 0: CSS_CUSTOM_IDENTIFIER@12..13 + 0: IDENT@12..13 "a" [] [] + 1: CSS_GENERIC_DELIMITER@13..15 + 0: COMMA@13..15 "," [] [Whitespace(" ")] + 2: CSS_CUSTOM_IDENTIFIER@15..16 + 0: IDENT@15..16 "b" [] [] + 3: CSS_GENERIC_DELIMITER@16..18 + 0: COMMA@16..18 "," [] [Whitespace(" ")] + 4: CSS_CUSTOM_IDENTIFIER@18..19 + 0: IDENT@18..19 "c" [] [] + 2: R_BRACK@19..20 "]" [] [] 3: SCSS_VARIABLE_MODIFIER_LIST@20..20 4: SEMICOLON@20..21 ";" [] [] 1: SCSS_DECLARATION@21..75 @@ -193,25 +198,26 @@ CssRoot { 1: CSS_IDENTIFIER@23..28 0: IDENT@23..28 "lines" [] [] 1: COLON@28..30 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@30..74 - 0: CSS_BRACKETED_VALUE@30..74 - 0: L_BRACK@30..31 "[" [] [] - 1: CSS_BRACKETED_VALUE_LIST@31..73 - 0: CSS_CUSTOM_IDENTIFIER@31..41 - 0: IDENT@31..41 "full-start" [] [] - 1: CSS_GENERIC_DELIMITER@41..43 - 0: COMMA@41..43 "," [] [Whitespace(" ")] - 2: CSS_CUSTOM_IDENTIFIER@43..53 - 0: IDENT@43..53 "main-start" [] [] - 3: CSS_GENERIC_DELIMITER@53..55 - 0: COMMA@53..55 "," [] [Whitespace(" ")] - 4: CSS_CUSTOM_IDENTIFIER@55..63 - 0: IDENT@55..63 "main-end" [] [] - 5: CSS_GENERIC_DELIMITER@63..65 - 0: COMMA@63..65 "," [] [Whitespace(" ")] - 6: CSS_CUSTOM_IDENTIFIER@65..73 - 0: IDENT@65..73 "full-end" [] [] - 2: R_BRACK@73..74 "]" [] [] + 2: SCSS_EXPRESSION@30..74 + 0: SCSS_EXPRESSION_ITEM_LIST@30..74 + 0: CSS_BRACKETED_VALUE@30..74 + 0: L_BRACK@30..31 "[" [] [] + 1: CSS_BRACKETED_VALUE_LIST@31..73 + 0: CSS_CUSTOM_IDENTIFIER@31..41 + 0: IDENT@31..41 "full-start" [] [] + 1: CSS_GENERIC_DELIMITER@41..43 + 0: COMMA@41..43 "," [] [Whitespace(" ")] + 2: CSS_CUSTOM_IDENTIFIER@43..53 + 0: IDENT@43..53 "main-start" [] [] + 3: CSS_GENERIC_DELIMITER@53..55 + 0: COMMA@53..55 "," [] [Whitespace(" ")] + 4: CSS_CUSTOM_IDENTIFIER@55..63 + 0: IDENT@55..63 "main-end" [] [] + 5: CSS_GENERIC_DELIMITER@63..65 + 0: COMMA@63..65 "," [] [Whitespace(" ")] + 6: CSS_CUSTOM_IDENTIFIER@65..73 + 0: IDENT@65..73 "full-end" [] [] + 2: R_BRACK@73..74 "]" [] [] 3: SCSS_VARIABLE_MODIFIER_LIST@74..74 4: SEMICOLON@74..75 ";" [] [] 2: CSS_QUALIFIED_RULE@75..126 diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/value/parent-and-colon-values.scss.snap b/crates/biome_css_parser/tests/css_test_suite/ok/scss/value/parent-and-colon-values.scss.snap index 7dd5033682bb..a19e22b81370 100644 --- a/crates/biome_css_parser/tests/css_test_suite/ok/scss/value/parent-and-colon-values.scss.snap +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/value/parent-and-colon-values.scss.snap @@ -1,6 +1,5 @@ --- source: crates/biome_css_parser/tests/spec_test.rs -assertion_line: 208 expression: snapshot --- @@ -49,11 +48,13 @@ CssRoot { }, }, colon_token: COLON@17..19 ":" [] [Whitespace(" ")], - value: CssGenericComponentValueList [ - ScssParentSelectorValue { - amp_token: AMP@19..20 "&" [] [], - }, - ], + value: ScssExpression { + items: ScssExpressionItemList [ + ScssParentSelectorValue { + amp_token: AMP@19..20 "&" [] [], + }, + ], + }, modifiers: ScssVariableModifierList [], semicolon_token: SEMICOLON@20..21 ";" [] [], }, @@ -135,9 +136,10 @@ CssRoot { 1: CSS_IDENTIFIER@13..17 0: IDENT@13..17 "self" [] [] 1: COLON@17..19 ":" [] [Whitespace(" ")] - 2: CSS_GENERIC_COMPONENT_VALUE_LIST@19..20 - 0: SCSS_PARENT_SELECTOR_VALUE@19..20 - 0: AMP@19..20 "&" [] [] + 2: SCSS_EXPRESSION@19..20 + 0: SCSS_EXPRESSION_ITEM_LIST@19..20 + 0: SCSS_PARENT_SELECTOR_VALUE@19..20 + 0: AMP@19..20 "&" [] [] 3: SCSS_VARIABLE_MODIFIER_LIST@20..20 4: SEMICOLON@20..21 ";" [] [] 1: CSS_NESTED_QUALIFIED_RULE@21..56 diff --git a/crates/biome_css_syntax/src/generated/kind.rs b/crates/biome_css_syntax/src/generated/kind.rs index bdb13548d1ad..97c96d6dbc77 100644 --- a/crates/biome_css_syntax/src/generated/kind.rs +++ b/crates/biome_css_syntax/src/generated/kind.rs @@ -37,6 +37,7 @@ pub enum CssSyntaxKind { COLON, COLON2, EQ, + EQ2, BANG, NEQ, MINUS, @@ -538,6 +539,7 @@ pub enum CssSyntaxKind { SCSS_DECLARATION, SCSS_EXPRESSION, SCSS_EXPRESSION_ITEM_LIST, + SCSS_BINARY_EXPRESSION, SCSS_LIST_EXPRESSION, SCSS_LIST_EXPRESSION_ELEMENT, SCSS_LIST_EXPRESSION_ELEMENT_LIST, @@ -546,6 +548,7 @@ pub enum CssSyntaxKind { SCSS_MAP_EXPRESSION_PAIR_LIST, SCSS_PARENT_SELECTOR_VALUE, SCSS_PARENTHESIZED_EXPRESSION, + SCSS_UNARY_EXPRESSION, SCSS_NESTING_DECLARATION, SCSS_NAMESPACED_IDENTIFIER, SCSS_QUALIFIED_NAME, @@ -639,6 +642,7 @@ impl CssSyntaxKind { | COLON | COLON2 | EQ + | EQ2 | BANG | NEQ | MINUS @@ -965,6 +969,7 @@ impl CssSyntaxKind { COLON => ":", COLON2 => "::", EQ => "=", + EQ2 => "==", BANG => "!", NEQ => "!=", MINUS => "-", @@ -1194,4 +1199,4 @@ impl CssSyntaxKind { } #[doc = r" Utility macro for creating a SyntaxKind through simple macro syntax"] #[macro_export] -macro_rules ! T { [;] => { $ crate :: CssSyntaxKind :: SEMICOLON } ; [,] => { $ crate :: CssSyntaxKind :: COMMA } ; ['('] => { $ crate :: CssSyntaxKind :: L_PAREN } ; [')'] => { $ crate :: CssSyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: CssSyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: CssSyntaxKind :: R_CURLY } ; ['['] => { $ crate :: CssSyntaxKind :: L_BRACK } ; [']'] => { $ crate :: CssSyntaxKind :: R_BRACK } ; [<] => { $ crate :: CssSyntaxKind :: L_ANGLE } ; [>] => { $ crate :: CssSyntaxKind :: R_ANGLE } ; [~] => { $ crate :: CssSyntaxKind :: TILDE } ; [$] => { $ crate :: CssSyntaxKind :: DOLLAR } ; [#] => { $ crate :: CssSyntaxKind :: HASH } ; [&] => { $ crate :: CssSyntaxKind :: AMP } ; [|] => { $ crate :: CssSyntaxKind :: PIPE } ; [||] => { $ crate :: CssSyntaxKind :: PIPE2 } ; [+] => { $ crate :: CssSyntaxKind :: PLUS } ; [*] => { $ crate :: CssSyntaxKind :: STAR } ; [/] => { $ crate :: CssSyntaxKind :: SLASH } ; [^] => { $ crate :: CssSyntaxKind :: CARET } ; [%] => { $ crate :: CssSyntaxKind :: PERCENT } ; [.] => { $ crate :: CssSyntaxKind :: DOT } ; [:] => { $ crate :: CssSyntaxKind :: COLON } ; [::] => { $ crate :: CssSyntaxKind :: COLON2 } ; [=] => { $ crate :: CssSyntaxKind :: EQ } ; [!] => { $ crate :: CssSyntaxKind :: BANG } ; [!=] => { $ crate :: CssSyntaxKind :: NEQ } ; [-] => { $ crate :: CssSyntaxKind :: MINUS } ; [<=] => { $ crate :: CssSyntaxKind :: LTEQ } ; [>=] => { $ crate :: CssSyntaxKind :: GTEQ } ; [+=] => { $ crate :: CssSyntaxKind :: PLUSEQ } ; [|=] => { $ crate :: CssSyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: CssSyntaxKind :: AMPEQ } ; [^=] => { $ crate :: CssSyntaxKind :: CARETEQ } ; [/=] => { $ crate :: CssSyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: CssSyntaxKind :: STAREQ } ; [%=] => { $ crate :: CssSyntaxKind :: PERCENTEQ } ; [@] => { $ crate :: CssSyntaxKind :: AT } ; ["$="] => { $ crate :: CssSyntaxKind :: DOLLAR_EQ } ; [~=] => { $ crate :: CssSyntaxKind :: TILDE_EQ } ; [-->] => { $ crate :: CssSyntaxKind :: CDC } ; [] => { $ crate :: CssSyntaxKind :: CDC } ; [