diff --git a/crates/biome_css_analyze/src/assist/source/use_sorted_properties.rs b/crates/biome_css_analyze/src/assist/source/use_sorted_properties.rs index 96bab0ef84a5..a5d7ba8eefad 100644 --- a/crates/biome_css_analyze/src/assist/source/use_sorted_properties.rs +++ b/crates/biome_css_analyze/src/assist/source/use_sorted_properties.rs @@ -243,6 +243,7 @@ impl RecessOrderMember { AnyCssDeclarationOrRule::CssBogus(_) => NodeKindOrder::UnknownKind, AnyCssDeclarationOrRule::CssMetavariable(_) => NodeKindOrder::UnknownKind, AnyCssDeclarationOrRule::ScssDeclaration(_) => NodeKindOrder::UnknownKind, + AnyCssDeclarationOrRule::ScssNestingDeclaration(_) => NodeKindOrder::UnknownKind, AnyCssDeclarationOrRule::AnyCssRule(rule) => match rule { AnyCssRule::CssAtRule(_) => NodeKindOrder::NestedRuleOrAtRule, AnyCssRule::CssBogusRule(_) => NodeKindOrder::UnknownKind, diff --git a/crates/biome_css_analyze/src/lint/correctness/no_unknown_function.rs b/crates/biome_css_analyze/src/lint/correctness/no_unknown_function.rs index cad129681340..09ddab022a51 100644 --- a/crates/biome_css_analyze/src/lint/correctness/no_unknown_function.rs +++ b/crates/biome_css_analyze/src/lint/correctness/no_unknown_function.rs @@ -78,7 +78,10 @@ impl Rule for NoUnknownFunction { fn run(ctx: &RuleContext) -> Option { let node = ctx.query(); - let binding = node.name().ok()?.value_token().ok()?; + let binding = node.name().ok().and_then(|name| { + name.as_css_identifier() + .and_then(|name| name.value_token().ok()) + })?; let function_name = binding.text_trimmed(); // We don't have a semantic model yet, so we can't determine if functions are defined elsewhere. diff --git a/crates/biome_css_analyze/src/lint/correctness/no_unknown_unit.rs b/crates/biome_css_analyze/src/lint/correctness/no_unknown_unit.rs index 39cdc92add38..738a79c731dd 100644 --- a/crates/biome_css_analyze/src/lint/correctness/no_unknown_unit.rs +++ b/crates/biome_css_analyze/src/lint/correctness/no_unknown_unit.rs @@ -115,11 +115,11 @@ impl Rule for NoUnknownUnit { match ancestor.kind() { CssSyntaxKind::CSS_FUNCTION => { let function_name_token = ancestor - .cast::()? - .name() - .ok()? - .value_token() - .ok()?; + .cast::()? + .name() + .ok()? + .as_css_identifier() + .and_then(|name| name.value_token().ok())?; let function_name = function_name_token .text_trimmed() .to_ascii_lowercase_cow(); diff --git a/crates/biome_css_factory/src/generated/node_factory.rs b/crates/biome_css_factory/src/generated/node_factory.rs index df2c585243e9..11ee3a4626e3 100644 --- a/crates/biome_css_factory/src/generated/node_factory.rs +++ b/crates/biome_css_factory/src/generated/node_factory.rs @@ -865,7 +865,7 @@ pub fn css_font_palette_values_at_rule_declarator( )) } pub fn css_function( - name: CssIdentifier, + name: AnyCssFunctionName, l_paren_token: SyntaxToken, items: CssParameterList, r_paren_token: SyntaxToken, @@ -2703,6 +2703,18 @@ impl CssTypeSelectorBuilder { )) } } +pub fn css_unary_expression( + operator_token: SyntaxToken, + expression: AnyCssExpression, +) -> CssUnaryExpression { + CssUnaryExpression::unwrap_cast(SyntaxNode::new_detached( + CssSyntaxKind::CSS_UNARY_EXPRESSION, + [ + Some(SyntaxElement::Token(operator_token)), + Some(SyntaxElement::Node(expression.into_syntax())), + ], + )) +} pub fn css_unicode_codepoint(value_token: SyntaxToken) -> CssUnicodeCodepoint { CssUnicodeCodepoint::unwrap_cast(SyntaxNode::new_detached( CssSyntaxKind::CSS_UNICODE_CODEPOINT, @@ -3027,6 +3039,36 @@ pub fn scss_namespaced_identifier( ], )) } +pub fn scss_nesting_declaration( + name: CssIdentifier, + colon_token: SyntaxToken, + value: CssGenericComponentValueList, + block: AnyCssDeclarationOrRuleBlock, +) -> ScssNestingDeclaration { + ScssNestingDeclaration::unwrap_cast(SyntaxNode::new_detached( + CssSyntaxKind::SCSS_NESTING_DECLARATION, + [ + Some(SyntaxElement::Node(name.into_syntax())), + Some(SyntaxElement::Token(colon_token)), + Some(SyntaxElement::Node(value.into_syntax())), + Some(SyntaxElement::Node(block.into_syntax())), + ], + )) +} +pub fn scss_qualified_name( + module: CssIdentifier, + dot_token: SyntaxToken, + member: AnyScssModuleMember, +) -> ScssQualifiedName { + ScssQualifiedName::unwrap_cast(SyntaxNode::new_detached( + CssSyntaxKind::SCSS_QUALIFIED_NAME, + [ + Some(SyntaxElement::Node(module.into_syntax())), + Some(SyntaxElement::Token(dot_token)), + Some(SyntaxElement::Node(member.into_syntax())), + ], + )) +} pub fn scss_variable_modifier( excl_token: SyntaxToken, value_token: SyntaxToken, @@ -3336,7 +3378,7 @@ where } pub fn css_bracketed_value_list(items: I) -> CssBracketedValueList where - I: IntoIterator, + I: IntoIterator, I::IntoIter: ExactSizeIterator, { CssBracketedValueList::unwrap_cast(SyntaxNode::new_detached( diff --git a/crates/biome_css_factory/src/generated/syntax_factory.rs b/crates/biome_css_factory/src/generated/syntax_factory.rs index 6bdc6de04d52..763aa1a8a38f 100644 --- a/crates/biome_css_factory/src/generated/syntax_factory.rs +++ b/crates/biome_css_factory/src/generated/syntax_factory.rs @@ -1686,7 +1686,7 @@ impl SyntaxFactory for CssSyntaxFactory { let mut slots: RawNodeSlots<4usize> = RawNodeSlots::default(); let mut current_element = elements.next(); if let Some(element) = ¤t_element - && CssIdentifier::can_cast(element.kind()) + && AnyCssFunctionName::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); @@ -5522,6 +5522,32 @@ impl SyntaxFactory for CssSyntaxFactory { } slots.into_node(CSS_TYPE_SELECTOR, children) } + CSS_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 ! [*]) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && AnyCssExpression::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + CSS_UNARY_EXPRESSION.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(CSS_UNARY_EXPRESSION, children) + } CSS_UNICODE_CODEPOINT => { let mut elements = (&children).into_iter(); let mut slots: RawNodeSlots<1usize> = RawNodeSlots::default(); @@ -6200,6 +6226,79 @@ impl SyntaxFactory for CssSyntaxFactory { } slots.into_node(SCSS_NAMESPACED_IDENTIFIER, children) } + SCSS_NESTING_DECLARATION => { + let mut elements = (&children).into_iter(); + let mut slots: RawNodeSlots<4usize> = RawNodeSlots::default(); + let mut current_element = elements.next(); + if let Some(element) = ¤t_element + && CssIdentifier::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && element.kind() == T ! [:] + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && CssGenericComponentValueList::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && AnyCssDeclarationOrRuleBlock::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + SCSS_NESTING_DECLARATION.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(SCSS_NESTING_DECLARATION, children) + } + SCSS_QUALIFIED_NAME => { + 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 + && CssIdentifier::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && element.kind() == T ! [.] + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && AnyScssModuleMember::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + SCSS_QUALIFIED_NAME.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(SCSS_QUALIFIED_NAME, children) + } SCSS_VARIABLE_MODIFIER => { let mut elements = (&children).into_iter(); let mut slots: RawNodeSlots<2usize> = RawNodeSlots::default(); @@ -6717,7 +6816,7 @@ impl SyntaxFactory for CssSyntaxFactory { false, ), CSS_BRACKETED_VALUE_LIST => { - Self::make_node_list_syntax(kind, children, AnyCssCustomIdentifier::can_cast) + Self::make_node_list_syntax(kind, children, AnyCssBracketedValueItem::can_cast) } CSS_COMPONENT_VALUE_LIST => { Self::make_node_list_syntax(kind, children, AnyCssValue::can_cast) diff --git a/crates/biome_css_formatter/Cargo.toml b/crates/biome_css_formatter/Cargo.toml index 27ab7be950b1..42c4993d8bb7 100644 --- a/crates/biome_css_formatter/Cargo.toml +++ b/crates/biome_css_formatter/Cargo.toml @@ -32,6 +32,7 @@ biome_suppression = { workspace = true } [dev-dependencies] biome_configuration = { path = "../biome_configuration" } biome_css_parser = { path = "../biome_css_parser" } +biome_css_syntax = { path = "../biome_css_syntax", features = ["scss"] } biome_formatter = { workspace = true, features = ["countme"] } biome_formatter_test = { path = "../biome_formatter_test" } biome_fs = { path = "../biome_fs" } diff --git a/crates/biome_css_formatter/src/css/any/bracketed_value_item.rs b/crates/biome_css_formatter/src/css/any/bracketed_value_item.rs new file mode 100644 index 000000000000..dfe87d34b2c3 --- /dev/null +++ b/crates/biome_css_formatter/src/css/any/bracketed_value_item.rs @@ -0,0 +1,15 @@ +//! This is a generated file. Don't modify it by hand! Run 'cargo codegen formatter' to re-generate the file. + +use crate::prelude::*; +use biome_css_syntax::AnyCssBracketedValueItem; +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatAnyCssBracketedValueItem; +impl FormatRule for FormatAnyCssBracketedValueItem { + type Context = CssFormatContext; + fn fmt(&self, node: &AnyCssBracketedValueItem, f: &mut CssFormatter) -> FormatResult<()> { + match node { + AnyCssBracketedValueItem::AnyCssCustomIdentifier(node) => node.format().fmt(f), + AnyCssBracketedValueItem::CssGenericDelimiter(node) => node.format().fmt(f), + } + } +} diff --git a/crates/biome_css_formatter/src/css/any/declaration.rs b/crates/biome_css_formatter/src/css/any/declaration.rs index 0f7f8405eb6b..5fcbe617f3f0 100644 --- a/crates/biome_css_formatter/src/css/any/declaration.rs +++ b/crates/biome_css_formatter/src/css/any/declaration.rs @@ -11,6 +11,7 @@ impl FormatRule for FormatAnyCssDeclaration { AnyCssDeclaration::CssDeclarationWithSemicolon(node) => node.format().fmt(f), AnyCssDeclaration::CssEmptyDeclaration(node) => node.format().fmt(f), AnyCssDeclaration::ScssDeclaration(node) => node.format().fmt(f), + AnyCssDeclaration::ScssNestingDeclaration(node) => node.format().fmt(f), } } } diff --git a/crates/biome_css_formatter/src/css/any/declaration_or_at_rule.rs b/crates/biome_css_formatter/src/css/any/declaration_or_at_rule.rs index 1a0c58f70eaf..d4ff050ef480 100644 --- a/crates/biome_css_formatter/src/css/any/declaration_or_at_rule.rs +++ b/crates/biome_css_formatter/src/css/any/declaration_or_at_rule.rs @@ -12,6 +12,7 @@ impl FormatRule for FormatAnyCssDeclarationOrAtRule { AnyCssDeclarationOrAtRule::CssDeclarationWithSemicolon(node) => node.format().fmt(f), AnyCssDeclarationOrAtRule::CssEmptyDeclaration(node) => node.format().fmt(f), AnyCssDeclarationOrAtRule::ScssDeclaration(node) => node.format().fmt(f), + AnyCssDeclarationOrAtRule::ScssNestingDeclaration(node) => node.format().fmt(f), } } } diff --git a/crates/biome_css_formatter/src/css/any/declaration_or_rule.rs b/crates/biome_css_formatter/src/css/any/declaration_or_rule.rs index 6884ff730e03..a7773afcd237 100644 --- a/crates/biome_css_formatter/src/css/any/declaration_or_rule.rs +++ b/crates/biome_css_formatter/src/css/any/declaration_or_rule.rs @@ -14,6 +14,7 @@ impl FormatRule for FormatAnyCssDeclarationOrRule { AnyCssDeclarationOrRule::CssEmptyDeclaration(node) => node.format().fmt(f), AnyCssDeclarationOrRule::CssMetavariable(node) => node.format().fmt(f), AnyCssDeclarationOrRule::ScssDeclaration(node) => node.format().fmt(f), + AnyCssDeclarationOrRule::ScssNestingDeclaration(node) => node.format().fmt(f), } } } diff --git a/crates/biome_css_formatter/src/css/any/expression.rs b/crates/biome_css_formatter/src/css/any/expression.rs index 5b078825c86a..2a126ef86c3b 100644 --- a/crates/biome_css_formatter/src/css/any/expression.rs +++ b/crates/biome_css_formatter/src/css/any/expression.rs @@ -12,6 +12,7 @@ impl FormatRule for FormatAnyCssExpression { AnyCssExpression::CssCommaSeparatedValue(node) => node.format().fmt(f), AnyCssExpression::CssListOfComponentValuesExpression(node) => node.format().fmt(f), AnyCssExpression::CssParenthesizedExpression(node) => node.format().fmt(f), + AnyCssExpression::CssUnaryExpression(node) => node.format().fmt(f), } } } diff --git a/crates/biome_css_formatter/src/css/any/function_name.rs b/crates/biome_css_formatter/src/css/any/function_name.rs new file mode 100644 index 000000000000..56dd72230b8a --- /dev/null +++ b/crates/biome_css_formatter/src/css/any/function_name.rs @@ -0,0 +1,15 @@ +//! This is a generated file. Don't modify it by hand! Run 'cargo codegen formatter' to re-generate the file. + +use crate::prelude::*; +use biome_css_syntax::AnyCssFunctionName; +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatAnyCssFunctionName; +impl FormatRule for FormatAnyCssFunctionName { + type Context = CssFormatContext; + fn fmt(&self, node: &AnyCssFunctionName, f: &mut CssFormatter) -> FormatResult<()> { + match node { + AnyCssFunctionName::CssIdentifier(node) => node.format().fmt(f), + AnyCssFunctionName::ScssQualifiedName(node) => node.format().fmt(f), + } + } +} diff --git a/crates/biome_css_formatter/src/css/any/mod.rs b/crates/biome_css_formatter/src/css/any/mod.rs index 4b568c7290f0..0ed14d030401 100644 --- a/crates/biome_css_formatter/src/css/any/mod.rs +++ b/crates/biome_css_formatter/src/css/any/mod.rs @@ -6,6 +6,7 @@ pub(crate) mod attr_name; pub(crate) mod attr_type; pub(crate) mod attr_unit; pub(crate) mod attribute_matcher_value; +pub(crate) mod bracketed_value_item; pub(crate) mod composes_import_source; pub(crate) mod compound_selector; pub(crate) mod conditional_block; @@ -32,6 +33,7 @@ pub(crate) mod font_family_name; pub(crate) mod font_feature_values_block; pub(crate) mod font_feature_values_item; pub(crate) mod function; +pub(crate) mod function_name; pub(crate) mod function_parameter; pub(crate) mod generic_component_value; pub(crate) mod if_branch; diff --git a/crates/biome_css_formatter/src/css/any/page_at_rule_item.rs b/crates/biome_css_formatter/src/css/any/page_at_rule_item.rs index eaef76d68084..00038a68068f 100644 --- a/crates/biome_css_formatter/src/css/any/page_at_rule_item.rs +++ b/crates/biome_css_formatter/src/css/any/page_at_rule_item.rs @@ -13,6 +13,8 @@ impl FormatRule for FormatAnyCssPageAtRuleItem { AnyCssPageAtRuleItem::CssDeclarationWithSemicolon(node) => node.format().fmt(f), AnyCssPageAtRuleItem::CssEmptyDeclaration(node) => node.format().fmt(f), AnyCssPageAtRuleItem::CssMarginAtRule(node) => node.format().fmt(f), + AnyCssPageAtRuleItem::ScssDeclaration(node) => node.format().fmt(f), + AnyCssPageAtRuleItem::ScssNestingDeclaration(node) => node.format().fmt(f), } } } diff --git a/crates/biome_css_formatter/src/css/any/value.rs b/crates/biome_css_formatter/src/css/any/value.rs index 7f9ec54ef0ee..a9a7b64b7f02 100644 --- a/crates/biome_css_formatter/src/css/any/value.rs +++ b/crates/biome_css_formatter/src/css/any/value.rs @@ -21,6 +21,7 @@ impl FormatRule for FormatAnyCssValue { AnyCssValue::CssString(node) => node.format().fmt(f), AnyCssValue::CssUnicodeRange(node) => node.format().fmt(f), AnyCssValue::ScssIdentifier(node) => node.format().fmt(f), + AnyCssValue::ScssQualifiedName(node) => node.format().fmt(f), AnyCssValue::TwValueThemeReference(node) => node.format().fmt(f), } } diff --git a/crates/biome_css_formatter/src/css/auxiliary/mod.rs b/crates/biome_css_formatter/src/css/auxiliary/mod.rs index 2d08b4e96c8b..e20ac802f46a 100644 --- a/crates/biome_css_formatter/src/css/auxiliary/mod.rs +++ b/crates/biome_css_formatter/src/css/auxiliary/mod.rs @@ -116,6 +116,7 @@ pub(crate) mod syntax_component_without_multiplier; pub(crate) mod syntax_multiplier; pub(crate) mod syntax_type; pub(crate) mod type_function; +pub(crate) mod unary_expression; pub(crate) mod unicode_codepoint; pub(crate) mod unicode_range; pub(crate) mod unicode_range_interval; diff --git a/crates/biome_css_formatter/src/css/auxiliary/unary_expression.rs b/crates/biome_css_formatter/src/css/auxiliary/unary_expression.rs new file mode 100644 index 000000000000..9d54622cafa6 --- /dev/null +++ b/crates/biome_css_formatter/src/css/auxiliary/unary_expression.rs @@ -0,0 +1,18 @@ +use crate::prelude::*; +use biome_css_syntax::{CssUnaryExpression, CssUnaryExpressionFields}; +use biome_formatter::write; + +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatCssUnaryExpression; +impl FormatNodeRule for FormatCssUnaryExpression { + fn fmt_fields(&self, node: &CssUnaryExpression, f: &mut CssFormatter) -> FormatResult<()> { + let CssUnaryExpressionFields { + operator, + expression, + } = node.as_fields(); + let operator = operator?; + let expression = expression?; + + write!(f, [operator.format(), expression.format()]) + } +} diff --git a/crates/biome_css_formatter/src/css/lists/bracketed_value_list.rs b/crates/biome_css_formatter/src/css/lists/bracketed_value_list.rs index d1173e58cb23..2f44878decb3 100644 --- a/crates/biome_css_formatter/src/css/lists/bracketed_value_list.rs +++ b/crates/biome_css_formatter/src/css/lists/bracketed_value_list.rs @@ -1,12 +1,11 @@ use crate::prelude::*; +use crate::utils::component_value_list::write_component_value_list; use biome_css_syntax::CssBracketedValueList; #[derive(Debug, Clone, Default)] pub(crate) struct FormatCssBracketedValueList; impl FormatRule for FormatCssBracketedValueList { type Context = CssFormatContext; fn fmt(&self, node: &CssBracketedValueList, f: &mut CssFormatter) -> FormatResult<()> { - f.join_with(&space()) - .entries(node.iter().formatted()) - .finish() + write_component_value_list(node, f) } } diff --git a/crates/biome_css_formatter/src/generated.rs b/crates/biome_css_formatter/src/generated.rs index 7501ff55c27c..ac18cdd89bd8 100644 --- a/crates/biome_css_formatter/src/generated.rs +++ b/crates/biome_css_formatter/src/generated.rs @@ -6225,6 +6225,44 @@ impl IntoFormat for biome_css_syntax::CssTypeSelector { ) } } +impl FormatRule + for crate::css::auxiliary::unary_expression::FormatCssUnaryExpression +{ + type Context = CssFormatContext; + #[inline(always)] + fn fmt( + &self, + node: &biome_css_syntax::CssUnaryExpression, + f: &mut CssFormatter, + ) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl AsFormat for biome_css_syntax::CssUnaryExpression { + type Format<'a> = FormatRefWithRule< + 'a, + biome_css_syntax::CssUnaryExpression, + crate::css::auxiliary::unary_expression::FormatCssUnaryExpression, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::css::auxiliary::unary_expression::FormatCssUnaryExpression::default(), + ) + } +} +impl IntoFormat for biome_css_syntax::CssUnaryExpression { + type Format = FormatOwnedWithRule< + biome_css_syntax::CssUnaryExpression, + crate::css::auxiliary::unary_expression::FormatCssUnaryExpression, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::css::auxiliary::unary_expression::FormatCssUnaryExpression::default(), + ) + } +} impl FormatRule for crate::css::auxiliary::unicode_codepoint::FormatCssUnicodeCodepoint { @@ -7072,6 +7110,82 @@ impl IntoFormat for biome_css_syntax::ScssNamespacedIdentifier ) } } +impl FormatRule + for crate::scss::auxiliary::nesting_declaration::FormatScssNestingDeclaration +{ + type Context = CssFormatContext; + #[inline(always)] + fn fmt( + &self, + node: &biome_css_syntax::ScssNestingDeclaration, + f: &mut CssFormatter, + ) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl AsFormat for biome_css_syntax::ScssNestingDeclaration { + type Format<'a> = FormatRefWithRule< + 'a, + biome_css_syntax::ScssNestingDeclaration, + crate::scss::auxiliary::nesting_declaration::FormatScssNestingDeclaration, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::scss::auxiliary::nesting_declaration::FormatScssNestingDeclaration::default(), + ) + } +} +impl IntoFormat for biome_css_syntax::ScssNestingDeclaration { + type Format = FormatOwnedWithRule< + biome_css_syntax::ScssNestingDeclaration, + crate::scss::auxiliary::nesting_declaration::FormatScssNestingDeclaration, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::scss::auxiliary::nesting_declaration::FormatScssNestingDeclaration::default(), + ) + } +} +impl FormatRule + for crate::scss::auxiliary::qualified_name::FormatScssQualifiedName +{ + type Context = CssFormatContext; + #[inline(always)] + fn fmt( + &self, + node: &biome_css_syntax::ScssQualifiedName, + f: &mut CssFormatter, + ) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl AsFormat for biome_css_syntax::ScssQualifiedName { + type Format<'a> = FormatRefWithRule< + 'a, + biome_css_syntax::ScssQualifiedName, + crate::scss::auxiliary::qualified_name::FormatScssQualifiedName, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::scss::auxiliary::qualified_name::FormatScssQualifiedName::default(), + ) + } +} +impl IntoFormat for biome_css_syntax::ScssQualifiedName { + type Format = FormatOwnedWithRule< + biome_css_syntax::ScssQualifiedName, + crate::scss::auxiliary::qualified_name::FormatScssQualifiedName, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::scss::auxiliary::qualified_name::FormatScssQualifiedName::default(), + ) + } +} impl FormatRule for crate::scss::auxiliary::variable_modifier::FormatScssVariableModifier { @@ -9952,6 +10066,31 @@ impl IntoFormat for biome_css_syntax::AnyCssAttributeMatcherVa ) } } +impl AsFormat for biome_css_syntax::AnyCssBracketedValueItem { + type Format<'a> = FormatRefWithRule< + 'a, + biome_css_syntax::AnyCssBracketedValueItem, + crate::css::any::bracketed_value_item::FormatAnyCssBracketedValueItem, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::css::any::bracketed_value_item::FormatAnyCssBracketedValueItem::default(), + ) + } +} +impl IntoFormat for biome_css_syntax::AnyCssBracketedValueItem { + type Format = FormatOwnedWithRule< + biome_css_syntax::AnyCssBracketedValueItem, + crate::css::any::bracketed_value_item::FormatAnyCssBracketedValueItem, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::css::any::bracketed_value_item::FormatAnyCssBracketedValueItem::default(), + ) + } +} impl AsFormat for biome_css_syntax::AnyCssComposesImportSource { type Format<'a> = FormatRefWithRule< 'a, @@ -10566,6 +10705,31 @@ impl IntoFormat for biome_css_syntax::AnyCssFunction { ) } } +impl AsFormat for biome_css_syntax::AnyCssFunctionName { + type Format<'a> = FormatRefWithRule< + 'a, + biome_css_syntax::AnyCssFunctionName, + crate::css::any::function_name::FormatAnyCssFunctionName, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::css::any::function_name::FormatAnyCssFunctionName::default(), + ) + } +} +impl IntoFormat for biome_css_syntax::AnyCssFunctionName { + type Format = FormatOwnedWithRule< + biome_css_syntax::AnyCssFunctionName, + crate::css::any::function_name::FormatAnyCssFunctionName, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::css::any::function_name::FormatAnyCssFunctionName::default(), + ) + } +} impl AsFormat for biome_css_syntax::AnyCssFunctionParameter { type Format<'a> = FormatRefWithRule< 'a, @@ -12159,6 +12323,31 @@ impl IntoFormat for biome_css_syntax::AnyScssDeclarationName { ) } } +impl AsFormat for biome_css_syntax::AnyScssModuleMember { + type Format<'a> = FormatRefWithRule< + 'a, + biome_css_syntax::AnyScssModuleMember, + crate::scss::any::module_member::FormatAnyScssModuleMember, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::scss::any::module_member::FormatAnyScssModuleMember::default(), + ) + } +} +impl IntoFormat for biome_css_syntax::AnyScssModuleMember { + type Format = FormatOwnedWithRule< + biome_css_syntax::AnyScssModuleMember, + crate::scss::any::module_member::FormatAnyScssModuleMember, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::scss::any::module_member::FormatAnyScssModuleMember::default(), + ) + } +} impl AsFormat for biome_css_syntax::AnyTwCustomVariantSelector { type Format<'a> = FormatRefWithRule< 'a, diff --git a/crates/biome_css_formatter/src/scss/any/mod.rs b/crates/biome_css_formatter/src/scss/any/mod.rs index 859c41d9f77f..40b6c122f4ee 100644 --- a/crates/biome_css_formatter/src/scss/any/mod.rs +++ b/crates/biome_css_formatter/src/scss/any/mod.rs @@ -1,3 +1,4 @@ //! This is a generated file. Don't modify it by hand! Run 'cargo codegen formatter' to re-generate the file. pub(crate) mod declaration_name; +pub(crate) mod module_member; diff --git a/crates/biome_css_formatter/src/scss/any/module_member.rs b/crates/biome_css_formatter/src/scss/any/module_member.rs new file mode 100644 index 000000000000..bbd7a583d387 --- /dev/null +++ b/crates/biome_css_formatter/src/scss/any/module_member.rs @@ -0,0 +1,15 @@ +//! This is a generated file. Don't modify it by hand! Run 'cargo codegen formatter' to re-generate the file. + +use crate::prelude::*; +use biome_css_syntax::AnyScssModuleMember; +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatAnyScssModuleMember; +impl FormatRule for FormatAnyScssModuleMember { + type Context = CssFormatContext; + fn fmt(&self, node: &AnyScssModuleMember, f: &mut CssFormatter) -> FormatResult<()> { + match node { + AnyScssModuleMember::CssIdentifier(node) => node.format().fmt(f), + AnyScssModuleMember::ScssIdentifier(node) => node.format().fmt(f), + } + } +} diff --git a/crates/biome_css_formatter/src/scss/auxiliary/mod.rs b/crates/biome_css_formatter/src/scss/auxiliary/mod.rs index cb5948b72b73..bec1ba300c52 100644 --- a/crates/biome_css_formatter/src/scss/auxiliary/mod.rs +++ b/crates/biome_css_formatter/src/scss/auxiliary/mod.rs @@ -1,4 +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 declaration; +pub(crate) mod nesting_declaration; +pub(crate) mod qualified_name; pub(crate) mod variable_modifier; diff --git a/crates/biome_css_formatter/src/scss/auxiliary/nesting_declaration.rs b/crates/biome_css_formatter/src/scss/auxiliary/nesting_declaration.rs new file mode 100644 index 000000000000..ce38190e79cf --- /dev/null +++ b/crates/biome_css_formatter/src/scss/auxiliary/nesting_declaration.rs @@ -0,0 +1,24 @@ +use crate::prelude::*; +use biome_css_syntax::{ScssNestingDeclaration, ScssNestingDeclarationFields}; +use biome_formatter::write; + +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatScssNestingDeclaration; +impl FormatNodeRule for FormatScssNestingDeclaration { + fn fmt_fields(&self, node: &ScssNestingDeclaration, f: &mut CssFormatter) -> FormatResult<()> { + let ScssNestingDeclarationFields { + name, + colon_token, + value, + block, + } = node.as_fields(); + + write!(f, [name.format(), colon_token.format()])?; + + if !value.is_empty() { + write!(f, [space(), value.format()])?; + } + + write!(f, [space(), block.format()]) + } +} diff --git a/crates/biome_css_formatter/src/scss/auxiliary/qualified_name.rs b/crates/biome_css_formatter/src/scss/auxiliary/qualified_name.rs new file mode 100644 index 000000000000..c7fa25c6ceb1 --- /dev/null +++ b/crates/biome_css_formatter/src/scss/auxiliary/qualified_name.rs @@ -0,0 +1,17 @@ +use crate::prelude::*; +use biome_css_syntax::{ScssQualifiedName, ScssQualifiedNameFields}; +use biome_formatter::write; + +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatScssQualifiedName; +impl FormatNodeRule for FormatScssQualifiedName { + fn fmt_fields(&self, node: &ScssQualifiedName, f: &mut CssFormatter) -> FormatResult<()> { + let ScssQualifiedNameFields { + module, + dot_token, + member, + } = node.as_fields(); + + write!(f, [module.format(), dot_token.format(), member.format()]) + } +} diff --git a/crates/biome_css_formatter/tests/specs/css/scss/declaration/ambiguous-selector-vs-nesting.scss b/crates/biome_css_formatter/tests/specs/css/scss/declaration/ambiguous-selector-vs-nesting.scss new file mode 100644 index 000000000000..c5da54bc142f --- /dev/null +++ b/crates/biome_css_formatter/tests/specs/css/scss/declaration/ambiguous-selector-vs-nesting.scss @@ -0,0 +1,6 @@ +.test{ + label:hover{color:red;} + font:bold{color:blue;} + font:12px{family:sans-serif;} + font: bold{family:serif;} +} diff --git a/crates/biome_css_formatter/tests/specs/css/scss/declaration/ambiguous-selector-vs-nesting.scss.snap b/crates/biome_css_formatter/tests/specs/css/scss/declaration/ambiguous-selector-vs-nesting.scss.snap new file mode 100644 index 000000000000..d55916415710 --- /dev/null +++ b/crates/biome_css_formatter/tests/specs/css/scss/declaration/ambiguous-selector-vs-nesting.scss.snap @@ -0,0 +1,50 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: css/scss/declaration/ambiguous-selector-vs-nesting.scss +--- + +# Input + +```scss +.test{ + label:hover{color:red;} + font:bold{color:blue;} + font:12px{family:sans-serif;} + font: bold{family:serif;} +} + +``` + + +============================= + +# Outputs + +## Output 1 + +----- +Indent style: Tab +Indent width: 2 +Line ending: LF +Line width: 80 +Quote style: Double Quotes +Trailing newline: true +----- + +```scss +.test { + label:hover { + color: red; + } + font:bold { + color: blue; + } + font: 12px { + family: sans-serif; + } + font: bold { + family: serif; + } +} + +``` diff --git a/crates/biome_css_formatter/tests/specs/css/scss/declaration/bracketed-values.scss b/crates/biome_css_formatter/tests/specs/css/scss/declaration/bracketed-values.scss new file mode 100644 index 000000000000..0793ba19d3a6 --- /dev/null +++ b/crates/biome_css_formatter/tests/specs/css/scss/declaration/bracketed-values.scss @@ -0,0 +1,5 @@ +$brackets:[a,b,c]; +$lines:[full-start , main-start,main-end +, full-end]; + +.grid{grid-column:[col-start]/[col-end];} diff --git a/crates/biome_css_formatter/tests/specs/css/scss/declaration/bracketed-values.scss.snap b/crates/biome_css_formatter/tests/specs/css/scss/declaration/bracketed-values.scss.snap new file mode 100644 index 000000000000..39495220ba0c --- /dev/null +++ b/crates/biome_css_formatter/tests/specs/css/scss/declaration/bracketed-values.scss.snap @@ -0,0 +1,41 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: css/scss/declaration/bracketed-values.scss +--- + +# Input + +```scss +$brackets:[a,b,c]; +$lines:[full-start , main-start,main-end +, full-end]; + +.grid{grid-column:[col-start]/[col-end];} + +``` + + +============================= + +# Outputs + +## Output 1 + +----- +Indent style: Tab +Indent width: 2 +Line ending: LF +Line width: 80 +Quote style: Double Quotes +Trailing newline: true +----- + +```scss +$brackets: [a, b, c]; +$lines: [full-start, main-start, main-end, full-end]; + +.grid { + grid-column: [col-start] / [col-end]; +} + +``` diff --git a/crates/biome_css_formatter/tests/specs/css/scss/declaration/mixed.scss.snap b/crates/biome_css_formatter/tests/specs/css/scss/declaration/mixed.scss.snap index 0b22524b4cb7..f826dd927158 100644 --- a/crates/biome_css_formatter/tests/specs/css/scss/declaration/mixed.scss.snap +++ b/crates/biome_css_formatter/tests/specs/css/scss/declaration/mixed.scss.snap @@ -44,7 +44,7 @@ Trailing newline: true $combined: green !default !global !global; padding: $local-var; - margin: ns.$namespaced-var; + margin: ns.$namespaced-var; } ``` diff --git a/crates/biome_css_formatter/tests/specs/css/scss/declaration/nested-properties-empty-value.scss b/crates/biome_css_formatter/tests/specs/css/scss/declaration/nested-properties-empty-value.scss new file mode 100644 index 000000000000..d9e33367c795 --- /dev/null +++ b/crates/biome_css_formatter/tests/specs/css/scss/declaration/nested-properties-empty-value.scss @@ -0,0 +1,6 @@ +.font{ + color:red; + font:{ + size:12px; + } +} diff --git a/crates/biome_css_formatter/tests/specs/css/scss/declaration/nested-properties-empty-value.scss.snap b/crates/biome_css_formatter/tests/specs/css/scss/declaration/nested-properties-empty-value.scss.snap new file mode 100644 index 000000000000..53feb60450ec --- /dev/null +++ b/crates/biome_css_formatter/tests/specs/css/scss/declaration/nested-properties-empty-value.scss.snap @@ -0,0 +1,43 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +assertion_line: 212 +info: css/scss/declaration/nested-properties-empty-value.scss +--- + +# Input + +```scss +.font{ + color:red; + font:{ + size:12px; + } +} + +``` + + +============================= + +# Outputs + +## Output 1 + +----- +Indent style: Tab +Indent width: 2 +Line ending: LF +Line width: 80 +Quote style: Double Quotes +Trailing newline: true +----- + +```scss +.font { + color: red; + font: { + size: 12px; + } +} + +``` diff --git a/crates/biome_css_formatter/tests/specs/css/scss/declaration/nested-properties-with-value.scss b/crates/biome_css_formatter/tests/specs/css/scss/declaration/nested-properties-with-value.scss new file mode 100644 index 000000000000..4721b4e6d863 --- /dev/null +++ b/crates/biome_css_formatter/tests/specs/css/scss/declaration/nested-properties-with-value.scss @@ -0,0 +1,6 @@ +.font{ + color:red; + font:12px/1.2{ + family:sans-serif; + } +} diff --git a/crates/biome_css_formatter/tests/specs/css/scss/declaration/nested-properties-with-value.scss.snap b/crates/biome_css_formatter/tests/specs/css/scss/declaration/nested-properties-with-value.scss.snap new file mode 100644 index 000000000000..710f717b44f8 --- /dev/null +++ b/crates/biome_css_formatter/tests/specs/css/scss/declaration/nested-properties-with-value.scss.snap @@ -0,0 +1,42 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: css/scss/declaration/nested-properties-with-value.scss +--- + +# Input + +```scss +.font{ + color:red; + font:12px/1.2{ + family:sans-serif; + } +} + +``` + + +============================= + +# Outputs + +## Output 1 + +----- +Indent style: Tab +Indent width: 2 +Line ending: LF +Line width: 80 +Quote style: Double Quotes +Trailing newline: true +----- + +```scss +.font { + color: red; + font: 12px / 1.2 { + family: sans-serif; + } +} + +``` diff --git a/crates/biome_css_formatter/tests/specs/css/scss/declaration/page-at-rule.scss b/crates/biome_css_formatter/tests/specs/css/scss/declaration/page-at-rule.scss new file mode 100644 index 000000000000..955f2781b432 --- /dev/null +++ b/crates/biome_css_formatter/tests/specs/css/scss/declaration/page-at-rule.scss @@ -0,0 +1,13 @@ +@page :left{ +$padding:12px !default; +padding:$padding; + +font:{ +size:12px; +} + +@top-left{ +$margin:4px !global; +margin:$margin; +} +} diff --git a/crates/biome_css_formatter/tests/specs/css/scss/declaration/page-at-rule.scss.snap b/crates/biome_css_formatter/tests/specs/css/scss/declaration/page-at-rule.scss.snap new file mode 100644 index 000000000000..33c6ea50db92 --- /dev/null +++ b/crates/biome_css_formatter/tests/specs/css/scss/declaration/page-at-rule.scss.snap @@ -0,0 +1,56 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: css/scss/declaration/page-at-rule.scss +--- + +# Input + +```scss +@page :left{ +$padding:12px !default; +padding:$padding; + +font:{ +size:12px; +} + +@top-left{ +$margin:4px !global; +margin:$margin; +} +} + +``` + + +============================= + +# Outputs + +## Output 1 + +----- +Indent style: Tab +Indent width: 2 +Line ending: LF +Line width: 80 +Quote style: Double Quotes +Trailing newline: true +----- + +```scss +@page :left { + $padding: 12px !default; + padding: $padding; + + font: { + size: 12px; + } + + @top-left { + $margin: 4px !global; + margin: $margin; + } +} + +``` diff --git a/crates/biome_css_formatter/tests/specs/css/scss/declaration/spacing-after-colon.scss b/crates/biome_css_formatter/tests/specs/css/scss/declaration/spacing-after-colon.scss new file mode 100644 index 000000000000..8c114f89ed72 --- /dev/null +++ b/crates/biome_css_formatter/tests/specs/css/scss/declaration/spacing-after-colon.scss @@ -0,0 +1,6 @@ +.test{ + font:bold{color:red;} + font: bold{family:serif;} + font: + bold{family:sans-serif;} +} diff --git a/crates/biome_css_formatter/tests/specs/css/scss/declaration/spacing-after-colon.scss.snap b/crates/biome_css_formatter/tests/specs/css/scss/declaration/spacing-after-colon.scss.snap new file mode 100644 index 000000000000..00402d53d319 --- /dev/null +++ b/crates/biome_css_formatter/tests/specs/css/scss/declaration/spacing-after-colon.scss.snap @@ -0,0 +1,47 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: css/scss/declaration/spacing-after-colon.scss +--- + +# Input + +```scss +.test{ + font:bold{color:red;} + font: bold{family:serif;} + font: + bold{family:sans-serif;} +} + +``` + + +============================= + +# Outputs + +## Output 1 + +----- +Indent style: Tab +Indent width: 2 +Line ending: LF +Line width: 80 +Quote style: Double Quotes +Trailing newline: true +----- + +```scss +.test { + font:bold { + color: red; + } + font: bold { + family: serif; + } + font: bold { + family: sans-serif; + } +} + +``` diff --git a/crates/biome_css_formatter/tests/specs/css/scss/expression/qualified-names.scss b/crates/biome_css_formatter/tests/specs/css/scss/expression/qualified-names.scss new file mode 100644 index 000000000000..a16656c96429 --- /dev/null +++ b/crates/biome_css_formatter/tests/specs/css/scss/expression/qualified-names.scss @@ -0,0 +1,21 @@ +.test{ + +width:math.div(10px +, +2); + +height: + +math.ceil( 3.5px + +); + + +value:map.get( $map + , a + ); + +variable: + +map.$default ; + } diff --git a/crates/biome_css_formatter/tests/specs/css/scss/expression/qualified-names.scss.snap b/crates/biome_css_formatter/tests/specs/css/scss/expression/qualified-names.scss.snap new file mode 100644 index 000000000000..cdcaf6cd0c3a --- /dev/null +++ b/crates/biome_css_formatter/tests/specs/css/scss/expression/qualified-names.scss.snap @@ -0,0 +1,60 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: css/scss/expression/qualified-names.scss +--- + +# Input + +```scss +.test{ + +width:math.div(10px +, +2); + +height: + +math.ceil( 3.5px + +); + + +value:map.get( $map + , a + ); + +variable: + +map.$default ; + } + +``` + + +============================= + +# Outputs + +## Output 1 + +----- +Indent style: Tab +Indent width: 2 +Line ending: LF +Line width: 80 +Quote style: Double Quotes +Trailing newline: true +----- + +```scss +.test { + width: math.div(10px, 2); + + height: math.ceil(3.5px); + + value: map.get($map, a); + + variable: map.$default; +} + +``` diff --git a/crates/biome_css_formatter/tests/specs/css/unary-precedence.css b/crates/biome_css_formatter/tests/specs/css/unary-precedence.css new file mode 100644 index 000000000000..0d1adb980d2b --- /dev/null +++ b/crates/biome_css_formatter/tests/specs/css/unary-precedence.css @@ -0,0 +1,5 @@ +.unary-precedence{ + width:calc(-1 +2); + width:calc(+var(--x)+1px); + width:calc(- var(--y)*2); +} diff --git a/crates/biome_css_formatter/tests/specs/css/unary-precedence.css.snap b/crates/biome_css_formatter/tests/specs/css/unary-precedence.css.snap new file mode 100644 index 000000000000..89c830ff9e55 --- /dev/null +++ b/crates/biome_css_formatter/tests/specs/css/unary-precedence.css.snap @@ -0,0 +1,41 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +assertion_line: 212 +info: css/unary-precedence.css +--- + +# Input + +```css +.unary-precedence{ + width:calc(-1 +2); + width:calc(+var(--x)+1px); + width:calc(- var(--y)*2); +} + +``` + + +============================= + +# Outputs + +## Output 1 + +----- +Indent style: Tab +Indent width: 2 +Line ending: LF +Line width: 80 +Quote style: Double Quotes +Trailing newline: true +----- + +```css +.unary-precedence { + width: calc(-1 +2); + width: calc(+var(--x) +1px); + width: calc(-var(--y) * 2); +} + +``` diff --git a/crates/biome_css_formatter/tests/specs/prettier/css/color/color-adjuster.css.snap b/crates/biome_css_formatter/tests/specs/prettier/css/color/color-adjuster.css.snap index 7ecb3d7f415e..41d291195fdd 100644 --- a/crates/biome_css_formatter/tests/specs/prettier/css/color/color-adjuster.css.snap +++ b/crates/biome_css_formatter/tests/specs/prettier/css/color/color-adjuster.css.snap @@ -136,45 +136,131 @@ info: css/color/color-adjuster.css ```diff --- Prettier +++ Biome -@@ -14,7 +14,7 @@ - color: color(red red(- 20%)); - color: color(red red(- 128)); - color: color(red alpha(- 50%)); +@@ -1,6 +1,6 @@ + .foo { +- color: color(red l(+ 20%)); +- color: color(red w(+ 20%) s(+ 20%)); ++ color: color(red l(+20%)); ++ color: color(red w(+20%) s(+20%)); + color: color(swopc, 0 206 190 77); + color: color(indigo, 24 160 86 42 0 18 31); + color: color(prophoto, 233 150 122); +@@ -8,43 +8,43 @@ + color: color(#eb8fa9 alpha(75%) blackness(20%)); + color: color(red blue(20)); + color: color(red blue(20%)); +- color: color(red green(+ 20)); +- color: color(red green(+ 20%)); +- color: color(red red(- 20)); +- color: color(red red(- 20%)); +- color: color(red red(- 128)); +- color: color(red alpha(- 50%)); - color: color(red alpha(- 0.75)); -+ color: color(red alpha(- .75)); - color: color(red rgb(+ 0 255 0)); - color: color(red rgb(+ #0f0)); - color: color(red rgb(- 60% 0 0)); -@@ -44,7 +44,7 @@ +- color: color(red rgb(+ 0 255 0)); +- color: color(red rgb(+ #0f0)); +- color: color(red rgb(- 60% 0 0)); +- color: color(red rgb(- #900)); +- color: color(rebeccapurple rgb(* 1%)); ++ color: color(red green(+20)); ++ color: color(red green(+20%)); ++ color: color(red red(-20)); ++ color: color(red red(-20%)); ++ color: color(red red(-128)); ++ color: color(red alpha(-50%)); ++ color: color(red alpha(-0.75)); ++ color: color(red rgb(+0 255 0)); ++ color: color(red rgb(+#0f0)); ++ color: color(red rgb(-60% 0 0)); ++ color: color(red rgb(-#900)); ++ color: color(rebeccapurple rgb(*1%)); + color: color(red hue(20)); + color: color(red hue(20deg)); +- color: color(red hue(+ 20)); +- color: color(red hue(+ 20deg)); +- color: color(red hue(- 20)); +- color: color(red hue(- 20deg)); +- color: color(red hue(* 20)); +- color: color(red hue(* 20deg)); ++ color: color(red hue(+20)); ++ color: color(red hue(+20deg)); ++ color: color(red hue(-20)); ++ color: color(red hue(-20deg)); ++ color: color(red hue(*20)); ++ color: color(red hue(*20deg)); + color: color(red lightness(50%)); + color: color(red lightness(20%)); +- color: color(red lightness(+ 20%)); +- color: color(red lightness(- 20%)); +- color: color(red lightness(* 1.5%)); ++ color: color(red lightness(+20%)); ++ color: color(red lightness(-20%)); ++ color: color(red lightness(*1.5%)); + color: color(beige saturation(20%)); +- color: color(beige saturation(+ 20%)); +- color: color(beige saturation(- 20%)); +- color: color(beige saturation(* 1.5%)); ++ color: color(beige saturation(+20%)); ++ color: color(beige saturation(-20%)); ++ color: color(beige saturation(*1.5%)); + color: color(beige blackness(20%)); +- color: color(beige blackness(+ 20%)); +- color: color(beige blackness(- 1%)); +- color: color(beige blackness(* 20%)); ++ color: color(beige blackness(+20%)); ++ color: color(beige blackness(-1%)); ++ color: color(beige blackness(*20%)); color: color(beige whiteness(20%)); - color: color(beige whiteness(+ 1%)); - color: color(beige whiteness(- 20%)); +- color: color(beige whiteness(+ 1%)); +- color: color(beige whiteness(- 20%)); - color: color(beige whiteness(* 0.5%)); -+ color: color(beige whiteness(* .5%)); ++ color: color(beige whiteness(+1%)); ++ color: color(beige whiteness(-20%)); ++ color: color(beige whiteness(*.5%)); color: color(red); color: color(red tint(0%)); color: color(red shade(0%)); -@@ -106,10 +106,7 @@ - color: color(yellow contrast(50%)); +@@ -83,12 +83,12 @@ + color: color(0grad); + color: color(0rad); + color: color(beige); +- color: color(beige hue(+ 0deg)); +- color: color(beige saturation(+ 0%)); +- color: color(beige lightness(+ 0%)); ++ color: color(beige hue(+0deg)); ++ color: color(beige saturation(+0%)); ++ color: color(beige lightness(+0%)); + color: color(beige alpha(1)); +- color: color(beige alpha(+ 0)); +- color: color(beige alpha(+ 0%)); ++ color: color(beige alpha(+0)); ++ color: color(beige alpha(+0%)); + color: color(beige blend(beige 0% hsl)); + color: color(red); + color: color(red tint(0%)); +@@ -107,18 +107,18 @@ color: color(yellow contrast(75%)); color: color(yellow contrast(100%)); -- color: color( + color: color( - color-mod(0deg blue(10%)) rgb(+ 0 10 0) hue(+ 10deg) tint(10%) - lightness(+ 10%) saturation(+ 10%) blend(rebeccapurple 50%) -- ); -+ color: color(color-mod(0deg blue(10%)) rgb(+ 0 10 0) hue(+ 10deg) tint(10%) lightness(+ 10%) saturation(+ 10%) blend(rebeccapurple 50%)); ++ color-mod(0deg blue(10%)) rgb(+0 10 0) hue(+10deg) tint(10%) lightness(+10%) ++ saturation(+10%) blend(rebeccapurple 50%) + ); color: color(var(--color)); - color: color(var(--color) l(+ 20%)); +- color: color(var(--color) l(+ 20%)); ++ color: color(var(--color) l(+20%)); color: color(red l(+20%)); /* interpreted as part of the number */ -@@ -118,7 +115,7 @@ + color: color(red l(-20%)); /* interpreted as part of the number */ + color: color(red hue(+20)); color: color(red hue(+20deg)); color: color(red hue(-20)); color: color(red hue(-20deg)); - color: color(red hue(* 20)); - color: color(red hue(* 20deg)); +- color: color(var(--highlightColor) blackness(+ 20%)); + color: color(red hue(*20)); + color: color(red hue(*20deg)); - color: color(var(--highlightColor) blackness(+ 20%)); ++ color: color(var(--highlightColor) blackness(+20%)); } ``` @@ -182,8 +268,8 @@ info: css/color/color-adjuster.css ```css .foo { - color: color(red l(+ 20%)); - color: color(red w(+ 20%) s(+ 20%)); + color: color(red l(+20%)); + color: color(red w(+20%) s(+20%)); color: color(swopc, 0 206 190 77); color: color(indigo, 24 160 86 42 0 18 31); color: color(prophoto, 233 150 122); @@ -191,43 +277,43 @@ info: css/color/color-adjuster.css color: color(#eb8fa9 alpha(75%) blackness(20%)); color: color(red blue(20)); color: color(red blue(20%)); - color: color(red green(+ 20)); - color: color(red green(+ 20%)); - color: color(red red(- 20)); - color: color(red red(- 20%)); - color: color(red red(- 128)); - color: color(red alpha(- 50%)); - color: color(red alpha(- .75)); - color: color(red rgb(+ 0 255 0)); - color: color(red rgb(+ #0f0)); - color: color(red rgb(- 60% 0 0)); - color: color(red rgb(- #900)); - color: color(rebeccapurple rgb(* 1%)); + color: color(red green(+20)); + color: color(red green(+20%)); + color: color(red red(-20)); + color: color(red red(-20%)); + color: color(red red(-128)); + color: color(red alpha(-50%)); + color: color(red alpha(-0.75)); + color: color(red rgb(+0 255 0)); + color: color(red rgb(+#0f0)); + color: color(red rgb(-60% 0 0)); + color: color(red rgb(-#900)); + color: color(rebeccapurple rgb(*1%)); color: color(red hue(20)); color: color(red hue(20deg)); - color: color(red hue(+ 20)); - color: color(red hue(+ 20deg)); - color: color(red hue(- 20)); - color: color(red hue(- 20deg)); - color: color(red hue(* 20)); - color: color(red hue(* 20deg)); + color: color(red hue(+20)); + color: color(red hue(+20deg)); + color: color(red hue(-20)); + color: color(red hue(-20deg)); + color: color(red hue(*20)); + color: color(red hue(*20deg)); color: color(red lightness(50%)); color: color(red lightness(20%)); - color: color(red lightness(+ 20%)); - color: color(red lightness(- 20%)); - color: color(red lightness(* 1.5%)); + color: color(red lightness(+20%)); + color: color(red lightness(-20%)); + color: color(red lightness(*1.5%)); color: color(beige saturation(20%)); - color: color(beige saturation(+ 20%)); - color: color(beige saturation(- 20%)); - color: color(beige saturation(* 1.5%)); + color: color(beige saturation(+20%)); + color: color(beige saturation(-20%)); + color: color(beige saturation(*1.5%)); color: color(beige blackness(20%)); - color: color(beige blackness(+ 20%)); - color: color(beige blackness(- 1%)); - color: color(beige blackness(* 20%)); + color: color(beige blackness(+20%)); + color: color(beige blackness(-1%)); + color: color(beige blackness(*20%)); color: color(beige whiteness(20%)); - color: color(beige whiteness(+ 1%)); - color: color(beige whiteness(- 20%)); - color: color(beige whiteness(* .5%)); + color: color(beige whiteness(+1%)); + color: color(beige whiteness(-20%)); + color: color(beige whiteness(*.5%)); color: color(red); color: color(red tint(0%)); color: color(red shade(0%)); @@ -266,12 +352,12 @@ info: css/color/color-adjuster.css color: color(0grad); color: color(0rad); color: color(beige); - color: color(beige hue(+ 0deg)); - color: color(beige saturation(+ 0%)); - color: color(beige lightness(+ 0%)); + color: color(beige hue(+0deg)); + color: color(beige saturation(+0%)); + color: color(beige lightness(+0%)); color: color(beige alpha(1)); - color: color(beige alpha(+ 0)); - color: color(beige alpha(+ 0%)); + color: color(beige alpha(+0)); + color: color(beige alpha(+0%)); color: color(beige blend(beige 0% hsl)); color: color(red); color: color(red tint(0%)); @@ -289,9 +375,12 @@ info: css/color/color-adjuster.css color: color(yellow contrast(50%)); color: color(yellow contrast(75%)); color: color(yellow contrast(100%)); - color: color(color-mod(0deg blue(10%)) rgb(+ 0 10 0) hue(+ 10deg) tint(10%) lightness(+ 10%) saturation(+ 10%) blend(rebeccapurple 50%)); + color: color( + color-mod(0deg blue(10%)) rgb(+0 10 0) hue(+10deg) tint(10%) lightness(+10%) + saturation(+10%) blend(rebeccapurple 50%) + ); color: color(var(--color)); - color: color(var(--color) l(+ 20%)); + color: color(var(--color) l(+20%)); color: color(red l(+20%)); /* interpreted as part of the number */ color: color(red l(-20%)); /* interpreted as part of the number */ color: color(red hue(+20)); @@ -300,1531 +389,6 @@ info: css/color/color-adjuster.css color: color(red hue(-20deg)); color: color(red hue(*20)); color: color(red hue(*20deg)); - color: color(var(--highlightColor) blackness(+ 20%)); + color: color(var(--highlightColor) blackness(+20%)); } ``` - -# Errors -``` -color-adjuster.css:2:24 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 1 │ .foo { - > 2 │ color: color(red l(+ 20%)); - │ ^ - 3 │ color: color(red w(+ 20%) s(+ 20%)); - 4 │ color: color(swopc, 0 206 190 77); - - i Expected a declaration item here. - - 1 │ .foo { - > 2 │ color: color(red l(+ 20%)); - │ ^ - 3 │ color: color(red w(+ 20%) s(+ 20%)); - 4 │ color: color(swopc, 0 206 190 77); - -color-adjuster.css:2:26 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 1 │ .foo { - > 2 │ color: color(red l(+ 20%)); - │ ^^ - 3 │ color: color(red w(+ 20%) s(+ 20%)); - 4 │ color: color(swopc, 0 206 190 77); - - i Remove 20 - -color-adjuster.css:3:24 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 1 │ .foo { - 2 │ color: color(red l(+ 20%)); - > 3 │ color: color(red w(+ 20%) s(+ 20%)); - │ ^ - 4 │ color: color(swopc, 0 206 190 77); - 5 │ color: color(indigo, 24 160 86 42 0 18 31); - - i Expected a declaration item here. - - 1 │ .foo { - 2 │ color: color(red l(+ 20%)); - > 3 │ color: color(red w(+ 20%) s(+ 20%)); - │ ^ - 4 │ color: color(swopc, 0 206 190 77); - 5 │ color: color(indigo, 24 160 86 42 0 18 31); - -color-adjuster.css:3:26 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 1 │ .foo { - 2 │ color: color(red l(+ 20%)); - > 3 │ color: color(red w(+ 20%) s(+ 20%)); - │ ^^ - 4 │ color: color(swopc, 0 206 190 77); - 5 │ color: color(indigo, 24 160 86 42 0 18 31); - - i Remove 20 - -color-adjuster.css:3:33 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 1 │ .foo { - 2 │ color: color(red l(+ 20%)); - > 3 │ color: color(red w(+ 20%) s(+ 20%)); - │ ^ - 4 │ color: color(swopc, 0 206 190 77); - 5 │ color: color(indigo, 24 160 86 42 0 18 31); - - i Expected a declaration item here. - - 1 │ .foo { - 2 │ color: color(red l(+ 20%)); - > 3 │ color: color(red w(+ 20%) s(+ 20%)); - │ ^ - 4 │ color: color(swopc, 0 206 190 77); - 5 │ color: color(indigo, 24 160 86 42 0 18 31); - -color-adjuster.css:3:35 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 1 │ .foo { - 2 │ color: color(red l(+ 20%)); - > 3 │ color: color(red w(+ 20%) s(+ 20%)); - │ ^^ - 4 │ color: color(swopc, 0 206 190 77); - 5 │ color: color(indigo, 24 160 86 42 0 18 31); - - i Remove 20 - -color-adjuster.css:11:28 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 9 │ color: color(red blue(20)); - 10 │ color: color(red blue(20%)); - > 11 │ color: color(red green(+ 20)); - │ ^ - 12 │ color: color(red green(+ 20%)); - 13 │ color: color(red red(- 20)); - - i Expected a declaration item here. - - 9 │ color: color(red blue(20)); - 10 │ color: color(red blue(20%)); - > 11 │ color: color(red green(+ 20)); - │ ^ - 12 │ color: color(red green(+ 20%)); - 13 │ color: color(red red(- 20)); - -color-adjuster.css:11:30 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 9 │ color: color(red blue(20)); - 10 │ color: color(red blue(20%)); - > 11 │ color: color(red green(+ 20)); - │ ^^ - 12 │ color: color(red green(+ 20%)); - 13 │ color: color(red red(- 20)); - - i Remove 20 - -color-adjuster.css:12:28 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 10 │ color: color(red blue(20%)); - 11 │ color: color(red green(+ 20)); - > 12 │ color: color(red green(+ 20%)); - │ ^ - 13 │ color: color(red red(- 20)); - 14 │ color: color(red red(- 20%)); - - i Expected a declaration item here. - - 10 │ color: color(red blue(20%)); - 11 │ color: color(red green(+ 20)); - > 12 │ color: color(red green(+ 20%)); - │ ^ - 13 │ color: color(red red(- 20)); - 14 │ color: color(red red(- 20%)); - -color-adjuster.css:12:30 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 10 │ color: color(red blue(20%)); - 11 │ color: color(red green(+ 20)); - > 12 │ color: color(red green(+ 20%)); - │ ^^ - 13 │ color: color(red red(- 20)); - 14 │ color: color(red red(- 20%)); - - i Remove 20 - -color-adjuster.css:13:26 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '-'. - - 11 │ color: color(red green(+ 20)); - 12 │ color: color(red green(+ 20%)); - > 13 │ color: color(red red(- 20)); - │ ^ - 14 │ color: color(red red(- 20%)); - 15 │ color: color(red red(- 128)); - - i Expected a declaration item here. - - 11 │ color: color(red green(+ 20)); - 12 │ color: color(red green(+ 20%)); - > 13 │ color: color(red red(- 20)); - │ ^ - 14 │ color: color(red red(- 20%)); - 15 │ color: color(red red(- 128)); - -color-adjuster.css:13:28 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 11 │ color: color(red green(+ 20)); - 12 │ color: color(red green(+ 20%)); - > 13 │ color: color(red red(- 20)); - │ ^^ - 14 │ color: color(red red(- 20%)); - 15 │ color: color(red red(- 128)); - - i Remove 20 - -color-adjuster.css:14:26 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '-'. - - 12 │ color: color(red green(+ 20%)); - 13 │ color: color(red red(- 20)); - > 14 │ color: color(red red(- 20%)); - │ ^ - 15 │ color: color(red red(- 128)); - 16 │ color: color(red alpha(- 50%)); - - i Expected a declaration item here. - - 12 │ color: color(red green(+ 20%)); - 13 │ color: color(red red(- 20)); - > 14 │ color: color(red red(- 20%)); - │ ^ - 15 │ color: color(red red(- 128)); - 16 │ color: color(red alpha(- 50%)); - -color-adjuster.css:14:28 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 12 │ color: color(red green(+ 20%)); - 13 │ color: color(red red(- 20)); - > 14 │ color: color(red red(- 20%)); - │ ^^ - 15 │ color: color(red red(- 128)); - 16 │ color: color(red alpha(- 50%)); - - i Remove 20 - -color-adjuster.css:15:26 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '-'. - - 13 │ color: color(red red(- 20)); - 14 │ color: color(red red(- 20%)); - > 15 │ color: color(red red(- 128)); - │ ^ - 16 │ color: color(red alpha(- 50%)); - 17 │ color: color(red alpha(- .75)); - - i Expected a declaration item here. - - 13 │ color: color(red red(- 20)); - 14 │ color: color(red red(- 20%)); - > 15 │ color: color(red red(- 128)); - │ ^ - 16 │ color: color(red alpha(- 50%)); - 17 │ color: color(red alpha(- .75)); - -color-adjuster.css:15:28 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `128` - - 13 │ color: color(red red(- 20)); - 14 │ color: color(red red(- 20%)); - > 15 │ color: color(red red(- 128)); - │ ^^^ - 16 │ color: color(red alpha(- 50%)); - 17 │ color: color(red alpha(- .75)); - - i Remove 128 - -color-adjuster.css:16:28 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '-'. - - 14 │ color: color(red red(- 20%)); - 15 │ color: color(red red(- 128)); - > 16 │ color: color(red alpha(- 50%)); - │ ^ - 17 │ color: color(red alpha(- .75)); - 18 │ color: color(red rgb(+ 0 255 0)); - - i Expected a declaration item here. - - 14 │ color: color(red red(- 20%)); - 15 │ color: color(red red(- 128)); - > 16 │ color: color(red alpha(- 50%)); - │ ^ - 17 │ color: color(red alpha(- .75)); - 18 │ color: color(red rgb(+ 0 255 0)); - -color-adjuster.css:16:30 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `50` - - 14 │ color: color(red red(- 20%)); - 15 │ color: color(red red(- 128)); - > 16 │ color: color(red alpha(- 50%)); - │ ^^ - 17 │ color: color(red alpha(- .75)); - 18 │ color: color(red rgb(+ 0 255 0)); - - i Remove 50 - -color-adjuster.css:17:28 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '-'. - - 15 │ color: color(red red(- 128)); - 16 │ color: color(red alpha(- 50%)); - > 17 │ color: color(red alpha(- .75)); - │ ^ - 18 │ color: color(red rgb(+ 0 255 0)); - 19 │ color: color(red rgb(+ #0f0)); - - i Expected a declaration item here. - - 15 │ color: color(red red(- 128)); - 16 │ color: color(red alpha(- 50%)); - > 17 │ color: color(red alpha(- .75)); - │ ^ - 18 │ color: color(red rgb(+ 0 255 0)); - 19 │ color: color(red rgb(+ #0f0)); - -color-adjuster.css:17:30 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `.75` - - 15 │ color: color(red red(- 128)); - 16 │ color: color(red alpha(- 50%)); - > 17 │ color: color(red alpha(- .75)); - │ ^^^ - 18 │ color: color(red rgb(+ 0 255 0)); - 19 │ color: color(red rgb(+ #0f0)); - - i Remove .75 - -color-adjuster.css:18:26 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 16 │ color: color(red alpha(- 50%)); - 17 │ color: color(red alpha(- .75)); - > 18 │ color: color(red rgb(+ 0 255 0)); - │ ^ - 19 │ color: color(red rgb(+ #0f0)); - 20 │ color: color(red rgb(- 60% 0 0)); - - i Expected a declaration item here. - - 16 │ color: color(red alpha(- 50%)); - 17 │ color: color(red alpha(- .75)); - > 18 │ color: color(red rgb(+ 0 255 0)); - │ ^ - 19 │ color: color(red rgb(+ #0f0)); - 20 │ color: color(red rgb(- 60% 0 0)); - -color-adjuster.css:18:28 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `0` - - 16 │ color: color(red alpha(- 50%)); - 17 │ color: color(red alpha(- .75)); - > 18 │ color: color(red rgb(+ 0 255 0)); - │ ^ - 19 │ color: color(red rgb(+ #0f0)); - 20 │ color: color(red rgb(- 60% 0 0)); - - i Remove 0 - -color-adjuster.css:19:26 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 17 │ color: color(red alpha(- .75)); - 18 │ color: color(red rgb(+ 0 255 0)); - > 19 │ color: color(red rgb(+ #0f0)); - │ ^ - 20 │ color: color(red rgb(- 60% 0 0)); - 21 │ color: color(red rgb(- #900)); - - i Expected a declaration item here. - - 17 │ color: color(red alpha(- .75)); - 18 │ color: color(red rgb(+ 0 255 0)); - > 19 │ color: color(red rgb(+ #0f0)); - │ ^ - 20 │ color: color(red rgb(- 60% 0 0)); - 21 │ color: color(red rgb(- #900)); - -color-adjuster.css:19:28 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `#` - - 17 │ color: color(red alpha(- .75)); - 18 │ color: color(red rgb(+ 0 255 0)); - > 19 │ color: color(red rgb(+ #0f0)); - │ ^ - 20 │ color: color(red rgb(- 60% 0 0)); - 21 │ color: color(red rgb(- #900)); - - i Remove # - -color-adjuster.css:20:26 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '-'. - - 18 │ color: color(red rgb(+ 0 255 0)); - 19 │ color: color(red rgb(+ #0f0)); - > 20 │ color: color(red rgb(- 60% 0 0)); - │ ^ - 21 │ color: color(red rgb(- #900)); - 22 │ color: color(rebeccapurple rgb(* 1%)); - - i Expected a declaration item here. - - 18 │ color: color(red rgb(+ 0 255 0)); - 19 │ color: color(red rgb(+ #0f0)); - > 20 │ color: color(red rgb(- 60% 0 0)); - │ ^ - 21 │ color: color(red rgb(- #900)); - 22 │ color: color(rebeccapurple rgb(* 1%)); - -color-adjuster.css:20:28 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `60` - - 18 │ color: color(red rgb(+ 0 255 0)); - 19 │ color: color(red rgb(+ #0f0)); - > 20 │ color: color(red rgb(- 60% 0 0)); - │ ^^ - 21 │ color: color(red rgb(- #900)); - 22 │ color: color(rebeccapurple rgb(* 1%)); - - i Remove 60 - -color-adjuster.css:21:26 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '-'. - - 19 │ color: color(red rgb(+ #0f0)); - 20 │ color: color(red rgb(- 60% 0 0)); - > 21 │ color: color(red rgb(- #900)); - │ ^ - 22 │ color: color(rebeccapurple rgb(* 1%)); - 23 │ color: color(red hue(20)); - - i Expected a declaration item here. - - 19 │ color: color(red rgb(+ #0f0)); - 20 │ color: color(red rgb(- 60% 0 0)); - > 21 │ color: color(red rgb(- #900)); - │ ^ - 22 │ color: color(rebeccapurple rgb(* 1%)); - 23 │ color: color(red hue(20)); - -color-adjuster.css:21:28 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `#` - - 19 │ color: color(red rgb(+ #0f0)); - 20 │ color: color(red rgb(- 60% 0 0)); - > 21 │ color: color(red rgb(- #900)); - │ ^ - 22 │ color: color(rebeccapurple rgb(* 1%)); - 23 │ color: color(red hue(20)); - - i Remove # - -color-adjuster.css:22:36 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '*'. - - 20 │ color: color(red rgb(- 60% 0 0)); - 21 │ color: color(red rgb(- #900)); - > 22 │ color: color(rebeccapurple rgb(* 1%)); - │ ^ - 23 │ color: color(red hue(20)); - 24 │ color: color(red hue(20deg)); - - i Expected a declaration item here. - - 20 │ color: color(red rgb(- 60% 0 0)); - 21 │ color: color(red rgb(- #900)); - > 22 │ color: color(rebeccapurple rgb(* 1%)); - │ ^ - 23 │ color: color(red hue(20)); - 24 │ color: color(red hue(20deg)); - -color-adjuster.css:22:38 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `1` - - 20 │ color: color(red rgb(- 60% 0 0)); - 21 │ color: color(red rgb(- #900)); - > 22 │ color: color(rebeccapurple rgb(* 1%)); - │ ^ - 23 │ color: color(red hue(20)); - 24 │ color: color(red hue(20deg)); - - i Remove 1 - -color-adjuster.css:25:26 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 23 │ color: color(red hue(20)); - 24 │ color: color(red hue(20deg)); - > 25 │ color: color(red hue(+ 20)); - │ ^ - 26 │ color: color(red hue(+ 20deg)); - 27 │ color: color(red hue(- 20)); - - i Expected a declaration item here. - - 23 │ color: color(red hue(20)); - 24 │ color: color(red hue(20deg)); - > 25 │ color: color(red hue(+ 20)); - │ ^ - 26 │ color: color(red hue(+ 20deg)); - 27 │ color: color(red hue(- 20)); - -color-adjuster.css:25:28 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 23 │ color: color(red hue(20)); - 24 │ color: color(red hue(20deg)); - > 25 │ color: color(red hue(+ 20)); - │ ^^ - 26 │ color: color(red hue(+ 20deg)); - 27 │ color: color(red hue(- 20)); - - i Remove 20 - -color-adjuster.css:26:26 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 24 │ color: color(red hue(20deg)); - 25 │ color: color(red hue(+ 20)); - > 26 │ color: color(red hue(+ 20deg)); - │ ^ - 27 │ color: color(red hue(- 20)); - 28 │ color: color(red hue(- 20deg)); - - i Expected a declaration item here. - - 24 │ color: color(red hue(20deg)); - 25 │ color: color(red hue(+ 20)); - > 26 │ color: color(red hue(+ 20deg)); - │ ^ - 27 │ color: color(red hue(- 20)); - 28 │ color: color(red hue(- 20deg)); - -color-adjuster.css:26:28 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 24 │ color: color(red hue(20deg)); - 25 │ color: color(red hue(+ 20)); - > 26 │ color: color(red hue(+ 20deg)); - │ ^^ - 27 │ color: color(red hue(- 20)); - 28 │ color: color(red hue(- 20deg)); - - i Remove 20 - -color-adjuster.css:27:26 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '-'. - - 25 │ color: color(red hue(+ 20)); - 26 │ color: color(red hue(+ 20deg)); - > 27 │ color: color(red hue(- 20)); - │ ^ - 28 │ color: color(red hue(- 20deg)); - 29 │ color: color(red hue(* 20)); - - i Expected a declaration item here. - - 25 │ color: color(red hue(+ 20)); - 26 │ color: color(red hue(+ 20deg)); - > 27 │ color: color(red hue(- 20)); - │ ^ - 28 │ color: color(red hue(- 20deg)); - 29 │ color: color(red hue(* 20)); - -color-adjuster.css:27:28 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 25 │ color: color(red hue(+ 20)); - 26 │ color: color(red hue(+ 20deg)); - > 27 │ color: color(red hue(- 20)); - │ ^^ - 28 │ color: color(red hue(- 20deg)); - 29 │ color: color(red hue(* 20)); - - i Remove 20 - -color-adjuster.css:28:26 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '-'. - - 26 │ color: color(red hue(+ 20deg)); - 27 │ color: color(red hue(- 20)); - > 28 │ color: color(red hue(- 20deg)); - │ ^ - 29 │ color: color(red hue(* 20)); - 30 │ color: color(red hue(* 20deg)); - - i Expected a declaration item here. - - 26 │ color: color(red hue(+ 20deg)); - 27 │ color: color(red hue(- 20)); - > 28 │ color: color(red hue(- 20deg)); - │ ^ - 29 │ color: color(red hue(* 20)); - 30 │ color: color(red hue(* 20deg)); - -color-adjuster.css:28:28 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 26 │ color: color(red hue(+ 20deg)); - 27 │ color: color(red hue(- 20)); - > 28 │ color: color(red hue(- 20deg)); - │ ^^ - 29 │ color: color(red hue(* 20)); - 30 │ color: color(red hue(* 20deg)); - - i Remove 20 - -color-adjuster.css:29:26 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '*'. - - 27 │ color: color(red hue(- 20)); - 28 │ color: color(red hue(- 20deg)); - > 29 │ color: color(red hue(* 20)); - │ ^ - 30 │ color: color(red hue(* 20deg)); - 31 │ color: color(red lightness(50%)); - - i Expected a declaration item here. - - 27 │ color: color(red hue(- 20)); - 28 │ color: color(red hue(- 20deg)); - > 29 │ color: color(red hue(* 20)); - │ ^ - 30 │ color: color(red hue(* 20deg)); - 31 │ color: color(red lightness(50%)); - -color-adjuster.css:29:28 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 27 │ color: color(red hue(- 20)); - 28 │ color: color(red hue(- 20deg)); - > 29 │ color: color(red hue(* 20)); - │ ^^ - 30 │ color: color(red hue(* 20deg)); - 31 │ color: color(red lightness(50%)); - - i Remove 20 - -color-adjuster.css:30:26 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '*'. - - 28 │ color: color(red hue(- 20deg)); - 29 │ color: color(red hue(* 20)); - > 30 │ color: color(red hue(* 20deg)); - │ ^ - 31 │ color: color(red lightness(50%)); - 32 │ color: color(red lightness(20%)); - - i Expected a declaration item here. - - 28 │ color: color(red hue(- 20deg)); - 29 │ color: color(red hue(* 20)); - > 30 │ color: color(red hue(* 20deg)); - │ ^ - 31 │ color: color(red lightness(50%)); - 32 │ color: color(red lightness(20%)); - -color-adjuster.css:30:28 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 28 │ color: color(red hue(- 20deg)); - 29 │ color: color(red hue(* 20)); - > 30 │ color: color(red hue(* 20deg)); - │ ^^ - 31 │ color: color(red lightness(50%)); - 32 │ color: color(red lightness(20%)); - - i Remove 20 - -color-adjuster.css:33:32 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 31 │ color: color(red lightness(50%)); - 32 │ color: color(red lightness(20%)); - > 33 │ color: color(red lightness(+ 20%)); - │ ^ - 34 │ color: color(red lightness(- 20%)); - 35 │ color: color(red lightness(* 1.5%)); - - i Expected a declaration item here. - - 31 │ color: color(red lightness(50%)); - 32 │ color: color(red lightness(20%)); - > 33 │ color: color(red lightness(+ 20%)); - │ ^ - 34 │ color: color(red lightness(- 20%)); - 35 │ color: color(red lightness(* 1.5%)); - -color-adjuster.css:33:34 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 31 │ color: color(red lightness(50%)); - 32 │ color: color(red lightness(20%)); - > 33 │ color: color(red lightness(+ 20%)); - │ ^^ - 34 │ color: color(red lightness(- 20%)); - 35 │ color: color(red lightness(* 1.5%)); - - i Remove 20 - -color-adjuster.css:34:32 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '-'. - - 32 │ color: color(red lightness(20%)); - 33 │ color: color(red lightness(+ 20%)); - > 34 │ color: color(red lightness(- 20%)); - │ ^ - 35 │ color: color(red lightness(* 1.5%)); - 36 │ color: color(beige saturation(20%)); - - i Expected a declaration item here. - - 32 │ color: color(red lightness(20%)); - 33 │ color: color(red lightness(+ 20%)); - > 34 │ color: color(red lightness(- 20%)); - │ ^ - 35 │ color: color(red lightness(* 1.5%)); - 36 │ color: color(beige saturation(20%)); - -color-adjuster.css:34:34 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 32 │ color: color(red lightness(20%)); - 33 │ color: color(red lightness(+ 20%)); - > 34 │ color: color(red lightness(- 20%)); - │ ^^ - 35 │ color: color(red lightness(* 1.5%)); - 36 │ color: color(beige saturation(20%)); - - i Remove 20 - -color-adjuster.css:35:32 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '*'. - - 33 │ color: color(red lightness(+ 20%)); - 34 │ color: color(red lightness(- 20%)); - > 35 │ color: color(red lightness(* 1.5%)); - │ ^ - 36 │ color: color(beige saturation(20%)); - 37 │ color: color(beige saturation(+ 20%)); - - i Expected a declaration item here. - - 33 │ color: color(red lightness(+ 20%)); - 34 │ color: color(red lightness(- 20%)); - > 35 │ color: color(red lightness(* 1.5%)); - │ ^ - 36 │ color: color(beige saturation(20%)); - 37 │ color: color(beige saturation(+ 20%)); - -color-adjuster.css:35:34 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `1.5` - - 33 │ color: color(red lightness(+ 20%)); - 34 │ color: color(red lightness(- 20%)); - > 35 │ color: color(red lightness(* 1.5%)); - │ ^^^ - 36 │ color: color(beige saturation(20%)); - 37 │ color: color(beige saturation(+ 20%)); - - i Remove 1.5 - -color-adjuster.css:37:35 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 35 │ color: color(red lightness(* 1.5%)); - 36 │ color: color(beige saturation(20%)); - > 37 │ color: color(beige saturation(+ 20%)); - │ ^ - 38 │ color: color(beige saturation(- 20%)); - 39 │ color: color(beige saturation(* 1.5%)); - - i Expected a declaration item here. - - 35 │ color: color(red lightness(* 1.5%)); - 36 │ color: color(beige saturation(20%)); - > 37 │ color: color(beige saturation(+ 20%)); - │ ^ - 38 │ color: color(beige saturation(- 20%)); - 39 │ color: color(beige saturation(* 1.5%)); - -color-adjuster.css:37:37 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 35 │ color: color(red lightness(* 1.5%)); - 36 │ color: color(beige saturation(20%)); - > 37 │ color: color(beige saturation(+ 20%)); - │ ^^ - 38 │ color: color(beige saturation(- 20%)); - 39 │ color: color(beige saturation(* 1.5%)); - - i Remove 20 - -color-adjuster.css:38:35 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '-'. - - 36 │ color: color(beige saturation(20%)); - 37 │ color: color(beige saturation(+ 20%)); - > 38 │ color: color(beige saturation(- 20%)); - │ ^ - 39 │ color: color(beige saturation(* 1.5%)); - 40 │ color: color(beige blackness(20%)); - - i Expected a declaration item here. - - 36 │ color: color(beige saturation(20%)); - 37 │ color: color(beige saturation(+ 20%)); - > 38 │ color: color(beige saturation(- 20%)); - │ ^ - 39 │ color: color(beige saturation(* 1.5%)); - 40 │ color: color(beige blackness(20%)); - -color-adjuster.css:38:37 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 36 │ color: color(beige saturation(20%)); - 37 │ color: color(beige saturation(+ 20%)); - > 38 │ color: color(beige saturation(- 20%)); - │ ^^ - 39 │ color: color(beige saturation(* 1.5%)); - 40 │ color: color(beige blackness(20%)); - - i Remove 20 - -color-adjuster.css:39:35 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '*'. - - 37 │ color: color(beige saturation(+ 20%)); - 38 │ color: color(beige saturation(- 20%)); - > 39 │ color: color(beige saturation(* 1.5%)); - │ ^ - 40 │ color: color(beige blackness(20%)); - 41 │ color: color(beige blackness(+ 20%)); - - i Expected a declaration item here. - - 37 │ color: color(beige saturation(+ 20%)); - 38 │ color: color(beige saturation(- 20%)); - > 39 │ color: color(beige saturation(* 1.5%)); - │ ^ - 40 │ color: color(beige blackness(20%)); - 41 │ color: color(beige blackness(+ 20%)); - -color-adjuster.css:39:37 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `1.5` - - 37 │ color: color(beige saturation(+ 20%)); - 38 │ color: color(beige saturation(- 20%)); - > 39 │ color: color(beige saturation(* 1.5%)); - │ ^^^ - 40 │ color: color(beige blackness(20%)); - 41 │ color: color(beige blackness(+ 20%)); - - i Remove 1.5 - -color-adjuster.css:41:34 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 39 │ color: color(beige saturation(* 1.5%)); - 40 │ color: color(beige blackness(20%)); - > 41 │ color: color(beige blackness(+ 20%)); - │ ^ - 42 │ color: color(beige blackness(- 1%)); - 43 │ color: color(beige blackness(* 20%)); - - i Expected a declaration item here. - - 39 │ color: color(beige saturation(* 1.5%)); - 40 │ color: color(beige blackness(20%)); - > 41 │ color: color(beige blackness(+ 20%)); - │ ^ - 42 │ color: color(beige blackness(- 1%)); - 43 │ color: color(beige blackness(* 20%)); - -color-adjuster.css:41:36 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 39 │ color: color(beige saturation(* 1.5%)); - 40 │ color: color(beige blackness(20%)); - > 41 │ color: color(beige blackness(+ 20%)); - │ ^^ - 42 │ color: color(beige blackness(- 1%)); - 43 │ color: color(beige blackness(* 20%)); - - i Remove 20 - -color-adjuster.css:42:34 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '-'. - - 40 │ color: color(beige blackness(20%)); - 41 │ color: color(beige blackness(+ 20%)); - > 42 │ color: color(beige blackness(- 1%)); - │ ^ - 43 │ color: color(beige blackness(* 20%)); - 44 │ color: color(beige whiteness(20%)); - - i Expected a declaration item here. - - 40 │ color: color(beige blackness(20%)); - 41 │ color: color(beige blackness(+ 20%)); - > 42 │ color: color(beige blackness(- 1%)); - │ ^ - 43 │ color: color(beige blackness(* 20%)); - 44 │ color: color(beige whiteness(20%)); - -color-adjuster.css:42:36 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `1` - - 40 │ color: color(beige blackness(20%)); - 41 │ color: color(beige blackness(+ 20%)); - > 42 │ color: color(beige blackness(- 1%)); - │ ^ - 43 │ color: color(beige blackness(* 20%)); - 44 │ color: color(beige whiteness(20%)); - - i Remove 1 - -color-adjuster.css:43:34 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '*'. - - 41 │ color: color(beige blackness(+ 20%)); - 42 │ color: color(beige blackness(- 1%)); - > 43 │ color: color(beige blackness(* 20%)); - │ ^ - 44 │ color: color(beige whiteness(20%)); - 45 │ color: color(beige whiteness(+ 1%)); - - i Expected a declaration item here. - - 41 │ color: color(beige blackness(+ 20%)); - 42 │ color: color(beige blackness(- 1%)); - > 43 │ color: color(beige blackness(* 20%)); - │ ^ - 44 │ color: color(beige whiteness(20%)); - 45 │ color: color(beige whiteness(+ 1%)); - -color-adjuster.css:43:36 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 41 │ color: color(beige blackness(+ 20%)); - 42 │ color: color(beige blackness(- 1%)); - > 43 │ color: color(beige blackness(* 20%)); - │ ^^ - 44 │ color: color(beige whiteness(20%)); - 45 │ color: color(beige whiteness(+ 1%)); - - i Remove 20 - -color-adjuster.css:45:34 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 43 │ color: color(beige blackness(* 20%)); - 44 │ color: color(beige whiteness(20%)); - > 45 │ color: color(beige whiteness(+ 1%)); - │ ^ - 46 │ color: color(beige whiteness(- 20%)); - 47 │ color: color(beige whiteness(* .5%)); - - i Expected a declaration item here. - - 43 │ color: color(beige blackness(* 20%)); - 44 │ color: color(beige whiteness(20%)); - > 45 │ color: color(beige whiteness(+ 1%)); - │ ^ - 46 │ color: color(beige whiteness(- 20%)); - 47 │ color: color(beige whiteness(* .5%)); - -color-adjuster.css:45:36 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `1` - - 43 │ color: color(beige blackness(* 20%)); - 44 │ color: color(beige whiteness(20%)); - > 45 │ color: color(beige whiteness(+ 1%)); - │ ^ - 46 │ color: color(beige whiteness(- 20%)); - 47 │ color: color(beige whiteness(* .5%)); - - i Remove 1 - -color-adjuster.css:46:34 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '-'. - - 44 │ color: color(beige whiteness(20%)); - 45 │ color: color(beige whiteness(+ 1%)); - > 46 │ color: color(beige whiteness(- 20%)); - │ ^ - 47 │ color: color(beige whiteness(* .5%)); - 48 │ color: color(red); - - i Expected a declaration item here. - - 44 │ color: color(beige whiteness(20%)); - 45 │ color: color(beige whiteness(+ 1%)); - > 46 │ color: color(beige whiteness(- 20%)); - │ ^ - 47 │ color: color(beige whiteness(* .5%)); - 48 │ color: color(red); - -color-adjuster.css:46:36 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 44 │ color: color(beige whiteness(20%)); - 45 │ color: color(beige whiteness(+ 1%)); - > 46 │ color: color(beige whiteness(- 20%)); - │ ^^ - 47 │ color: color(beige whiteness(* .5%)); - 48 │ color: color(red); - - i Remove 20 - -color-adjuster.css:47:34 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '*'. - - 45 │ color: color(beige whiteness(+ 1%)); - 46 │ color: color(beige whiteness(- 20%)); - > 47 │ color: color(beige whiteness(* .5%)); - │ ^ - 48 │ color: color(red); - 49 │ color: color(red tint(0%)); - - i Expected a declaration item here. - - 45 │ color: color(beige whiteness(+ 1%)); - 46 │ color: color(beige whiteness(- 20%)); - > 47 │ color: color(beige whiteness(* .5%)); - │ ^ - 48 │ color: color(red); - 49 │ color: color(red tint(0%)); - -color-adjuster.css:47:36 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `.5` - - 45 │ color: color(beige whiteness(+ 1%)); - 46 │ color: color(beige whiteness(- 20%)); - > 47 │ color: color(beige whiteness(* .5%)); - │ ^^ - 48 │ color: color(red); - 49 │ color: color(red tint(0%)); - - i Remove .5 - -color-adjuster.css:86:28 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 84 │ color: color(0rad); - 85 │ color: color(beige); - > 86 │ color: color(beige hue(+ 0deg)); - │ ^ - 87 │ color: color(beige saturation(+ 0%)); - 88 │ color: color(beige lightness(+ 0%)); - - i Expected a declaration item here. - - 84 │ color: color(0rad); - 85 │ color: color(beige); - > 86 │ color: color(beige hue(+ 0deg)); - │ ^ - 87 │ color: color(beige saturation(+ 0%)); - 88 │ color: color(beige lightness(+ 0%)); - -color-adjuster.css:86:30 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `0` - - 84 │ color: color(0rad); - 85 │ color: color(beige); - > 86 │ color: color(beige hue(+ 0deg)); - │ ^ - 87 │ color: color(beige saturation(+ 0%)); - 88 │ color: color(beige lightness(+ 0%)); - - i Remove 0 - -color-adjuster.css:87:35 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 85 │ color: color(beige); - 86 │ color: color(beige hue(+ 0deg)); - > 87 │ color: color(beige saturation(+ 0%)); - │ ^ - 88 │ color: color(beige lightness(+ 0%)); - 89 │ color: color(beige alpha(1)); - - i Expected a declaration item here. - - 85 │ color: color(beige); - 86 │ color: color(beige hue(+ 0deg)); - > 87 │ color: color(beige saturation(+ 0%)); - │ ^ - 88 │ color: color(beige lightness(+ 0%)); - 89 │ color: color(beige alpha(1)); - -color-adjuster.css:87:37 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `0` - - 85 │ color: color(beige); - 86 │ color: color(beige hue(+ 0deg)); - > 87 │ color: color(beige saturation(+ 0%)); - │ ^ - 88 │ color: color(beige lightness(+ 0%)); - 89 │ color: color(beige alpha(1)); - - i Remove 0 - -color-adjuster.css:88:34 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 86 │ color: color(beige hue(+ 0deg)); - 87 │ color: color(beige saturation(+ 0%)); - > 88 │ color: color(beige lightness(+ 0%)); - │ ^ - 89 │ color: color(beige alpha(1)); - 90 │ color: color(beige alpha(+ 0)); - - i Expected a declaration item here. - - 86 │ color: color(beige hue(+ 0deg)); - 87 │ color: color(beige saturation(+ 0%)); - > 88 │ color: color(beige lightness(+ 0%)); - │ ^ - 89 │ color: color(beige alpha(1)); - 90 │ color: color(beige alpha(+ 0)); - -color-adjuster.css:88:36 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `0` - - 86 │ color: color(beige hue(+ 0deg)); - 87 │ color: color(beige saturation(+ 0%)); - > 88 │ color: color(beige lightness(+ 0%)); - │ ^ - 89 │ color: color(beige alpha(1)); - 90 │ color: color(beige alpha(+ 0)); - - i Remove 0 - -color-adjuster.css:90:30 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 88 │ color: color(beige lightness(+ 0%)); - 89 │ color: color(beige alpha(1)); - > 90 │ color: color(beige alpha(+ 0)); - │ ^ - 91 │ color: color(beige alpha(+ 0%)); - 92 │ color: color(beige blend(beige 0% hsl)); - - i Expected a declaration item here. - - 88 │ color: color(beige lightness(+ 0%)); - 89 │ color: color(beige alpha(1)); - > 90 │ color: color(beige alpha(+ 0)); - │ ^ - 91 │ color: color(beige alpha(+ 0%)); - 92 │ color: color(beige blend(beige 0% hsl)); - -color-adjuster.css:90:32 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `0` - - 88 │ color: color(beige lightness(+ 0%)); - 89 │ color: color(beige alpha(1)); - > 90 │ color: color(beige alpha(+ 0)); - │ ^ - 91 │ color: color(beige alpha(+ 0%)); - 92 │ color: color(beige blend(beige 0% hsl)); - - i Remove 0 - -color-adjuster.css:91:30 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 89 │ color: color(beige alpha(1)); - 90 │ color: color(beige alpha(+ 0)); - > 91 │ color: color(beige alpha(+ 0%)); - │ ^ - 92 │ color: color(beige blend(beige 0% hsl)); - 93 │ color: color(red); - - i Expected a declaration item here. - - 89 │ color: color(beige alpha(1)); - 90 │ color: color(beige alpha(+ 0)); - > 91 │ color: color(beige alpha(+ 0%)); - │ ^ - 92 │ color: color(beige blend(beige 0% hsl)); - 93 │ color: color(red); - -color-adjuster.css:91:32 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `0` - - 89 │ color: color(beige alpha(1)); - 90 │ color: color(beige alpha(+ 0)); - > 91 │ color: color(beige alpha(+ 0%)); - │ ^ - 92 │ color: color(beige blend(beige 0% hsl)); - 93 │ color: color(red); - - i Remove 0 - -color-adjuster.css:109:48 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 107 │ color: color(yellow contrast(75%)); - 108 │ color: color(yellow contrast(100%)); - > 109 │ color: color(color-mod(0deg blue(10%)) rgb(+ 0 10 0) hue(+ 10deg) tint(10%) lightness(+ 10%) saturation(+ 10%) blend(rebeccapurple 50%)); - │ ^ - 110 │ color: color(var(--color)); - 111 │ color: color(var(--color) l(+ 20%)); - - i Expected a declaration item here. - - 107 │ color: color(yellow contrast(75%)); - 108 │ color: color(yellow contrast(100%)); - > 109 │ color: color(color-mod(0deg blue(10%)) rgb(+ 0 10 0) hue(+ 10deg) tint(10%) lightness(+ 10%) saturation(+ 10%) blend(rebeccapurple 50%)); - │ ^ - 110 │ color: color(var(--color)); - 111 │ color: color(var(--color) l(+ 20%)); - -color-adjuster.css:109:50 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `0` - - 107 │ color: color(yellow contrast(75%)); - 108 │ color: color(yellow contrast(100%)); - > 109 │ color: color(color-mod(0deg blue(10%)) rgb(+ 0 10 0) hue(+ 10deg) tint(10%) lightness(+ 10%) saturation(+ 10%) blend(rebeccapurple 50%)); - │ ^ - 110 │ color: color(var(--color)); - 111 │ color: color(var(--color) l(+ 20%)); - - i Remove 0 - -color-adjuster.css:109:62 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 107 │ color: color(yellow contrast(75%)); - 108 │ color: color(yellow contrast(100%)); - > 109 │ color: color(color-mod(0deg blue(10%)) rgb(+ 0 10 0) hue(+ 10deg) tint(10%) lightness(+ 10%) saturation(+ 10%) blend(rebeccapurple 50%)); - │ ^ - 110 │ color: color(var(--color)); - 111 │ color: color(var(--color) l(+ 20%)); - - i Expected a declaration item here. - - 107 │ color: color(yellow contrast(75%)); - 108 │ color: color(yellow contrast(100%)); - > 109 │ color: color(color-mod(0deg blue(10%)) rgb(+ 0 10 0) hue(+ 10deg) tint(10%) lightness(+ 10%) saturation(+ 10%) blend(rebeccapurple 50%)); - │ ^ - 110 │ color: color(var(--color)); - 111 │ color: color(var(--color) l(+ 20%)); - -color-adjuster.css:109:64 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `10` - - 107 │ color: color(yellow contrast(75%)); - 108 │ color: color(yellow contrast(100%)); - > 109 │ color: color(color-mod(0deg blue(10%)) rgb(+ 0 10 0) hue(+ 10deg) tint(10%) lightness(+ 10%) saturation(+ 10%) blend(rebeccapurple 50%)); - │ ^^ - 110 │ color: color(var(--color)); - 111 │ color: color(var(--color) l(+ 20%)); - - i Remove 10 - -color-adjuster.css:109:91 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 107 │ color: color(yellow contrast(75%)); - 108 │ color: color(yellow contrast(100%)); - > 109 │ color: color(color-mod(0deg blue(10%)) rgb(+ 0 10 0) hue(+ 10deg) tint(10%) lightness(+ 10%) saturation(+ 10%) blend(rebeccapurple 50%)); - │ ^ - 110 │ color: color(var(--color)); - 111 │ color: color(var(--color) l(+ 20%)); - - i Expected a declaration item here. - - 107 │ color: color(yellow contrast(75%)); - 108 │ color: color(yellow contrast(100%)); - > 109 │ color: color(color-mod(0deg blue(10%)) rgb(+ 0 10 0) hue(+ 10deg) tint(10%) lightness(+ 10%) saturation(+ 10%) blend(rebeccapurple 50%)); - │ ^ - 110 │ color: color(var(--color)); - 111 │ color: color(var(--color) l(+ 20%)); - -color-adjuster.css:109:93 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `10` - - 107 │ color: color(yellow contrast(75%)); - 108 │ color: color(yellow contrast(100%)); - > 109 │ color: color(color-mod(0deg blue(10%)) rgb(+ 0 10 0) hue(+ 10deg) tint(10%) lightness(+ 10%) saturation(+ 10%) blend(rebeccapurple 50%)); - │ ^^ - 110 │ color: color(var(--color)); - 111 │ color: color(var(--color) l(+ 20%)); - - i Remove 10 - -color-adjuster.css:109:109 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 107 │ color: color(yellow contrast(75%)); - 108 │ color: color(yellow contrast(100%)); - > 109 │ color: color(color-mod(0deg blue(10%)) rgb(+ 0 10 0) hue(+ 10deg) tint(10%) lightness(+ 10%) saturation(+ 10%) blend(rebeccapurple 50%)); - │ ^ - 110 │ color: color(var(--color)); - 111 │ color: color(var(--color) l(+ 20%)); - - i Expected a declaration item here. - - 107 │ color: color(yellow contrast(75%)); - 108 │ color: color(yellow contrast(100%)); - > 109 │ color: color(color-mod(0deg blue(10%)) rgb(+ 0 10 0) hue(+ 10deg) tint(10%) lightness(+ 10%) saturation(+ 10%) blend(rebeccapurple 50%)); - │ ^ - 110 │ color: color(var(--color)); - 111 │ color: color(var(--color) l(+ 20%)); - -color-adjuster.css:109:111 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `10` - - 107 │ color: color(yellow contrast(75%)); - 108 │ color: color(yellow contrast(100%)); - > 109 │ color: color(color-mod(0deg blue(10%)) rgb(+ 0 10 0) hue(+ 10deg) tint(10%) lightness(+ 10%) saturation(+ 10%) blend(rebeccapurple 50%)); - │ ^^ - 110 │ color: color(var(--color)); - 111 │ color: color(var(--color) l(+ 20%)); - - i Remove 10 - -color-adjuster.css:111:33 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 109 │ color: color(color-mod(0deg blue(10%)) rgb(+ 0 10 0) hue(+ 10deg) tint(10%) lightness(+ 10%) saturation(+ 10%) blend(rebeccapurple 50%)); - 110 │ color: color(var(--color)); - > 111 │ color: color(var(--color) l(+ 20%)); - │ ^ - 112 │ color: color(red l(+20%)); /* interpreted as part of the number */ - 113 │ color: color(red l(-20%)); /* interpreted as part of the number */ - - i Expected a declaration item here. - - 109 │ color: color(color-mod(0deg blue(10%)) rgb(+ 0 10 0) hue(+ 10deg) tint(10%) lightness(+ 10%) saturation(+ 10%) blend(rebeccapurple 50%)); - 110 │ color: color(var(--color)); - > 111 │ color: color(var(--color) l(+ 20%)); - │ ^ - 112 │ color: color(red l(+20%)); /* interpreted as part of the number */ - 113 │ color: color(red l(-20%)); /* interpreted as part of the number */ - -color-adjuster.css:111:35 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 109 │ color: color(color-mod(0deg blue(10%)) rgb(+ 0 10 0) hue(+ 10deg) tint(10%) lightness(+ 10%) saturation(+ 10%) blend(rebeccapurple 50%)); - 110 │ color: color(var(--color)); - > 111 │ color: color(var(--color) l(+ 20%)); - │ ^^ - 112 │ color: color(red l(+20%)); /* interpreted as part of the number */ - 113 │ color: color(red l(-20%)); /* interpreted as part of the number */ - - i Remove 20 - -color-adjuster.css:118:26 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '*'. - - 116 │ color: color(red hue(-20)); - 117 │ color: color(red hue(-20deg)); - > 118 │ color: color(red hue(*20)); - │ ^ - 119 │ color: color(red hue(*20deg)); - 120 │ color: color(var(--highlightColor) blackness(+ 20%)); - - i Expected a declaration item here. - - 116 │ color: color(red hue(-20)); - 117 │ color: color(red hue(-20deg)); - > 118 │ color: color(red hue(*20)); - │ ^ - 119 │ color: color(red hue(*20deg)); - 120 │ color: color(var(--highlightColor) blackness(+ 20%)); - -color-adjuster.css:118:27 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 116 │ color: color(red hue(-20)); - 117 │ color: color(red hue(-20deg)); - > 118 │ color: color(red hue(*20)); - │ ^^ - 119 │ color: color(red hue(*20deg)); - 120 │ color: color(var(--highlightColor) blackness(+ 20%)); - - i Remove 20 - -color-adjuster.css:119:26 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '*'. - - 117 │ color: color(red hue(-20deg)); - 118 │ color: color(red hue(*20)); - > 119 │ color: color(red hue(*20deg)); - │ ^ - 120 │ color: color(var(--highlightColor) blackness(+ 20%)); - 121 │ } - - i Expected a declaration item here. - - 117 │ color: color(red hue(-20deg)); - 118 │ color: color(red hue(*20)); - > 119 │ color: color(red hue(*20deg)); - │ ^ - 120 │ color: color(var(--highlightColor) blackness(+ 20%)); - 121 │ } - -color-adjuster.css:119:27 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 117 │ color: color(red hue(-20deg)); - 118 │ color: color(red hue(*20)); - > 119 │ color: color(red hue(*20deg)); - │ ^^ - 120 │ color: color(var(--highlightColor) blackness(+ 20%)); - 121 │ } - - i Remove 20 - -color-adjuster.css:120:50 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 118 │ color: color(red hue(*20)); - 119 │ color: color(red hue(*20deg)); - > 120 │ color: color(var(--highlightColor) blackness(+ 20%)); - │ ^ - 121 │ } - 122 │ - - i Expected a declaration item here. - - 118 │ color: color(red hue(*20)); - 119 │ color: color(red hue(*20deg)); - > 120 │ color: color(var(--highlightColor) blackness(+ 20%)); - │ ^ - 121 │ } - 122 │ - -color-adjuster.css:120:52 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 118 │ color: color(red hue(*20)); - 119 │ color: color(red hue(*20deg)); - > 120 │ color: color(var(--highlightColor) blackness(+ 20%)); - │ ^^ - 121 │ } - 122 │ - - i Remove 20 - - -``` - -# Lines exceeding max width of 80 characters -``` - 109: color: color(color-mod(0deg blue(10%)) rgb(+ 0 10 0) hue(+ 10deg) tint(10%) lightness(+ 10%) saturation(+ 10%) blend(rebeccapurple 50%)); -``` diff --git a/crates/biome_css_formatter/tests/specs/prettier/css/parens/parens.css.snap b/crates/biome_css_formatter/tests/specs/prettier/css/parens/parens.css.snap index 3f9603599e96..8948a1ac1456 100644 --- a/crates/biome_css_formatter/tests/specs/prettier/css/parens/parens.css.snap +++ b/crates/biome_css_formatter/tests/specs/prettier/css/parens/parens.css.snap @@ -304,9 +304,8 @@ a { - prop32: func(8px/2); + prop32: func(8px / 2); prop33: 5px + 8px/2px; -- prop34: func(+20px, +20px); + prop34: func(+20px, +20px); - prop35: 1+1+1+1; -+ prop34: func(+20px, + 20px); + prop35: 1 +1 +1 +1; prop36: 1 + 1 + 1 + 1; prop37: 1 +1 1 +1; @@ -436,7 +435,7 @@ a { prop30: (8px / 2px) (8px / 1) (1 / 2px) (1 / 2); prop32: func(8px / 2); prop33: 5px + 8px/2px; - prop34: func(+20px, + 20px); + prop34: func(+20px, +20px); prop35: 1 +1 +1 +1; prop36: 1 + 1 + 1 + 1; prop37: 1 +1 1 +1; @@ -759,39 +758,6 @@ parens.css:131:15 parse ━━━━━━━━━━━━━━━━━━ - custom property - function -parens.css:132:23 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × Expected a declaration item but instead found '+'. - - 130 │ prop32: func(8px/2); - 131 │ prop33: 5px + 8px/2px; - > 132 │ prop34: func(+20px, + 20px); - │ ^ - 133 │ prop35: 1+1+1+1; - 134 │ prop36: 1 + 1 + 1 + 1; - - i Expected a declaration item here. - - 130 │ prop32: func(8px/2); - 131 │ prop33: 5px + 8px/2px; - > 132 │ prop34: func(+20px, + 20px); - │ ^ - 133 │ prop35: 1+1+1+1; - 134 │ prop36: 1 + 1 + 1 + 1; - -parens.css:132:25 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - × expected `,` but instead found `20` - - 130 │ prop32: func(8px/2); - 131 │ prop33: 5px + 8px/2px; - > 132 │ prop34: func(+20px, + 20px); - │ ^^ - 133 │ prop35: 1+1+1+1; - 134 │ prop36: 1 + 1 + 1 + 1; - - i Remove 20 - parens.css:134:13 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ × Unexpected value or character. diff --git a/crates/biome_css_parser/src/lexer/mod.rs b/crates/biome_css_parser/src/lexer/mod.rs index 7b7a9ee96532..e6f08c22b613 100644 --- a/crates/biome_css_parser/src/lexer/mod.rs +++ b/crates/biome_css_parser/src/lexer/mod.rs @@ -76,6 +76,8 @@ pub(crate) struct CssLexer<'src> { /// `true` if there has been a line break between the last non-trivia token and the next non-trivia token. after_newline: bool, + /// `true` if there has been trivia between the last non-trivia token and the next non-trivia token. + after_whitespace: bool, /// If the source starts with a Unicode BOM, this is the number of bytes for that token. unicode_bom_length: usize, @@ -145,10 +147,15 @@ impl<'src> Lexer<'src> for CssLexer<'src> { self.current_flags .set(TokenFlags::PRECEDING_LINE_BREAK, self.after_newline); + self.current_flags + .set(TokenFlags::PRECEDING_WHITESPACE, self.after_whitespace); self.current_kind = kind; if !kind.is_trivia() { self.after_newline = false; + self.after_whitespace = false; + } else if kind == Self::WHITESPACE { + self.after_whitespace = true; } kind @@ -169,6 +176,7 @@ impl<'src> Lexer<'src> for CssLexer<'src> { current_flags, current_kind, after_line_break, + after_whitespace, unicode_bom_length, diagnostics_pos, } = checkpoint; @@ -180,6 +188,7 @@ impl<'src> Lexer<'src> for CssLexer<'src> { self.current_start = current_start; self.current_flags = current_flags; self.after_newline = after_line_break; + self.after_whitespace = after_whitespace; self.unicode_bom_length = unicode_bom_length; self.diagnostics.truncate(diagnostics_pos as usize); } @@ -211,6 +220,7 @@ impl<'src> CssLexer<'src> { Self { source, after_newline: false, + after_whitespace: false, unicode_bom_length: 0, current_kind: TOMBSTONE, current_start: TextSize::from(0), @@ -1437,6 +1447,7 @@ impl<'src> LexerWithCheckpoint<'src> for CssLexer<'src> { current_flags: self.current_flags, current_kind: self.current_kind, after_line_break: self.after_newline, + after_whitespace: self.after_whitespace, unicode_bom_length: self.unicode_bom_length, diagnostics_pos: self.diagnostics.len() as u32, } diff --git a/crates/biome_css_parser/src/syntax/at_rule/page.rs b/crates/biome_css_parser/src/syntax/at_rule/page.rs index 8bd6bb1c088e..8aa45a48ad63 100644 --- a/crates/biome_css_parser/src/syntax/at_rule/page.rs +++ b/crates/biome_css_parser/src/syntax/at_rule/page.rs @@ -5,13 +5,16 @@ use crate::syntax::at_rule::parse_error::{ }; use crate::syntax::at_rule::{is_at_at_rule, parse_at_rule}; use crate::syntax::block::{ParseBlockBody, parse_declaration_or_at_rule_list_block}; +use crate::syntax::parse_error::scss_only_syntax_error; +use crate::syntax::scss::{is_at_scss_nesting_declaration, parse_scss_nesting_declaration}; use crate::syntax::{ - is_at_any_declaration_with_semicolon, is_at_identifier, is_at_qualified_rule, - parse_any_declaration_with_semicolon, parse_custom_identifier_with_keywords, - parse_qualified_rule, parse_regular_identifier, + CssSyntaxFeatures, is_at_any_declaration_with_semicolon, is_at_identifier, + is_at_qualified_rule, parse_any_declaration_with_semicolon, + parse_custom_identifier_with_keywords, parse_qualified_rule, parse_regular_identifier, }; use biome_css_syntax::CssSyntaxKind::*; use biome_css_syntax::{CssSyntaxKind, T}; +use biome_parser::SyntaxFeature; use biome_parser::parse_lists::{ParseNodeList, ParseSeparatedList}; use biome_parser::parse_recovery::{ParseRecoveryTokenSet, RecoveryResult}; use biome_parser::parsed_syntax::ParsedSyntax::Present; @@ -169,6 +172,7 @@ impl ParseBlockBody for PageBlock { fn is_at_element(&self, p: &mut CssParser) -> bool { at_margin_rule(p) || is_at_at_rule(p) + || is_at_scss_nesting_declaration(p) || is_at_any_declaration_with_semicolon(p) || is_at_qualified_rule(p) } @@ -192,6 +196,12 @@ impl ParseNodeList for PageAtRuleItemList { parse_margin_at_rule(p) } else if is_at_at_rule(p) { parse_at_rule(p) + } else if is_at_scss_nesting_declaration(p) { + CssSyntaxFeatures::Scss.parse_exclusive_syntax( + p, + parse_scss_nesting_declaration, + |p, marker| scss_only_syntax_error(p, "SCSS nesting declarations", marker.range(p)), + ) } else if is_at_any_declaration_with_semicolon(p) { parse_any_declaration_with_semicolon(p) } else if is_at_qualified_rule(p) { diff --git a/crates/biome_css_parser/src/syntax/block/declaration_or_at_rule_list_block.rs b/crates/biome_css_parser/src/syntax/block/declaration_or_at_rule_list_block.rs index 71b084d7a74b..cb53b04b83ba 100644 --- a/crates/biome_css_parser/src/syntax/block/declaration_or_at_rule_list_block.rs +++ b/crates/biome_css_parser/src/syntax/block/declaration_or_at_rule_list_block.rs @@ -1,15 +1,21 @@ use crate::parser::CssParser; use crate::syntax::at_rule::{is_at_at_rule, parse_at_rule}; use crate::syntax::block::ParseBlockBody; -use crate::syntax::parse_error::expected_any_declaration_or_at_rule; -use crate::syntax::{is_at_any_declaration_with_semicolon, parse_any_declaration_with_semicolon}; +use crate::syntax::parse_error::{expected_any_declaration_or_at_rule, scss_only_syntax_error}; +use crate::syntax::scss::{ + is_at_scss_declaration, is_at_scss_nesting_declaration, parse_scss_declaration, + parse_scss_nesting_declaration, +}; +use crate::syntax::{ + CssSyntaxFeatures, is_at_any_declaration_with_semicolon, parse_any_declaration_with_semicolon, +}; use biome_css_syntax::CssSyntaxKind::*; use biome_css_syntax::{CssSyntaxKind, T}; use biome_parser::parse_lists::ParseNodeList; use biome_parser::parse_recovery::{ParseRecovery, RecoveryResult}; use biome_parser::parsed_syntax::ParsedSyntax; use biome_parser::parsed_syntax::ParsedSyntax::Absent; -use biome_parser::{CompletedMarker, Parser}; +use biome_parser::{CompletedMarker, Parser, SyntaxFeature}; #[inline] pub(crate) fn parse_declaration_or_at_rule_list_block(p: &mut CssParser) -> CompletedMarker { @@ -32,7 +38,10 @@ impl ParseBlockBody for DeclarationOrAtRuleListBlock { #[inline] fn is_at_declaration_or_at_rule_item(p: &mut CssParser) -> bool { - is_at_at_rule(p) || is_at_any_declaration_with_semicolon(p) + is_at_at_rule(p) + || is_at_scss_declaration(p) + || is_at_scss_nesting_declaration(p) + || is_at_any_declaration_with_semicolon(p) } struct DeclarationOrAtRuleListParseRecovery; @@ -55,6 +64,21 @@ impl ParseNodeList for DeclarationOrAtRuleList { fn parse_element(&mut self, p: &mut Self::Parser<'_>) -> ParsedSyntax { if is_at_at_rule(p) { parse_at_rule(p) + } else if is_at_scss_declaration(p) { + CssSyntaxFeatures::Scss.parse_exclusive_syntax( + p, + parse_scss_declaration, + |p, marker| { + scss_only_syntax_error(p, "SCSS variable declarations", marker.range(p)) + }, + ) + } else if is_at_scss_nesting_declaration(p) { + // Parse nested properties before generic declarations to keep `{` blocks intact. + CssSyntaxFeatures::Scss.parse_exclusive_syntax( + p, + parse_scss_nesting_declaration, + |p, marker| scss_only_syntax_error(p, "SCSS nesting declarations", marker.range(p)), + ) } else if is_at_any_declaration_with_semicolon(p) { parse_any_declaration_with_semicolon(p) } else { diff --git a/crates/biome_css_parser/src/syntax/block/declaration_or_rule_list_block.rs b/crates/biome_css_parser/src/syntax/block/declaration_or_rule_list_block.rs index 57820aab2107..3c65657ced77 100644 --- a/crates/biome_css_parser/src/syntax/block/declaration_or_rule_list_block.rs +++ b/crates/biome_css_parser/src/syntax/block/declaration_or_rule_list_block.rs @@ -1,11 +1,16 @@ use crate::parser::CssParser; use crate::syntax::at_rule::{is_at_at_rule, parse_at_rule}; use crate::syntax::block::ParseBlockBody; -use crate::syntax::parse_error::expected_any_declaration_or_at_rule; +use crate::syntax::parse_error::{expected_any_declaration_or_at_rule, scss_only_syntax_error}; +use crate::syntax::scss::{ + is_at_scss_declaration, is_at_scss_nesting_declaration, parse_scss_declaration, + parse_scss_nesting_declaration, +}; use crate::syntax::{ - is_at_any_declaration_with_semicolon, is_at_metavariable, is_at_nested_qualified_rule, - parse_any_declaration_with_semicolon, parse_metavariable, parse_nested_qualified_rule, - try_parse, + CssSyntaxFeatures, is_at_any_declaration_with_semicolon, is_at_metavariable, + is_at_nested_qualified_rule, is_nth_at_identifier, parse_any_declaration_with_semicolon, + parse_metavariable, parse_nested_qualified_rule, try_parse, + try_parse_nested_qualified_rule_without_selector_recovery, }; use biome_css_syntax::CssSyntaxKind::*; use biome_css_syntax::{CssSyntaxKind, T}; @@ -13,7 +18,8 @@ use biome_parser::parse_lists::ParseNodeList; use biome_parser::parse_recovery::{ParseRecovery, RecoveryResult}; use biome_parser::prelude::ParsedSyntax; use biome_parser::prelude::ParsedSyntax::Absent; -use biome_parser::{CompletedMarker, Parser}; +use biome_parser::token_source::TokenSourceWithBufferedLexer; +use biome_parser::{CompletedMarker, Parser, SyntaxFeature}; #[inline] pub(crate) fn parse_declaration_or_rule_list_block(p: &mut CssParser) -> CompletedMarker { @@ -38,10 +44,32 @@ impl ParseBlockBody for DeclarationOrRuleListBlock { fn is_at_declaration_or_rule_item(p: &mut CssParser) -> bool { is_at_at_rule(p) || is_at_nested_qualified_rule(p) + || is_at_scss_nesting_declaration(p) + || is_at_scss_declaration(p) || is_at_any_declaration_with_semicolon(p) || is_at_metavariable(p) } +#[inline] +fn has_whitespace_after_scss_property_colon(p: &mut CssParser) -> bool { + // We enter this helper at `ident` in `ident:...`. + // `nth_non_trivia(1)` is the `:` token, so `nth_non_trivia(2)` is the first token + // after `:`. Its preceding flags tell us whether there was spacing after the colon. + let Some(after_colon) = p.source_mut().lexer().nth_non_trivia(2) else { + return false; + }; + + after_colon.has_preceding_whitespace() || after_colon.has_preceding_line_break() +} + +#[inline] +fn is_at_ambiguous_scss_nesting_item(p: &mut CssParser) -> bool { + // Match Sass's ambiguity gate: only no-spacing `name:ident` and `name::...` + // forms can be nested selectors. + !has_whitespace_after_scss_property_colon(p) + && (is_nth_at_identifier(p, 2) || p.nth_at(2, T![:])) +} + struct DeclarationOrRuleListParseRecovery { end_kind: CssSyntaxKind, } @@ -80,6 +108,47 @@ impl ParseNodeList for DeclarationOrRuleList { fn parse_element(&mut self, p: &mut Self::Parser<'_>) -> ParsedSyntax { if is_at_at_rule(p) { parse_at_rule(p) + } else if is_at_scss_nesting_declaration(p) { + let is_ambiguous = is_at_ambiguous_scss_nesting_item(p); + + if is_ambiguous { + // Match Sass's declaration-first strategy for ambiguous `name:ident` and + // `name::...` forms. Parse as declaration first, then backtrack to selector + // parsing when the result is declaration-like but selector-ambiguous. + let declaration = try_parse(p, |p| { + let declaration = parse_scss_nesting_declaration(p); + + match declaration.kind(p) { + Some(SCSS_NESTING_DECLARATION) => Err(()), + Some(CSS_DECLARATION_WITH_SEMICOLON) + if matches!(p.last(), Some(T![;])) || p.at(self.end_kind) => + { + Ok(declaration) + } + _ => Err(()), + } + }); + + if let Ok(declaration) = declaration { + return declaration; + } + + if let Ok(rule) = + try_parse_nested_qualified_rule_without_selector_recovery(p, self.end_kind) + { + return rule; + } + } + + parse_scss_nesting_declaration(p) + } else if is_at_scss_declaration(p) { + CssSyntaxFeatures::Scss.parse_exclusive_syntax( + p, + parse_scss_declaration, + |p, marker| { + scss_only_syntax_error(p, "SCSS variable declarations", marker.range(p)) + }, + ) } else if is_at_any_declaration_with_semicolon(p) { // if we are at a declaration, // we still can have a nested qualified rule or a declaration @@ -119,11 +188,8 @@ impl ParseNodeList for DeclarationOrRuleList { // } <--- // The closing brace indicates the end of the declaration block. // If either condition is true, the declaration is considered valid. - if matches!(p.last(), Some(T![;])) || p.at(self.end_kind) { - Ok(declaration) - } else { - Err(()) - } + let valid = matches!(p.last(), Some(T![;])) || p.at(self.end_kind); + if valid { Ok(declaration) } else { Err(()) } }); // If parsing as a declaration was successful, return the parsed declaration. diff --git a/crates/biome_css_parser/src/syntax/declaration.rs b/crates/biome_css_parser/src/syntax/declaration.rs index 06a80c8d5798..fd348b1719ca 100644 --- a/crates/biome_css_parser/src/syntax/declaration.rs +++ b/crates/biome_css_parser/src/syntax/declaration.rs @@ -2,7 +2,10 @@ use crate::parser::CssParser; use crate::syntax::CssSyntaxFeatures; use crate::syntax::parse_error::{expected_declaration_item, scss_only_syntax_error}; use crate::syntax::property::{is_at_any_property, parse_any_property}; -use crate::syntax::scss::{is_at_scss_declaration, parse_scss_declaration}; +use crate::syntax::scss::{ + is_at_scss_declaration, is_at_scss_nesting_declaration, parse_scss_declaration, + parse_scss_nesting_declaration, +}; use biome_css_syntax::CssSyntaxKind::*; use biome_css_syntax::{CssSyntaxKind, T}; use biome_parser::parse_lists::ParseNodeList; @@ -19,7 +22,15 @@ impl ParseNodeList for DeclarationList { const LIST_KIND: Self::Kind = CSS_DECLARATION_LIST; fn parse_element(&mut self, p: &mut Self::Parser<'_>) -> ParsedSyntax { - parse_any_declaration_with_semicolon(p) + if is_at_scss_nesting_declaration(p) { + CssSyntaxFeatures::Scss.parse_exclusive_syntax( + p, + parse_scss_nesting_declaration, + |p, marker| scss_only_syntax_error(p, "SCSS nesting declarations", marker.range(p)), + ) + } else { + parse_any_declaration_with_semicolon(p) + } } fn is_at_list_end(&self, p: &mut Self::Parser<'_>) -> bool { diff --git a/crates/biome_css_parser/src/syntax/mod.rs b/crates/biome_css_parser/src/syntax/mod.rs index 6abc40228bfc..8b3bec8359d1 100644 --- a/crates/biome_css_parser/src/syntax/mod.rs +++ b/crates/biome_css_parser/src/syntax/mod.rs @@ -15,12 +15,13 @@ use crate::syntax::at_rule::{is_at_at_rule, parse_at_rule}; use crate::syntax::block::{DeclarationOrRuleList, parse_declaration_or_rule_list_block}; use crate::syntax::parse_error::{ expected_any_rule, expected_component_value, expected_non_css_wide_keyword_identifier, - scss_only_syntax_error, tailwind_disabled, + inconsistent_scss_bracketed_list_separators, scss_only_syntax_error, tailwind_disabled, }; use crate::syntax::property::color::{is_at_color, parse_color}; use crate::syntax::property::unicode_range::{is_at_unicode_range, parse_unicode_range}; use crate::syntax::scss::{ - is_at_scss_declaration, is_at_scss_identifier, parse_scss_declaration, parse_scss_identifier, + is_at_scss_declaration, is_at_scss_identifier, is_at_scss_qualified_name, + parse_scss_declaration, parse_scss_identifier, parse_scss_qualified_name, }; use crate::syntax::selector::SelectorList; use crate::syntax::selector::is_nth_at_selector; @@ -244,17 +245,67 @@ pub(crate) fn is_at_nested_qualified_rule(p: &mut CssParser) -> bool { /// the success of parsing the block. #[inline] pub(crate) fn parse_nested_qualified_rule(p: &mut CssParser) -> ParsedSyntax { + parse_nested_qualified_rule_with_selector_recovery(p, false).map_or(Absent, |(rule, _)| rule) +} + +/// Speculatively parses a nested qualified rule without selector recovery. +/// +/// This is used to disambiguate SCSS nesting declarations from nested qualified rules. +/// The parse is considered successful only when the selector is strict and the parsed +/// block is complete. +#[inline] +pub(crate) fn try_parse_nested_qualified_rule_without_selector_recovery( + p: &mut CssParser, + end_kind: CssSyntaxKind, +) -> Result { + try_parse(p, |p| { + let Some((rule, block_kind)) = parse_nested_qualified_rule_with_selector_recovery(p, true) + else { + return Err(()); + }; + + if block_kind != CSS_DECLARATION_OR_RULE_BLOCK + || p.last().is_none_or(|kind| kind != end_kind) + { + return Err(()); + } + + Ok(rule) + }) +} + +#[inline] +fn parse_nested_qualified_rule_with_selector_recovery( + p: &mut CssParser, + disable_selector_recovery: bool, +) -> Option<(ParsedSyntax, CssSyntaxKind)> { if !is_at_nested_qualified_rule(p) { - return Absent; + return None; } let m = p.start(); - RelativeSelectorList::new(T!['{']).parse_list(p); + if disable_selector_recovery { + RelativeSelectorList::new(T!['{']) + .disable_recovery() + .parse_list(p); - parse_declaration_or_rule_list_block(p); + // In strict mode, reject selectors that don't reach the opening brace. + if !p.at(T!['{']) { + m.abandon(p); + return None; + } + } else { + RelativeSelectorList::new(T!['{']).parse_list(p); + } + + let block = parse_declaration_or_rule_list_block(p); + let block_kind = block.kind(p); - Present(m.complete(p, CSS_NESTED_QUALIFIED_RULE)) + Some(( + Present(m.complete(p, CSS_NESTED_QUALIFIED_RULE)), + block_kind, + )) } #[inline] @@ -281,6 +332,7 @@ fn parse_metavariable(p: &mut CssParser) -> ParsedSyntax { pub(crate) fn is_at_any_value(p: &mut CssParser) -> bool { is_at_any_function(p) || is_at_scss_identifier(p) + || (CssSyntaxFeatures::Scss.is_supported(p) && is_at_scss_qualified_name(p)) || is_at_identifier(p) || p.at(CSS_STRING_LITERAL) || is_at_any_dimension(p) @@ -300,6 +352,8 @@ pub(crate) fn parse_any_value(p: &mut CssParser) -> ParsedSyntax { }) } else if is_at_any_function(p) { parse_any_function(p) + } else if CssSyntaxFeatures::Scss.is_supported(p) && is_at_scss_qualified_name(p) { + parse_scss_qualified_name(p) } else if is_at_dashed_identifier(p) { if p.nth_at(1, T![-]) && p.nth_at(2, T![*]) { CssSyntaxFeatures::Tailwind.parse_exclusive_syntax( @@ -534,7 +588,7 @@ pub(crate) fn parse_bracketed_value(p: &mut CssParser) -> ParsedSyntax { let m = p.start(); p.bump(T!['[']); - BracketedValueList.parse_list(p); + BracketedValueList::default().parse_list(p); p.expect(T![']']); Present(m.complete(p, CSS_BRACKETED_VALUE)) @@ -543,7 +597,43 @@ pub(crate) fn parse_bracketed_value(p: &mut CssParser) -> ParsedSyntax { /// The list parser for bracketed values. /// /// This parser is responsible for parsing a list of identifiers inside a bracketed value. -pub(crate) struct BracketedValueList; +#[derive(Default)] +pub(crate) struct BracketedValueList { + separator: Option, + mixed_separators_reported: bool, +} + +#[derive(Copy, Clone, Eq, PartialEq)] +enum BracketedValueSeparator { + Comma, + Slash, +} + +impl BracketedValueSeparator { + fn from_current_token(p: &mut CssParser) -> Option { + if p.at(T![,]) { + Some(Self::Comma) + } else if p.at(T![/]) { + Some(Self::Slash) + } else { + None + } + } + + fn bump(self, p: &mut CssParser) { + match self { + Self::Comma => p.bump(T![,]), + Self::Slash => p.bump(T![/]), + } + } + + fn as_str(self) -> &'static str { + match self { + Self::Comma => "`,`", + Self::Slash => "`/`", + } + } +} impl ParseNodeList for BracketedValueList { type Kind = CssSyntaxKind; @@ -563,6 +653,10 @@ impl ParseNodeList for BracketedValueList { ); } + if let Some(separator) = BracketedValueSeparator::from_current_token(p) { + return self.parse_scss_bracketed_value_delimiter(p, separator); + } + parse_custom_identifier(p, CssLexContext::Regular) } @@ -583,6 +677,50 @@ impl ParseNodeList for BracketedValueList { } } +impl BracketedValueList { + fn parse_scss_bracketed_value_delimiter( + &mut self, + p: &mut CssParser, + separator: BracketedValueSeparator, + ) -> ParsedSyntax { + // Preserve explicit separators inside bracketed values so Sass list + // separators survive parsing (e.g. `[a, b, c]`). + // Example: `$list: [a, b, c];` + // Docs: https://sass-lang.com/documentation/values/lists + CssSyntaxFeatures::Scss.parse_exclusive_syntax( + p, + |p| { + let m = p.start(); + self.report_mixed_separator_if_needed(p, separator); + separator.bump(p); + Present(m.complete(p, CSS_GENERIC_DELIMITER)) + }, + |p, m| scss_only_syntax_error(p, "Sass list separators", m.range(p)), + ) + } + + fn report_mixed_separator_if_needed( + &mut self, + p: &mut CssParser, + separator: BracketedValueSeparator, + ) { + let Some(previous_separator) = self.separator else { + self.separator = Some(separator); + return; + }; + + if previous_separator != separator && !self.mixed_separators_reported { + p.error(inconsistent_scss_bracketed_list_separators( + p, + previous_separator.as_str(), + separator.as_str(), + p.cur_range(), + )); + self.mixed_separators_reported = true; + } + } +} + /// Recovery strategy for bracketed value lists. /// /// This recovery strategy handles the recovery process when parsing bracketed value lists. @@ -595,7 +733,9 @@ impl ParseRecovery for BracketedValueListRecovery { fn is_at_recovered(&self, p: &mut Self::Parser<'_>) -> bool { // If the next token is the end of the list or the next element, we're at a recovery point. - p.at(T![']']) || is_at_identifier(p) + p.at(T![']']) + || is_at_identifier(p) + || (CssSyntaxFeatures::Scss.is_supported(p) && (p.at(T![,]) || p.at(T![/]))) } } diff --git a/crates/biome_css_parser/src/syntax/parse_error.rs b/crates/biome_css_parser/src/syntax/parse_error.rs index 4893542fa550..30c19d29326d 100644 --- a/crates/biome_css_parser/src/syntax/parse_error.rs +++ b/crates/biome_css_parser/src/syntax/parse_error.rs @@ -257,3 +257,20 @@ pub(crate) fn scss_only_syntax_error( ) .with_hint(markup! { "SCSS only syntax" }) } + +pub(crate) fn inconsistent_scss_bracketed_list_separators( + p: &CssParser, + expected: &str, + found: &str, + range: TextRange, +) -> ParseDiagnostic { + p.err_builder( + format!( + "Mixed separators in SCSS bracketed lists are not supported. Expected {expected} but found {found}." + ), + range, + ) + .with_hint(markup! { + "Use one separator style per bracketed list." + }) +} diff --git a/crates/biome_css_parser/src/syntax/scss/declaration/mod.rs b/crates/biome_css_parser/src/syntax/scss/declaration/mod.rs new file mode 100644 index 000000000000..cefc97da22c2 --- /dev/null +++ b/crates/biome_css_parser/src/syntax/scss/declaration/mod.rs @@ -0,0 +1,5 @@ +mod nesting; +mod variable; + +pub(crate) use nesting::{is_at_scss_nesting_declaration, parse_scss_nesting_declaration}; +pub(crate) use variable::{is_at_scss_declaration, parse_scss_declaration}; diff --git a/crates/biome_css_parser/src/syntax/scss/declaration/nesting.rs b/crates/biome_css_parser/src/syntax/scss/declaration/nesting.rs new file mode 100644 index 000000000000..93c820fbfe21 --- /dev/null +++ b/crates/biome_css_parser/src/syntax/scss/declaration/nesting.rs @@ -0,0 +1,142 @@ +use crate::parser::CssParser; +use crate::syntax::block::parse_declaration_or_rule_list_block; +use crate::syntax::parse_error::expected_component_value; +use crate::syntax::property::parse_generic_component_value; +use crate::syntax::{ + CssSyntaxFeatures, is_at_dashed_identifier, is_at_identifier, parse_regular_identifier, +}; +use biome_css_syntax::CssSyntaxKind::{ + CSS_BOGUS_PROPERTY_VALUE, CSS_DECLARATION, CSS_DECLARATION_IMPORTANT, + CSS_DECLARATION_WITH_SEMICOLON, CSS_GENERIC_PROPERTY, EOF, SCSS_NESTING_DECLARATION, +}; +use biome_css_syntax::{CssSyntaxKind, T}; +use biome_parser::parse_lists::ParseNodeList; +use biome_parser::parse_recovery::{ParseRecoveryTokenSet, RecoveryResult}; +use biome_parser::prelude::ParsedSyntax; +use biome_parser::prelude::ParsedSyntax::{Absent, Present}; +use biome_parser::{CompletedMarker, Parser, SyntaxFeature, token_set}; + +/// Detects nested property syntax (`prop: { ... }`) while excluding custom properties +/// and CSS Modules declarations that must remain regular properties. +/// +/// Example: +/// ```scss +/// font: { size: 12px; } +/// ``` +/// +/// Docs: https://sass-lang.com/documentation/style-rules/declarations#nested-properties +#[inline] +pub(crate) fn is_at_scss_nesting_declaration(p: &mut CssParser) -> bool { + CssSyntaxFeatures::Scss.is_supported(p) + && is_at_identifier(p) + && p.nth_at(1, T![:]) + && !is_at_dashed_identifier(p) + && !p.at(T![composes]) +} + +/// Parses a SCSS nested property declaration block, or falls back to a regular declaration +/// when no block follows. +/// +/// Example: +/// ```scss +/// font: { +/// family: sans-serif; +/// size: 12px; +/// } +/// ``` +/// +/// Specification: https://sass-lang.com/documentation/style-rules/declarations#nested-properties +#[inline] +pub(crate) fn parse_scss_nesting_declaration(p: &mut CssParser) -> ParsedSyntax { + if !is_at_scss_nesting_declaration(p) { + return Absent; + } + + let m = p.start(); + let property = p.start(); + parse_regular_identifier(p).ok(); + p.expect(T![:]); + let missing_value = p.at(T![;]) || p.at(T!['}']) || p.at(EOF) || p.at(T![!]); + ScssNestingDeclarationValueList.parse_list(p); + + if p.at(T!['{']) { + // Upgrade to a nested-property block only if `{` follows the value. + property.abandon(p); + parse_declaration_or_rule_list_block(p); + return Present(m.complete(p, SCSS_NESTING_DECLARATION)); + } + + if missing_value { + p.error(expected_component_value(p, p.cur_range())); + } + + // Otherwise, reinterpret the parsed property/value as a regular declaration. + let property = property.complete(p, CSS_GENERIC_PROPERTY); + let declaration = property.precede(p); + parse_declaration_important(p).ok(); + let declaration = declaration.complete(p, CSS_DECLARATION); + + m.abandon(p); + Present(complete_declaration_with_semicolon(p, declaration)) +} + +#[inline] +fn complete_declaration_with_semicolon( + p: &mut CssParser, + declaration: CompletedMarker, +) -> CompletedMarker { + let m = declaration.precede(p); + + if !p.at(T!['}']) { + if p.nth_at(1, T!['}']) { + p.eat(T![;]); + } else { + p.expect(T![;]); + } + } + + m.complete(p, CSS_DECLARATION_WITH_SEMICOLON) +} + +#[inline] +fn parse_declaration_important(p: &mut CssParser) -> ParsedSyntax { + if !(p.at(T![!]) && p.nth_at(1, T![important])) { + return Absent; + } + + let m = p.start(); + p.bump(T![!]); + p.bump(T![important]); + Present(m.complete(p, CSS_DECLARATION_IMPORTANT)) +} + +struct ScssNestingDeclarationValueList; + +impl ParseNodeList for ScssNestingDeclarationValueList { + type Kind = CssSyntaxKind; + type Parser<'source> = CssParser<'source>; + const LIST_KIND: Self::Kind = CssSyntaxKind::CSS_GENERIC_COMPONENT_VALUE_LIST; + + fn parse_element(&mut self, p: &mut Self::Parser<'_>) -> ParsedSyntax { + parse_generic_component_value(p) + } + + fn is_at_list_end(&self, p: &mut Self::Parser<'_>) -> bool { + p.at(T!['{']) || p.at(T![;]) || p.at(T!['}']) || p.at(EOF) || p.at(T![!]) + } + + fn recover( + &mut self, + p: &mut Self::Parser<'_>, + parsed_element: ParsedSyntax, + ) -> RecoveryResult { + parsed_element.or_recover_with_token_set( + p, + &ParseRecoveryTokenSet::new( + CSS_BOGUS_PROPERTY_VALUE, + token_set!(T!['{'], T![;], T!['}'], T![!], EOF), + ), + expected_component_value, + ) + } +} diff --git a/crates/biome_css_parser/src/syntax/scss/declaration.rs b/crates/biome_css_parser/src/syntax/scss/declaration/variable.rs similarity index 86% rename from crates/biome_css_parser/src/syntax/scss/declaration.rs rename to crates/biome_css_parser/src/syntax/scss/declaration/variable.rs index 2288681ae9a4..4dd9c08baec4 100644 --- a/crates/biome_css_parser/src/syntax/scss/declaration.rs +++ b/crates/biome_css_parser/src/syntax/scss/declaration/variable.rs @@ -1,5 +1,4 @@ -use super::is_at_scss_identifier; -use super::parse_scss_identifier; +use super::super::{is_at_scss_identifier, parse_scss_identifier}; use crate::parser::CssParser; use crate::syntax::property::GenericComponentValueList; use crate::syntax::{is_at_identifier, is_nth_at_identifier, parse_regular_identifier}; @@ -15,6 +14,14 @@ use biome_parser::prelude::ParsedSyntax; use biome_parser::prelude::ParsedSyntax::{Absent, Present}; use biome_parser::{Parser, TokenSet, token_set}; +/// Detects a SCSS variable declaration (including module-qualified variables). +/// +/// Example: +/// ```scss +/// $primary: #c00; +/// ``` +/// +/// Docs: https://sass-lang.com/documentation/variables #[inline] pub(crate) fn is_at_scss_declaration(p: &mut CssParser) -> bool { if is_at_scss_identifier(p) { @@ -26,6 +33,15 @@ pub(crate) fn is_at_scss_declaration(p: &mut CssParser) -> bool { } } +/// Parses a SCSS variable declaration, including trailing `!default`/`!global`. +/// +/// Examples: +/// ```scss +/// $primary: #c00; +/// $spacing: 1rem; +/// ``` +/// +/// Specification: https://sass-lang.com/documentation/variables #[inline] pub(crate) fn parse_scss_declaration(p: &mut CssParser) -> ParsedSyntax { if !is_at_scss_declaration(p) { @@ -42,6 +58,7 @@ pub(crate) fn parse_scss_declaration(p: &mut CssParser) -> ParsedSyntax { if !p.at(T!['}']) && !p.at(EOF) { if p.nth_at(1, T!['}']) { + // Allow a trailing `;` before `}` but don't require it. p.eat(T![;]); } else { p.expect(T![;]); diff --git a/crates/biome_css_parser/src/syntax/scss/mod.rs b/crates/biome_css_parser/src/syntax/scss/mod.rs index 693435b7efd0..c44f7ec4b555 100644 --- a/crates/biome_css_parser/src/syntax/scss/mod.rs +++ b/crates/biome_css_parser/src/syntax/scss/mod.rs @@ -1,14 +1,17 @@ mod declaration; use crate::parser::CssParser; -use crate::syntax::{is_nth_at_identifier, parse_regular_identifier}; -use biome_css_syntax::CssSyntaxKind::SCSS_IDENTIFIER; +use crate::syntax::{is_at_identifier, is_nth_at_identifier, parse_regular_identifier}; +use biome_css_syntax::CssSyntaxKind::{SCSS_IDENTIFIER, SCSS_QUALIFIED_NAME}; use biome_css_syntax::T; use biome_parser::Parser; use biome_parser::prelude::ParsedSyntax; use biome_parser::prelude::ParsedSyntax::{Absent, Present}; -pub(crate) use declaration::{is_at_scss_declaration, parse_scss_declaration}; +pub(crate) use declaration::{ + is_at_scss_declaration, is_at_scss_nesting_declaration, parse_scss_declaration, + parse_scss_nesting_declaration, +}; #[inline] pub(crate) fn is_at_scss_identifier(p: &mut CssParser) -> bool { @@ -26,3 +29,41 @@ pub(crate) fn parse_scss_identifier(p: &mut CssParser) -> ParsedSyntax { parse_regular_identifier(p).ok(); Present(m.complete(p, SCSS_IDENTIFIER)) } + +#[inline] +pub(crate) fn is_at_scss_qualified_name(p: &mut CssParser) -> bool { + is_at_identifier(p) + && p.nth_at(1, T![.]) + && ((p.nth_at(2, T![$]) && is_nth_at_identifier(p, 3)) || is_nth_at_identifier(p, 2)) +} + +#[inline] +pub(crate) fn parse_scss_qualified_name(p: &mut CssParser) -> ParsedSyntax { + if !is_at_scss_qualified_name(p) { + return Absent; + } + + let m = p.start(); + parse_regular_identifier(p).ok(); + p.expect(T![.]); + if is_at_scss_identifier(p) { + parse_scss_identifier(p).ok(); + } else { + parse_regular_identifier(p).ok(); + } + Present(m.complete(p, SCSS_QUALIFIED_NAME)) +} + +#[inline] +pub(crate) fn is_at_scss_qualified_name_function(p: &mut CssParser) -> bool { + is_at_scss_qualified_name(p) && p.nth_at(3, T!['(']) +} + +#[inline] +pub(crate) fn parse_scss_function_name(p: &mut CssParser) -> ParsedSyntax { + if is_at_scss_qualified_name(p) { + parse_scss_qualified_name(p) + } else { + parse_regular_identifier(p) + } +} diff --git a/crates/biome_css_parser/src/syntax/value/function.rs b/crates/biome_css_parser/src/syntax/value/function.rs index 62c49ab65ae2..07d655d95025 100644 --- a/crates/biome_css_parser/src/syntax/value/function.rs +++ b/crates/biome_css_parser/src/syntax/value/function.rs @@ -3,8 +3,13 @@ use super::parse_error::expected_expression; use super::url::{is_at_url_function, parse_url_function}; use crate::parser::CssParser; use crate::syntax::css_modules::v_bind_not_allowed; -use crate::syntax::parse_error::{expected_component_value, expected_declaration_item}; +use crate::syntax::parse_error::{ + expected_component_value, expected_declaration_item, expected_identifier, +}; use crate::syntax::property::parse_generic_component_value; +use crate::syntax::scss::{ + is_at_scss_qualified_name, is_at_scss_qualified_name_function, 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; use crate::syntax::{ @@ -66,6 +71,10 @@ pub(crate) fn parse_any_function(p: &mut CssParser) -> ParsedSyntax { /// excluding URL functions (since URL functions are also considered simple functions but are handled separately). #[inline] pub(crate) fn is_at_function(p: &mut CssParser) -> bool { + if CssSyntaxFeatures::Scss.is_supported(p) && is_at_scss_qualified_name(p) { + return is_at_scss_qualified_name_function(p); + } + is_nth_at_function(p, 0) && !is_at_url_function(p) } @@ -104,7 +113,11 @@ pub(crate) fn parse_function(p: &mut CssParser) -> ParsedSyntax { let m = p.start(); - parse_regular_identifier(p).ok(); + if CssSyntaxFeatures::Scss.is_supported(p) { + parse_scss_function_name(p).or_add_diagnostic(p, expected_identifier); + } else { + parse_regular_identifier(p).or_add_diagnostic(p, expected_identifier); + } p.bump(T!['(']); ParameterList.parse_list(p); p.expect(T![')']); @@ -201,33 +214,22 @@ pub(crate) fn parse_parameter(p: &mut CssParser) -> ParsedSyntax { } /// Determines if the current position in the CSS parser is at the start of any CSS expression. -/// -/// This function checks whether the parser's current position is at the beginning of -/// either a parenthesized expression or any CSS value. It's a preliminary check used -/// to decide if parsing should proceed for a general CSS expression. #[inline] pub(crate) fn is_at_any_expression(p: &mut CssParser) -> bool { - is_at_parenthesized(p) || is_at_any_value(p) || is_at_comma_separated_value(p) + is_at_unary_operator(p) + || is_at_parenthesized(p) + || is_at_any_value(p) + || is_at_comma_separated_value(p) } /// Parses any CSS expression from the current position in the CSS parser. -/// -/// Depending on the current position, it either parses a parenthesized expression -/// or a list of component values. If a binary operator is encountered after parsing -/// the expression, it continues to parse as a binary expression. #[inline] pub(crate) fn parse_any_expression(p: &mut CssParser) -> ParsedSyntax { if !is_at_any_expression(p) { return Absent; } - let param = if is_at_parenthesized(p) { - parse_parenthesized_expression(p) - } else if is_at_comma_separated_value(p) { - parse_comma_separated_value(p) - } else { - parse_list_of_component_values_expression(p) - }; + let param = parse_unary_expression_operand(p); if is_at_binary_operator(p) { let binary_expression = param.precede(p); @@ -243,6 +245,7 @@ pub(crate) fn parse_any_expression(p: &mut CssParser) -> ParsedSyntax { pub(crate) const BINARY_OPERATION_TOKEN: TokenSet = token_set![T![+], T![-], T![*], T![/]]; +const UNARY_OPERATION_TOKEN: TokenSet = token_set![T![+], T![-], T![*]]; /// Checks if the current position in the CSS parser is at a binary operator. /// @@ -254,6 +257,36 @@ pub(crate) fn is_at_binary_operator(p: &mut CssParser) -> bool { p.at_ts(BINARY_OPERATION_TOKEN) } +#[inline] +pub(crate) fn is_at_unary_operator(p: &mut CssParser) -> bool { + p.at_ts(UNARY_OPERATION_TOKEN) +} + +#[inline] +pub(crate) fn parse_unary_expression(p: &mut CssParser) -> ParsedSyntax { + if !is_at_unary_operator(p) { + return Absent; + } + + let m = p.start(); + p.bump_ts(UNARY_OPERATION_TOKEN); + parse_unary_expression_operand(p).or_add_diagnostic(p, expected_expression); + Present(m.complete(p, CSS_UNARY_EXPRESSION)) +} + +#[inline] +fn parse_unary_expression_operand(p: &mut CssParser) -> ParsedSyntax { + if is_at_unary_operator(p) { + parse_unary_expression(p) + } else if is_at_parenthesized(p) { + parse_parenthesized_expression(p) + } else if is_at_comma_separated_value(p) { + parse_comma_separated_value(p) + } else { + parse_list_of_component_values_expression(p) + } +} + /// Determines if the current position in the CSS parser is at the start of a parenthesized expression. /// /// This function checks if the parser is currently positioned at an opening parenthesis '(', diff --git a/crates/biome_css_parser/tests/css_test_suite/error/at_rule/at_rule_page_error.css.snap b/crates/biome_css_parser/tests/css_test_suite/error/at_rule/at_rule_page_error.css.snap index 30b2837ac7cc..6573c6615434 100644 --- a/crates/biome_css_parser/tests/css_test_suite/error/at_rule/at_rule_page_error.css.snap +++ b/crates/biome_css_parser/tests/css_test_suite/error/at_rule/at_rule_page_error.css.snap @@ -1,5 +1,6 @@ --- source: crates/biome_css_parser/tests/spec_test.rs +assertion_line: 208 expression: snapshot --- diff --git a/crates/biome_css_parser/tests/css_test_suite/error/property/bracketed_value_separators.css b/crates/biome_css_parser/tests/css_test_suite/error/property/bracketed_value_separators.css new file mode 100644 index 000000000000..b3f496997241 --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/error/property/bracketed_value_separators.css @@ -0,0 +1,8 @@ +.a { + grid-template-columns: [full-start , main-start / main-end , full-end]; + grid-column: [col-start] /[col-end]; +} + +.b { + content: [a, b / c]; +} diff --git a/crates/biome_css_parser/tests/css_test_suite/error/property/bracketed_value_separators.css.snap b/crates/biome_css_parser/tests/css_test_suite/error/property/bracketed_value_separators.css.snap new file mode 100644 index 000000000000..3b9f29dc9846 --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/error/property/bracketed_value_separators.css.snap @@ -0,0 +1,387 @@ +--- +source: crates/biome_css_parser/tests/spec_test.rs +expression: snapshot +--- + +## Input + +```css +.a { + grid-template-columns: [full-start , main-start / main-end , full-end]; + grid-column: [col-start] /[col-end]; +} + +.b { + content: [a, b / c]; +} + +``` + + +## AST + +``` +CssRoot { + bom_token: missing (optional), + items: CssRootItemList [ + CssQualifiedRule { + prelude: CssSelectorList [ + CssCompoundSelector { + nesting_selectors: CssNestedSelectorList [], + simple_selector: missing (optional), + sub_selectors: CssSubSelectorList [ + CssClassSelector { + dot_token: DOT@0..1 "." [] [], + name: CssCustomIdentifier { + value_token: IDENT@1..3 "a" [] [Whitespace(" ")], + }, + }, + ], + }, + ], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@3..4 "{" [] [], + items: CssDeclarationOrRuleList [ + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssBogusProperty { + items: [ + CssIdentifier { + value_token: IDENT@4..28 "grid-template-columns" [Newline("\n"), Whitespace(" ")] [], + }, + COLON@28..30 ":" [] [Whitespace(" ")], + CssBogus { + items: [ + CssBogusSupportsCondition { + items: [ + L_BRACK@30..31 "[" [] [], + CssBogus { + items: [ + CssCustomIdentifier { + value_token: IDENT@31..42 "full-start" [] [Whitespace(" ")], + }, + CssBogus { + items: [ + COMMA@42..44 "," [] [Whitespace(" ")], + ], + }, + CssCustomIdentifier { + value_token: IDENT@44..55 "main-start" [] [Whitespace(" ")], + }, + CssBogus { + items: [ + SLASH@55..57 "/" [] [Whitespace(" ")], + ], + }, + CssCustomIdentifier { + value_token: IDENT@57..66 "main-end" [] [Whitespace(" ")], + }, + CssBogus { + items: [ + COMMA@66..68 "," [] [Whitespace(" ")], + ], + }, + CssCustomIdentifier { + value_token: IDENT@68..76 "full-end" [] [], + }, + ], + }, + R_BRACK@76..77 "]" [] [], + ], + }, + ], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@77..78 ";" [] [], + }, + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@78..92 "grid-column" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@92..94 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssBracketedValue { + l_brack_token: L_BRACK@94..95 "[" [] [], + items: CssBracketedValueList [ + CssCustomIdentifier { + value_token: IDENT@95..104 "col-start" [] [], + }, + ], + r_brack_token: R_BRACK@104..106 "]" [] [Whitespace(" ")], + }, + CssGenericDelimiter { + value: SLASH@106..107 "/" [] [], + }, + CssBracketedValue { + l_brack_token: L_BRACK@107..108 "[" [] [], + items: CssBracketedValueList [ + CssCustomIdentifier { + value_token: IDENT@108..115 "col-end" [] [], + }, + ], + r_brack_token: R_BRACK@115..116 "]" [] [], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@116..117 ";" [] [], + }, + ], + r_curly_token: R_CURLY@117..119 "}" [Newline("\n")] [], + }, + }, + CssQualifiedRule { + prelude: CssSelectorList [ + CssCompoundSelector { + nesting_selectors: CssNestedSelectorList [], + simple_selector: missing (optional), + sub_selectors: CssSubSelectorList [ + CssClassSelector { + dot_token: DOT@119..122 "." [Newline("\n"), Newline("\n")] [], + name: CssCustomIdentifier { + value_token: IDENT@122..124 "b" [] [Whitespace(" ")], + }, + }, + ], + }, + ], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@124..125 "{" [] [], + items: CssDeclarationOrRuleList [ + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssBogusProperty { + items: [ + CssIdentifier { + value_token: IDENT@125..135 "content" [Newline("\n"), Whitespace(" ")] [], + }, + COLON@135..137 ":" [] [Whitespace(" ")], + CssBogus { + items: [ + CssBogusSupportsCondition { + items: [ + L_BRACK@137..138 "[" [] [], + CssBogus { + items: [ + CssCustomIdentifier { + value_token: IDENT@138..139 "a" [] [], + }, + CssBogus { + items: [ + COMMA@139..141 "," [] [Whitespace(" ")], + ], + }, + CssCustomIdentifier { + value_token: IDENT@141..143 "b" [] [Whitespace(" ")], + }, + CssBogus { + items: [ + SLASH@143..145 "/" [] [Whitespace(" ")], + ], + }, + CssCustomIdentifier { + value_token: IDENT@145..146 "c" [] [], + }, + ], + }, + R_BRACK@146..147 "]" [] [], + ], + }, + ], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@147..148 ";" [] [], + }, + ], + r_curly_token: R_CURLY@148..150 "}" [Newline("\n")] [], + }, + }, + ], + eof_token: EOF@150..151 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: CSS_ROOT@0..151 + 0: (empty) + 1: CSS_ROOT_ITEM_LIST@0..150 + 0: CSS_QUALIFIED_RULE@0..119 + 0: CSS_SELECTOR_LIST@0..3 + 0: CSS_COMPOUND_SELECTOR@0..3 + 0: CSS_NESTED_SELECTOR_LIST@0..0 + 1: (empty) + 2: CSS_SUB_SELECTOR_LIST@0..3 + 0: CSS_CLASS_SELECTOR@0..3 + 0: DOT@0..1 "." [] [] + 1: CSS_CUSTOM_IDENTIFIER@1..3 + 0: IDENT@1..3 "a" [] [Whitespace(" ")] + 1: CSS_DECLARATION_OR_RULE_BLOCK@3..119 + 0: L_CURLY@3..4 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@4..117 + 0: CSS_DECLARATION_WITH_SEMICOLON@4..78 + 0: CSS_DECLARATION@4..77 + 0: CSS_BOGUS_PROPERTY@4..77 + 0: CSS_IDENTIFIER@4..28 + 0: IDENT@4..28 "grid-template-columns" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@28..30 ":" [] [Whitespace(" ")] + 2: CSS_BOGUS@30..77 + 0: CSS_BOGUS_SUPPORTS_CONDITION@30..77 + 0: L_BRACK@30..31 "[" [] [] + 1: CSS_BOGUS@31..76 + 0: CSS_CUSTOM_IDENTIFIER@31..42 + 0: IDENT@31..42 "full-start" [] [Whitespace(" ")] + 1: CSS_BOGUS@42..44 + 0: COMMA@42..44 "," [] [Whitespace(" ")] + 2: CSS_CUSTOM_IDENTIFIER@44..55 + 0: IDENT@44..55 "main-start" [] [Whitespace(" ")] + 3: CSS_BOGUS@55..57 + 0: SLASH@55..57 "/" [] [Whitespace(" ")] + 4: CSS_CUSTOM_IDENTIFIER@57..66 + 0: IDENT@57..66 "main-end" [] [Whitespace(" ")] + 5: CSS_BOGUS@66..68 + 0: COMMA@66..68 "," [] [Whitespace(" ")] + 6: CSS_CUSTOM_IDENTIFIER@68..76 + 0: IDENT@68..76 "full-end" [] [] + 2: R_BRACK@76..77 "]" [] [] + 1: (empty) + 1: SEMICOLON@77..78 ";" [] [] + 1: CSS_DECLARATION_WITH_SEMICOLON@78..117 + 0: CSS_DECLARATION@78..116 + 0: CSS_GENERIC_PROPERTY@78..116 + 0: CSS_IDENTIFIER@78..92 + 0: IDENT@78..92 "grid-column" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@92..94 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@94..116 + 0: CSS_BRACKETED_VALUE@94..106 + 0: L_BRACK@94..95 "[" [] [] + 1: CSS_BRACKETED_VALUE_LIST@95..104 + 0: CSS_CUSTOM_IDENTIFIER@95..104 + 0: IDENT@95..104 "col-start" [] [] + 2: R_BRACK@104..106 "]" [] [Whitespace(" ")] + 1: CSS_GENERIC_DELIMITER@106..107 + 0: SLASH@106..107 "/" [] [] + 2: CSS_BRACKETED_VALUE@107..116 + 0: L_BRACK@107..108 "[" [] [] + 1: CSS_BRACKETED_VALUE_LIST@108..115 + 0: CSS_CUSTOM_IDENTIFIER@108..115 + 0: IDENT@108..115 "col-end" [] [] + 2: R_BRACK@115..116 "]" [] [] + 1: (empty) + 1: SEMICOLON@116..117 ";" [] [] + 2: R_CURLY@117..119 "}" [Newline("\n")] [] + 1: CSS_QUALIFIED_RULE@119..150 + 0: CSS_SELECTOR_LIST@119..124 + 0: CSS_COMPOUND_SELECTOR@119..124 + 0: CSS_NESTED_SELECTOR_LIST@119..119 + 1: (empty) + 2: CSS_SUB_SELECTOR_LIST@119..124 + 0: CSS_CLASS_SELECTOR@119..124 + 0: DOT@119..122 "." [Newline("\n"), Newline("\n")] [] + 1: CSS_CUSTOM_IDENTIFIER@122..124 + 0: IDENT@122..124 "b" [] [Whitespace(" ")] + 1: CSS_DECLARATION_OR_RULE_BLOCK@124..150 + 0: L_CURLY@124..125 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@125..148 + 0: CSS_DECLARATION_WITH_SEMICOLON@125..148 + 0: CSS_DECLARATION@125..147 + 0: CSS_BOGUS_PROPERTY@125..147 + 0: CSS_IDENTIFIER@125..135 + 0: IDENT@125..135 "content" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@135..137 ":" [] [Whitespace(" ")] + 2: CSS_BOGUS@137..147 + 0: CSS_BOGUS_SUPPORTS_CONDITION@137..147 + 0: L_BRACK@137..138 "[" [] [] + 1: CSS_BOGUS@138..146 + 0: CSS_CUSTOM_IDENTIFIER@138..139 + 0: IDENT@138..139 "a" [] [] + 1: CSS_BOGUS@139..141 + 0: COMMA@139..141 "," [] [Whitespace(" ")] + 2: CSS_CUSTOM_IDENTIFIER@141..143 + 0: IDENT@141..143 "b" [] [Whitespace(" ")] + 3: CSS_BOGUS@143..145 + 0: SLASH@143..145 "/" [] [Whitespace(" ")] + 4: CSS_CUSTOM_IDENTIFIER@145..146 + 0: IDENT@145..146 "c" [] [] + 2: R_BRACK@146..147 "]" [] [] + 1: (empty) + 1: SEMICOLON@147..148 ";" [] [] + 2: R_CURLY@148..150 "}" [Newline("\n")] [] + 2: EOF@150..151 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +bracketed_value_separators.css:2:38 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Sass list separators are an SCSS only feature. Convert your file to an SCSS file or remove the syntax. + + 1 │ .a { + > 2 │ grid-template-columns: [full-start , main-start / main-end , full-end]; + │ ^ + 3 │ grid-column: [col-start] /[col-end]; + 4 │ } + + i SCSS only syntax + +bracketed_value_separators.css:2:51 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Sass list separators are an SCSS only feature. Convert your file to an SCSS file or remove the syntax. + + 1 │ .a { + > 2 │ grid-template-columns: [full-start , main-start / main-end , full-end]; + │ ^ + 3 │ grid-column: [col-start] /[col-end]; + 4 │ } + + i SCSS only syntax + +bracketed_value_separators.css:2:62 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Sass list separators are an SCSS only feature. Convert your file to an SCSS file or remove the syntax. + + 1 │ .a { + > 2 │ grid-template-columns: [full-start , main-start / main-end , full-end]; + │ ^ + 3 │ grid-column: [col-start] /[col-end]; + 4 │ } + + i SCSS only syntax + +bracketed_value_separators.css:7:14 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Sass list separators are an SCSS only feature. Convert your file to an SCSS file or remove the syntax. + + 6 │ .b { + > 7 │ content: [a, b / c]; + │ ^ + 8 │ } + 9 │ + + i SCSS only syntax + +bracketed_value_separators.css:7:18 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Sass list separators are an SCSS only feature. Convert your file to an SCSS file or remove the syntax. + + 6 │ .b { + > 7 │ content: [a, b / c]; + │ ^ + 8 │ } + 9 │ + + i SCSS only syntax + +``` diff --git a/crates/biome_css_parser/tests/css_test_suite/error/scss/value/bracketed-mixed-separators.scss b/crates/biome_css_parser/tests/css_test_suite/error/scss/value/bracketed-mixed-separators.scss new file mode 100644 index 000000000000..fd0c0283246b --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/error/scss/value/bracketed-mixed-separators.scss @@ -0,0 +1,2 @@ +$list: [a, b / c]; +$also_mixed: [x / y, z]; 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 new file mode 100644 index 000000000000..e3b36e9da1c8 --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/error/scss/value/bracketed-mixed-separators.scss.snap @@ -0,0 +1,175 @@ +--- +source: crates/biome_css_parser/tests/spec_test.rs +expression: snapshot +--- + +## Input + +```css +$list: [a, b / c]; +$also_mixed: [x / y, z]; + +``` + + +## AST + +``` +CssRoot { + bom_token: missing (optional), + items: CssRootItemList [ + ScssDeclaration { + name: ScssIdentifier { + dollar_token: DOLLAR@0..1 "$" [] [], + name: CssIdentifier { + value_token: IDENT@1..5 "list" [] [], + }, + }, + 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 "]" [] [], + }, + ], + modifiers: ScssVariableModifierList [], + semicolon_token: SEMICOLON@17..18 ";" [] [], + }, + ScssDeclaration { + name: ScssIdentifier { + dollar_token: DOLLAR@18..20 "$" [Newline("\n")] [], + name: CssIdentifier { + value_token: IDENT@20..30 "also_mixed" [] [], + }, + }, + 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 "]" [] [], + }, + ], + modifiers: ScssVariableModifierList [], + semicolon_token: SEMICOLON@42..43 ";" [] [], + }, + ], + eof_token: EOF@43..44 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: CSS_ROOT@0..44 + 0: (empty) + 1: CSS_ROOT_ITEM_LIST@0..43 + 0: SCSS_DECLARATION@0..18 + 0: SCSS_IDENTIFIER@0..5 + 0: DOLLAR@0..1 "$" [] [] + 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 "]" [] [] + 3: SCSS_VARIABLE_MODIFIER_LIST@17..17 + 4: SEMICOLON@17..18 ";" [] [] + 1: SCSS_DECLARATION@18..43 + 0: SCSS_IDENTIFIER@18..30 + 0: DOLLAR@18..20 "$" [Newline("\n")] [] + 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 "]" [] [] + 3: SCSS_VARIABLE_MODIFIER_LIST@42..42 + 4: SEMICOLON@42..43 ";" [] [] + 2: EOF@43..44 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +bracketed-mixed-separators.scss:1:14 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Mixed separators in SCSS bracketed lists are not supported. Expected `,` but found `/`. + + > 1 │ $list: [a, b / c]; + │ ^ + 2 │ $also_mixed: [x / y, z]; + 3 │ + + i Use one separator style per bracketed list. + +bracketed-mixed-separators.scss:2:20 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Mixed separators in SCSS bracketed lists are not supported. Expected `/` but found `,`. + + 1 │ $list: [a, b / c]; + > 2 │ $also_mixed: [x / y, z]; + │ ^ + 3 │ + + i Use one separator style per bracketed list. + +``` diff --git a/crates/biome_css_parser/tests/css_test_suite/error/scss/value/bracketed-recovery-separators.scss b/crates/biome_css_parser/tests/css_test_suite/error/scss/value/bracketed-recovery-separators.scss new file mode 100644 index 000000000000..c2293f7f1f6b --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/error/scss/value/bracketed-recovery-separators.scss @@ -0,0 +1,2 @@ +$comma_list: [a, 1, b, c]; +$slash_list: [x / 2 / y / z]; 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 new file mode 100644 index 000000000000..dcd582bfeb69 --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/error/scss/value/bracketed-recovery-separators.scss.snap @@ -0,0 +1,209 @@ +--- +source: crates/biome_css_parser/tests/spec_test.rs +expression: snapshot +--- + +## Input + +```css +$comma_list: [a, 1, b, c]; +$slash_list: [x / 2 / y / z]; + +``` + + +## AST + +``` +CssRoot { + bom_token: missing (optional), + items: CssRootItemList [ + ScssDeclaration { + name: ScssIdentifier { + dollar_token: DOLLAR@0..1 "$" [] [], + name: CssIdentifier { + value_token: IDENT@1..11 "comma_list" [] [], + }, + }, + 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 "]" [] [], + }, + ], + modifiers: ScssVariableModifierList [], + semicolon_token: SEMICOLON@25..26 ";" [] [], + }, + ScssDeclaration { + name: ScssIdentifier { + dollar_token: DOLLAR@26..28 "$" [Newline("\n")] [], + name: CssIdentifier { + value_token: IDENT@28..38 "slash_list" [] [], + }, + }, + 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 "]" [] [], + }, + ], + modifiers: ScssVariableModifierList [], + semicolon_token: SEMICOLON@55..56 ";" [] [], + }, + ], + eof_token: EOF@56..57 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: CSS_ROOT@0..57 + 0: (empty) + 1: CSS_ROOT_ITEM_LIST@0..56 + 0: SCSS_DECLARATION@0..26 + 0: SCSS_IDENTIFIER@0..11 + 0: DOLLAR@0..1 "$" [] [] + 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 "]" [] [] + 3: SCSS_VARIABLE_MODIFIER_LIST@25..25 + 4: SEMICOLON@25..26 ";" [] [] + 1: SCSS_DECLARATION@26..56 + 0: SCSS_IDENTIFIER@26..38 + 0: DOLLAR@26..28 "$" [Newline("\n")] [] + 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 "]" [] [] + 3: SCSS_VARIABLE_MODIFIER_LIST@55..55 + 4: SEMICOLON@55..56 ";" [] [] + 2: EOF@56..57 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +bracketed-recovery-separators.scss:1:18 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected an identifier but instead found '1'. + + > 1 │ $comma_list: [a, 1, b, c]; + │ ^ + 2 │ $slash_list: [x / 2 / y / z]; + 3 │ + + i Expected an identifier here. + + > 1 │ $comma_list: [a, 1, b, c]; + │ ^ + 2 │ $slash_list: [x / 2 / y / z]; + 3 │ + +bracketed-recovery-separators.scss:2:19 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected an identifier but instead found '2'. + + 1 │ $comma_list: [a, 1, b, c]; + > 2 │ $slash_list: [x / 2 / y / z]; + │ ^ + 3 │ + + i Expected an identifier here. + + 1 │ $comma_list: [a, 1, b, c]; + > 2 │ $slash_list: [x / 2 / y / z]; + │ ^ + 3 │ + +``` diff --git a/crates/biome_css_parser/tests/css_test_suite/error/scss/value/qualified-name-dollar-function.scss b/crates/biome_css_parser/tests/css_test_suite/error/scss/value/qualified-name-dollar-function.scss new file mode 100644 index 000000000000..06684c23812b --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/error/scss/value/qualified-name-dollar-function.scss @@ -0,0 +1,4 @@ +.test { + width: math.$div(10px, 2); + value: map.$get($map, a); +} diff --git a/crates/biome_css_parser/tests/css_test_suite/error/scss/value/qualified-name-dollar-function.scss.snap b/crates/biome_css_parser/tests/css_test_suite/error/scss/value/qualified-name-dollar-function.scss.snap new file mode 100644 index 000000000000..6cdf3c6732aa --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/error/scss/value/qualified-name-dollar-function.scss.snap @@ -0,0 +1,246 @@ +--- +source: crates/biome_css_parser/tests/spec_test.rs +expression: snapshot +--- + +## Input + +```css +.test { + width: math.$div(10px, 2); + value: map.$get($map, a); +} + +``` + + +## AST + +``` +CssRoot { + bom_token: missing (optional), + items: CssRootItemList [ + CssQualifiedRule { + prelude: CssSelectorList [ + CssCompoundSelector { + nesting_selectors: CssNestedSelectorList [], + simple_selector: missing (optional), + sub_selectors: CssSubSelectorList [ + CssClassSelector { + dot_token: DOT@0..1 "." [] [], + name: CssCustomIdentifier { + value_token: IDENT@1..6 "test" [] [Whitespace(" ")], + }, + }, + ], + }, + ], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@6..7 "{" [] [], + items: CssDeclarationOrRuleList [ + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssBogusProperty { + items: [ + CssIdentifier { + value_token: IDENT@7..15 "width" [Newline("\n"), Whitespace(" ")] [], + }, + COLON@15..17 ":" [] [Whitespace(" ")], + CssBogus { + items: [ + ScssQualifiedName { + module: CssIdentifier { + value_token: IDENT@17..21 "math" [] [], + }, + dot_token: DOT@21..22 "." [] [], + member: ScssIdentifier { + dollar_token: DOLLAR@22..23 "$" [] [], + name: CssIdentifier { + value_token: IDENT@23..26 "div" [] [], + }, + }, + }, + CssBogusPropertyValue { + items: [ + L_PAREN@26..27 "(" [] [], + CSS_DIMENSION_VALUE@27..29 "10" [] [], + PX_KW@29..31 "px" [] [], + COMMA@31..33 "," [] [Whitespace(" ")], + CSS_NUMBER_LITERAL@33..34 "2" [] [], + R_PAREN@34..35 ")" [] [], + ], + }, + ], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@35..36 ";" [] [], + }, + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssBogusProperty { + items: [ + CssIdentifier { + value_token: IDENT@36..44 "value" [Newline("\n"), Whitespace(" ")] [], + }, + COLON@44..46 ":" [] [Whitespace(" ")], + CssBogus { + items: [ + ScssQualifiedName { + module: CssIdentifier { + value_token: IDENT@46..49 "map" [] [], + }, + dot_token: DOT@49..50 "." [] [], + member: ScssIdentifier { + dollar_token: DOLLAR@50..51 "$" [] [], + name: CssIdentifier { + value_token: IDENT@51..54 "get" [] [], + }, + }, + }, + CssBogusPropertyValue { + items: [ + L_PAREN@54..55 "(" [] [], + DOLLAR@55..56 "$" [] [], + IDENT@56..59 "map" [] [], + COMMA@59..61 "," [] [Whitespace(" ")], + IDENT@61..62 "a" [] [], + R_PAREN@62..63 ")" [] [], + ], + }, + ], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@63..64 ";" [] [], + }, + ], + r_curly_token: R_CURLY@64..66 "}" [Newline("\n")] [], + }, + }, + ], + eof_token: EOF@66..67 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: CSS_ROOT@0..67 + 0: (empty) + 1: CSS_ROOT_ITEM_LIST@0..66 + 0: CSS_QUALIFIED_RULE@0..66 + 0: CSS_SELECTOR_LIST@0..6 + 0: CSS_COMPOUND_SELECTOR@0..6 + 0: CSS_NESTED_SELECTOR_LIST@0..0 + 1: (empty) + 2: CSS_SUB_SELECTOR_LIST@0..6 + 0: CSS_CLASS_SELECTOR@0..6 + 0: DOT@0..1 "." [] [] + 1: CSS_CUSTOM_IDENTIFIER@1..6 + 0: IDENT@1..6 "test" [] [Whitespace(" ")] + 1: CSS_DECLARATION_OR_RULE_BLOCK@6..66 + 0: L_CURLY@6..7 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@7..64 + 0: CSS_DECLARATION_WITH_SEMICOLON@7..36 + 0: CSS_DECLARATION@7..35 + 0: CSS_BOGUS_PROPERTY@7..35 + 0: CSS_IDENTIFIER@7..15 + 0: IDENT@7..15 "width" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@15..17 ":" [] [Whitespace(" ")] + 2: CSS_BOGUS@17..35 + 0: SCSS_QUALIFIED_NAME@17..26 + 0: CSS_IDENTIFIER@17..21 + 0: IDENT@17..21 "math" [] [] + 1: DOT@21..22 "." [] [] + 2: SCSS_IDENTIFIER@22..26 + 0: DOLLAR@22..23 "$" [] [] + 1: CSS_IDENTIFIER@23..26 + 0: IDENT@23..26 "div" [] [] + 1: CSS_BOGUS_PROPERTY_VALUE@26..35 + 0: L_PAREN@26..27 "(" [] [] + 1: CSS_DIMENSION_VALUE@27..29 "10" [] [] + 2: PX_KW@29..31 "px" [] [] + 3: COMMA@31..33 "," [] [Whitespace(" ")] + 4: CSS_NUMBER_LITERAL@33..34 "2" [] [] + 5: R_PAREN@34..35 ")" [] [] + 1: (empty) + 1: SEMICOLON@35..36 ";" [] [] + 1: CSS_DECLARATION_WITH_SEMICOLON@36..64 + 0: CSS_DECLARATION@36..63 + 0: CSS_BOGUS_PROPERTY@36..63 + 0: CSS_IDENTIFIER@36..44 + 0: IDENT@36..44 "value" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@44..46 ":" [] [Whitespace(" ")] + 2: CSS_BOGUS@46..63 + 0: SCSS_QUALIFIED_NAME@46..54 + 0: CSS_IDENTIFIER@46..49 + 0: IDENT@46..49 "map" [] [] + 1: DOT@49..50 "." [] [] + 2: SCSS_IDENTIFIER@50..54 + 0: DOLLAR@50..51 "$" [] [] + 1: CSS_IDENTIFIER@51..54 + 0: IDENT@51..54 "get" [] [] + 1: CSS_BOGUS_PROPERTY_VALUE@54..63 + 0: L_PAREN@54..55 "(" [] [] + 1: DOLLAR@55..56 "$" [] [] + 2: IDENT@56..59 "map" [] [] + 3: COMMA@59..61 "," [] [Whitespace(" ")] + 4: IDENT@61..62 "a" [] [] + 5: R_PAREN@62..63 ")" [] [] + 1: (empty) + 1: SEMICOLON@63..64 ";" [] [] + 2: R_CURLY@64..66 "}" [Newline("\n")] [] + 2: EOF@66..67 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +qualified-name-dollar-function.scss:2:19 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Unexpected value or character. + + 1 │ .test { + > 2 │ width: math.$div(10px, 2); + │ ^^^^^^^^^ + 3 │ value: map.$get($map, a); + 4 │ } + + i Expected one of: + + - identifier + - string + - number + - dimension + - ratio + - custom property + - function + +qualified-name-dollar-function.scss:3:18 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Unexpected value or character. + + 1 │ .test { + 2 │ width: math.$div(10px, 2); + > 3 │ value: map.$get($map, a); + │ ^^^^^^^^^ + 4 │ } + 5 │ + + i Expected one of: + + - identifier + - string + - number + - dimension + - ratio + - custom property + - function + +``` diff --git a/crates/biome_css_parser/tests/css_test_suite/error/scss/value/qualified-name-missing-member.scss b/crates/biome_css_parser/tests/css_test_suite/error/scss/value/qualified-name-missing-member.scss new file mode 100644 index 000000000000..833edd29859b --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/error/scss/value/qualified-name-missing-member.scss @@ -0,0 +1,3 @@ +.test { + value: map.$; +} diff --git a/crates/biome_css_parser/tests/css_test_suite/error/scss/value/qualified-name-missing-member.scss.snap b/crates/biome_css_parser/tests/css_test_suite/error/scss/value/qualified-name-missing-member.scss.snap new file mode 100644 index 000000000000..bffc3f1e55ef --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/error/scss/value/qualified-name-missing-member.scss.snap @@ -0,0 +1,137 @@ +--- +source: crates/biome_css_parser/tests/spec_test.rs +expression: snapshot +--- + +## Input + +```css +.test { + value: map.$; +} + +``` + + +## AST + +``` +CssRoot { + bom_token: missing (optional), + items: CssRootItemList [ + CssQualifiedRule { + prelude: CssSelectorList [ + CssCompoundSelector { + nesting_selectors: CssNestedSelectorList [], + simple_selector: missing (optional), + sub_selectors: CssSubSelectorList [ + CssClassSelector { + dot_token: DOT@0..1 "." [] [], + name: CssCustomIdentifier { + value_token: IDENT@1..6 "test" [] [Whitespace(" ")], + }, + }, + ], + }, + ], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@6..7 "{" [] [], + items: CssDeclarationOrRuleList [ + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssBogusProperty { + items: [ + CssIdentifier { + value_token: IDENT@7..15 "value" [Newline("\n"), Whitespace(" ")] [], + }, + COLON@15..17 ":" [] [Whitespace(" ")], + CssBogus { + items: [ + CssIdentifier { + value_token: IDENT@17..20 "map" [] [], + }, + CssBogusPropertyValue { + items: [ + DOT@20..21 "." [] [], + DOLLAR@21..22 "$" [] [], + ], + }, + ], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@22..23 ";" [] [], + }, + ], + r_curly_token: R_CURLY@23..25 "}" [Newline("\n")] [], + }, + }, + ], + eof_token: EOF@25..26 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: CSS_ROOT@0..26 + 0: (empty) + 1: CSS_ROOT_ITEM_LIST@0..25 + 0: CSS_QUALIFIED_RULE@0..25 + 0: CSS_SELECTOR_LIST@0..6 + 0: CSS_COMPOUND_SELECTOR@0..6 + 0: CSS_NESTED_SELECTOR_LIST@0..0 + 1: (empty) + 2: CSS_SUB_SELECTOR_LIST@0..6 + 0: CSS_CLASS_SELECTOR@0..6 + 0: DOT@0..1 "." [] [] + 1: CSS_CUSTOM_IDENTIFIER@1..6 + 0: IDENT@1..6 "test" [] [Whitespace(" ")] + 1: CSS_DECLARATION_OR_RULE_BLOCK@6..25 + 0: L_CURLY@6..7 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@7..23 + 0: CSS_DECLARATION_WITH_SEMICOLON@7..23 + 0: CSS_DECLARATION@7..22 + 0: CSS_BOGUS_PROPERTY@7..22 + 0: CSS_IDENTIFIER@7..15 + 0: IDENT@7..15 "value" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@15..17 ":" [] [Whitespace(" ")] + 2: CSS_BOGUS@17..22 + 0: CSS_IDENTIFIER@17..20 + 0: IDENT@17..20 "map" [] [] + 1: CSS_BOGUS_PROPERTY_VALUE@20..22 + 0: DOT@20..21 "." [] [] + 1: DOLLAR@21..22 "$" [] [] + 1: (empty) + 1: SEMICOLON@22..23 ";" [] [] + 2: R_CURLY@23..25 "}" [Newline("\n")] [] + 2: EOF@25..26 "" [Newline("\n")] [] + +``` + +## Diagnostics + +``` +qualified-name-missing-member.scss:2:13 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Unexpected value or character. + + 1 │ .test { + > 2 │ value: map.$; + │ ^^ + 3 │ } + 4 │ + + i Expected one of: + + - identifier + - string + - number + - dimension + - ratio + - custom property + - function + +``` diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/function/unary-precedence.css b/crates/biome_css_parser/tests/css_test_suite/ok/function/unary-precedence.css new file mode 100644 index 000000000000..074ea749d74a --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/ok/function/unary-precedence.css @@ -0,0 +1,5 @@ +.unary-precedence { + width: calc(-1 + 2); + width: calc(+var(--x) + 1px); + width: calc(- var(--y) * 2); +} diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/function/unary-precedence.css.snap b/crates/biome_css_parser/tests/css_test_suite/ok/function/unary-precedence.css.snap new file mode 100644 index 000000000000..220ddb1a579c --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/ok/function/unary-precedence.css.snap @@ -0,0 +1,338 @@ +--- +source: crates/biome_css_parser/tests/spec_test.rs +assertion_line: 208 +expression: snapshot +--- + +## Input + +```css +.unary-precedence { + width: calc(-1 + 2); + width: calc(+var(--x) + 1px); + width: calc(- var(--y) * 2); +} + +``` + + +## AST + +``` +CssRoot { + bom_token: missing (optional), + items: CssRootItemList [ + CssQualifiedRule { + prelude: CssSelectorList [ + CssCompoundSelector { + nesting_selectors: CssNestedSelectorList [], + simple_selector: missing (optional), + sub_selectors: CssSubSelectorList [ + CssClassSelector { + dot_token: DOT@0..1 "." [] [], + name: CssCustomIdentifier { + value_token: IDENT@1..18 "unary-precedence" [] [Whitespace(" ")], + }, + }, + ], + }, + ], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@18..19 "{" [] [], + items: CssDeclarationOrRuleList [ + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@19..27 "width" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@27..29 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssFunction { + name: CssIdentifier { + value_token: IDENT@29..33 "calc" [] [], + }, + l_paren_token: L_PAREN@33..34 "(" [] [], + items: CssParameterList [ + CssParameter { + any_css_expression: CssBinaryExpression { + left: CssListOfComponentValuesExpression { + css_component_value_list: CssComponentValueList [ + CssNumber { + value_token: CSS_NUMBER_LITERAL@34..37 "-1" [] [Whitespace(" ")], + }, + ], + }, + operator_token: PLUS@37..39 "+" [] [Whitespace(" ")], + right: CssListOfComponentValuesExpression { + css_component_value_list: CssComponentValueList [ + CssNumber { + value_token: CSS_NUMBER_LITERAL@39..40 "2" [] [], + }, + ], + }, + }, + }, + ], + r_paren_token: R_PAREN@40..41 ")" [] [], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@41..42 ";" [] [], + }, + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@42..50 "width" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@50..52 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssFunction { + name: CssIdentifier { + value_token: IDENT@52..56 "calc" [] [], + }, + l_paren_token: L_PAREN@56..57 "(" [] [], + items: CssParameterList [ + CssParameter { + any_css_expression: CssBinaryExpression { + left: CssUnaryExpression { + operator: PLUS@57..58 "+" [] [], + expression: CssListOfComponentValuesExpression { + css_component_value_list: CssComponentValueList [ + CssFunction { + name: CssIdentifier { + value_token: IDENT@58..61 "var" [] [], + }, + l_paren_token: L_PAREN@61..62 "(" [] [], + items: CssParameterList [ + CssParameter { + any_css_expression: CssListOfComponentValuesExpression { + css_component_value_list: CssComponentValueList [ + CssDashedIdentifier { + value_token: IDENT@62..65 "--x" [] [], + }, + ], + }, + }, + ], + r_paren_token: R_PAREN@65..67 ")" [] [Whitespace(" ")], + }, + ], + }, + }, + operator_token: PLUS@67..69 "+" [] [Whitespace(" ")], + right: CssListOfComponentValuesExpression { + css_component_value_list: CssComponentValueList [ + CssRegularDimension { + value_token: CSS_NUMBER_LITERAL@69..70 "1" [] [], + unit_token: IDENT@70..72 "px" [] [], + }, + ], + }, + }, + }, + ], + r_paren_token: R_PAREN@72..73 ")" [] [], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@73..74 ";" [] [], + }, + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@74..82 "width" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@82..84 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssFunction { + name: CssIdentifier { + value_token: IDENT@84..88 "calc" [] [], + }, + l_paren_token: L_PAREN@88..89 "(" [] [], + items: CssParameterList [ + CssParameter { + any_css_expression: CssBinaryExpression { + left: CssUnaryExpression { + operator: MINUS@89..91 "-" [] [Whitespace(" ")], + expression: CssListOfComponentValuesExpression { + css_component_value_list: CssComponentValueList [ + CssFunction { + name: CssIdentifier { + value_token: IDENT@91..94 "var" [] [], + }, + l_paren_token: L_PAREN@94..95 "(" [] [], + items: CssParameterList [ + CssParameter { + any_css_expression: CssListOfComponentValuesExpression { + css_component_value_list: CssComponentValueList [ + CssDashedIdentifier { + value_token: IDENT@95..98 "--y" [] [], + }, + ], + }, + }, + ], + r_paren_token: R_PAREN@98..100 ")" [] [Whitespace(" ")], + }, + ], + }, + }, + operator_token: STAR@100..102 "*" [] [Whitespace(" ")], + right: CssListOfComponentValuesExpression { + css_component_value_list: CssComponentValueList [ + CssNumber { + value_token: CSS_NUMBER_LITERAL@102..103 "2" [] [], + }, + ], + }, + }, + }, + ], + r_paren_token: R_PAREN@103..104 ")" [] [], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@104..105 ";" [] [], + }, + ], + r_curly_token: R_CURLY@105..107 "}" [Newline("\n")] [], + }, + }, + ], + eof_token: EOF@107..108 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: CSS_ROOT@0..108 + 0: (empty) + 1: CSS_ROOT_ITEM_LIST@0..107 + 0: CSS_QUALIFIED_RULE@0..107 + 0: CSS_SELECTOR_LIST@0..18 + 0: CSS_COMPOUND_SELECTOR@0..18 + 0: CSS_NESTED_SELECTOR_LIST@0..0 + 1: (empty) + 2: CSS_SUB_SELECTOR_LIST@0..18 + 0: CSS_CLASS_SELECTOR@0..18 + 0: DOT@0..1 "." [] [] + 1: CSS_CUSTOM_IDENTIFIER@1..18 + 0: IDENT@1..18 "unary-precedence" [] [Whitespace(" ")] + 1: CSS_DECLARATION_OR_RULE_BLOCK@18..107 + 0: L_CURLY@18..19 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@19..105 + 0: CSS_DECLARATION_WITH_SEMICOLON@19..42 + 0: CSS_DECLARATION@19..41 + 0: CSS_GENERIC_PROPERTY@19..41 + 0: CSS_IDENTIFIER@19..27 + 0: IDENT@19..27 "width" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@27..29 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@29..41 + 0: CSS_FUNCTION@29..41 + 0: CSS_IDENTIFIER@29..33 + 0: IDENT@29..33 "calc" [] [] + 1: L_PAREN@33..34 "(" [] [] + 2: CSS_PARAMETER_LIST@34..40 + 0: CSS_PARAMETER@34..40 + 0: CSS_BINARY_EXPRESSION@34..40 + 0: CSS_LIST_OF_COMPONENT_VALUES_EXPRESSION@34..37 + 0: CSS_COMPONENT_VALUE_LIST@34..37 + 0: CSS_NUMBER@34..37 + 0: CSS_NUMBER_LITERAL@34..37 "-1" [] [Whitespace(" ")] + 1: PLUS@37..39 "+" [] [Whitespace(" ")] + 2: CSS_LIST_OF_COMPONENT_VALUES_EXPRESSION@39..40 + 0: CSS_COMPONENT_VALUE_LIST@39..40 + 0: CSS_NUMBER@39..40 + 0: CSS_NUMBER_LITERAL@39..40 "2" [] [] + 3: R_PAREN@40..41 ")" [] [] + 1: (empty) + 1: SEMICOLON@41..42 ";" [] [] + 1: CSS_DECLARATION_WITH_SEMICOLON@42..74 + 0: CSS_DECLARATION@42..73 + 0: CSS_GENERIC_PROPERTY@42..73 + 0: CSS_IDENTIFIER@42..50 + 0: IDENT@42..50 "width" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@50..52 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@52..73 + 0: CSS_FUNCTION@52..73 + 0: CSS_IDENTIFIER@52..56 + 0: IDENT@52..56 "calc" [] [] + 1: L_PAREN@56..57 "(" [] [] + 2: CSS_PARAMETER_LIST@57..72 + 0: CSS_PARAMETER@57..72 + 0: CSS_BINARY_EXPRESSION@57..72 + 0: CSS_UNARY_EXPRESSION@57..67 + 0: PLUS@57..58 "+" [] [] + 1: CSS_LIST_OF_COMPONENT_VALUES_EXPRESSION@58..67 + 0: CSS_COMPONENT_VALUE_LIST@58..67 + 0: CSS_FUNCTION@58..67 + 0: CSS_IDENTIFIER@58..61 + 0: IDENT@58..61 "var" [] [] + 1: L_PAREN@61..62 "(" [] [] + 2: CSS_PARAMETER_LIST@62..65 + 0: CSS_PARAMETER@62..65 + 0: CSS_LIST_OF_COMPONENT_VALUES_EXPRESSION@62..65 + 0: CSS_COMPONENT_VALUE_LIST@62..65 + 0: CSS_DASHED_IDENTIFIER@62..65 + 0: IDENT@62..65 "--x" [] [] + 3: R_PAREN@65..67 ")" [] [Whitespace(" ")] + 1: PLUS@67..69 "+" [] [Whitespace(" ")] + 2: CSS_LIST_OF_COMPONENT_VALUES_EXPRESSION@69..72 + 0: CSS_COMPONENT_VALUE_LIST@69..72 + 0: CSS_REGULAR_DIMENSION@69..72 + 0: CSS_NUMBER_LITERAL@69..70 "1" [] [] + 1: IDENT@70..72 "px" [] [] + 3: R_PAREN@72..73 ")" [] [] + 1: (empty) + 1: SEMICOLON@73..74 ";" [] [] + 2: CSS_DECLARATION_WITH_SEMICOLON@74..105 + 0: CSS_DECLARATION@74..104 + 0: CSS_GENERIC_PROPERTY@74..104 + 0: CSS_IDENTIFIER@74..82 + 0: IDENT@74..82 "width" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@82..84 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@84..104 + 0: CSS_FUNCTION@84..104 + 0: CSS_IDENTIFIER@84..88 + 0: IDENT@84..88 "calc" [] [] + 1: L_PAREN@88..89 "(" [] [] + 2: CSS_PARAMETER_LIST@89..103 + 0: CSS_PARAMETER@89..103 + 0: CSS_BINARY_EXPRESSION@89..103 + 0: CSS_UNARY_EXPRESSION@89..100 + 0: MINUS@89..91 "-" [] [Whitespace(" ")] + 1: CSS_LIST_OF_COMPONENT_VALUES_EXPRESSION@91..100 + 0: CSS_COMPONENT_VALUE_LIST@91..100 + 0: CSS_FUNCTION@91..100 + 0: CSS_IDENTIFIER@91..94 + 0: IDENT@91..94 "var" [] [] + 1: L_PAREN@94..95 "(" [] [] + 2: CSS_PARAMETER_LIST@95..98 + 0: CSS_PARAMETER@95..98 + 0: CSS_LIST_OF_COMPONENT_VALUES_EXPRESSION@95..98 + 0: CSS_COMPONENT_VALUE_LIST@95..98 + 0: CSS_DASHED_IDENTIFIER@95..98 + 0: IDENT@95..98 "--y" [] [] + 3: R_PAREN@98..100 ")" [] [Whitespace(" ")] + 1: STAR@100..102 "*" [] [Whitespace(" ")] + 2: CSS_LIST_OF_COMPONENT_VALUES_EXPRESSION@102..103 + 0: CSS_COMPONENT_VALUE_LIST@102..103 + 0: CSS_NUMBER@102..103 + 0: CSS_NUMBER_LITERAL@102..103 "2" [] [] + 3: R_PAREN@103..104 ")" [] [] + 1: (empty) + 1: SEMICOLON@104..105 ";" [] [] + 2: R_CURLY@105..107 "}" [Newline("\n")] [] + 2: EOF@107..108 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/page.scss b/crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/page.scss new file mode 100644 index 000000000000..22ba60e256c9 --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/page.scss @@ -0,0 +1,13 @@ +@page :left { + $padding: 12px !default; + padding: $padding; + + font: { + size: 12px; + } + + @top-left { + $margin: 4px !global; + margin: $margin; + } +} 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 new file mode 100644 index 000000000000..1f5e484fe0d0 --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/at-rule/page.scss.snap @@ -0,0 +1,295 @@ +--- +source: crates/biome_css_parser/tests/spec_test.rs +assertion_line: 208 +expression: snapshot +--- +## Input + +```css +@page :left { + $padding: 12px !default; + padding: $padding; + + font: { + size: 12px; + } + + @top-left { + $margin: 4px !global; + margin: $margin; + } +} + +``` + + +## AST + +``` +CssRoot { + bom_token: missing (optional), + items: CssRootItemList [ + CssAtRule { + at_token: AT@0..1 "@" [] [], + rule: CssPageAtRule { + page_token: PAGE_KW@1..6 "page" [] [Whitespace(" ")], + selectors: CssPageSelectorList [ + CssPageSelector { + ty: missing (optional), + pseudos: CssPageSelectorPseudoList [ + CssPageSelectorPseudo { + colon_token: COLON@6..7 ":" [] [], + selector: CssIdentifier { + value_token: IDENT@7..12 "left" [] [Whitespace(" ")], + }, + }, + ], + }, + ], + block: CssPageAtRuleBlock { + l_curly_token: L_CURLY@12..13 "{" [] [], + items: CssPageAtRuleItemList [ + ScssDeclaration { + name: ScssIdentifier { + dollar_token: DOLLAR@13..17 "$" [Newline("\n"), Whitespace(" ")] [], + name: CssIdentifier { + value_token: IDENT@17..24 "padding" [] [], + }, + }, + colon_token: COLON@24..26 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssRegularDimension { + value_token: CSS_NUMBER_LITERAL@26..28 "12" [] [], + unit_token: IDENT@28..31 "px" [] [Whitespace(" ")], + }, + ], + modifiers: ScssVariableModifierList [ + ScssVariableModifier { + excl_token: BANG@31..32 "!" [] [], + value: DEFAULT_KW@32..39 "default" [] [], + }, + ], + semicolon_token: SEMICOLON@39..40 ";" [] [], + }, + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@40..50 "padding" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@50..52 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + ScssIdentifier { + dollar_token: DOLLAR@52..53 "$" [] [], + name: CssIdentifier { + value_token: IDENT@53..60 "padding" [] [], + }, + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@60..61 ";" [] [], + }, + ScssNestingDeclaration { + name: CssIdentifier { + value_token: IDENT@61..69 "font" [Newline("\n"), Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@69..71 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@71..72 "{" [] [], + items: CssDeclarationOrRuleList [ + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@72..81 "size" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@81..83 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssRegularDimension { + value_token: CSS_NUMBER_LITERAL@83..85 "12" [] [], + unit_token: IDENT@85..87 "px" [] [], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@87..88 ";" [] [], + }, + ], + r_curly_token: R_CURLY@88..92 "}" [Newline("\n"), Whitespace(" ")] [], + }, + }, + CssMarginAtRule { + at_token: AT@92..97 "@" [Newline("\n"), Newline("\n"), Whitespace(" ")] [], + name: TOP_LEFT_KW@97..106 "top-left" [] [Whitespace(" ")], + block: CssDeclarationOrAtRuleBlock { + l_curly_token: L_CURLY@106..107 "{" [] [], + items: CssDeclarationOrAtRuleList [ + ScssDeclaration { + name: ScssIdentifier { + dollar_token: DOLLAR@107..113 "$" [Newline("\n"), Whitespace(" ")] [], + name: CssIdentifier { + value_token: IDENT@113..119 "margin" [] [], + }, + }, + colon_token: COLON@119..121 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssRegularDimension { + value_token: CSS_NUMBER_LITERAL@121..122 "4" [] [], + unit_token: IDENT@122..125 "px" [] [Whitespace(" ")], + }, + ], + modifiers: ScssVariableModifierList [ + ScssVariableModifier { + excl_token: BANG@125..126 "!" [] [], + value: GLOBAL_KW@126..132 "global" [] [], + }, + ], + semicolon_token: SEMICOLON@132..133 ";" [] [], + }, + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@133..144 "margin" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@144..146 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + ScssIdentifier { + dollar_token: DOLLAR@146..147 "$" [] [], + name: CssIdentifier { + value_token: IDENT@147..153 "margin" [] [], + }, + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@153..154 ";" [] [], + }, + ], + r_curly_token: R_CURLY@154..158 "}" [Newline("\n"), Whitespace(" ")] [], + }, + }, + ], + r_curly_token: R_CURLY@158..160 "}" [Newline("\n")] [], + }, + }, + }, + ], + eof_token: EOF@160..161 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: CSS_ROOT@0..161 + 0: (empty) + 1: CSS_ROOT_ITEM_LIST@0..160 + 0: CSS_AT_RULE@0..160 + 0: AT@0..1 "@" [] [] + 1: CSS_PAGE_AT_RULE@1..160 + 0: PAGE_KW@1..6 "page" [] [Whitespace(" ")] + 1: CSS_PAGE_SELECTOR_LIST@6..12 + 0: CSS_PAGE_SELECTOR@6..12 + 0: (empty) + 1: CSS_PAGE_SELECTOR_PSEUDO_LIST@6..12 + 0: CSS_PAGE_SELECTOR_PSEUDO@6..12 + 0: COLON@6..7 ":" [] [] + 1: CSS_IDENTIFIER@7..12 + 0: IDENT@7..12 "left" [] [Whitespace(" ")] + 2: CSS_PAGE_AT_RULE_BLOCK@12..160 + 0: L_CURLY@12..13 "{" [] [] + 1: CSS_PAGE_AT_RULE_ITEM_LIST@13..158 + 0: SCSS_DECLARATION@13..40 + 0: SCSS_IDENTIFIER@13..24 + 0: DOLLAR@13..17 "$" [Newline("\n"), Whitespace(" ")] [] + 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(" ")] + 3: SCSS_VARIABLE_MODIFIER_LIST@31..39 + 0: SCSS_VARIABLE_MODIFIER@31..39 + 0: BANG@31..32 "!" [] [] + 1: DEFAULT_KW@32..39 "default" [] [] + 4: SEMICOLON@39..40 ";" [] [] + 1: CSS_DECLARATION_WITH_SEMICOLON@40..61 + 0: CSS_DECLARATION@40..60 + 0: CSS_GENERIC_PROPERTY@40..60 + 0: CSS_IDENTIFIER@40..50 + 0: IDENT@40..50 "padding" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@50..52 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@52..60 + 0: SCSS_IDENTIFIER@52..60 + 0: DOLLAR@52..53 "$" [] [] + 1: CSS_IDENTIFIER@53..60 + 0: IDENT@53..60 "padding" [] [] + 1: (empty) + 1: SEMICOLON@60..61 ";" [] [] + 2: SCSS_NESTING_DECLARATION@61..92 + 0: CSS_IDENTIFIER@61..69 + 0: IDENT@61..69 "font" [Newline("\n"), Newline("\n"), Whitespace(" ")] [] + 1: COLON@69..71 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@71..71 + 3: CSS_DECLARATION_OR_RULE_BLOCK@71..92 + 0: L_CURLY@71..72 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@72..88 + 0: CSS_DECLARATION_WITH_SEMICOLON@72..88 + 0: CSS_DECLARATION@72..87 + 0: CSS_GENERIC_PROPERTY@72..87 + 0: CSS_IDENTIFIER@72..81 + 0: IDENT@72..81 "size" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@81..83 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@83..87 + 0: CSS_REGULAR_DIMENSION@83..87 + 0: CSS_NUMBER_LITERAL@83..85 "12" [] [] + 1: IDENT@85..87 "px" [] [] + 1: (empty) + 1: SEMICOLON@87..88 ";" [] [] + 2: R_CURLY@88..92 "}" [Newline("\n"), Whitespace(" ")] [] + 3: CSS_MARGIN_AT_RULE@92..158 + 0: AT@92..97 "@" [Newline("\n"), Newline("\n"), Whitespace(" ")] [] + 1: TOP_LEFT_KW@97..106 "top-left" [] [Whitespace(" ")] + 2: CSS_DECLARATION_OR_AT_RULE_BLOCK@106..158 + 0: L_CURLY@106..107 "{" [] [] + 1: CSS_DECLARATION_OR_AT_RULE_LIST@107..154 + 0: SCSS_DECLARATION@107..133 + 0: SCSS_IDENTIFIER@107..119 + 0: DOLLAR@107..113 "$" [Newline("\n"), Whitespace(" ")] [] + 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(" ")] + 3: SCSS_VARIABLE_MODIFIER_LIST@125..132 + 0: SCSS_VARIABLE_MODIFIER@125..132 + 0: BANG@125..126 "!" [] [] + 1: GLOBAL_KW@126..132 "global" [] [] + 4: SEMICOLON@132..133 ";" [] [] + 1: CSS_DECLARATION_WITH_SEMICOLON@133..154 + 0: CSS_DECLARATION@133..153 + 0: CSS_GENERIC_PROPERTY@133..153 + 0: CSS_IDENTIFIER@133..144 + 0: IDENT@133..144 "margin" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@144..146 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@146..153 + 0: SCSS_IDENTIFIER@146..153 + 0: DOLLAR@146..147 "$" [] [] + 1: CSS_IDENTIFIER@147..153 + 0: IDENT@147..153 "margin" [] [] + 1: (empty) + 1: SEMICOLON@153..154 ";" [] [] + 2: R_CURLY@154..158 "}" [Newline("\n"), Whitespace(" ")] [] + 2: R_CURLY@158..160 "}" [Newline("\n")] [] + 2: EOF@160..161 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/ambiguous-selector-vs-nesting.scss b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/ambiguous-selector-vs-nesting.scss new file mode 100644 index 000000000000..4e52a603bb06 --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/ambiguous-selector-vs-nesting.scss @@ -0,0 +1,17 @@ +.test { + label:hover { + color: red; + } + + font:bold { + color: blue; + } + + font:12px { + family: sans-serif; + } + + font: bold { + family: serif; + } +} diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/ambiguous-selector-vs-nesting.scss.snap b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/ambiguous-selector-vs-nesting.scss.snap new file mode 100644 index 000000000000..c5577f894dc7 --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/ambiguous-selector-vs-nesting.scss.snap @@ -0,0 +1,359 @@ +--- +source: crates/biome_css_parser/tests/spec_test.rs +expression: snapshot +--- + +## Input + +```css +.test { + label:hover { + color: red; + } + + font:bold { + color: blue; + } + + font:12px { + family: sans-serif; + } + + font: bold { + family: serif; + } +} + +``` + + +## AST + +``` +CssRoot { + bom_token: missing (optional), + items: CssRootItemList [ + CssQualifiedRule { + prelude: CssSelectorList [ + CssCompoundSelector { + nesting_selectors: CssNestedSelectorList [], + simple_selector: missing (optional), + sub_selectors: CssSubSelectorList [ + CssClassSelector { + dot_token: DOT@0..1 "." [] [], + name: CssCustomIdentifier { + value_token: IDENT@1..6 "test" [] [Whitespace(" ")], + }, + }, + ], + }, + ], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@6..7 "{" [] [], + items: CssDeclarationOrRuleList [ + CssNestedQualifiedRule { + prelude: CssRelativeSelectorList [ + CssRelativeSelector { + combinator: missing (optional), + selector: CssCompoundSelector { + nesting_selectors: CssNestedSelectorList [], + simple_selector: CssTypeSelector { + namespace: missing (optional), + ident: CssIdentifier { + value_token: IDENT@7..15 "label" [Newline("\n"), Whitespace(" ")] [], + }, + }, + sub_selectors: CssSubSelectorList [ + CssPseudoClassSelector { + colon_token: COLON@15..16 ":" [] [], + class: CssPseudoClassIdentifier { + name: CssIdentifier { + value_token: IDENT@16..22 "hover" [] [Whitespace(" ")], + }, + }, + }, + ], + }, + }, + ], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@22..23 "{" [] [], + items: CssDeclarationOrRuleList [ + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@23..33 "color" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@33..35 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssIdentifier { + value_token: IDENT@35..38 "red" [] [], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@38..39 ";" [] [], + }, + ], + r_curly_token: R_CURLY@39..43 "}" [Newline("\n"), Whitespace(" ")] [], + }, + }, + CssNestedQualifiedRule { + prelude: CssRelativeSelectorList [ + CssRelativeSelector { + combinator: missing (optional), + selector: CssCompoundSelector { + nesting_selectors: CssNestedSelectorList [], + simple_selector: CssTypeSelector { + namespace: missing (optional), + ident: CssIdentifier { + value_token: IDENT@43..51 "font" [Newline("\n"), Newline("\n"), Whitespace(" ")] [], + }, + }, + sub_selectors: CssSubSelectorList [ + CssPseudoClassSelector { + colon_token: COLON@51..52 ":" [] [], + class: CssPseudoClassIdentifier { + name: CssIdentifier { + value_token: IDENT@52..57 "bold" [] [Whitespace(" ")], + }, + }, + }, + ], + }, + }, + ], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@57..58 "{" [] [], + items: CssDeclarationOrRuleList [ + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@58..68 "color" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@68..70 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssIdentifier { + value_token: IDENT@70..74 "blue" [] [], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@74..75 ";" [] [], + }, + ], + r_curly_token: R_CURLY@75..79 "}" [Newline("\n"), Whitespace(" ")] [], + }, + }, + ScssNestingDeclaration { + name: CssIdentifier { + value_token: IDENT@79..87 "font" [Newline("\n"), Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@87..88 ":" [] [], + value: CssGenericComponentValueList [ + CssRegularDimension { + value_token: CSS_NUMBER_LITERAL@88..90 "12" [] [], + unit_token: IDENT@90..93 "px" [] [Whitespace(" ")], + }, + ], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@93..94 "{" [] [], + items: CssDeclarationOrRuleList [ + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@94..105 "family" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@105..107 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssIdentifier { + value_token: IDENT@107..117 "sans-serif" [] [], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@117..118 ";" [] [], + }, + ], + r_curly_token: R_CURLY@118..122 "}" [Newline("\n"), Whitespace(" ")] [], + }, + }, + ScssNestingDeclaration { + name: CssIdentifier { + value_token: IDENT@122..130 "font" [Newline("\n"), Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@130..132 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssIdentifier { + value_token: IDENT@132..137 "bold" [] [Whitespace(" ")], + }, + ], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@137..138 "{" [] [], + items: CssDeclarationOrRuleList [ + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@138..149 "family" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@149..151 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssIdentifier { + value_token: IDENT@151..156 "serif" [] [], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@156..157 ";" [] [], + }, + ], + r_curly_token: R_CURLY@157..161 "}" [Newline("\n"), Whitespace(" ")] [], + }, + }, + ], + r_curly_token: R_CURLY@161..163 "}" [Newline("\n")] [], + }, + }, + ], + eof_token: EOF@163..164 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: CSS_ROOT@0..164 + 0: (empty) + 1: CSS_ROOT_ITEM_LIST@0..163 + 0: CSS_QUALIFIED_RULE@0..163 + 0: CSS_SELECTOR_LIST@0..6 + 0: CSS_COMPOUND_SELECTOR@0..6 + 0: CSS_NESTED_SELECTOR_LIST@0..0 + 1: (empty) + 2: CSS_SUB_SELECTOR_LIST@0..6 + 0: CSS_CLASS_SELECTOR@0..6 + 0: DOT@0..1 "." [] [] + 1: CSS_CUSTOM_IDENTIFIER@1..6 + 0: IDENT@1..6 "test" [] [Whitespace(" ")] + 1: CSS_DECLARATION_OR_RULE_BLOCK@6..163 + 0: L_CURLY@6..7 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@7..161 + 0: CSS_NESTED_QUALIFIED_RULE@7..43 + 0: CSS_RELATIVE_SELECTOR_LIST@7..22 + 0: CSS_RELATIVE_SELECTOR@7..22 + 0: (empty) + 1: CSS_COMPOUND_SELECTOR@7..22 + 0: CSS_NESTED_SELECTOR_LIST@7..7 + 1: CSS_TYPE_SELECTOR@7..15 + 0: (empty) + 1: CSS_IDENTIFIER@7..15 + 0: IDENT@7..15 "label" [Newline("\n"), Whitespace(" ")] [] + 2: CSS_SUB_SELECTOR_LIST@15..22 + 0: CSS_PSEUDO_CLASS_SELECTOR@15..22 + 0: COLON@15..16 ":" [] [] + 1: CSS_PSEUDO_CLASS_IDENTIFIER@16..22 + 0: CSS_IDENTIFIER@16..22 + 0: IDENT@16..22 "hover" [] [Whitespace(" ")] + 1: CSS_DECLARATION_OR_RULE_BLOCK@22..43 + 0: L_CURLY@22..23 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@23..39 + 0: CSS_DECLARATION_WITH_SEMICOLON@23..39 + 0: CSS_DECLARATION@23..38 + 0: CSS_GENERIC_PROPERTY@23..38 + 0: CSS_IDENTIFIER@23..33 + 0: IDENT@23..33 "color" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@33..35 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@35..38 + 0: CSS_IDENTIFIER@35..38 + 0: IDENT@35..38 "red" [] [] + 1: (empty) + 1: SEMICOLON@38..39 ";" [] [] + 2: R_CURLY@39..43 "}" [Newline("\n"), Whitespace(" ")] [] + 1: CSS_NESTED_QUALIFIED_RULE@43..79 + 0: CSS_RELATIVE_SELECTOR_LIST@43..57 + 0: CSS_RELATIVE_SELECTOR@43..57 + 0: (empty) + 1: CSS_COMPOUND_SELECTOR@43..57 + 0: CSS_NESTED_SELECTOR_LIST@43..43 + 1: CSS_TYPE_SELECTOR@43..51 + 0: (empty) + 1: CSS_IDENTIFIER@43..51 + 0: IDENT@43..51 "font" [Newline("\n"), Newline("\n"), Whitespace(" ")] [] + 2: CSS_SUB_SELECTOR_LIST@51..57 + 0: CSS_PSEUDO_CLASS_SELECTOR@51..57 + 0: COLON@51..52 ":" [] [] + 1: CSS_PSEUDO_CLASS_IDENTIFIER@52..57 + 0: CSS_IDENTIFIER@52..57 + 0: IDENT@52..57 "bold" [] [Whitespace(" ")] + 1: CSS_DECLARATION_OR_RULE_BLOCK@57..79 + 0: L_CURLY@57..58 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@58..75 + 0: CSS_DECLARATION_WITH_SEMICOLON@58..75 + 0: CSS_DECLARATION@58..74 + 0: CSS_GENERIC_PROPERTY@58..74 + 0: CSS_IDENTIFIER@58..68 + 0: IDENT@58..68 "color" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@68..70 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@70..74 + 0: CSS_IDENTIFIER@70..74 + 0: IDENT@70..74 "blue" [] [] + 1: (empty) + 1: SEMICOLON@74..75 ";" [] [] + 2: R_CURLY@75..79 "}" [Newline("\n"), Whitespace(" ")] [] + 2: SCSS_NESTING_DECLARATION@79..122 + 0: CSS_IDENTIFIER@79..87 + 0: IDENT@79..87 "font" [Newline("\n"), Newline("\n"), Whitespace(" ")] [] + 1: COLON@87..88 ":" [] [] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@88..93 + 0: CSS_REGULAR_DIMENSION@88..93 + 0: CSS_NUMBER_LITERAL@88..90 "12" [] [] + 1: IDENT@90..93 "px" [] [Whitespace(" ")] + 3: CSS_DECLARATION_OR_RULE_BLOCK@93..122 + 0: L_CURLY@93..94 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@94..118 + 0: CSS_DECLARATION_WITH_SEMICOLON@94..118 + 0: CSS_DECLARATION@94..117 + 0: CSS_GENERIC_PROPERTY@94..117 + 0: CSS_IDENTIFIER@94..105 + 0: IDENT@94..105 "family" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@105..107 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@107..117 + 0: CSS_IDENTIFIER@107..117 + 0: IDENT@107..117 "sans-serif" [] [] + 1: (empty) + 1: SEMICOLON@117..118 ";" [] [] + 2: R_CURLY@118..122 "}" [Newline("\n"), Whitespace(" ")] [] + 3: SCSS_NESTING_DECLARATION@122..161 + 0: CSS_IDENTIFIER@122..130 + 0: IDENT@122..130 "font" [Newline("\n"), Newline("\n"), Whitespace(" ")] [] + 1: COLON@130..132 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@132..137 + 0: CSS_IDENTIFIER@132..137 + 0: IDENT@132..137 "bold" [] [Whitespace(" ")] + 3: CSS_DECLARATION_OR_RULE_BLOCK@137..161 + 0: L_CURLY@137..138 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@138..157 + 0: CSS_DECLARATION_WITH_SEMICOLON@138..157 + 0: CSS_DECLARATION@138..156 + 0: CSS_GENERIC_PROPERTY@138..156 + 0: CSS_IDENTIFIER@138..149 + 0: IDENT@138..149 "family" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@149..151 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@151..156 + 0: CSS_IDENTIFIER@151..156 + 0: IDENT@151..156 "serif" [] [] + 1: (empty) + 1: SEMICOLON@156..157 ";" [] [] + 2: R_CURLY@157..161 "}" [Newline("\n"), Whitespace(" ")] [] + 2: R_CURLY@161..163 "}" [Newline("\n")] [] + 2: EOF@163..164 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/nested-properties-empty-value.scss b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/nested-properties-empty-value.scss new file mode 100644 index 000000000000..13e0f577659f --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/nested-properties-empty-value.scss @@ -0,0 +1,5 @@ +.font { + font: { + size: 12px; + } +} diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/nested-properties-empty-value.scss.snap b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/nested-properties-empty-value.scss.snap new file mode 100644 index 000000000000..170d4fbb734d --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/nested-properties-empty-value.scss.snap @@ -0,0 +1,125 @@ +--- +source: crates/biome_css_parser/tests/spec_test.rs +assertion_line: 208 +expression: snapshot +--- +## Input + +```css +.font { + font: { + size: 12px; + } +} + +``` + + +## AST + +``` +CssRoot { + bom_token: missing (optional), + items: CssRootItemList [ + CssQualifiedRule { + prelude: CssSelectorList [ + CssCompoundSelector { + nesting_selectors: CssNestedSelectorList [], + simple_selector: missing (optional), + sub_selectors: CssSubSelectorList [ + CssClassSelector { + dot_token: DOT@0..1 "." [] [], + name: CssCustomIdentifier { + value_token: IDENT@1..6 "font" [] [Whitespace(" ")], + }, + }, + ], + }, + ], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@6..7 "{" [] [], + items: CssDeclarationOrRuleList [ + ScssNestingDeclaration { + name: CssIdentifier { + value_token: IDENT@7..14 "font" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@14..16 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@16..17 "{" [] [], + items: CssDeclarationOrRuleList [ + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@17..26 "size" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@26..28 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssRegularDimension { + value_token: CSS_NUMBER_LITERAL@28..30 "12" [] [], + unit_token: IDENT@30..32 "px" [] [], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@32..33 ";" [] [], + }, + ], + r_curly_token: R_CURLY@33..37 "}" [Newline("\n"), Whitespace(" ")] [], + }, + }, + ], + r_curly_token: R_CURLY@37..39 "}" [Newline("\n")] [], + }, + }, + ], + eof_token: EOF@39..40 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: CSS_ROOT@0..40 + 0: (empty) + 1: CSS_ROOT_ITEM_LIST@0..39 + 0: CSS_QUALIFIED_RULE@0..39 + 0: CSS_SELECTOR_LIST@0..6 + 0: CSS_COMPOUND_SELECTOR@0..6 + 0: CSS_NESTED_SELECTOR_LIST@0..0 + 1: (empty) + 2: CSS_SUB_SELECTOR_LIST@0..6 + 0: CSS_CLASS_SELECTOR@0..6 + 0: DOT@0..1 "." [] [] + 1: CSS_CUSTOM_IDENTIFIER@1..6 + 0: IDENT@1..6 "font" [] [Whitespace(" ")] + 1: CSS_DECLARATION_OR_RULE_BLOCK@6..39 + 0: L_CURLY@6..7 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@7..37 + 0: SCSS_NESTING_DECLARATION@7..37 + 0: CSS_IDENTIFIER@7..14 + 0: IDENT@7..14 "font" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@14..16 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@16..16 + 3: CSS_DECLARATION_OR_RULE_BLOCK@16..37 + 0: L_CURLY@16..17 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@17..33 + 0: CSS_DECLARATION_WITH_SEMICOLON@17..33 + 0: CSS_DECLARATION@17..32 + 0: CSS_GENERIC_PROPERTY@17..32 + 0: CSS_IDENTIFIER@17..26 + 0: IDENT@17..26 "size" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@26..28 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@28..32 + 0: CSS_REGULAR_DIMENSION@28..32 + 0: CSS_NUMBER_LITERAL@28..30 "12" [] [] + 1: IDENT@30..32 "px" [] [] + 1: (empty) + 1: SEMICOLON@32..33 ";" [] [] + 2: R_CURLY@33..37 "}" [Newline("\n"), Whitespace(" ")] [] + 2: R_CURLY@37..39 "}" [Newline("\n")] [] + 2: EOF@39..40 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/nested-properties-with-value.scss b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/nested-properties-with-value.scss new file mode 100644 index 000000000000..c19e45c903a2 --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/nested-properties-with-value.scss @@ -0,0 +1,5 @@ +.font { + font: 12px/1.2 { + family: sans-serif; + } +} diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/nested-properties-with-value.scss.snap b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/nested-properties-with-value.scss.snap new file mode 100644 index 000000000000..e63ea3c41296 --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/nested-properties-with-value.scss.snap @@ -0,0 +1,141 @@ +--- +source: crates/biome_css_parser/tests/spec_test.rs +expression: snapshot +--- + +## Input + +```css +.font { + font: 12px/1.2 { + family: sans-serif; + } +} + +``` + + +## AST + +``` +CssRoot { + bom_token: missing (optional), + items: CssRootItemList [ + CssQualifiedRule { + prelude: CssSelectorList [ + CssCompoundSelector { + nesting_selectors: CssNestedSelectorList [], + simple_selector: missing (optional), + sub_selectors: CssSubSelectorList [ + CssClassSelector { + dot_token: DOT@0..1 "." [] [], + name: CssCustomIdentifier { + value_token: IDENT@1..6 "font" [] [Whitespace(" ")], + }, + }, + ], + }, + ], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@6..7 "{" [] [], + items: CssDeclarationOrRuleList [ + ScssNestingDeclaration { + name: CssIdentifier { + value_token: IDENT@7..14 "font" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@14..16 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssRegularDimension { + value_token: CSS_NUMBER_LITERAL@16..18 "12" [] [], + unit_token: IDENT@18..20 "px" [] [], + }, + CssGenericDelimiter { + value: SLASH@20..21 "/" [] [], + }, + CssNumber { + value_token: CSS_NUMBER_LITERAL@21..25 "1.2" [] [Whitespace(" ")], + }, + ], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@25..26 "{" [] [], + items: CssDeclarationOrRuleList [ + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@26..37 "family" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@37..39 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssIdentifier { + value_token: IDENT@39..49 "sans-serif" [] [], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@49..50 ";" [] [], + }, + ], + r_curly_token: R_CURLY@50..54 "}" [Newline("\n"), Whitespace(" ")] [], + }, + }, + ], + r_curly_token: R_CURLY@54..56 "}" [Newline("\n")] [], + }, + }, + ], + eof_token: EOF@56..57 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: CSS_ROOT@0..57 + 0: (empty) + 1: CSS_ROOT_ITEM_LIST@0..56 + 0: CSS_QUALIFIED_RULE@0..56 + 0: CSS_SELECTOR_LIST@0..6 + 0: CSS_COMPOUND_SELECTOR@0..6 + 0: CSS_NESTED_SELECTOR_LIST@0..0 + 1: (empty) + 2: CSS_SUB_SELECTOR_LIST@0..6 + 0: CSS_CLASS_SELECTOR@0..6 + 0: DOT@0..1 "." [] [] + 1: CSS_CUSTOM_IDENTIFIER@1..6 + 0: IDENT@1..6 "font" [] [Whitespace(" ")] + 1: CSS_DECLARATION_OR_RULE_BLOCK@6..56 + 0: L_CURLY@6..7 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@7..54 + 0: SCSS_NESTING_DECLARATION@7..54 + 0: CSS_IDENTIFIER@7..14 + 0: IDENT@7..14 "font" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@14..16 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@16..25 + 0: CSS_REGULAR_DIMENSION@16..20 + 0: CSS_NUMBER_LITERAL@16..18 "12" [] [] + 1: IDENT@18..20 "px" [] [] + 1: CSS_GENERIC_DELIMITER@20..21 + 0: SLASH@20..21 "/" [] [] + 2: CSS_NUMBER@21..25 + 0: CSS_NUMBER_LITERAL@21..25 "1.2" [] [Whitespace(" ")] + 3: CSS_DECLARATION_OR_RULE_BLOCK@25..54 + 0: L_CURLY@25..26 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@26..50 + 0: CSS_DECLARATION_WITH_SEMICOLON@26..50 + 0: CSS_DECLARATION@26..49 + 0: CSS_GENERIC_PROPERTY@26..49 + 0: CSS_IDENTIFIER@26..37 + 0: IDENT@26..37 "family" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@37..39 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@39..49 + 0: CSS_IDENTIFIER@39..49 + 0: IDENT@39..49 "sans-serif" [] [] + 1: (empty) + 1: SEMICOLON@49..50 ";" [] [] + 2: R_CURLY@50..54 "}" [Newline("\n"), Whitespace(" ")] [] + 2: R_CURLY@54..56 "}" [Newline("\n")] [] + 2: EOF@56..57 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/spacing-after-colon.scss b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/spacing-after-colon.scss new file mode 100644 index 000000000000..583817425764 --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/spacing-after-colon.scss @@ -0,0 +1,27 @@ +.test { + font:bold { + color: red; + } + + font: bold { + family: serif; + } + + font: + bold { + family: sans-serif; + } + + font:/*comment*/bold { + color: blue; + } + + font:/*comment*/ bold { + family: monospace; + } + + font:/*comment*/ + bold { + family: fantasy; + } +} diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/spacing-after-colon.scss.snap b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/spacing-after-colon.scss.snap new file mode 100644 index 000000000000..2a1d0afeda86 --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/declaration/spacing-after-colon.scss.snap @@ -0,0 +1,479 @@ +--- +source: crates/biome_css_parser/tests/spec_test.rs +expression: snapshot +--- + +## Input + +```css +.test { + font:bold { + color: red; + } + + font: bold { + family: serif; + } + + font: + bold { + family: sans-serif; + } + + font:/*comment*/bold { + color: blue; + } + + font:/*comment*/ bold { + family: monospace; + } + + font:/*comment*/ + bold { + family: fantasy; + } +} + +``` + + +## AST + +``` +CssRoot { + bom_token: missing (optional), + items: CssRootItemList [ + CssQualifiedRule { + prelude: CssSelectorList [ + CssCompoundSelector { + nesting_selectors: CssNestedSelectorList [], + simple_selector: missing (optional), + sub_selectors: CssSubSelectorList [ + CssClassSelector { + dot_token: DOT@0..1 "." [] [], + name: CssCustomIdentifier { + value_token: IDENT@1..6 "test" [] [Whitespace(" ")], + }, + }, + ], + }, + ], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@6..7 "{" [] [], + items: CssDeclarationOrRuleList [ + CssNestedQualifiedRule { + prelude: CssRelativeSelectorList [ + CssRelativeSelector { + combinator: missing (optional), + selector: CssCompoundSelector { + nesting_selectors: CssNestedSelectorList [], + simple_selector: CssTypeSelector { + namespace: missing (optional), + ident: CssIdentifier { + value_token: IDENT@7..14 "font" [Newline("\n"), Whitespace(" ")] [], + }, + }, + sub_selectors: CssSubSelectorList [ + CssPseudoClassSelector { + colon_token: COLON@14..15 ":" [] [], + class: CssPseudoClassIdentifier { + name: CssIdentifier { + value_token: IDENT@15..20 "bold" [] [Whitespace(" ")], + }, + }, + }, + ], + }, + }, + ], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@20..21 "{" [] [], + items: CssDeclarationOrRuleList [ + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@21..31 "color" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@31..33 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssIdentifier { + value_token: IDENT@33..36 "red" [] [], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@36..37 ";" [] [], + }, + ], + r_curly_token: R_CURLY@37..41 "}" [Newline("\n"), Whitespace(" ")] [], + }, + }, + ScssNestingDeclaration { + name: CssIdentifier { + value_token: IDENT@41..49 "font" [Newline("\n"), Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@49..51 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssIdentifier { + value_token: IDENT@51..56 "bold" [] [Whitespace(" ")], + }, + ], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@56..57 "{" [] [], + items: CssDeclarationOrRuleList [ + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@57..68 "family" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@68..70 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssIdentifier { + value_token: IDENT@70..75 "serif" [] [], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@75..76 ";" [] [], + }, + ], + r_curly_token: R_CURLY@76..80 "}" [Newline("\n"), Whitespace(" ")] [], + }, + }, + ScssNestingDeclaration { + name: CssIdentifier { + value_token: IDENT@80..88 "font" [Newline("\n"), Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@88..89 ":" [] [], + value: CssGenericComponentValueList [ + CssIdentifier { + value_token: IDENT@89..97 "bold" [Newline("\n"), Whitespace(" ")] [Whitespace(" ")], + }, + ], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@97..98 "{" [] [], + items: CssDeclarationOrRuleList [ + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@98..109 "family" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@109..111 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssIdentifier { + value_token: IDENT@111..121 "sans-serif" [] [], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@121..122 ";" [] [], + }, + ], + r_curly_token: R_CURLY@122..126 "}" [Newline("\n"), Whitespace(" ")] [], + }, + }, + CssNestedQualifiedRule { + prelude: CssRelativeSelectorList [ + CssRelativeSelector { + combinator: missing (optional), + selector: CssCompoundSelector { + nesting_selectors: CssNestedSelectorList [], + simple_selector: CssTypeSelector { + namespace: missing (optional), + ident: CssIdentifier { + value_token: IDENT@126..134 "font" [Newline("\n"), Newline("\n"), Whitespace(" ")] [], + }, + }, + sub_selectors: CssSubSelectorList [ + CssPseudoClassSelector { + colon_token: COLON@134..146 ":" [] [Comments("/*comment*/")], + class: CssPseudoClassIdentifier { + name: CssIdentifier { + value_token: IDENT@146..151 "bold" [] [Whitespace(" ")], + }, + }, + }, + ], + }, + }, + ], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@151..152 "{" [] [], + items: CssDeclarationOrRuleList [ + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@152..162 "color" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@162..164 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssIdentifier { + value_token: IDENT@164..168 "blue" [] [], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@168..169 ";" [] [], + }, + ], + r_curly_token: R_CURLY@169..173 "}" [Newline("\n"), Whitespace(" ")] [], + }, + }, + ScssNestingDeclaration { + name: CssIdentifier { + value_token: IDENT@173..181 "font" [Newline("\n"), Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@181..194 ":" [] [Comments("/*comment*/"), Whitespace(" ")], + value: CssGenericComponentValueList [ + CssIdentifier { + value_token: IDENT@194..199 "bold" [] [Whitespace(" ")], + }, + ], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@199..200 "{" [] [], + items: CssDeclarationOrRuleList [ + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@200..211 "family" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@211..213 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssIdentifier { + value_token: IDENT@213..222 "monospace" [] [], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@222..223 ";" [] [], + }, + ], + r_curly_token: R_CURLY@223..227 "}" [Newline("\n"), Whitespace(" ")] [], + }, + }, + ScssNestingDeclaration { + name: CssIdentifier { + value_token: IDENT@227..235 "font" [Newline("\n"), Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@235..247 ":" [] [Comments("/*comment*/")], + value: CssGenericComponentValueList [ + CssIdentifier { + value_token: IDENT@247..255 "bold" [Newline("\n"), Whitespace(" ")] [Whitespace(" ")], + }, + ], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@255..256 "{" [] [], + items: CssDeclarationOrRuleList [ + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@256..267 "family" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@267..269 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssIdentifier { + value_token: IDENT@269..276 "fantasy" [] [], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@276..277 ";" [] [], + }, + ], + r_curly_token: R_CURLY@277..281 "}" [Newline("\n"), Whitespace(" ")] [], + }, + }, + ], + r_curly_token: R_CURLY@281..283 "}" [Newline("\n")] [], + }, + }, + ], + eof_token: EOF@283..284 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: CSS_ROOT@0..284 + 0: (empty) + 1: CSS_ROOT_ITEM_LIST@0..283 + 0: CSS_QUALIFIED_RULE@0..283 + 0: CSS_SELECTOR_LIST@0..6 + 0: CSS_COMPOUND_SELECTOR@0..6 + 0: CSS_NESTED_SELECTOR_LIST@0..0 + 1: (empty) + 2: CSS_SUB_SELECTOR_LIST@0..6 + 0: CSS_CLASS_SELECTOR@0..6 + 0: DOT@0..1 "." [] [] + 1: CSS_CUSTOM_IDENTIFIER@1..6 + 0: IDENT@1..6 "test" [] [Whitespace(" ")] + 1: CSS_DECLARATION_OR_RULE_BLOCK@6..283 + 0: L_CURLY@6..7 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@7..281 + 0: CSS_NESTED_QUALIFIED_RULE@7..41 + 0: CSS_RELATIVE_SELECTOR_LIST@7..20 + 0: CSS_RELATIVE_SELECTOR@7..20 + 0: (empty) + 1: CSS_COMPOUND_SELECTOR@7..20 + 0: CSS_NESTED_SELECTOR_LIST@7..7 + 1: CSS_TYPE_SELECTOR@7..14 + 0: (empty) + 1: CSS_IDENTIFIER@7..14 + 0: IDENT@7..14 "font" [Newline("\n"), Whitespace(" ")] [] + 2: CSS_SUB_SELECTOR_LIST@14..20 + 0: CSS_PSEUDO_CLASS_SELECTOR@14..20 + 0: COLON@14..15 ":" [] [] + 1: CSS_PSEUDO_CLASS_IDENTIFIER@15..20 + 0: CSS_IDENTIFIER@15..20 + 0: IDENT@15..20 "bold" [] [Whitespace(" ")] + 1: CSS_DECLARATION_OR_RULE_BLOCK@20..41 + 0: L_CURLY@20..21 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@21..37 + 0: CSS_DECLARATION_WITH_SEMICOLON@21..37 + 0: CSS_DECLARATION@21..36 + 0: CSS_GENERIC_PROPERTY@21..36 + 0: CSS_IDENTIFIER@21..31 + 0: IDENT@21..31 "color" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@31..33 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@33..36 + 0: CSS_IDENTIFIER@33..36 + 0: IDENT@33..36 "red" [] [] + 1: (empty) + 1: SEMICOLON@36..37 ";" [] [] + 2: R_CURLY@37..41 "}" [Newline("\n"), Whitespace(" ")] [] + 1: SCSS_NESTING_DECLARATION@41..80 + 0: CSS_IDENTIFIER@41..49 + 0: IDENT@41..49 "font" [Newline("\n"), Newline("\n"), Whitespace(" ")] [] + 1: COLON@49..51 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@51..56 + 0: CSS_IDENTIFIER@51..56 + 0: IDENT@51..56 "bold" [] [Whitespace(" ")] + 3: CSS_DECLARATION_OR_RULE_BLOCK@56..80 + 0: L_CURLY@56..57 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@57..76 + 0: CSS_DECLARATION_WITH_SEMICOLON@57..76 + 0: CSS_DECLARATION@57..75 + 0: CSS_GENERIC_PROPERTY@57..75 + 0: CSS_IDENTIFIER@57..68 + 0: IDENT@57..68 "family" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@68..70 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@70..75 + 0: CSS_IDENTIFIER@70..75 + 0: IDENT@70..75 "serif" [] [] + 1: (empty) + 1: SEMICOLON@75..76 ";" [] [] + 2: R_CURLY@76..80 "}" [Newline("\n"), Whitespace(" ")] [] + 2: SCSS_NESTING_DECLARATION@80..126 + 0: CSS_IDENTIFIER@80..88 + 0: IDENT@80..88 "font" [Newline("\n"), Newline("\n"), Whitespace(" ")] [] + 1: COLON@88..89 ":" [] [] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@89..97 + 0: CSS_IDENTIFIER@89..97 + 0: IDENT@89..97 "bold" [Newline("\n"), Whitespace(" ")] [Whitespace(" ")] + 3: CSS_DECLARATION_OR_RULE_BLOCK@97..126 + 0: L_CURLY@97..98 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@98..122 + 0: CSS_DECLARATION_WITH_SEMICOLON@98..122 + 0: CSS_DECLARATION@98..121 + 0: CSS_GENERIC_PROPERTY@98..121 + 0: CSS_IDENTIFIER@98..109 + 0: IDENT@98..109 "family" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@109..111 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@111..121 + 0: CSS_IDENTIFIER@111..121 + 0: IDENT@111..121 "sans-serif" [] [] + 1: (empty) + 1: SEMICOLON@121..122 ";" [] [] + 2: R_CURLY@122..126 "}" [Newline("\n"), Whitespace(" ")] [] + 3: CSS_NESTED_QUALIFIED_RULE@126..173 + 0: CSS_RELATIVE_SELECTOR_LIST@126..151 + 0: CSS_RELATIVE_SELECTOR@126..151 + 0: (empty) + 1: CSS_COMPOUND_SELECTOR@126..151 + 0: CSS_NESTED_SELECTOR_LIST@126..126 + 1: CSS_TYPE_SELECTOR@126..134 + 0: (empty) + 1: CSS_IDENTIFIER@126..134 + 0: IDENT@126..134 "font" [Newline("\n"), Newline("\n"), Whitespace(" ")] [] + 2: CSS_SUB_SELECTOR_LIST@134..151 + 0: CSS_PSEUDO_CLASS_SELECTOR@134..151 + 0: COLON@134..146 ":" [] [Comments("/*comment*/")] + 1: CSS_PSEUDO_CLASS_IDENTIFIER@146..151 + 0: CSS_IDENTIFIER@146..151 + 0: IDENT@146..151 "bold" [] [Whitespace(" ")] + 1: CSS_DECLARATION_OR_RULE_BLOCK@151..173 + 0: L_CURLY@151..152 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@152..169 + 0: CSS_DECLARATION_WITH_SEMICOLON@152..169 + 0: CSS_DECLARATION@152..168 + 0: CSS_GENERIC_PROPERTY@152..168 + 0: CSS_IDENTIFIER@152..162 + 0: IDENT@152..162 "color" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@162..164 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@164..168 + 0: CSS_IDENTIFIER@164..168 + 0: IDENT@164..168 "blue" [] [] + 1: (empty) + 1: SEMICOLON@168..169 ";" [] [] + 2: R_CURLY@169..173 "}" [Newline("\n"), Whitespace(" ")] [] + 4: SCSS_NESTING_DECLARATION@173..227 + 0: CSS_IDENTIFIER@173..181 + 0: IDENT@173..181 "font" [Newline("\n"), Newline("\n"), Whitespace(" ")] [] + 1: COLON@181..194 ":" [] [Comments("/*comment*/"), Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@194..199 + 0: CSS_IDENTIFIER@194..199 + 0: IDENT@194..199 "bold" [] [Whitespace(" ")] + 3: CSS_DECLARATION_OR_RULE_BLOCK@199..227 + 0: L_CURLY@199..200 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@200..223 + 0: CSS_DECLARATION_WITH_SEMICOLON@200..223 + 0: CSS_DECLARATION@200..222 + 0: CSS_GENERIC_PROPERTY@200..222 + 0: CSS_IDENTIFIER@200..211 + 0: IDENT@200..211 "family" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@211..213 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@213..222 + 0: CSS_IDENTIFIER@213..222 + 0: IDENT@213..222 "monospace" [] [] + 1: (empty) + 1: SEMICOLON@222..223 ";" [] [] + 2: R_CURLY@223..227 "}" [Newline("\n"), Whitespace(" ")] [] + 5: SCSS_NESTING_DECLARATION@227..281 + 0: CSS_IDENTIFIER@227..235 + 0: IDENT@227..235 "font" [Newline("\n"), Newline("\n"), Whitespace(" ")] [] + 1: COLON@235..247 ":" [] [Comments("/*comment*/")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@247..255 + 0: CSS_IDENTIFIER@247..255 + 0: IDENT@247..255 "bold" [Newline("\n"), Whitespace(" ")] [Whitespace(" ")] + 3: CSS_DECLARATION_OR_RULE_BLOCK@255..281 + 0: L_CURLY@255..256 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@256..277 + 0: CSS_DECLARATION_WITH_SEMICOLON@256..277 + 0: CSS_DECLARATION@256..276 + 0: CSS_GENERIC_PROPERTY@256..276 + 0: CSS_IDENTIFIER@256..267 + 0: IDENT@256..267 "family" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@267..269 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@269..276 + 0: CSS_IDENTIFIER@269..276 + 0: IDENT@269..276 "fantasy" [] [] + 1: (empty) + 1: SEMICOLON@276..277 ";" [] [] + 2: R_CURLY@277..281 "}" [Newline("\n"), Whitespace(" ")] [] + 2: R_CURLY@281..283 "}" [Newline("\n")] [] + 2: EOF@283..284 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/value/bracketed-values.scss b/crates/biome_css_parser/tests/css_test_suite/ok/scss/value/bracketed-values.scss new file mode 100644 index 000000000000..9e1a537f7f3a --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/value/bracketed-values.scss @@ -0,0 +1,6 @@ +$brackets: [a, b, c]; +$lines: [full-start, main-start, main-end, full-end]; + +.grid { + grid-column: [col-start] / [col-end]; +} 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 new file mode 100644 index 000000000000..bd7be0419e8d --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/value/bracketed-values.scss.snap @@ -0,0 +1,256 @@ +--- +source: crates/biome_css_parser/tests/spec_test.rs +expression: snapshot +--- + +## Input + +```css +$brackets: [a, b, c]; +$lines: [full-start, main-start, main-end, full-end]; + +.grid { + grid-column: [col-start] / [col-end]; +} + +``` + + +## AST + +``` +CssRoot { + bom_token: missing (optional), + items: CssRootItemList [ + ScssDeclaration { + name: ScssIdentifier { + dollar_token: DOLLAR@0..1 "$" [] [], + name: CssIdentifier { + value_token: IDENT@1..9 "brackets" [] [], + }, + }, + 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 "]" [] [], + }, + ], + modifiers: ScssVariableModifierList [], + semicolon_token: SEMICOLON@20..21 ";" [] [], + }, + ScssDeclaration { + name: ScssIdentifier { + dollar_token: DOLLAR@21..23 "$" [Newline("\n")] [], + name: CssIdentifier { + value_token: IDENT@23..28 "lines" [] [], + }, + }, + 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 "]" [] [], + }, + ], + modifiers: ScssVariableModifierList [], + semicolon_token: SEMICOLON@74..75 ";" [] [], + }, + CssQualifiedRule { + prelude: CssSelectorList [ + CssCompoundSelector { + nesting_selectors: CssNestedSelectorList [], + simple_selector: missing (optional), + sub_selectors: CssSubSelectorList [ + CssClassSelector { + dot_token: DOT@75..78 "." [Newline("\n"), Newline("\n")] [], + name: CssCustomIdentifier { + value_token: IDENT@78..83 "grid" [] [Whitespace(" ")], + }, + }, + ], + }, + ], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@83..84 "{" [] [], + items: CssDeclarationOrRuleList [ + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@84..98 "grid-column" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@98..100 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssBracketedValue { + l_brack_token: L_BRACK@100..101 "[" [] [], + items: CssBracketedValueList [ + CssCustomIdentifier { + value_token: IDENT@101..110 "col-start" [] [], + }, + ], + r_brack_token: R_BRACK@110..112 "]" [] [Whitespace(" ")], + }, + CssGenericDelimiter { + value: SLASH@112..114 "/" [] [Whitespace(" ")], + }, + CssBracketedValue { + l_brack_token: L_BRACK@114..115 "[" [] [], + items: CssBracketedValueList [ + CssCustomIdentifier { + value_token: IDENT@115..122 "col-end" [] [], + }, + ], + r_brack_token: R_BRACK@122..123 "]" [] [], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@123..124 ";" [] [], + }, + ], + r_curly_token: R_CURLY@124..126 "}" [Newline("\n")] [], + }, + }, + ], + eof_token: EOF@126..127 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: CSS_ROOT@0..127 + 0: (empty) + 1: CSS_ROOT_ITEM_LIST@0..126 + 0: SCSS_DECLARATION@0..21 + 0: SCSS_IDENTIFIER@0..9 + 0: DOLLAR@0..1 "$" [] [] + 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 "]" [] [] + 3: SCSS_VARIABLE_MODIFIER_LIST@20..20 + 4: SEMICOLON@20..21 ";" [] [] + 1: SCSS_DECLARATION@21..75 + 0: SCSS_IDENTIFIER@21..28 + 0: DOLLAR@21..23 "$" [Newline("\n")] [] + 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 "]" [] [] + 3: SCSS_VARIABLE_MODIFIER_LIST@74..74 + 4: SEMICOLON@74..75 ";" [] [] + 2: CSS_QUALIFIED_RULE@75..126 + 0: CSS_SELECTOR_LIST@75..83 + 0: CSS_COMPOUND_SELECTOR@75..83 + 0: CSS_NESTED_SELECTOR_LIST@75..75 + 1: (empty) + 2: CSS_SUB_SELECTOR_LIST@75..83 + 0: CSS_CLASS_SELECTOR@75..83 + 0: DOT@75..78 "." [Newline("\n"), Newline("\n")] [] + 1: CSS_CUSTOM_IDENTIFIER@78..83 + 0: IDENT@78..83 "grid" [] [Whitespace(" ")] + 1: CSS_DECLARATION_OR_RULE_BLOCK@83..126 + 0: L_CURLY@83..84 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@84..124 + 0: CSS_DECLARATION_WITH_SEMICOLON@84..124 + 0: CSS_DECLARATION@84..123 + 0: CSS_GENERIC_PROPERTY@84..123 + 0: CSS_IDENTIFIER@84..98 + 0: IDENT@84..98 "grid-column" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@98..100 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@100..123 + 0: CSS_BRACKETED_VALUE@100..112 + 0: L_BRACK@100..101 "[" [] [] + 1: CSS_BRACKETED_VALUE_LIST@101..110 + 0: CSS_CUSTOM_IDENTIFIER@101..110 + 0: IDENT@101..110 "col-start" [] [] + 2: R_BRACK@110..112 "]" [] [Whitespace(" ")] + 1: CSS_GENERIC_DELIMITER@112..114 + 0: SLASH@112..114 "/" [] [Whitespace(" ")] + 2: CSS_BRACKETED_VALUE@114..123 + 0: L_BRACK@114..115 "[" [] [] + 1: CSS_BRACKETED_VALUE_LIST@115..122 + 0: CSS_CUSTOM_IDENTIFIER@115..122 + 0: IDENT@115..122 "col-end" [] [] + 2: R_BRACK@122..123 "]" [] [] + 1: (empty) + 1: SEMICOLON@123..124 ";" [] [] + 2: R_CURLY@124..126 "}" [Newline("\n")] [] + 2: EOF@126..127 "" [Newline("\n")] [] + +``` diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/value/qualified-names.scss b/crates/biome_css_parser/tests/css_test_suite/ok/scss/value/qualified-names.scss new file mode 100644 index 000000000000..5d52baf01cbb --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/value/qualified-names.scss @@ -0,0 +1,9 @@ +.test { + width: math.div(10px, 2); + height: math.ceil(3.5px); + value: map.get($map, a); + variable: map.$default; +} + + + diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/scss/value/qualified-names.scss.snap b/crates/biome_css_parser/tests/css_test_suite/ok/scss/value/qualified-names.scss.snap new file mode 100644 index 000000000000..5371ebd4c066 --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/ok/scss/value/qualified-names.scss.snap @@ -0,0 +1,347 @@ +--- +source: crates/biome_css_parser/tests/spec_test.rs +expression: snapshot +--- + +## Input + +```css +.test { + width: math.div(10px, 2); + height: math.ceil(3.5px); + value: map.get($map, a); + variable: map.$default; +} + + + + +``` + + +## AST + +``` +CssRoot { + bom_token: missing (optional), + items: CssRootItemList [ + CssQualifiedRule { + prelude: CssSelectorList [ + CssCompoundSelector { + nesting_selectors: CssNestedSelectorList [], + simple_selector: missing (optional), + sub_selectors: CssSubSelectorList [ + CssClassSelector { + dot_token: DOT@0..1 "." [] [], + name: CssCustomIdentifier { + value_token: IDENT@1..6 "test" [] [Whitespace(" ")], + }, + }, + ], + }, + ], + block: CssDeclarationOrRuleBlock { + l_curly_token: L_CURLY@6..7 "{" [] [], + items: CssDeclarationOrRuleList [ + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@7..15 "width" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@15..17 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssFunction { + name: ScssQualifiedName { + module: CssIdentifier { + value_token: IDENT@17..21 "math" [] [], + }, + dot_token: DOT@21..22 "." [] [], + member: CssIdentifier { + value_token: IDENT@22..25 "div" [] [], + }, + }, + l_paren_token: L_PAREN@25..26 "(" [] [], + items: CssParameterList [ + CssParameter { + any_css_expression: CssListOfComponentValuesExpression { + css_component_value_list: CssComponentValueList [ + CssRegularDimension { + value_token: CSS_NUMBER_LITERAL@26..28 "10" [] [], + unit_token: IDENT@28..30 "px" [] [], + }, + ], + }, + }, + COMMA@30..32 "," [] [Whitespace(" ")], + CssParameter { + any_css_expression: CssListOfComponentValuesExpression { + css_component_value_list: CssComponentValueList [ + CssNumber { + value_token: CSS_NUMBER_LITERAL@32..33 "2" [] [], + }, + ], + }, + }, + ], + r_paren_token: R_PAREN@33..34 ")" [] [], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@34..35 ";" [] [], + }, + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@35..44 "height" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@44..46 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssFunction { + name: ScssQualifiedName { + module: CssIdentifier { + value_token: IDENT@46..50 "math" [] [], + }, + dot_token: DOT@50..51 "." [] [], + member: CssIdentifier { + value_token: IDENT@51..55 "ceil" [] [], + }, + }, + l_paren_token: L_PAREN@55..56 "(" [] [], + items: CssParameterList [ + CssParameter { + any_css_expression: CssListOfComponentValuesExpression { + css_component_value_list: CssComponentValueList [ + CssRegularDimension { + value_token: CSS_NUMBER_LITERAL@56..59 "3.5" [] [], + unit_token: IDENT@59..61 "px" [] [], + }, + ], + }, + }, + ], + r_paren_token: R_PAREN@61..62 ")" [] [], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@62..63 ";" [] [], + }, + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@63..71 "value" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@71..73 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + CssFunction { + name: ScssQualifiedName { + module: CssIdentifier { + value_token: IDENT@73..76 "map" [] [], + }, + dot_token: DOT@76..77 "." [] [], + member: CssIdentifier { + value_token: IDENT@77..80 "get" [] [], + }, + }, + l_paren_token: L_PAREN@80..81 "(" [] [], + items: CssParameterList [ + CssParameter { + any_css_expression: CssListOfComponentValuesExpression { + css_component_value_list: CssComponentValueList [ + ScssIdentifier { + dollar_token: DOLLAR@81..82 "$" [] [], + name: CssIdentifier { + value_token: IDENT@82..85 "map" [] [], + }, + }, + ], + }, + }, + COMMA@85..87 "," [] [Whitespace(" ")], + CssParameter { + any_css_expression: CssListOfComponentValuesExpression { + css_component_value_list: CssComponentValueList [ + CssIdentifier { + value_token: IDENT@87..88 "a" [] [], + }, + ], + }, + }, + ], + r_paren_token: R_PAREN@88..89 ")" [] [], + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@89..90 ";" [] [], + }, + CssDeclarationWithSemicolon { + declaration: CssDeclaration { + property: CssGenericProperty { + name: CssIdentifier { + value_token: IDENT@90..101 "variable" [Newline("\n"), Whitespace(" ")] [], + }, + colon_token: COLON@101..103 ":" [] [Whitespace(" ")], + value: CssGenericComponentValueList [ + ScssQualifiedName { + module: CssIdentifier { + value_token: IDENT@103..106 "map" [] [], + }, + dot_token: DOT@106..107 "." [] [], + member: ScssIdentifier { + dollar_token: DOLLAR@107..108 "$" [] [], + name: CssIdentifier { + value_token: IDENT@108..115 "default" [] [], + }, + }, + }, + ], + }, + important: missing (optional), + }, + semicolon_token: SEMICOLON@115..116 ";" [] [], + }, + ], + r_curly_token: R_CURLY@116..118 "}" [Newline("\n")] [], + }, + }, + ], + eof_token: EOF@118..122 "" [Newline("\n"), Newline("\n"), Newline("\n"), Newline("\n")] [], +} +``` + +## CST + +``` +0: CSS_ROOT@0..122 + 0: (empty) + 1: CSS_ROOT_ITEM_LIST@0..118 + 0: CSS_QUALIFIED_RULE@0..118 + 0: CSS_SELECTOR_LIST@0..6 + 0: CSS_COMPOUND_SELECTOR@0..6 + 0: CSS_NESTED_SELECTOR_LIST@0..0 + 1: (empty) + 2: CSS_SUB_SELECTOR_LIST@0..6 + 0: CSS_CLASS_SELECTOR@0..6 + 0: DOT@0..1 "." [] [] + 1: CSS_CUSTOM_IDENTIFIER@1..6 + 0: IDENT@1..6 "test" [] [Whitespace(" ")] + 1: CSS_DECLARATION_OR_RULE_BLOCK@6..118 + 0: L_CURLY@6..7 "{" [] [] + 1: CSS_DECLARATION_OR_RULE_LIST@7..116 + 0: CSS_DECLARATION_WITH_SEMICOLON@7..35 + 0: CSS_DECLARATION@7..34 + 0: CSS_GENERIC_PROPERTY@7..34 + 0: CSS_IDENTIFIER@7..15 + 0: IDENT@7..15 "width" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@15..17 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@17..34 + 0: CSS_FUNCTION@17..34 + 0: SCSS_QUALIFIED_NAME@17..25 + 0: CSS_IDENTIFIER@17..21 + 0: IDENT@17..21 "math" [] [] + 1: DOT@21..22 "." [] [] + 2: CSS_IDENTIFIER@22..25 + 0: IDENT@22..25 "div" [] [] + 1: L_PAREN@25..26 "(" [] [] + 2: CSS_PARAMETER_LIST@26..33 + 0: CSS_PARAMETER@26..30 + 0: CSS_LIST_OF_COMPONENT_VALUES_EXPRESSION@26..30 + 0: CSS_COMPONENT_VALUE_LIST@26..30 + 0: CSS_REGULAR_DIMENSION@26..30 + 0: CSS_NUMBER_LITERAL@26..28 "10" [] [] + 1: IDENT@28..30 "px" [] [] + 1: COMMA@30..32 "," [] [Whitespace(" ")] + 2: CSS_PARAMETER@32..33 + 0: CSS_LIST_OF_COMPONENT_VALUES_EXPRESSION@32..33 + 0: CSS_COMPONENT_VALUE_LIST@32..33 + 0: CSS_NUMBER@32..33 + 0: CSS_NUMBER_LITERAL@32..33 "2" [] [] + 3: R_PAREN@33..34 ")" [] [] + 1: (empty) + 1: SEMICOLON@34..35 ";" [] [] + 1: CSS_DECLARATION_WITH_SEMICOLON@35..63 + 0: CSS_DECLARATION@35..62 + 0: CSS_GENERIC_PROPERTY@35..62 + 0: CSS_IDENTIFIER@35..44 + 0: IDENT@35..44 "height" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@44..46 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@46..62 + 0: CSS_FUNCTION@46..62 + 0: SCSS_QUALIFIED_NAME@46..55 + 0: CSS_IDENTIFIER@46..50 + 0: IDENT@46..50 "math" [] [] + 1: DOT@50..51 "." [] [] + 2: CSS_IDENTIFIER@51..55 + 0: IDENT@51..55 "ceil" [] [] + 1: L_PAREN@55..56 "(" [] [] + 2: CSS_PARAMETER_LIST@56..61 + 0: CSS_PARAMETER@56..61 + 0: CSS_LIST_OF_COMPONENT_VALUES_EXPRESSION@56..61 + 0: CSS_COMPONENT_VALUE_LIST@56..61 + 0: CSS_REGULAR_DIMENSION@56..61 + 0: CSS_NUMBER_LITERAL@56..59 "3.5" [] [] + 1: IDENT@59..61 "px" [] [] + 3: R_PAREN@61..62 ")" [] [] + 1: (empty) + 1: SEMICOLON@62..63 ";" [] [] + 2: CSS_DECLARATION_WITH_SEMICOLON@63..90 + 0: CSS_DECLARATION@63..89 + 0: CSS_GENERIC_PROPERTY@63..89 + 0: CSS_IDENTIFIER@63..71 + 0: IDENT@63..71 "value" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@71..73 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@73..89 + 0: CSS_FUNCTION@73..89 + 0: SCSS_QUALIFIED_NAME@73..80 + 0: CSS_IDENTIFIER@73..76 + 0: IDENT@73..76 "map" [] [] + 1: DOT@76..77 "." [] [] + 2: CSS_IDENTIFIER@77..80 + 0: IDENT@77..80 "get" [] [] + 1: L_PAREN@80..81 "(" [] [] + 2: CSS_PARAMETER_LIST@81..88 + 0: CSS_PARAMETER@81..85 + 0: CSS_LIST_OF_COMPONENT_VALUES_EXPRESSION@81..85 + 0: CSS_COMPONENT_VALUE_LIST@81..85 + 0: SCSS_IDENTIFIER@81..85 + 0: DOLLAR@81..82 "$" [] [] + 1: CSS_IDENTIFIER@82..85 + 0: IDENT@82..85 "map" [] [] + 1: COMMA@85..87 "," [] [Whitespace(" ")] + 2: CSS_PARAMETER@87..88 + 0: CSS_LIST_OF_COMPONENT_VALUES_EXPRESSION@87..88 + 0: CSS_COMPONENT_VALUE_LIST@87..88 + 0: CSS_IDENTIFIER@87..88 + 0: IDENT@87..88 "a" [] [] + 3: R_PAREN@88..89 ")" [] [] + 1: (empty) + 1: SEMICOLON@89..90 ";" [] [] + 3: CSS_DECLARATION_WITH_SEMICOLON@90..116 + 0: CSS_DECLARATION@90..115 + 0: CSS_GENERIC_PROPERTY@90..115 + 0: CSS_IDENTIFIER@90..101 + 0: IDENT@90..101 "variable" [Newline("\n"), Whitespace(" ")] [] + 1: COLON@101..103 ":" [] [Whitespace(" ")] + 2: CSS_GENERIC_COMPONENT_VALUE_LIST@103..115 + 0: SCSS_QUALIFIED_NAME@103..115 + 0: CSS_IDENTIFIER@103..106 + 0: IDENT@103..106 "map" [] [] + 1: DOT@106..107 "." [] [] + 2: SCSS_IDENTIFIER@107..115 + 0: DOLLAR@107..108 "$" [] [] + 1: CSS_IDENTIFIER@108..115 + 0: IDENT@108..115 "default" [] [] + 1: (empty) + 1: SEMICOLON@115..116 ";" [] [] + 2: R_CURLY@116..118 "}" [Newline("\n")] [] + 2: EOF@118..122 "" [Newline("\n"), Newline("\n"), Newline("\n"), Newline("\n")] [] + +``` diff --git a/crates/biome_css_parser/tests/quick_test.rs b/crates/biome_css_parser/tests/quick_test.rs index 1ea08167ce73..bb1eb467ac69 100644 --- a/crates/biome_css_parser/tests/quick_test.rs +++ b/crates/biome_css_parser/tests/quick_test.rs @@ -6,18 +6,16 @@ use biome_test_utils::has_bogus_nodes_or_empty_slots; #[test] pub fn quick_test() { let code = r#" -@utility border-overlay-* { - position: relative; - - &::after { - border-width: 1px; + .card { + label:hover { + color: red; } -} + } "#; let root = parse_css( code, - CssFileSource::css(), + CssFileSource::scss(), CssParserOptions::default() .allow_wrong_line_comments() .allow_css_modules() diff --git a/crates/biome_css_syntax/src/generated/kind.rs b/crates/biome_css_syntax/src/generated/kind.rs index 712c7e956f06..933bb9395d08 100644 --- a/crates/biome_css_syntax/src/generated/kind.rs +++ b/crates/biome_css_syntax/src/generated/kind.rs @@ -369,6 +369,7 @@ pub enum CssSyntaxKind { CSS_LIST_OF_COMPONENT_VALUES_EXPRESSION, CSS_COMMA_SEPARATED_VALUE, CSS_BINARY_EXPRESSION, + CSS_UNARY_EXPRESSION, CSS_URL_VALUE_RAW, CSS_URL_FUNCTION, CSS_IF_FUNCTION, @@ -535,7 +536,9 @@ pub enum CssSyntaxKind { CSS_FUNCTION_PARAMETER_LIST, CSS_RETURNS_STATEMENT, SCSS_DECLARATION, + SCSS_NESTING_DECLARATION, SCSS_NAMESPACED_IDENTIFIER, + SCSS_QUALIFIED_NAME, SCSS_VARIABLE_MODIFIER_LIST, SCSS_VARIABLE_MODIFIER, SCSS_IDENTIFIER, diff --git a/crates/biome_css_syntax/src/generated/macros.rs b/crates/biome_css_syntax/src/generated/macros.rs index 1880a8f92b67..8c43a5afdab3 100644 --- a/crates/biome_css_syntax/src/generated/macros.rs +++ b/crates/biome_css_syntax/src/generated/macros.rs @@ -814,6 +814,10 @@ macro_rules! map_syntax_node { let $pattern = unsafe { $crate::CssTypeSelector::new_unchecked(node) }; $body } + $crate::CssSyntaxKind::CSS_UNARY_EXPRESSION => { + let $pattern = unsafe { $crate::CssUnaryExpression::new_unchecked(node) }; + $body + } $crate::CssSyntaxKind::CSS_UNICODE_CODEPOINT => { let $pattern = unsafe { $crate::CssUnicodeCodepoint::new_unchecked(node) }; $body @@ -921,6 +925,14 @@ macro_rules! map_syntax_node { let $pattern = unsafe { $crate::ScssNamespacedIdentifier::new_unchecked(node) }; $body } + $crate::CssSyntaxKind::SCSS_NESTING_DECLARATION => { + let $pattern = unsafe { $crate::ScssNestingDeclaration::new_unchecked(node) }; + $body + } + $crate::CssSyntaxKind::SCSS_QUALIFIED_NAME => { + let $pattern = unsafe { $crate::ScssQualifiedName::new_unchecked(node) }; + $body + } $crate::CssSyntaxKind::SCSS_VARIABLE_MODIFIER => { let $pattern = unsafe { $crate::ScssVariableModifier::new_unchecked(node) }; $body diff --git a/crates/biome_css_syntax/src/generated/nodes.rs b/crates/biome_css_syntax/src/generated/nodes.rs index da296f6dbbb2..6d5fd67e8e56 100644 --- a/crates/biome_css_syntax/src/generated/nodes.rs +++ b/crates/biome_css_syntax/src/generated/nodes.rs @@ -2369,7 +2369,7 @@ impl CssFunction { r_paren_token: self.r_paren_token(), } } - pub fn name(&self) -> SyntaxResult { + pub fn name(&self) -> SyntaxResult { support::required_node(&self.syntax, 0usize) } pub fn l_paren_token(&self) -> SyntaxResult { @@ -2392,7 +2392,7 @@ impl Serialize for CssFunction { } #[derive(Serialize)] pub struct CssFunctionFields { - pub name: SyntaxResult, + pub name: SyntaxResult, pub l_paren_token: SyntaxResult, pub items: CssParameterList, pub r_paren_token: SyntaxResult, @@ -7835,6 +7835,46 @@ pub struct CssTypeSelectorFields { pub ident: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] +pub struct CssUnaryExpression { + pub(crate) syntax: SyntaxNode, +} +impl CssUnaryExpression { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> CssUnaryExpressionFields { + CssUnaryExpressionFields { + operator: self.operator(), + expression: self.expression(), + } + } + pub fn operator(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } + pub fn expression(&self) -> SyntaxResult { + support::required_node(&self.syntax, 1usize) + } +} +impl Serialize for CssUnaryExpression { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct CssUnaryExpressionFields { + pub operator: SyntaxResult, + pub expression: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] pub struct CssUnicodeCodepoint { pub(crate) syntax: SyntaxNode, } @@ -8853,6 +8893,101 @@ pub struct ScssNamespacedIdentifierFields { pub name: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] +pub struct ScssNestingDeclaration { + pub(crate) syntax: SyntaxNode, +} +impl ScssNestingDeclaration { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> ScssNestingDeclarationFields { + ScssNestingDeclarationFields { + name: self.name(), + colon_token: self.colon_token(), + value: self.value(), + block: self.block(), + } + } + pub fn name(&self) -> SyntaxResult { + support::required_node(&self.syntax, 0usize) + } + pub fn colon_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 1usize) + } + pub fn value(&self) -> CssGenericComponentValueList { + support::list(&self.syntax, 2usize) + } + pub fn block(&self) -> SyntaxResult { + support::required_node(&self.syntax, 3usize) + } +} +impl Serialize for ScssNestingDeclaration { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct ScssNestingDeclarationFields { + pub name: SyntaxResult, + pub colon_token: SyntaxResult, + pub value: CssGenericComponentValueList, + pub block: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct ScssQualifiedName { + pub(crate) syntax: SyntaxNode, +} +impl ScssQualifiedName { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> ScssQualifiedNameFields { + ScssQualifiedNameFields { + module: self.module(), + dot_token: self.dot_token(), + member: self.member(), + } + } + pub fn module(&self) -> SyntaxResult { + support::required_node(&self.syntax, 0usize) + } + pub fn dot_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 1usize) + } + pub fn member(&self) -> SyntaxResult { + support::required_node(&self.syntax, 2usize) + } +} +impl Serialize for ScssQualifiedName { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct ScssQualifiedNameFields { + pub module: SyntaxResult, + pub dot_token: SyntaxResult, + pub member: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] pub struct ScssVariableModifier { pub(crate) syntax: SyntaxNode, } @@ -9986,6 +10121,25 @@ impl AnyCssAttributeMatcherValue { } } #[derive(Clone, PartialEq, Eq, Hash, Serialize)] +pub enum AnyCssBracketedValueItem { + AnyCssCustomIdentifier(AnyCssCustomIdentifier), + CssGenericDelimiter(CssGenericDelimiter), +} +impl AnyCssBracketedValueItem { + pub fn as_any_css_custom_identifier(&self) -> Option<&AnyCssCustomIdentifier> { + match &self { + Self::AnyCssCustomIdentifier(item) => Some(item), + _ => None, + } + } + pub fn as_css_generic_delimiter(&self) -> Option<&CssGenericDelimiter> { + match &self { + Self::CssGenericDelimiter(item) => Some(item), + _ => None, + } + } +} +#[derive(Clone, PartialEq, Eq, Hash, Serialize)] pub enum AnyCssComposesImportSource { CssIdentifier(CssIdentifier), CssString(CssString), @@ -10278,6 +10432,7 @@ pub enum AnyCssDeclaration { CssDeclarationWithSemicolon(CssDeclarationWithSemicolon), CssEmptyDeclaration(CssEmptyDeclaration), ScssDeclaration(ScssDeclaration), + ScssNestingDeclaration(ScssNestingDeclaration), } impl AnyCssDeclaration { pub fn as_css_declaration_with_semicolon(&self) -> Option<&CssDeclarationWithSemicolon> { @@ -10298,6 +10453,12 @@ impl AnyCssDeclaration { _ => None, } } + pub fn as_scss_nesting_declaration(&self) -> Option<&ScssNestingDeclaration> { + match &self { + Self::ScssNestingDeclaration(item) => Some(item), + _ => None, + } + } } #[derive(Clone, PartialEq, Eq, Hash, Serialize)] pub enum AnyCssDeclarationBlock { @@ -10350,6 +10511,7 @@ pub enum AnyCssDeclarationOrAtRule { CssDeclarationWithSemicolon(CssDeclarationWithSemicolon), CssEmptyDeclaration(CssEmptyDeclaration), ScssDeclaration(ScssDeclaration), + ScssNestingDeclaration(ScssNestingDeclaration), } impl AnyCssDeclarationOrAtRule { pub fn as_css_at_rule(&self) -> Option<&CssAtRule> { @@ -10376,6 +10538,12 @@ impl AnyCssDeclarationOrAtRule { _ => None, } } + pub fn as_scss_nesting_declaration(&self) -> Option<&ScssNestingDeclaration> { + match &self { + Self::ScssNestingDeclaration(item) => Some(item), + _ => None, + } + } } #[derive(Clone, PartialEq, Eq, Hash, Serialize)] pub enum AnyCssDeclarationOrAtRuleBlock { @@ -10404,6 +10572,7 @@ pub enum AnyCssDeclarationOrRule { CssEmptyDeclaration(CssEmptyDeclaration), CssMetavariable(CssMetavariable), ScssDeclaration(ScssDeclaration), + ScssNestingDeclaration(ScssNestingDeclaration), } impl AnyCssDeclarationOrRule { pub fn as_any_css_rule(&self) -> Option<&AnyCssRule> { @@ -10442,6 +10611,12 @@ impl AnyCssDeclarationOrRule { _ => None, } } + pub fn as_scss_nesting_declaration(&self) -> Option<&ScssNestingDeclaration> { + match &self { + Self::ScssNestingDeclaration(item) => Some(item), + _ => None, + } + } } #[derive(Clone, PartialEq, Eq, Hash, Serialize)] pub enum AnyCssDeclarationOrRuleBlock { @@ -10520,6 +10695,7 @@ pub enum AnyCssExpression { CssCommaSeparatedValue(CssCommaSeparatedValue), CssListOfComponentValuesExpression(CssListOfComponentValuesExpression), CssParenthesizedExpression(CssParenthesizedExpression), + CssUnaryExpression(CssUnaryExpression), } impl AnyCssExpression { pub fn as_css_binary_expression(&self) -> Option<&CssBinaryExpression> { @@ -10548,6 +10724,12 @@ impl AnyCssExpression { _ => None, } } + pub fn as_css_unary_expression(&self) -> Option<&CssUnaryExpression> { + match &self { + Self::CssUnaryExpression(item) => Some(item), + _ => None, + } + } } #[derive(Clone, PartialEq, Eq, Hash, Serialize)] pub enum AnyCssFontFamilyName { @@ -10647,6 +10829,25 @@ impl AnyCssFunction { } } #[derive(Clone, PartialEq, Eq, Hash, Serialize)] +pub enum AnyCssFunctionName { + CssIdentifier(CssIdentifier), + ScssQualifiedName(ScssQualifiedName), +} +impl AnyCssFunctionName { + pub fn as_css_identifier(&self) -> Option<&CssIdentifier> { + match &self { + Self::CssIdentifier(item) => Some(item), + _ => None, + } + } + pub fn as_scss_qualified_name(&self) -> Option<&ScssQualifiedName> { + match &self { + Self::ScssQualifiedName(item) => Some(item), + _ => None, + } + } +} +#[derive(Clone, PartialEq, Eq, Hash, Serialize)] pub enum AnyCssFunctionParameter { CssBogusFunctionParameter(CssBogusFunctionParameter), CssFunctionParameter(CssFunctionParameter), @@ -11330,6 +11531,8 @@ pub enum AnyCssPageAtRuleItem { CssDeclarationWithSemicolon(CssDeclarationWithSemicolon), CssEmptyDeclaration(CssEmptyDeclaration), CssMarginAtRule(CssMarginAtRule), + ScssDeclaration(ScssDeclaration), + ScssNestingDeclaration(ScssNestingDeclaration), } impl AnyCssPageAtRuleItem { pub fn as_css_at_rule(&self) -> Option<&CssAtRule> { @@ -11362,6 +11565,18 @@ impl AnyCssPageAtRuleItem { _ => None, } } + pub fn as_scss_declaration(&self) -> Option<&ScssDeclaration> { + match &self { + Self::ScssDeclaration(item) => Some(item), + _ => None, + } + } + pub fn as_scss_nesting_declaration(&self) -> Option<&ScssNestingDeclaration> { + match &self { + Self::ScssNestingDeclaration(item) => Some(item), + _ => None, + } + } } #[derive(Clone, PartialEq, Eq, Hash, Serialize)] pub enum AnyCssPageSelector { @@ -12304,6 +12519,7 @@ pub enum AnyCssValue { CssString(CssString), CssUnicodeRange(CssUnicodeRange), ScssIdentifier(ScssIdentifier), + ScssQualifiedName(ScssQualifiedName), TwValueThemeReference(TwValueThemeReference), } impl AnyCssValue { @@ -12385,6 +12601,12 @@ impl AnyCssValue { _ => None, } } + pub fn as_scss_qualified_name(&self) -> Option<&ScssQualifiedName> { + match &self { + Self::ScssQualifiedName(item) => Some(item), + _ => None, + } + } pub fn as_tw_value_theme_reference(&self) -> Option<&TwValueThemeReference> { match &self { Self::TwValueThemeReference(item) => Some(item), @@ -12492,6 +12714,25 @@ impl AnyScssDeclarationName { } } #[derive(Clone, PartialEq, Eq, Hash, Serialize)] +pub enum AnyScssModuleMember { + CssIdentifier(CssIdentifier), + ScssIdentifier(ScssIdentifier), +} +impl AnyScssModuleMember { + pub fn as_css_identifier(&self) -> Option<&CssIdentifier> { + match &self { + Self::CssIdentifier(item) => Some(item), + _ => None, + } + } + pub fn as_scss_identifier(&self) -> Option<&ScssIdentifier> { + match &self { + Self::ScssIdentifier(item) => Some(item), + _ => None, + } + } +} +#[derive(Clone, PartialEq, Eq, Hash, Serialize)] pub enum AnyTwCustomVariantSelector { AnyCssRuleBlock(AnyCssRuleBlock), TwCustomVariantShorthand(TwCustomVariantShorthand), @@ -22052,6 +22293,54 @@ impl From for SyntaxElement { n.syntax.into() } } +impl AstNode for CssUnaryExpression { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(CSS_UNARY_EXPRESSION as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == CSS_UNARY_EXPRESSION + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for CssUnaryExpression { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("CssUnaryExpression") + .field("operator", &support::DebugSyntaxResult(self.operator())) + .field("expression", &support::DebugSyntaxResult(self.expression())) + .finish() + } else { + f.debug_struct("CssUnaryExpression").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: CssUnaryExpression) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: CssUnaryExpression) -> Self { + n.syntax.into() + } +} impl AstNode for CssUnicodeCodepoint { type Language = Language; const KIND_SET: SyntaxKindSet = @@ -23309,6 +23598,108 @@ impl From for SyntaxElement { n.syntax.into() } } +impl AstNode for ScssNestingDeclaration { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(SCSS_NESTING_DECLARATION as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == SCSS_NESTING_DECLARATION + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for ScssNestingDeclaration { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("ScssNestingDeclaration") + .field("name", &support::DebugSyntaxResult(self.name())) + .field( + "colon_token", + &support::DebugSyntaxResult(self.colon_token()), + ) + .field("value", &self.value()) + .field("block", &support::DebugSyntaxResult(self.block())) + .finish() + } else { + f.debug_struct("ScssNestingDeclaration").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: ScssNestingDeclaration) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: ScssNestingDeclaration) -> Self { + n.syntax.into() + } +} +impl AstNode for ScssQualifiedName { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(SCSS_QUALIFIED_NAME as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == SCSS_QUALIFIED_NAME + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for ScssQualifiedName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("ScssQualifiedName") + .field("module", &support::DebugSyntaxResult(self.module())) + .field("dot_token", &support::DebugSyntaxResult(self.dot_token())) + .field("member", &support::DebugSyntaxResult(self.member())) + .finish() + } else { + f.debug_struct("ScssQualifiedName").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: ScssQualifiedName) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: ScssQualifiedName) -> Self { + n.syntax.into() + } +} impl AstNode for ScssVariableModifier { type Language = Language; const KIND_SET: SyntaxKindSet = @@ -25088,6 +25479,69 @@ impl From for SyntaxElement { node.into() } } +impl From for AnyCssBracketedValueItem { + fn from(node: CssGenericDelimiter) -> Self { + Self::CssGenericDelimiter(node) + } +} +impl AstNode for AnyCssBracketedValueItem { + type Language = Language; + const KIND_SET: SyntaxKindSet = + AnyCssCustomIdentifier::KIND_SET.union(CssGenericDelimiter::KIND_SET); + fn can_cast(kind: SyntaxKind) -> bool { + match kind { + CSS_GENERIC_DELIMITER => true, + k if AnyCssCustomIdentifier::can_cast(k) => true, + _ => false, + } + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + CSS_GENERIC_DELIMITER => Self::CssGenericDelimiter(CssGenericDelimiter { syntax }), + _ => { + if let Some(any_css_custom_identifier) = AnyCssCustomIdentifier::cast(syntax) { + return Some(Self::AnyCssCustomIdentifier(any_css_custom_identifier)); + } + return None; + } + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { + match self { + Self::CssGenericDelimiter(it) => it.syntax(), + Self::AnyCssCustomIdentifier(it) => it.syntax(), + } + } + fn into_syntax(self) -> SyntaxNode { + match self { + Self::CssGenericDelimiter(it) => it.into_syntax(), + Self::AnyCssCustomIdentifier(it) => it.into_syntax(), + } + } +} +impl std::fmt::Debug for AnyCssBracketedValueItem { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::AnyCssCustomIdentifier(it) => std::fmt::Debug::fmt(it, f), + Self::CssGenericDelimiter(it) => std::fmt::Debug::fmt(it, f), + } + } +} +impl From for SyntaxNode { + fn from(n: AnyCssBracketedValueItem) -> Self { + match n { + AnyCssBracketedValueItem::AnyCssCustomIdentifier(it) => it.into_syntax(), + AnyCssBracketedValueItem::CssGenericDelimiter(it) => it.into_syntax(), + } + } +} +impl From for SyntaxElement { + fn from(n: AnyCssBracketedValueItem) -> Self { + let node: SyntaxNode = n.into(); + node.into() + } +} impl From for AnyCssComposesImportSource { fn from(node: CssIdentifier) -> Self { Self::CssIdentifier(node) @@ -25990,15 +26444,24 @@ impl From for AnyCssDeclaration { Self::ScssDeclaration(node) } } +impl From for AnyCssDeclaration { + fn from(node: ScssNestingDeclaration) -> Self { + Self::ScssNestingDeclaration(node) + } +} impl AstNode for AnyCssDeclaration { type Language = Language; const KIND_SET: SyntaxKindSet = CssDeclarationWithSemicolon::KIND_SET .union(CssEmptyDeclaration::KIND_SET) - .union(ScssDeclaration::KIND_SET); + .union(ScssDeclaration::KIND_SET) + .union(ScssNestingDeclaration::KIND_SET); fn can_cast(kind: SyntaxKind) -> bool { matches!( kind, - CSS_DECLARATION_WITH_SEMICOLON | CSS_EMPTY_DECLARATION | SCSS_DECLARATION + CSS_DECLARATION_WITH_SEMICOLON + | CSS_EMPTY_DECLARATION + | SCSS_DECLARATION + | SCSS_NESTING_DECLARATION ) } fn cast(syntax: SyntaxNode) -> Option { @@ -26008,6 +26471,9 @@ impl AstNode for AnyCssDeclaration { } CSS_EMPTY_DECLARATION => Self::CssEmptyDeclaration(CssEmptyDeclaration { syntax }), SCSS_DECLARATION => Self::ScssDeclaration(ScssDeclaration { syntax }), + SCSS_NESTING_DECLARATION => { + Self::ScssNestingDeclaration(ScssNestingDeclaration { syntax }) + } _ => return None, }; Some(res) @@ -26017,6 +26483,7 @@ impl AstNode for AnyCssDeclaration { Self::CssDeclarationWithSemicolon(it) => it.syntax(), Self::CssEmptyDeclaration(it) => it.syntax(), Self::ScssDeclaration(it) => it.syntax(), + Self::ScssNestingDeclaration(it) => it.syntax(), } } fn into_syntax(self) -> SyntaxNode { @@ -26024,6 +26491,7 @@ impl AstNode for AnyCssDeclaration { Self::CssDeclarationWithSemicolon(it) => it.into_syntax(), Self::CssEmptyDeclaration(it) => it.into_syntax(), Self::ScssDeclaration(it) => it.into_syntax(), + Self::ScssNestingDeclaration(it) => it.into_syntax(), } } } @@ -26033,6 +26501,7 @@ impl std::fmt::Debug for AnyCssDeclaration { Self::CssDeclarationWithSemicolon(it) => std::fmt::Debug::fmt(it, f), Self::CssEmptyDeclaration(it) => std::fmt::Debug::fmt(it, f), Self::ScssDeclaration(it) => std::fmt::Debug::fmt(it, f), + Self::ScssNestingDeclaration(it) => std::fmt::Debug::fmt(it, f), } } } @@ -26042,6 +26511,7 @@ impl From for SyntaxNode { AnyCssDeclaration::CssDeclarationWithSemicolon(it) => it.into_syntax(), AnyCssDeclaration::CssEmptyDeclaration(it) => it.into_syntax(), AnyCssDeclaration::ScssDeclaration(it) => it.into_syntax(), + AnyCssDeclaration::ScssNestingDeclaration(it) => it.into_syntax(), } } } @@ -26207,16 +26677,26 @@ impl From for AnyCssDeclarationOrAtRule { Self::ScssDeclaration(node) } } +impl From for AnyCssDeclarationOrAtRule { + fn from(node: ScssNestingDeclaration) -> Self { + Self::ScssNestingDeclaration(node) + } +} impl AstNode for AnyCssDeclarationOrAtRule { type Language = Language; const KIND_SET: SyntaxKindSet = CssAtRule::KIND_SET .union(CssDeclarationWithSemicolon::KIND_SET) .union(CssEmptyDeclaration::KIND_SET) - .union(ScssDeclaration::KIND_SET); + .union(ScssDeclaration::KIND_SET) + .union(ScssNestingDeclaration::KIND_SET); fn can_cast(kind: SyntaxKind) -> bool { matches!( kind, - CSS_AT_RULE | CSS_DECLARATION_WITH_SEMICOLON | CSS_EMPTY_DECLARATION | SCSS_DECLARATION + CSS_AT_RULE + | CSS_DECLARATION_WITH_SEMICOLON + | CSS_EMPTY_DECLARATION + | SCSS_DECLARATION + | SCSS_NESTING_DECLARATION ) } fn cast(syntax: SyntaxNode) -> Option { @@ -26227,6 +26707,9 @@ impl AstNode for AnyCssDeclarationOrAtRule { } CSS_EMPTY_DECLARATION => Self::CssEmptyDeclaration(CssEmptyDeclaration { syntax }), SCSS_DECLARATION => Self::ScssDeclaration(ScssDeclaration { syntax }), + SCSS_NESTING_DECLARATION => { + Self::ScssNestingDeclaration(ScssNestingDeclaration { syntax }) + } _ => return None, }; Some(res) @@ -26237,6 +26720,7 @@ impl AstNode for AnyCssDeclarationOrAtRule { Self::CssDeclarationWithSemicolon(it) => it.syntax(), Self::CssEmptyDeclaration(it) => it.syntax(), Self::ScssDeclaration(it) => it.syntax(), + Self::ScssNestingDeclaration(it) => it.syntax(), } } fn into_syntax(self) -> SyntaxNode { @@ -26245,6 +26729,7 @@ impl AstNode for AnyCssDeclarationOrAtRule { Self::CssDeclarationWithSemicolon(it) => it.into_syntax(), Self::CssEmptyDeclaration(it) => it.into_syntax(), Self::ScssDeclaration(it) => it.into_syntax(), + Self::ScssNestingDeclaration(it) => it.into_syntax(), } } } @@ -26255,6 +26740,7 @@ impl std::fmt::Debug for AnyCssDeclarationOrAtRule { Self::CssDeclarationWithSemicolon(it) => std::fmt::Debug::fmt(it, f), Self::CssEmptyDeclaration(it) => std::fmt::Debug::fmt(it, f), Self::ScssDeclaration(it) => std::fmt::Debug::fmt(it, f), + Self::ScssNestingDeclaration(it) => std::fmt::Debug::fmt(it, f), } } } @@ -26265,6 +26751,7 @@ impl From for SyntaxNode { AnyCssDeclarationOrAtRule::CssDeclarationWithSemicolon(it) => it.into_syntax(), AnyCssDeclarationOrAtRule::CssEmptyDeclaration(it) => it.into_syntax(), AnyCssDeclarationOrAtRule::ScssDeclaration(it) => it.into_syntax(), + AnyCssDeclarationOrAtRule::ScssNestingDeclaration(it) => it.into_syntax(), } } } @@ -26361,6 +26848,11 @@ impl From for AnyCssDeclarationOrRule { Self::ScssDeclaration(node) } } +impl From for AnyCssDeclarationOrRule { + fn from(node: ScssNestingDeclaration) -> Self { + Self::ScssNestingDeclaration(node) + } +} impl AstNode for AnyCssDeclarationOrRule { type Language = Language; const KIND_SET: SyntaxKindSet = AnyCssRule::KIND_SET @@ -26368,14 +26860,16 @@ impl AstNode for AnyCssDeclarationOrRule { .union(CssDeclarationWithSemicolon::KIND_SET) .union(CssEmptyDeclaration::KIND_SET) .union(CssMetavariable::KIND_SET) - .union(ScssDeclaration::KIND_SET); + .union(ScssDeclaration::KIND_SET) + .union(ScssNestingDeclaration::KIND_SET); fn can_cast(kind: SyntaxKind) -> bool { match kind { CSS_BOGUS | CSS_DECLARATION_WITH_SEMICOLON | CSS_EMPTY_DECLARATION | CSS_METAVARIABLE - | SCSS_DECLARATION => true, + | SCSS_DECLARATION + | SCSS_NESTING_DECLARATION => true, k if AnyCssRule::can_cast(k) => true, _ => false, } @@ -26389,6 +26883,9 @@ impl AstNode for AnyCssDeclarationOrRule { CSS_EMPTY_DECLARATION => Self::CssEmptyDeclaration(CssEmptyDeclaration { syntax }), CSS_METAVARIABLE => Self::CssMetavariable(CssMetavariable { syntax }), SCSS_DECLARATION => Self::ScssDeclaration(ScssDeclaration { syntax }), + SCSS_NESTING_DECLARATION => { + Self::ScssNestingDeclaration(ScssNestingDeclaration { syntax }) + } _ => { if let Some(any_css_rule) = AnyCssRule::cast(syntax) { return Some(Self::AnyCssRule(any_css_rule)); @@ -26405,6 +26902,7 @@ impl AstNode for AnyCssDeclarationOrRule { Self::CssEmptyDeclaration(it) => it.syntax(), Self::CssMetavariable(it) => it.syntax(), Self::ScssDeclaration(it) => it.syntax(), + Self::ScssNestingDeclaration(it) => it.syntax(), Self::AnyCssRule(it) => it.syntax(), } } @@ -26415,6 +26913,7 @@ impl AstNode for AnyCssDeclarationOrRule { Self::CssEmptyDeclaration(it) => it.into_syntax(), Self::CssMetavariable(it) => it.into_syntax(), Self::ScssDeclaration(it) => it.into_syntax(), + Self::ScssNestingDeclaration(it) => it.into_syntax(), Self::AnyCssRule(it) => it.into_syntax(), } } @@ -26428,6 +26927,7 @@ impl std::fmt::Debug for AnyCssDeclarationOrRule { Self::CssEmptyDeclaration(it) => std::fmt::Debug::fmt(it, f), Self::CssMetavariable(it) => std::fmt::Debug::fmt(it, f), Self::ScssDeclaration(it) => std::fmt::Debug::fmt(it, f), + Self::ScssNestingDeclaration(it) => std::fmt::Debug::fmt(it, f), } } } @@ -26440,6 +26940,7 @@ impl From for SyntaxNode { AnyCssDeclarationOrRule::CssEmptyDeclaration(it) => it.into_syntax(), AnyCssDeclarationOrRule::CssMetavariable(it) => it.into_syntax(), AnyCssDeclarationOrRule::ScssDeclaration(it) => it.into_syntax(), + AnyCssDeclarationOrRule::ScssNestingDeclaration(it) => it.into_syntax(), } } } @@ -26683,12 +27184,18 @@ impl From for AnyCssExpression { Self::CssParenthesizedExpression(node) } } +impl From for AnyCssExpression { + fn from(node: CssUnaryExpression) -> Self { + Self::CssUnaryExpression(node) + } +} impl AstNode for AnyCssExpression { type Language = Language; const KIND_SET: SyntaxKindSet = CssBinaryExpression::KIND_SET .union(CssCommaSeparatedValue::KIND_SET) .union(CssListOfComponentValuesExpression::KIND_SET) - .union(CssParenthesizedExpression::KIND_SET); + .union(CssParenthesizedExpression::KIND_SET) + .union(CssUnaryExpression::KIND_SET); fn can_cast(kind: SyntaxKind) -> bool { matches!( kind, @@ -26696,6 +27203,7 @@ impl AstNode for AnyCssExpression { | CSS_COMMA_SEPARATED_VALUE | CSS_LIST_OF_COMPONENT_VALUES_EXPRESSION | CSS_PARENTHESIZED_EXPRESSION + | CSS_UNARY_EXPRESSION ) } fn cast(syntax: SyntaxNode) -> Option { @@ -26712,6 +27220,7 @@ impl AstNode for AnyCssExpression { CSS_PARENTHESIZED_EXPRESSION => { Self::CssParenthesizedExpression(CssParenthesizedExpression { syntax }) } + CSS_UNARY_EXPRESSION => Self::CssUnaryExpression(CssUnaryExpression { syntax }), _ => return None, }; Some(res) @@ -26722,6 +27231,7 @@ impl AstNode for AnyCssExpression { Self::CssCommaSeparatedValue(it) => it.syntax(), Self::CssListOfComponentValuesExpression(it) => it.syntax(), Self::CssParenthesizedExpression(it) => it.syntax(), + Self::CssUnaryExpression(it) => it.syntax(), } } fn into_syntax(self) -> SyntaxNode { @@ -26730,6 +27240,7 @@ impl AstNode for AnyCssExpression { Self::CssCommaSeparatedValue(it) => it.into_syntax(), Self::CssListOfComponentValuesExpression(it) => it.into_syntax(), Self::CssParenthesizedExpression(it) => it.into_syntax(), + Self::CssUnaryExpression(it) => it.into_syntax(), } } } @@ -26740,6 +27251,7 @@ impl std::fmt::Debug for AnyCssExpression { Self::CssCommaSeparatedValue(it) => std::fmt::Debug::fmt(it, f), Self::CssListOfComponentValuesExpression(it) => std::fmt::Debug::fmt(it, f), Self::CssParenthesizedExpression(it) => std::fmt::Debug::fmt(it, f), + Self::CssUnaryExpression(it) => std::fmt::Debug::fmt(it, f), } } } @@ -26750,6 +27262,7 @@ impl From for SyntaxNode { AnyCssExpression::CssCommaSeparatedValue(it) => it.into_syntax(), AnyCssExpression::CssListOfComponentValuesExpression(it) => it.into_syntax(), AnyCssExpression::CssParenthesizedExpression(it) => it.into_syntax(), + AnyCssExpression::CssUnaryExpression(it) => it.into_syntax(), } } } @@ -27049,6 +27562,66 @@ impl From for SyntaxElement { node.into() } } +impl From for AnyCssFunctionName { + fn from(node: CssIdentifier) -> Self { + Self::CssIdentifier(node) + } +} +impl From for AnyCssFunctionName { + fn from(node: ScssQualifiedName) -> Self { + Self::ScssQualifiedName(node) + } +} +impl AstNode for AnyCssFunctionName { + type Language = Language; + const KIND_SET: SyntaxKindSet = + CssIdentifier::KIND_SET.union(ScssQualifiedName::KIND_SET); + fn can_cast(kind: SyntaxKind) -> bool { + matches!(kind, CSS_IDENTIFIER | SCSS_QUALIFIED_NAME) + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + CSS_IDENTIFIER => Self::CssIdentifier(CssIdentifier { syntax }), + SCSS_QUALIFIED_NAME => Self::ScssQualifiedName(ScssQualifiedName { syntax }), + _ => return None, + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { + match self { + Self::CssIdentifier(it) => it.syntax(), + Self::ScssQualifiedName(it) => it.syntax(), + } + } + fn into_syntax(self) -> SyntaxNode { + match self { + Self::CssIdentifier(it) => it.into_syntax(), + Self::ScssQualifiedName(it) => it.into_syntax(), + } + } +} +impl std::fmt::Debug for AnyCssFunctionName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::CssIdentifier(it) => std::fmt::Debug::fmt(it, f), + Self::ScssQualifiedName(it) => std::fmt::Debug::fmt(it, f), + } + } +} +impl From for SyntaxNode { + fn from(n: AnyCssFunctionName) -> Self { + match n { + AnyCssFunctionName::CssIdentifier(it) => it.into_syntax(), + AnyCssFunctionName::ScssQualifiedName(it) => it.into_syntax(), + } + } +} +impl From for SyntaxElement { + fn from(n: AnyCssFunctionName) -> Self { + let node: SyntaxNode = n.into(); + node.into() + } +} impl From for AnyCssFunctionParameter { fn from(node: CssBogusFunctionParameter) -> Self { Self::CssBogusFunctionParameter(node) @@ -29188,13 +29761,25 @@ impl From for AnyCssPageAtRuleItem { Self::CssMarginAtRule(node) } } +impl From for AnyCssPageAtRuleItem { + fn from(node: ScssDeclaration) -> Self { + Self::ScssDeclaration(node) + } +} +impl From for AnyCssPageAtRuleItem { + fn from(node: ScssNestingDeclaration) -> Self { + Self::ScssNestingDeclaration(node) + } +} impl AstNode for AnyCssPageAtRuleItem { type Language = Language; const KIND_SET: SyntaxKindSet = CssAtRule::KIND_SET .union(CssBogus::KIND_SET) .union(CssDeclarationWithSemicolon::KIND_SET) .union(CssEmptyDeclaration::KIND_SET) - .union(CssMarginAtRule::KIND_SET); + .union(CssMarginAtRule::KIND_SET) + .union(ScssDeclaration::KIND_SET) + .union(ScssNestingDeclaration::KIND_SET); fn can_cast(kind: SyntaxKind) -> bool { matches!( kind, @@ -29203,6 +29788,8 @@ impl AstNode for AnyCssPageAtRuleItem { | CSS_DECLARATION_WITH_SEMICOLON | CSS_EMPTY_DECLARATION | CSS_MARGIN_AT_RULE + | SCSS_DECLARATION + | SCSS_NESTING_DECLARATION ) } fn cast(syntax: SyntaxNode) -> Option { @@ -29214,6 +29801,10 @@ impl AstNode for AnyCssPageAtRuleItem { } CSS_EMPTY_DECLARATION => Self::CssEmptyDeclaration(CssEmptyDeclaration { syntax }), CSS_MARGIN_AT_RULE => Self::CssMarginAtRule(CssMarginAtRule { syntax }), + SCSS_DECLARATION => Self::ScssDeclaration(ScssDeclaration { syntax }), + SCSS_NESTING_DECLARATION => { + Self::ScssNestingDeclaration(ScssNestingDeclaration { syntax }) + } _ => return None, }; Some(res) @@ -29225,6 +29816,8 @@ impl AstNode for AnyCssPageAtRuleItem { Self::CssDeclarationWithSemicolon(it) => it.syntax(), Self::CssEmptyDeclaration(it) => it.syntax(), Self::CssMarginAtRule(it) => it.syntax(), + Self::ScssDeclaration(it) => it.syntax(), + Self::ScssNestingDeclaration(it) => it.syntax(), } } fn into_syntax(self) -> SyntaxNode { @@ -29234,6 +29827,8 @@ impl AstNode for AnyCssPageAtRuleItem { Self::CssDeclarationWithSemicolon(it) => it.into_syntax(), Self::CssEmptyDeclaration(it) => it.into_syntax(), Self::CssMarginAtRule(it) => it.into_syntax(), + Self::ScssDeclaration(it) => it.into_syntax(), + Self::ScssNestingDeclaration(it) => it.into_syntax(), } } } @@ -29245,6 +29840,8 @@ impl std::fmt::Debug for AnyCssPageAtRuleItem { Self::CssDeclarationWithSemicolon(it) => std::fmt::Debug::fmt(it, f), Self::CssEmptyDeclaration(it) => std::fmt::Debug::fmt(it, f), Self::CssMarginAtRule(it) => std::fmt::Debug::fmt(it, f), + Self::ScssDeclaration(it) => std::fmt::Debug::fmt(it, f), + Self::ScssNestingDeclaration(it) => std::fmt::Debug::fmt(it, f), } } } @@ -29256,6 +29853,8 @@ impl From for SyntaxNode { AnyCssPageAtRuleItem::CssDeclarationWithSemicolon(it) => it.into_syntax(), AnyCssPageAtRuleItem::CssEmptyDeclaration(it) => it.into_syntax(), AnyCssPageAtRuleItem::CssMarginAtRule(it) => it.into_syntax(), + AnyCssPageAtRuleItem::ScssDeclaration(it) => it.into_syntax(), + AnyCssPageAtRuleItem::ScssNestingDeclaration(it) => it.into_syntax(), } } } @@ -31881,6 +32480,11 @@ impl From for AnyCssValue { Self::ScssIdentifier(node) } } +impl From for AnyCssValue { + fn from(node: ScssQualifiedName) -> Self { + Self::ScssQualifiedName(node) + } +} impl From for AnyCssValue { fn from(node: TwValueThemeReference) -> Self { Self::TwValueThemeReference(node) @@ -31901,6 +32505,7 @@ impl AstNode for AnyCssValue { .union(CssString::KIND_SET) .union(CssUnicodeRange::KIND_SET) .union(ScssIdentifier::KIND_SET) + .union(ScssQualifiedName::KIND_SET) .union(TwValueThemeReference::KIND_SET); fn can_cast(kind: SyntaxKind) -> bool { match kind { @@ -31915,6 +32520,7 @@ impl AstNode for AnyCssValue { | CSS_STRING | CSS_UNICODE_RANGE | SCSS_IDENTIFIER + | SCSS_QUALIFIED_NAME | TW_VALUE_THEME_REFERENCE => true, k if AnyCssDimension::can_cast(k) => true, k if AnyCssFunction::can_cast(k) => true, @@ -31934,6 +32540,7 @@ impl AstNode for AnyCssValue { CSS_STRING => Self::CssString(CssString { syntax }), CSS_UNICODE_RANGE => Self::CssUnicodeRange(CssUnicodeRange { syntax }), SCSS_IDENTIFIER => Self::ScssIdentifier(ScssIdentifier { syntax }), + SCSS_QUALIFIED_NAME => Self::ScssQualifiedName(ScssQualifiedName { syntax }), TW_VALUE_THEME_REFERENCE => { Self::TwValueThemeReference(TwValueThemeReference { syntax }) } @@ -31965,6 +32572,7 @@ impl AstNode for AnyCssValue { Self::CssString(it) => it.syntax(), Self::CssUnicodeRange(it) => it.syntax(), Self::ScssIdentifier(it) => it.syntax(), + Self::ScssQualifiedName(it) => it.syntax(), Self::TwValueThemeReference(it) => it.syntax(), Self::AnyCssDimension(it) => it.syntax(), Self::AnyCssFunction(it) => it.syntax(), @@ -31983,6 +32591,7 @@ impl AstNode for AnyCssValue { Self::CssString(it) => it.into_syntax(), Self::CssUnicodeRange(it) => it.into_syntax(), Self::ScssIdentifier(it) => it.into_syntax(), + Self::ScssQualifiedName(it) => it.into_syntax(), Self::TwValueThemeReference(it) => it.into_syntax(), Self::AnyCssDimension(it) => it.into_syntax(), Self::AnyCssFunction(it) => it.into_syntax(), @@ -32005,6 +32614,7 @@ impl std::fmt::Debug for AnyCssValue { Self::CssString(it) => std::fmt::Debug::fmt(it, f), Self::CssUnicodeRange(it) => std::fmt::Debug::fmt(it, f), Self::ScssIdentifier(it) => std::fmt::Debug::fmt(it, f), + Self::ScssQualifiedName(it) => std::fmt::Debug::fmt(it, f), Self::TwValueThemeReference(it) => std::fmt::Debug::fmt(it, f), } } @@ -32025,6 +32635,7 @@ impl From for SyntaxNode { AnyCssValue::CssString(it) => it.into_syntax(), AnyCssValue::CssUnicodeRange(it) => it.into_syntax(), AnyCssValue::ScssIdentifier(it) => it.into_syntax(), + AnyCssValue::ScssQualifiedName(it) => it.into_syntax(), AnyCssValue::TwValueThemeReference(it) => it.into_syntax(), } } @@ -32359,6 +32970,66 @@ impl From for SyntaxElement { node.into() } } +impl From for AnyScssModuleMember { + fn from(node: CssIdentifier) -> Self { + Self::CssIdentifier(node) + } +} +impl From for AnyScssModuleMember { + fn from(node: ScssIdentifier) -> Self { + Self::ScssIdentifier(node) + } +} +impl AstNode for AnyScssModuleMember { + type Language = Language; + const KIND_SET: SyntaxKindSet = + CssIdentifier::KIND_SET.union(ScssIdentifier::KIND_SET); + fn can_cast(kind: SyntaxKind) -> bool { + matches!(kind, CSS_IDENTIFIER | SCSS_IDENTIFIER) + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + CSS_IDENTIFIER => Self::CssIdentifier(CssIdentifier { syntax }), + SCSS_IDENTIFIER => Self::ScssIdentifier(ScssIdentifier { syntax }), + _ => return None, + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { + match self { + Self::CssIdentifier(it) => it.syntax(), + Self::ScssIdentifier(it) => it.syntax(), + } + } + fn into_syntax(self) -> SyntaxNode { + match self { + Self::CssIdentifier(it) => it.into_syntax(), + Self::ScssIdentifier(it) => it.into_syntax(), + } + } +} +impl std::fmt::Debug for AnyScssModuleMember { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::CssIdentifier(it) => std::fmt::Debug::fmt(it, f), + Self::ScssIdentifier(it) => std::fmt::Debug::fmt(it, f), + } + } +} +impl From for SyntaxNode { + fn from(n: AnyScssModuleMember) -> Self { + match n { + AnyScssModuleMember::CssIdentifier(it) => it.into_syntax(), + AnyScssModuleMember::ScssIdentifier(it) => it.into_syntax(), + } + } +} +impl From for SyntaxElement { + fn from(n: AnyScssModuleMember) -> Self { + let node: SyntaxNode = n.into(); + node.into() + } +} impl From for AnyTwCustomVariantSelector { fn from(node: TwCustomVariantShorthand) -> Self { Self::TwCustomVariantShorthand(node) @@ -32635,6 +33306,11 @@ impl std::fmt::Display for AnyCssAttributeMatcherValue { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for AnyCssBracketedValueItem { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for AnyCssComposesImportSource { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -32765,6 +33441,11 @@ impl std::fmt::Display for AnyCssFunction { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for AnyCssFunctionName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for AnyCssFunctionParameter { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -33110,6 +33791,11 @@ impl std::fmt::Display for AnyScssDeclarationName { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for AnyScssModuleMember { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for AnyTwCustomVariantSelector { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -34050,6 +34736,11 @@ impl std::fmt::Display for CssTypeSelector { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for CssUnaryExpression { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for CssUnicodeCodepoint { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -34175,6 +34866,16 @@ impl std::fmt::Display for ScssNamespacedIdentifier { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for ScssNestingDeclaration { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for ScssQualifiedName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for ScssVariableModifier { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -36347,7 +37048,7 @@ impl Serialize for CssBracketedValueList { } impl AstNodeList for CssBracketedValueList { type Language = Language; - type Node = AnyCssCustomIdentifier; + type Node = AnyCssBracketedValueItem; fn syntax_list(&self) -> &SyntaxList { &self.syntax_list } @@ -36362,15 +37063,15 @@ impl Debug for CssBracketedValueList { } } impl IntoIterator for &CssBracketedValueList { - type Item = AnyCssCustomIdentifier; - type IntoIter = AstNodeListIterator; + type Item = AnyCssBracketedValueItem; + type IntoIter = AstNodeListIterator; fn into_iter(self) -> Self::IntoIter { self.iter() } } impl IntoIterator for CssBracketedValueList { - type Item = AnyCssCustomIdentifier; - type IntoIter = AstNodeListIterator; + type Item = AnyCssBracketedValueItem; + type IntoIter = AstNodeListIterator; fn into_iter(self) -> Self::IntoIter { self.iter() } diff --git a/crates/biome_css_syntax/src/generated/nodes_mut.rs b/crates/biome_css_syntax/src/generated/nodes_mut.rs index 9a6ef466a0d0..8113578a7d48 100644 --- a/crates/biome_css_syntax/src/generated/nodes_mut.rs +++ b/crates/biome_css_syntax/src/generated/nodes_mut.rs @@ -930,7 +930,7 @@ impl CssFontPaletteValuesAtRuleDeclarator { } } impl CssFunction { - pub fn with_name(self, element: CssIdentifier) -> Self { + pub fn with_name(self, element: AnyCssFunctionName) -> Self { Self::unwrap_cast( self.syntax .splice_slots(0usize..=0usize, once(Some(element.into_syntax().into()))), @@ -3137,6 +3137,20 @@ impl CssTypeSelector { ) } } +impl CssUnaryExpression { + pub fn with_operator_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } + pub fn with_expression(self, element: AnyCssExpression) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into_syntax().into()))), + ) + } +} impl CssUnicodeCodepoint { pub fn with_value_token(self, element: SyntaxToken) -> Self { Self::unwrap_cast( @@ -3511,6 +3525,52 @@ impl ScssNamespacedIdentifier { ) } } +impl ScssNestingDeclaration { + pub fn with_name(self, element: CssIdentifier) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_colon_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into()))), + ) + } + pub fn with_value(self, element: CssGenericComponentValueList) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(2usize..=2usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_block(self, element: AnyCssDeclarationOrRuleBlock) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(3usize..=3usize, once(Some(element.into_syntax().into()))), + ) + } +} +impl ScssQualifiedName { + pub fn with_module(self, element: CssIdentifier) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_dot_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into()))), + ) + } + pub fn with_member(self, element: AnyScssModuleMember) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(2usize..=2usize, once(Some(element.into_syntax().into()))), + ) + } +} impl ScssVariableModifier { pub fn with_excl_token(self, element: SyntaxToken) -> Self { Self::unwrap_cast( diff --git a/crates/biome_css_syntax/src/lib.rs b/crates/biome_css_syntax/src/lib.rs index ff793a1d1221..d73a68a7ac7e 100644 --- a/crates/biome_css_syntax/src/lib.rs +++ b/crates/biome_css_syntax/src/lib.rs @@ -132,6 +132,7 @@ impl biome_rowan::SyntaxKind for CssSyntaxKind { kind if AnyCssDeclarationOrRuleBlock::can_cast(*kind) => CSS_BOGUS_BLOCK, kind if AnyCssConditionalBlock::can_cast(*kind) => CSS_BOGUS_BLOCK, kind if AnyCssFontFeatureValuesBlock::can_cast(*kind) => CSS_BOGUS_BLOCK, + kind if AnyCssPageAtRuleBlock::can_cast(*kind) => CSS_BOGUS_BLOCK, kind if AnyCssUnicodeValue::can_cast(*kind) => CSS_BOGUS_UNICODE_RANGE_VALUE, kind if AnyCssSupportsCondition::can_cast(*kind) => CSS_BOGUS_SUPPORTS_CONDITION, kind if AnyCssIfBranch::can_cast(*kind) => CSS_BOGUS_IF_BRANCH, diff --git a/crates/biome_graphql_parser/src/lexer/mod.rs b/crates/biome_graphql_parser/src/lexer/mod.rs index 7df9eba7b60c..7537ac2bfc28 100644 --- a/crates/biome_graphql_parser/src/lexer/mod.rs +++ b/crates/biome_graphql_parser/src/lexer/mod.rs @@ -128,6 +128,7 @@ impl<'src> LexerWithCheckpoint<'src> for GraphqlLexer<'src> { current_flags: self.current_flags, current_kind: self.current_kind, after_line_break: self.has_preceding_line_break(), + after_whitespace: false, unicode_bom_length: self.unicode_bom_length, diagnostics_pos: self.diagnostics.len() as u32, } diff --git a/crates/biome_grit_patterns/src/grit_target_language/css_target_language/generated_mappings.rs b/crates/biome_grit_patterns/src/grit_target_language/css_target_language/generated_mappings.rs index b6b4f0f79549..20ce3fb1bb3f 100644 --- a/crates/biome_grit_patterns/src/grit_target_language/css_target_language/generated_mappings.rs +++ b/crates/biome_grit_patterns/src/grit_target_language/css_target_language/generated_mappings.rs @@ -241,6 +241,7 @@ pub fn kind_by_name(node_name: &str) -> Option { "CssSyntaxType" => lang::CssSyntaxType::KIND_SET.iter().next(), "CssTypeFunction" => lang::CssTypeFunction::KIND_SET.iter().next(), "CssTypeSelector" => lang::CssTypeSelector::KIND_SET.iter().next(), + "CssUnaryExpression" => lang::CssUnaryExpression::KIND_SET.iter().next(), "CssUnicodeCodepoint" => lang::CssUnicodeCodepoint::KIND_SET.iter().next(), "CssUnicodeRange" => lang::CssUnicodeRange::KIND_SET.iter().next(), "CssUnicodeRangeInterval" => lang::CssUnicodeRangeInterval::KIND_SET.iter().next(), @@ -276,6 +277,8 @@ pub fn kind_by_name(node_name: &str) -> Option { "ScssDeclaration" => lang::ScssDeclaration::KIND_SET.iter().next(), "ScssIdentifier" => lang::ScssIdentifier::KIND_SET.iter().next(), "ScssNamespacedIdentifier" => lang::ScssNamespacedIdentifier::KIND_SET.iter().next(), + "ScssNestingDeclaration" => lang::ScssNestingDeclaration::KIND_SET.iter().next(), + "ScssQualifiedName" => lang::ScssQualifiedName::KIND_SET.iter().next(), "ScssVariableModifier" => lang::ScssVariableModifier::KIND_SET.iter().next(), "TwApplyAtRule" => lang::TwApplyAtRule::KIND_SET.iter().next(), "TwConfigAtRule" => lang::TwConfigAtRule::KIND_SET.iter().next(), diff --git a/crates/biome_html_parser/src/lexer/mod.rs b/crates/biome_html_parser/src/lexer/mod.rs index b48bebb10d80..1c46d6fd554b 100644 --- a/crates/biome_html_parser/src/lexer/mod.rs +++ b/crates/biome_html_parser/src/lexer/mod.rs @@ -1316,6 +1316,7 @@ impl<'src> Lexer<'src> for HtmlLexer<'src> { current_flags, current_kind, after_line_break, + after_whitespace: _, unicode_bom_length, diagnostics_pos, } = checkpoint; @@ -1453,6 +1454,7 @@ impl<'src> LexerWithCheckpoint<'src> for HtmlLexer<'src> { current_flags: self.current_flags, current_kind: self.current_kind, after_line_break: self.after_newline, + after_whitespace: false, unicode_bom_length: self.unicode_bom_length, diagnostics_pos: self.diagnostics.len() as u32, } diff --git a/crates/biome_js_parser/src/lexer/mod.rs b/crates/biome_js_parser/src/lexer/mod.rs index 40ea38cae8b0..33019216a753 100644 --- a/crates/biome_js_parser/src/lexer/mod.rs +++ b/crates/biome_js_parser/src/lexer/mod.rs @@ -209,6 +209,7 @@ impl<'src> Lexer<'src> for JsLexer<'src> { current_flags, current_kind, after_line_break, + after_whitespace: _, unicode_bom_length, diagnostics_pos, } = checkpoint; @@ -292,6 +293,7 @@ impl<'src> LexerWithCheckpoint<'src> for JsLexer<'src> { current_flags: self.current_flags, current_kind: self.current_kind, after_line_break: self.after_newline, + after_whitespace: false, unicode_bom_length: self.unicode_bom_length, diagnostics_pos: self.diagnostics.len() as u32, } diff --git a/crates/biome_markdown_parser/src/lexer/mod.rs b/crates/biome_markdown_parser/src/lexer/mod.rs index 0f21aa144a5a..05d9b2b6c3e0 100644 --- a/crates/biome_markdown_parser/src/lexer/mod.rs +++ b/crates/biome_markdown_parser/src/lexer/mod.rs @@ -177,6 +177,7 @@ impl<'src> Lexer<'src> for MarkdownLexer<'src> { current_flags, current_kind, after_line_break, + after_whitespace: _, unicode_bom_length, diagnostics_pos, } = checkpoint; @@ -1268,6 +1269,7 @@ impl<'src> LexerWithCheckpoint<'src> for MarkdownLexer<'src> { current_flags: self.current_flags, current_kind: self.current_kind, after_line_break: self.after_newline, + after_whitespace: false, unicode_bom_length: self.unicode_bom_length, diagnostics_pos: self.diagnostics.len() as u32, } diff --git a/crates/biome_parser/src/lexer.rs b/crates/biome_parser/src/lexer.rs index 0e4ed39f6368..c6c37df10b07 100644 --- a/crates/biome_parser/src/lexer.rs +++ b/crates/biome_parser/src/lexer.rs @@ -655,6 +655,7 @@ where current_kind: Lex::Kind::EOF, current_flags: TokenFlags::empty(), after_line_break: checkpoint.after_line_break, + after_whitespace: checkpoint.after_whitespace, unicode_bom_length: checkpoint.unicode_bom_length, diagnostics_pos: checkpoint.diagnostics_pos, }; @@ -784,6 +785,10 @@ impl LookaheadToken { pub fn has_preceding_line_break(&self) -> bool { self.flags.has_preceding_line_break() } + + pub fn has_preceding_whitespace(&self) -> bool { + self.flags.has_preceding_whitespace() + } } impl From<&LexerCheckpoint> for LookaheadToken { @@ -803,6 +808,7 @@ pub struct LexerCheckpoint { pub current_kind: Kind, pub current_flags: TokenFlags, pub after_line_break: bool, + pub after_whitespace: bool, pub unicode_bom_length: usize, pub diagnostics_pos: u32, } @@ -828,6 +834,7 @@ impl LexerCheckpoint { enum TokenFlag { PrecedingLineBreak = 1 << 0, UnicodeEscape = 1 << 1, + PrecedingWhitespace = 1 << 2, } /// Flags for a lexed token. @@ -841,6 +848,10 @@ impl TokenFlags { /// Indicates that an identifier contains an unicode escape sequence pub const UNICODE_ESCAPE: Self = Self(make_bitflags!(TokenFlag::{UnicodeEscape})); + /// Indicates that there has been a whitespace token between the last + /// non-trivia token and the current token. + pub const PRECEDING_WHITESPACE: Self = Self(make_bitflags!(TokenFlag::{PrecedingWhitespace})); + pub const fn empty() -> Self { Self(BitFlags::EMPTY) } @@ -860,6 +871,10 @@ impl TokenFlags { pub fn has_unicode_escape(&self) -> bool { self.contains(Self::UNICODE_ESCAPE) } + + pub fn has_preceding_whitespace(&self) -> bool { + self.contains(Self::PRECEDING_WHITESPACE) + } } impl BitOr for TokenFlags { diff --git a/crates/biome_tailwind_parser/src/lexer/mod.rs b/crates/biome_tailwind_parser/src/lexer/mod.rs index 75c8f8ffdb9d..f9d6784d2090 100644 --- a/crates/biome_tailwind_parser/src/lexer/mod.rs +++ b/crates/biome_tailwind_parser/src/lexer/mod.rs @@ -330,6 +330,7 @@ impl<'src> Lexer<'src> for TailwindLexer<'src> { current_flags, current_kind, after_line_break, + after_whitespace: _, unicode_bom_length, diagnostics_pos, } = checkpoint; @@ -375,6 +376,7 @@ impl<'src> LexerWithCheckpoint<'src> for TailwindLexer<'src> { current_flags: self.current_flags, current_kind: self.current_kind, after_line_break: self.after_newline, + after_whitespace: false, unicode_bom_length: self.unicode_bom_length, diagnostics_pos: self.diagnostics.len() as u32, } diff --git a/xtask/codegen/css.ungram b/xtask/codegen/css.ungram index 907f7ac14dba..2a93292948d4 100644 --- a/xtask/codegen/css.ungram +++ b/xtask/codegen/css.ungram @@ -493,6 +493,7 @@ AnyCssDeclarationOrRule = AnyCssRule | CssDeclarationWithSemicolon | ScssDeclaration + | ScssNestingDeclaration | CssEmptyDeclaration | CssBogus | CssMetavariable @@ -513,6 +514,7 @@ CssDeclarationOrAtRuleList = AnyCssDeclarationOrAtRule* AnyCssDeclarationOrAtRule = CssDeclarationWithSemicolon | ScssDeclaration + | ScssNestingDeclaration | CssEmptyDeclaration | CssAtRule @@ -547,6 +549,7 @@ CssDeclarationList = AnyCssDeclaration* AnyCssDeclaration = CssDeclarationWithSemicolon | ScssDeclaration + | ScssNestingDeclaration | CssEmptyDeclaration AnyCssRuleBlock = @@ -1367,6 +1370,8 @@ CssPageAtRuleItemList = AnyCssPageAtRuleItem* AnyCssPageAtRuleItem = CssDeclarationWithSemicolon + | ScssDeclaration + | ScssNestingDeclaration | CssEmptyDeclaration | CssAtRule | CssMarginAtRule @@ -1845,6 +1850,7 @@ AnyCssValue = | CssMetavariable | TwValueThemeReference | ScssIdentifier + | ScssQualifiedName // https://drafts.csswg.org/css-syntax/#typedef-dimension-token @@ -1897,11 +1903,15 @@ AnyCssFunction = // content: counter(section); // ^^^^^^^^^^^^^^^^ CssFunction = - name: CssIdentifier + name: AnyCssFunctionName '(' items: CssParameterList ')' +AnyCssFunctionName = + CssIdentifier + | ScssQualifiedName + // https://drafts.csswg.org/css-values-4/#url-value // = | // @@ -2076,6 +2086,7 @@ AnyCssIfTest = AnyCssExpression = CssBinaryExpression + | CssUnaryExpression | CssParenthesizedExpression | CssListOfComponentValuesExpression | CssCommaSeparatedValue @@ -2094,6 +2105,10 @@ CssBinaryExpression = ) right: AnyCssExpression +CssUnaryExpression = + operator: ('+' | '-' | '*') + expression: AnyCssExpression + CssParenthesizedExpression = '(' expression: AnyCssExpression? ')' @@ -2113,7 +2128,11 @@ CssBracketedValue = items: CssBracketedValueList ']' -CssBracketedValueList = AnyCssCustomIdentifier* +CssBracketedValueList = AnyCssBracketedValueItem* + +AnyCssBracketedValueItem = + AnyCssCustomIdentifier + | CssGenericDelimiter AnyCssCustomIdentifier = CssCustomIdentifier @@ -2482,6 +2501,25 @@ ScssNamespacedIdentifier = '.' name: ScssIdentifier +// font: { family: sans-serif; size: 12px; } +// ^^^^ +ScssNestingDeclaration = + name: CssIdentifier + ':' + value: CssGenericComponentValueList + block: AnyCssDeclarationOrRuleBlock + +// color: module.$var; +// ^^^^^^^^^^^ +ScssQualifiedName = + module: CssIdentifier + '.' + member: AnyScssModuleMember + +AnyScssModuleMember = + CssIdentifier + | ScssIdentifier + // $var: 1 !default !global; // ^^^^^^^^^^^^^^^^ ScssVariableModifierList = ScssVariableModifier* diff --git a/xtask/codegen/src/css_kinds_src.rs b/xtask/codegen/src/css_kinds_src.rs index a56d83d9f31c..cff7fa97592c 100644 --- a/xtask/codegen/src/css_kinds_src.rs +++ b/xtask/codegen/src/css_kinds_src.rs @@ -398,6 +398,7 @@ pub const CSS_KINDS_SRC: KindsSrc = KindsSrc { "CSS_LIST_OF_COMPONENT_VALUES_EXPRESSION", "CSS_COMMA_SEPARATED_VALUE", "CSS_BINARY_EXPRESSION", + "CSS_UNARY_EXPRESSION", "CSS_URL_VALUE_RAW", "CSS_URL_FUNCTION", "CSS_IF_FUNCTION", @@ -566,7 +567,9 @@ pub const CSS_KINDS_SRC: KindsSrc = KindsSrc { "CSS_RETURNS_STATEMENT", // SCSS "SCSS_DECLARATION", + "SCSS_NESTING_DECLARATION", "SCSS_NAMESPACED_IDENTIFIER", + "SCSS_QUALIFIED_NAME", "SCSS_VARIABLE_MODIFIER_LIST", "SCSS_VARIABLE_MODIFIER", "SCSS_IDENTIFIER",