diff --git a/crates/biome_css_factory/src/generated/node_factory.rs b/crates/biome_css_factory/src/generated/node_factory.rs index c391ea2fbc4d..3c1834db6053 100644 --- a/crates/biome_css_factory/src/generated/node_factory.rs +++ b/crates/biome_css_factory/src/generated/node_factory.rs @@ -13,214 +13,12 @@ pub fn css_any_function(css_simple_function: CssSimpleFunction) -> CssAnyFunctio [Some(SyntaxElement::Node(css_simple_function.into_syntax()))], )) } -pub fn css_at_keyframes( - at_token: SyntaxToken, - keyframes_token: SyntaxToken, - name: CssIdentifier, - css_string: CssString, - body: CssAtKeyframesBody, -) -> CssAtKeyframes { - CssAtKeyframes::unwrap_cast(SyntaxNode::new_detached( - CssSyntaxKind::CSS_AT_KEYFRAMES, +pub fn css_at_rule(at_token: SyntaxToken, rule: AnyCssAtRule) -> CssAtRule { + CssAtRule::unwrap_cast(SyntaxNode::new_detached( + CssSyntaxKind::CSS_AT_RULE, [ Some(SyntaxElement::Token(at_token)), - Some(SyntaxElement::Token(keyframes_token)), - Some(SyntaxElement::Node(name.into_syntax())), - Some(SyntaxElement::Node(css_string.into_syntax())), - Some(SyntaxElement::Node(body.into_syntax())), - ], - )) -} -pub fn css_at_keyframes_body( - l_curly_token: SyntaxToken, - items: CssAtKeyframesItemList, - r_curly_token: SyntaxToken, -) -> CssAtKeyframesBody { - CssAtKeyframesBody::unwrap_cast(SyntaxNode::new_detached( - CssSyntaxKind::CSS_AT_KEYFRAMES_BODY, - [ - Some(SyntaxElement::Token(l_curly_token)), - Some(SyntaxElement::Node(items.into_syntax())), - Some(SyntaxElement::Token(r_curly_token)), - ], - )) -} -pub fn css_at_media( - at_token: SyntaxToken, - media_token: SyntaxToken, - query_list: CssAtMediaQueryList, - l_curly_token: SyntaxToken, - body: AnyCssRule, - r_curly_token: SyntaxToken, -) -> CssAtMedia { - CssAtMedia::unwrap_cast(SyntaxNode::new_detached( - CssSyntaxKind::CSS_AT_MEDIA, - [ - Some(SyntaxElement::Token(at_token)), - Some(SyntaxElement::Token(media_token)), - Some(SyntaxElement::Node(query_list.into_syntax())), - Some(SyntaxElement::Token(l_curly_token)), - Some(SyntaxElement::Node(body.into_syntax())), - Some(SyntaxElement::Token(r_curly_token)), - ], - )) -} -pub fn css_at_media_query( - condition_token: SyntaxToken, - or_token: SyntaxToken, - ty: AnyCssAtMediaQueryType, -) -> CssAtMediaQueryBuilder { - CssAtMediaQueryBuilder { - condition_token, - or_token, - ty, - only_token: None, - consequent: None, - } -} -pub struct CssAtMediaQueryBuilder { - condition_token: SyntaxToken, - or_token: SyntaxToken, - ty: AnyCssAtMediaQueryType, - only_token: Option, - consequent: Option, -} -impl CssAtMediaQueryBuilder { - pub fn with_only_token(mut self, only_token: SyntaxToken) -> Self { - self.only_token = Some(only_token); - self - } - pub fn with_consequent(mut self, consequent: CssAtMediaQueryConsequent) -> Self { - self.consequent = Some(consequent); - self - } - pub fn build(self) -> CssAtMediaQuery { - CssAtMediaQuery::unwrap_cast(SyntaxNode::new_detached( - CssSyntaxKind::CSS_AT_MEDIA_QUERY, - [ - Some(SyntaxElement::Token(self.condition_token)), - Some(SyntaxElement::Token(self.or_token)), - self.only_token.map(|token| SyntaxElement::Token(token)), - Some(SyntaxElement::Node(self.ty.into_syntax())), - self.consequent - .map(|token| SyntaxElement::Node(token.into_syntax())), - ], - )) - } -} -pub fn css_at_media_query_consequent( - and_token: SyntaxToken, - ty: AnyCssAtMediaQueryType, -) -> CssAtMediaQueryConsequentBuilder { - CssAtMediaQueryConsequentBuilder { - and_token, - ty, - condition_token: None, - } -} -pub struct CssAtMediaQueryConsequentBuilder { - and_token: SyntaxToken, - ty: AnyCssAtMediaQueryType, - condition_token: Option, -} -impl CssAtMediaQueryConsequentBuilder { - pub fn with_condition_token(mut self, condition_token: SyntaxToken) -> Self { - self.condition_token = Some(condition_token); - self - } - pub fn build(self) -> CssAtMediaQueryConsequent { - CssAtMediaQueryConsequent::unwrap_cast(SyntaxNode::new_detached( - CssSyntaxKind::CSS_AT_MEDIA_QUERY_CONSEQUENT, - [ - Some(SyntaxElement::Token(self.and_token)), - self.condition_token - .map(|token| SyntaxElement::Token(token)), - Some(SyntaxElement::Node(self.ty.into_syntax())), - ], - )) - } -} -pub fn css_at_media_query_feature( - l_paren_token: SyntaxToken, - feature: AnyCssAtMediaQueryFeatureType, - r_paren_token: SyntaxToken, -) -> CssAtMediaQueryFeature { - CssAtMediaQueryFeature::unwrap_cast(SyntaxNode::new_detached( - CssSyntaxKind::CSS_AT_MEDIA_QUERY_FEATURE, - [ - Some(SyntaxElement::Token(l_paren_token)), - Some(SyntaxElement::Node(feature.into_syntax())), - Some(SyntaxElement::Token(r_paren_token)), - ], - )) -} -pub fn css_at_media_query_feature_boolean( - css_identifier: CssIdentifier, -) -> CssAtMediaQueryFeatureBoolean { - CssAtMediaQueryFeatureBoolean::unwrap_cast(SyntaxNode::new_detached( - CssSyntaxKind::CSS_AT_MEDIA_QUERY_FEATURE_BOOLEAN, - [Some(SyntaxElement::Node(css_identifier.into_syntax()))], - )) -} -pub fn css_at_media_query_feature_compare( - name: CssIdentifier, - range: CssAtMediaQueryRange, - value: AnyCssValue, -) -> CssAtMediaQueryFeatureCompare { - CssAtMediaQueryFeatureCompare::unwrap_cast(SyntaxNode::new_detached( - CssSyntaxKind::CSS_AT_MEDIA_QUERY_FEATURE_COMPARE, - [ - Some(SyntaxElement::Node(name.into_syntax())), - Some(SyntaxElement::Node(range.into_syntax())), - Some(SyntaxElement::Node(value.into_syntax())), - ], - )) -} -pub fn css_at_media_query_feature_plain( - name: CssIdentifier, - colon_token: SyntaxToken, - value: AnyCssValue, -) -> CssAtMediaQueryFeaturePlain { - CssAtMediaQueryFeaturePlain::unwrap_cast(SyntaxNode::new_detached( - CssSyntaxKind::CSS_AT_MEDIA_QUERY_FEATURE_PLAIN, - [ - Some(SyntaxElement::Node(name.into_syntax())), - Some(SyntaxElement::Token(colon_token)), - Some(SyntaxElement::Node(value.into_syntax())), - ], - )) -} -pub fn css_at_media_query_feature_range( - first_value: AnyCssValue, - first_range: CssAtMediaQueryRange, - name: CssIdentifier, - second_value: AnyCssValue, - second_range: CssAtMediaQueryRange, -) -> CssAtMediaQueryFeatureRange { - CssAtMediaQueryFeatureRange::unwrap_cast(SyntaxNode::new_detached( - CssSyntaxKind::CSS_AT_MEDIA_QUERY_FEATURE_RANGE, - [ - Some(SyntaxElement::Node(first_value.into_syntax())), - Some(SyntaxElement::Node(first_range.into_syntax())), - Some(SyntaxElement::Node(name.into_syntax())), - Some(SyntaxElement::Node(second_value.into_syntax())), - Some(SyntaxElement::Node(second_range.into_syntax())), - ], - )) -} -pub fn css_at_media_query_range( - r_angle_token: SyntaxToken, - l_angle_token: SyntaxToken, - greater_than_equal_token: SyntaxToken, - less_than_equal_token: SyntaxToken, -) -> CssAtMediaQueryRange { - CssAtMediaQueryRange::unwrap_cast(SyntaxNode::new_detached( - CssSyntaxKind::CSS_AT_MEDIA_QUERY_RANGE, - [ - Some(SyntaxElement::Token(r_angle_token)), - Some(SyntaxElement::Token(l_angle_token)), - Some(SyntaxElement::Token(greater_than_equal_token)), - Some(SyntaxElement::Token(less_than_equal_token)), + Some(SyntaxElement::Node(rule.into_syntax())), ], )) } @@ -337,6 +135,20 @@ pub fn css_block( ], )) } +pub fn css_charset_at_rule( + charset_token: SyntaxToken, + encoding: CssString, + semicolon_token: SyntaxToken, +) -> CssCharsetAtRule { + CssCharsetAtRule::unwrap_cast(SyntaxNode::new_detached( + CssSyntaxKind::CSS_CHARSET_AT_RULE, + [ + Some(SyntaxElement::Token(charset_token)), + Some(SyntaxElement::Node(encoding.into_syntax())), + Some(SyntaxElement::Token(semicolon_token)), + ], + )) +} pub fn css_class_selector(dot_token: SyntaxToken, name: CssIdentifier) -> CssClassSelector { CssClassSelector::unwrap_cast(SyntaxNode::new_detached( CssSyntaxKind::CSS_CLASS_SELECTOR, @@ -476,6 +288,22 @@ pub fn css_identifier(value_token: SyntaxToken) -> CssIdentifier { [Some(SyntaxElement::Token(value_token))], )) } +pub fn css_keyframes_at_rule( + keyframes_token: SyntaxToken, + name: CssIdentifier, + css_string: CssString, + body: CssKeyframesBody, +) -> CssKeyframesAtRule { + CssKeyframesAtRule::unwrap_cast(SyntaxNode::new_detached( + CssSyntaxKind::CSS_KEYFRAMES_AT_RULE, + [ + Some(SyntaxElement::Token(keyframes_token)), + Some(SyntaxElement::Node(name.into_syntax())), + Some(SyntaxElement::Node(css_string.into_syntax())), + Some(SyntaxElement::Node(body.into_syntax())), + ], + )) +} pub fn css_keyframes_block( selectors: CssKeyframesSelectorList, l_curly_token: SyntaxToken, @@ -492,6 +320,20 @@ pub fn css_keyframes_block( ], )) } +pub fn css_keyframes_body( + l_curly_token: SyntaxToken, + items: CssKeyframesItemList, + r_curly_token: SyntaxToken, +) -> CssKeyframesBody { + CssKeyframesBody::unwrap_cast(SyntaxNode::new_detached( + CssSyntaxKind::CSS_KEYFRAMES_BODY, + [ + Some(SyntaxElement::Token(l_curly_token)), + Some(SyntaxElement::Node(items.into_syntax())), + Some(SyntaxElement::Token(r_curly_token)), + ], + )) +} pub fn css_keyframes_selector( from_token: SyntaxToken, to_token: SyntaxToken, @@ -506,6 +348,183 @@ pub fn css_keyframes_selector( ], )) } +pub fn css_media_at_rule( + media_token: SyntaxToken, + query_list: CssMediaQueryList, + l_curly_token: SyntaxToken, + body: AnyCssRule, + r_curly_token: SyntaxToken, +) -> CssMediaAtRule { + CssMediaAtRule::unwrap_cast(SyntaxNode::new_detached( + CssSyntaxKind::CSS_MEDIA_AT_RULE, + [ + Some(SyntaxElement::Token(media_token)), + Some(SyntaxElement::Node(query_list.into_syntax())), + Some(SyntaxElement::Token(l_curly_token)), + Some(SyntaxElement::Node(body.into_syntax())), + Some(SyntaxElement::Token(r_curly_token)), + ], + )) +} +pub fn css_media_query( + condition_token: SyntaxToken, + or_token: SyntaxToken, + ty: AnyCssMediaQueryType, +) -> CssMediaQueryBuilder { + CssMediaQueryBuilder { + condition_token, + or_token, + ty, + only_token: None, + consequent: None, + } +} +pub struct CssMediaQueryBuilder { + condition_token: SyntaxToken, + or_token: SyntaxToken, + ty: AnyCssMediaQueryType, + only_token: Option, + consequent: Option, +} +impl CssMediaQueryBuilder { + pub fn with_only_token(mut self, only_token: SyntaxToken) -> Self { + self.only_token = Some(only_token); + self + } + pub fn with_consequent(mut self, consequent: CssMediaQueryConsequent) -> Self { + self.consequent = Some(consequent); + self + } + pub fn build(self) -> CssMediaQuery { + CssMediaQuery::unwrap_cast(SyntaxNode::new_detached( + CssSyntaxKind::CSS_MEDIA_QUERY, + [ + Some(SyntaxElement::Token(self.condition_token)), + Some(SyntaxElement::Token(self.or_token)), + self.only_token.map(|token| SyntaxElement::Token(token)), + Some(SyntaxElement::Node(self.ty.into_syntax())), + self.consequent + .map(|token| SyntaxElement::Node(token.into_syntax())), + ], + )) + } +} +pub fn css_media_query_consequent( + and_token: SyntaxToken, + ty: AnyCssMediaQueryType, +) -> CssMediaQueryConsequentBuilder { + CssMediaQueryConsequentBuilder { + and_token, + ty, + condition_token: None, + } +} +pub struct CssMediaQueryConsequentBuilder { + and_token: SyntaxToken, + ty: AnyCssMediaQueryType, + condition_token: Option, +} +impl CssMediaQueryConsequentBuilder { + pub fn with_condition_token(mut self, condition_token: SyntaxToken) -> Self { + self.condition_token = Some(condition_token); + self + } + pub fn build(self) -> CssMediaQueryConsequent { + CssMediaQueryConsequent::unwrap_cast(SyntaxNode::new_detached( + CssSyntaxKind::CSS_MEDIA_QUERY_CONSEQUENT, + [ + Some(SyntaxElement::Token(self.and_token)), + self.condition_token + .map(|token| SyntaxElement::Token(token)), + Some(SyntaxElement::Node(self.ty.into_syntax())), + ], + )) + } +} +pub fn css_media_query_feature( + l_paren_token: SyntaxToken, + feature: AnyCssMediaQueryFeatureType, + r_paren_token: SyntaxToken, +) -> CssMediaQueryFeature { + CssMediaQueryFeature::unwrap_cast(SyntaxNode::new_detached( + CssSyntaxKind::CSS_MEDIA_QUERY_FEATURE, + [ + Some(SyntaxElement::Token(l_paren_token)), + Some(SyntaxElement::Node(feature.into_syntax())), + Some(SyntaxElement::Token(r_paren_token)), + ], + )) +} +pub fn css_media_query_feature_boolean( + css_identifier: CssIdentifier, +) -> CssMediaQueryFeatureBoolean { + CssMediaQueryFeatureBoolean::unwrap_cast(SyntaxNode::new_detached( + CssSyntaxKind::CSS_MEDIA_QUERY_FEATURE_BOOLEAN, + [Some(SyntaxElement::Node(css_identifier.into_syntax()))], + )) +} +pub fn css_media_query_feature_compare( + name: CssIdentifier, + range: CssMediaQueryRange, + value: AnyCssValue, +) -> CssMediaQueryFeatureCompare { + CssMediaQueryFeatureCompare::unwrap_cast(SyntaxNode::new_detached( + CssSyntaxKind::CSS_MEDIA_QUERY_FEATURE_COMPARE, + [ + Some(SyntaxElement::Node(name.into_syntax())), + Some(SyntaxElement::Node(range.into_syntax())), + Some(SyntaxElement::Node(value.into_syntax())), + ], + )) +} +pub fn css_media_query_feature_plain( + name: CssIdentifier, + colon_token: SyntaxToken, + value: AnyCssValue, +) -> CssMediaQueryFeaturePlain { + CssMediaQueryFeaturePlain::unwrap_cast(SyntaxNode::new_detached( + CssSyntaxKind::CSS_MEDIA_QUERY_FEATURE_PLAIN, + [ + Some(SyntaxElement::Node(name.into_syntax())), + Some(SyntaxElement::Token(colon_token)), + Some(SyntaxElement::Node(value.into_syntax())), + ], + )) +} +pub fn css_media_query_feature_range( + first_value: AnyCssValue, + first_range: CssMediaQueryRange, + name: CssIdentifier, + second_value: AnyCssValue, + second_range: CssMediaQueryRange, +) -> CssMediaQueryFeatureRange { + CssMediaQueryFeatureRange::unwrap_cast(SyntaxNode::new_detached( + CssSyntaxKind::CSS_MEDIA_QUERY_FEATURE_RANGE, + [ + Some(SyntaxElement::Node(first_value.into_syntax())), + Some(SyntaxElement::Node(first_range.into_syntax())), + Some(SyntaxElement::Node(name.into_syntax())), + Some(SyntaxElement::Node(second_value.into_syntax())), + Some(SyntaxElement::Node(second_range.into_syntax())), + ], + )) +} +pub fn css_media_query_range( + r_angle_token: SyntaxToken, + l_angle_token: SyntaxToken, + greater_than_equal_token: SyntaxToken, + less_than_equal_token: SyntaxToken, +) -> CssMediaQueryRange { + CssMediaQueryRange::unwrap_cast(SyntaxNode::new_detached( + CssSyntaxKind::CSS_MEDIA_QUERY_RANGE, + [ + Some(SyntaxElement::Token(r_angle_token)), + Some(SyntaxElement::Token(l_angle_token)), + Some(SyntaxElement::Token(greater_than_equal_token)), + Some(SyntaxElement::Token(less_than_equal_token)), + ], + )) +} pub fn css_named_namespace_prefix(name: CssIdentifier) -> CssNamedNamespacePrefix { CssNamedNamespacePrefix::unwrap_cast(SyntaxNode::new_detached( CssSyntaxKind::CSS_NAMED_NAMESPACE_PREFIX, @@ -1080,39 +1099,6 @@ pub fn css_var_function_value( ], )) } -pub fn css_at_keyframes_item_list(items: I) -> CssAtKeyframesItemList -where - I: IntoIterator, - I::IntoIter: ExactSizeIterator, -{ - CssAtKeyframesItemList::unwrap_cast(SyntaxNode::new_detached( - CssSyntaxKind::CSS_AT_KEYFRAMES_ITEM_LIST, - items - .into_iter() - .map(|item| Some(item.into_syntax().into())), - )) -} -pub fn css_at_media_query_list(items: I, separators: S) -> CssAtMediaQueryList -where - I: IntoIterator, - I::IntoIter: ExactSizeIterator, - S: IntoIterator, - S::IntoIter: ExactSizeIterator, -{ - let mut items = items.into_iter(); - let mut separators = separators.into_iter(); - let length = items.len() + separators.len(); - CssAtMediaQueryList::unwrap_cast(SyntaxNode::new_detached( - CssSyntaxKind::CSS_AT_MEDIA_QUERY_LIST, - (0..length).map(|index| { - if index % 2 == 0 { - Some(items.next()?.into_syntax().into()) - } else { - Some(separators.next()?.into()) - } - }), - )) -} pub fn css_compound_selector_list(items: I, separators: S) -> CssCompoundSelectorList where I: IntoIterator, @@ -1146,6 +1132,18 @@ where .map(|item| Some(item.into_syntax().into())), )) } +pub fn css_keyframes_item_list(items: I) -> CssKeyframesItemList +where + I: IntoIterator, + I::IntoIter: ExactSizeIterator, +{ + CssKeyframesItemList::unwrap_cast(SyntaxNode::new_detached( + CssSyntaxKind::CSS_KEYFRAMES_ITEM_LIST, + items + .into_iter() + .map(|item| Some(item.into_syntax().into())), + )) +} pub fn css_keyframes_selector_list(items: I, separators: S) -> CssKeyframesSelectorList where I: IntoIterator, @@ -1167,6 +1165,27 @@ where }), )) } +pub fn css_media_query_list(items: I, separators: S) -> CssMediaQueryList +where + I: IntoIterator, + I::IntoIter: ExactSizeIterator, + S: IntoIterator, + S::IntoIter: ExactSizeIterator, +{ + let mut items = items.into_iter(); + let mut separators = separators.into_iter(); + let length = items.len() + separators.len(); + CssMediaQueryList::unwrap_cast(SyntaxNode::new_detached( + CssSyntaxKind::CSS_MEDIA_QUERY_LIST, + (0..length).map(|index| { + if index % 2 == 0 { + Some(items.next()?.into_syntax().into()) + } else { + Some(separators.next()?.into()) + } + }), + )) +} pub fn css_parameter_list(items: I) -> CssParameterList where I: IntoIterator, @@ -1273,6 +1292,16 @@ where { CssBogus::unwrap_cast(SyntaxNode::new_detached(CssSyntaxKind::CSS_BOGUS, slots)) } +pub fn css_bogus_at_rule(slots: I) -> CssBogusAtRule +where + I: IntoIterator>, + I::IntoIter: ExactSizeIterator, +{ + CssBogusAtRule::unwrap_cast(SyntaxNode::new_detached( + CssSyntaxKind::CSS_BOGUS_AT_RULE, + slots, + )) +} pub fn css_bogus_body(slots: I) -> CssBogusBody where I: IntoIterator>, diff --git a/crates/biome_css_factory/src/generated/syntax_factory.rs b/crates/biome_css_factory/src/generated/syntax_factory.rs index 3b9897579495..d1db19262b7b 100644 --- a/crates/biome_css_factory/src/generated/syntax_factory.rs +++ b/crates/biome_css_factory/src/generated/syntax_factory.rs @@ -15,6 +15,7 @@ impl SyntaxFactory for CssSyntaxFactory { ) -> RawSyntaxNode { match kind { CSS_BOGUS + | CSS_BOGUS_AT_RULE | CSS_BOGUS_BODY | CSS_BOGUS_PSEUDO_CLASS | CSS_BOGUS_PSEUDO_ELEMENT @@ -40,9 +41,9 @@ impl SyntaxFactory for CssSyntaxFactory { } slots.into_node(CSS_ANY_FUNCTION, children) } - CSS_AT_KEYFRAMES => { + CSS_AT_RULE => { let mut elements = (&children).into_iter(); - let mut slots: RawNodeSlots<5usize> = RawNodeSlots::default(); + let mut slots: RawNodeSlots<2usize> = RawNodeSlots::default(); let mut current_element = elements.next(); if let Some(element) = ¤t_element { if element.kind() == T ! [@] { @@ -52,28 +53,43 @@ impl SyntaxFactory for CssSyntaxFactory { } slots.next_slot(); if let Some(element) = ¤t_element { - if element.kind() == T![keyframes] { + if AnyCssAtRule::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + CSS_AT_RULE.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(CSS_AT_RULE, children) + } + CSS_ATTRIBUTE_MATCHER => { + 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 { - if CssIdentifier::can_cast(element.kind()) { + if matches!( + element.kind(), + T ! [~=] | T ! [|=] | T ! [^=] | T!["$="] | T ! [*=] | T ! [=] + ) { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if CssString::can_cast(element.kind()) { + if CssAttributeMatcherValue::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if CssAtKeyframesBody::can_cast(element.kind()) { + if matches!(element.kind(), T![i] | T![s]) { slots.mark_present(); current_element = elements.next(); } @@ -81,32 +97,44 @@ impl SyntaxFactory for CssSyntaxFactory { slots.next_slot(); if current_element.is_some() { return RawSyntaxNode::new( - CSS_AT_KEYFRAMES.to_bogus(), + CSS_ATTRIBUTE_MATCHER.to_bogus(), children.into_iter().map(Some), ); } - slots.into_node(CSS_AT_KEYFRAMES, children) + slots.into_node(CSS_ATTRIBUTE_MATCHER, children) } - CSS_AT_KEYFRAMES_BODY => { + CSS_ATTRIBUTE_MATCHER_VALUE => { let mut elements = (&children).into_iter(); - let mut slots: RawNodeSlots<3usize> = RawNodeSlots::default(); + let mut slots: RawNodeSlots<1usize> = RawNodeSlots::default(); let mut current_element = elements.next(); if let Some(element) = ¤t_element { - if element.kind() == T!['{'] { + if AnyCssAttributeMatcherValue::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + CSS_ATTRIBUTE_MATCHER_VALUE.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(CSS_ATTRIBUTE_MATCHER_VALUE, children) + } + CSS_ATTRIBUTE_NAME => { + 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 { - if CssAtKeyframesItemList::can_cast(element.kind()) { + if CssNamespace::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if element.kind() == T!['}'] { + if CssIdentifier::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -114,37 +142,56 @@ impl SyntaxFactory for CssSyntaxFactory { slots.next_slot(); if current_element.is_some() { return RawSyntaxNode::new( - CSS_AT_KEYFRAMES_BODY.to_bogus(), + CSS_ATTRIBUTE_NAME.to_bogus(), children.into_iter().map(Some), ); } - slots.into_node(CSS_AT_KEYFRAMES_BODY, children) + slots.into_node(CSS_ATTRIBUTE_NAME, children) } - CSS_AT_MEDIA => { + CSS_ATTRIBUTE_SELECTOR => { let mut elements = (&children).into_iter(); - let mut slots: RawNodeSlots<6usize> = RawNodeSlots::default(); + let mut slots: RawNodeSlots<4usize> = RawNodeSlots::default(); let mut current_element = elements.next(); if let Some(element) = ¤t_element { - if element.kind() == T ! [@] { + if element.kind() == T!['['] { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if element.kind() == T![media] { + if CssAttributeName::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if CssAtMediaQueryList::can_cast(element.kind()) { + if CssAttributeMatcher::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); + if let Some(element) = ¤t_element { + if element.kind() == T![']'] { + slots.mark_present(); + current_element = elements.next(); + } + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + CSS_ATTRIBUTE_SELECTOR.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(CSS_ATTRIBUTE_SELECTOR, children) + } + CSS_BLOCK => { + 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 { if element.kind() == T!['{'] { slots.mark_present(); @@ -153,7 +200,7 @@ impl SyntaxFactory for CssSyntaxFactory { } slots.next_slot(); if let Some(element) = ¤t_element { - if AnyCssRule::can_cast(element.kind()) { + if CssDeclarationList::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -168,46 +215,58 @@ impl SyntaxFactory for CssSyntaxFactory { slots.next_slot(); if current_element.is_some() { return RawSyntaxNode::new( - CSS_AT_MEDIA.to_bogus(), + CSS_BLOCK.to_bogus(), children.into_iter().map(Some), ); } - slots.into_node(CSS_AT_MEDIA, children) + slots.into_node(CSS_BLOCK, children) } - CSS_AT_MEDIA_QUERY => { + CSS_CHARSET_AT_RULE => { let mut elements = (&children).into_iter(); - let mut slots: RawNodeSlots<5usize> = RawNodeSlots::default(); + let mut slots: RawNodeSlots<3usize> = RawNodeSlots::default(); let mut current_element = elements.next(); if let Some(element) = ¤t_element { - if element.kind() == T![not] { + if element.kind() == T![charset] { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if element.kind() == T![or] { + if CssString::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if element.kind() == T![only] { + if element.kind() == T ! [;] { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + CSS_CHARSET_AT_RULE.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(CSS_CHARSET_AT_RULE, children) + } + CSS_CLASS_SELECTOR => { + 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 { - if AnyCssAtMediaQueryType::can_cast(element.kind()) { + if element.kind() == T ! [.] { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if CssAtMediaQueryConsequent::can_cast(element.kind()) { + if CssIdentifier::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -215,32 +274,35 @@ impl SyntaxFactory for CssSyntaxFactory { slots.next_slot(); if current_element.is_some() { return RawSyntaxNode::new( - CSS_AT_MEDIA_QUERY.to_bogus(), + CSS_CLASS_SELECTOR.to_bogus(), children.into_iter().map(Some), ); } - slots.into_node(CSS_AT_MEDIA_QUERY, children) + slots.into_node(CSS_CLASS_SELECTOR, children) } - CSS_AT_MEDIA_QUERY_CONSEQUENT => { + CSS_COMPLEX_SELECTOR => { 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 { - if element.kind() == T![and] { + if AnyCssSelector::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if element.kind() == T![not] { + if matches!( + element.kind(), + T ! [>] | T ! [+] | T ! [~] | T ! [||] | CSS_SPACE_LITERAL + ) { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if AnyCssAtMediaQueryType::can_cast(element.kind()) { + if AnyCssSelector::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -248,32 +310,32 @@ impl SyntaxFactory for CssSyntaxFactory { slots.next_slot(); if current_element.is_some() { return RawSyntaxNode::new( - CSS_AT_MEDIA_QUERY_CONSEQUENT.to_bogus(), + CSS_COMPLEX_SELECTOR.to_bogus(), children.into_iter().map(Some), ); } - slots.into_node(CSS_AT_MEDIA_QUERY_CONSEQUENT, children) + slots.into_node(CSS_COMPLEX_SELECTOR, children) } - CSS_AT_MEDIA_QUERY_FEATURE => { + CSS_COMPOUND_SELECTOR => { 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 { - if element.kind() == T!['('] { + if element.kind() == T ! [&] { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if AnyCssAtMediaQueryFeatureType::can_cast(element.kind()) { + if AnyCssSimpleSelector::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if element.kind() == T![')'] { + if CssSubSelectorList::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -281,18 +343,18 @@ impl SyntaxFactory for CssSyntaxFactory { slots.next_slot(); if current_element.is_some() { return RawSyntaxNode::new( - CSS_AT_MEDIA_QUERY_FEATURE.to_bogus(), + CSS_COMPOUND_SELECTOR.to_bogus(), children.into_iter().map(Some), ); } - slots.into_node(CSS_AT_MEDIA_QUERY_FEATURE, children) + slots.into_node(CSS_COMPOUND_SELECTOR, children) } - CSS_AT_MEDIA_QUERY_FEATURE_BOOLEAN => { + CSS_CUSTOM_PROPERTY => { let mut elements = (&children).into_iter(); let mut slots: RawNodeSlots<1usize> = RawNodeSlots::default(); let mut current_element = elements.next(); if let Some(element) = ¤t_element { - if CssIdentifier::can_cast(element.kind()) { + if element.kind() == CSS_CUSTOM_PROPERTY { slots.mark_present(); current_element = elements.next(); } @@ -300,15 +362,15 @@ impl SyntaxFactory for CssSyntaxFactory { slots.next_slot(); if current_element.is_some() { return RawSyntaxNode::new( - CSS_AT_MEDIA_QUERY_FEATURE_BOOLEAN.to_bogus(), + CSS_CUSTOM_PROPERTY.to_bogus(), children.into_iter().map(Some), ); } - slots.into_node(CSS_AT_MEDIA_QUERY_FEATURE_BOOLEAN, children) + slots.into_node(CSS_CUSTOM_PROPERTY, children) } - CSS_AT_MEDIA_QUERY_FEATURE_COMPARE => { + CSS_DECLARATION => { let mut elements = (&children).into_iter(); - let mut slots: RawNodeSlots<3usize> = RawNodeSlots::default(); + let mut slots: RawNodeSlots<5usize> = RawNodeSlots::default(); let mut current_element = elements.next(); if let Some(element) = ¤t_element { if CssIdentifier::can_cast(element.kind()) { @@ -318,7 +380,14 @@ impl SyntaxFactory for CssSyntaxFactory { } slots.next_slot(); if let Some(element) = ¤t_element { - if CssAtMediaQueryRange::can_cast(element.kind()) { + if CssCustomProperty::can_cast(element.kind()) { + slots.mark_present(); + current_element = elements.next(); + } + } + slots.next_slot(); + if let Some(element) = ¤t_element { + if element.kind() == T ! [:] { slots.mark_present(); current_element = elements.next(); } @@ -331,18 +400,58 @@ impl SyntaxFactory for CssSyntaxFactory { } } slots.next_slot(); + if let Some(element) = ¤t_element { + if CssDeclarationImportant::can_cast(element.kind()) { + slots.mark_present(); + current_element = elements.next(); + } + } + slots.next_slot(); if current_element.is_some() { return RawSyntaxNode::new( - CSS_AT_MEDIA_QUERY_FEATURE_COMPARE.to_bogus(), + CSS_DECLARATION.to_bogus(), children.into_iter().map(Some), ); } - slots.into_node(CSS_AT_MEDIA_QUERY_FEATURE_COMPARE, children) + slots.into_node(CSS_DECLARATION, children) } - CSS_AT_MEDIA_QUERY_FEATURE_PLAIN => { + CSS_DECLARATION_IMPORTANT => { let mut elements = (&children).into_iter(); - let mut slots: RawNodeSlots<3usize> = RawNodeSlots::default(); + let mut slots: RawNodeSlots<2usize> = RawNodeSlots::default(); + let mut current_element = elements.next(); + if let Some(element) = ¤t_element { + if element.kind() == T![!] { + slots.mark_present(); + current_element = elements.next(); + } + } + slots.next_slot(); + if let Some(element) = ¤t_element { + if element.kind() == T![important] { + slots.mark_present(); + current_element = elements.next(); + } + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + CSS_DECLARATION_IMPORTANT.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(CSS_DECLARATION_IMPORTANT, children) + } + CSS_DIMENSION => { + 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 { + if CssNumber::can_cast(element.kind()) { + slots.mark_present(); + current_element = elements.next(); + } + } + slots.next_slot(); if let Some(element) = ¤t_element { if CssIdentifier::can_cast(element.kind()) { slots.mark_present(); @@ -350,15 +459,27 @@ impl SyntaxFactory for CssSyntaxFactory { } } slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + CSS_DIMENSION.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(CSS_DIMENSION, children) + } + CSS_ID_SELECTOR => { + 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 { - if element.kind() == T ! [:] { + if element.kind() == T ! [#] { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if AnyCssValue::can_cast(element.kind()) { + if CssIdentifier::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -366,25 +487,37 @@ impl SyntaxFactory for CssSyntaxFactory { slots.next_slot(); if current_element.is_some() { return RawSyntaxNode::new( - CSS_AT_MEDIA_QUERY_FEATURE_PLAIN.to_bogus(), + CSS_ID_SELECTOR.to_bogus(), children.into_iter().map(Some), ); } - slots.into_node(CSS_AT_MEDIA_QUERY_FEATURE_PLAIN, children) + slots.into_node(CSS_ID_SELECTOR, children) } - CSS_AT_MEDIA_QUERY_FEATURE_RANGE => { + CSS_IDENTIFIER => { let mut elements = (&children).into_iter(); - let mut slots: RawNodeSlots<5usize> = RawNodeSlots::default(); + let mut slots: RawNodeSlots<1usize> = RawNodeSlots::default(); let mut current_element = elements.next(); if let Some(element) = ¤t_element { - if AnyCssValue::can_cast(element.kind()) { + if element.kind() == IDENT { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + CSS_IDENTIFIER.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(CSS_IDENTIFIER, children) + } + CSS_KEYFRAMES_AT_RULE => { + 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 { - if CssAtMediaQueryRange::can_cast(element.kind()) { + if element.kind() == T![keyframes] { slots.mark_present(); current_element = elements.next(); } @@ -398,14 +531,14 @@ impl SyntaxFactory for CssSyntaxFactory { } slots.next_slot(); if let Some(element) = ¤t_element { - if AnyCssValue::can_cast(element.kind()) { + if CssString::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if CssAtMediaQueryRange::can_cast(element.kind()) { + if CssKeyframesBody::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -413,39 +546,39 @@ impl SyntaxFactory for CssSyntaxFactory { slots.next_slot(); if current_element.is_some() { return RawSyntaxNode::new( - CSS_AT_MEDIA_QUERY_FEATURE_RANGE.to_bogus(), + CSS_KEYFRAMES_AT_RULE.to_bogus(), children.into_iter().map(Some), ); } - slots.into_node(CSS_AT_MEDIA_QUERY_FEATURE_RANGE, children) + slots.into_node(CSS_KEYFRAMES_AT_RULE, children) } - CSS_AT_MEDIA_QUERY_RANGE => { + CSS_KEYFRAMES_BLOCK => { 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 { - if element.kind() == T ! [>] { + if CssKeyframesSelectorList::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if element.kind() == T ! [<] { + if element.kind() == T!['{'] { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if element.kind() == T ! [>=] { + if CssDeclarationList::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if element.kind() == T ! [<=] { + if element.kind() == T!['}'] { slots.mark_present(); current_element = elements.next(); } @@ -453,35 +586,32 @@ impl SyntaxFactory for CssSyntaxFactory { slots.next_slot(); if current_element.is_some() { return RawSyntaxNode::new( - CSS_AT_MEDIA_QUERY_RANGE.to_bogus(), + CSS_KEYFRAMES_BLOCK.to_bogus(), children.into_iter().map(Some), ); } - slots.into_node(CSS_AT_MEDIA_QUERY_RANGE, children) + slots.into_node(CSS_KEYFRAMES_BLOCK, children) } - CSS_ATTRIBUTE_MATCHER => { + CSS_KEYFRAMES_BODY => { 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 { - if matches!( - element.kind(), - T ! [~=] | T ! [|=] | T ! [^=] | T!["$="] | T ! [*=] | T ! [=] - ) { + if element.kind() == T!['{'] { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if CssAttributeMatcherValue::can_cast(element.kind()) { + if CssKeyframesItemList::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if matches!(element.kind(), T![i] | T![s]) { + if element.kind() == T!['}'] { slots.mark_present(); current_element = elements.next(); } @@ -489,44 +619,32 @@ impl SyntaxFactory for CssSyntaxFactory { slots.next_slot(); if current_element.is_some() { return RawSyntaxNode::new( - CSS_ATTRIBUTE_MATCHER.to_bogus(), + CSS_KEYFRAMES_BODY.to_bogus(), children.into_iter().map(Some), ); } - slots.into_node(CSS_ATTRIBUTE_MATCHER, children) + slots.into_node(CSS_KEYFRAMES_BODY, children) } - CSS_ATTRIBUTE_MATCHER_VALUE => { + CSS_KEYFRAMES_SELECTOR => { let mut elements = (&children).into_iter(); - let mut slots: RawNodeSlots<1usize> = RawNodeSlots::default(); + let mut slots: RawNodeSlots<3usize> = RawNodeSlots::default(); let mut current_element = elements.next(); if let Some(element) = ¤t_element { - if AnyCssAttributeMatcherValue::can_cast(element.kind()) { + if element.kind() == T![from] { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); - if current_element.is_some() { - return RawSyntaxNode::new( - CSS_ATTRIBUTE_MATCHER_VALUE.to_bogus(), - children.into_iter().map(Some), - ); - } - slots.into_node(CSS_ATTRIBUTE_MATCHER_VALUE, children) - } - CSS_ATTRIBUTE_NAME => { - 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 { - if CssNamespace::can_cast(element.kind()) { + if element.kind() == T![to] { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if CssIdentifier::can_cast(element.kind()) { + if CssPercentage::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -534,39 +652,46 @@ impl SyntaxFactory for CssSyntaxFactory { slots.next_slot(); if current_element.is_some() { return RawSyntaxNode::new( - CSS_ATTRIBUTE_NAME.to_bogus(), + CSS_KEYFRAMES_SELECTOR.to_bogus(), children.into_iter().map(Some), ); } - slots.into_node(CSS_ATTRIBUTE_NAME, children) + slots.into_node(CSS_KEYFRAMES_SELECTOR, children) } - CSS_ATTRIBUTE_SELECTOR => { + CSS_MEDIA_AT_RULE => { let mut elements = (&children).into_iter(); - let mut slots: RawNodeSlots<4usize> = RawNodeSlots::default(); + let mut slots: RawNodeSlots<5usize> = RawNodeSlots::default(); let mut current_element = elements.next(); if let Some(element) = ¤t_element { - if element.kind() == T!['['] { + if element.kind() == T![media] { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if CssAttributeName::can_cast(element.kind()) { + if CssMediaQueryList::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if CssAttributeMatcher::can_cast(element.kind()) { + if element.kind() == T!['{'] { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if element.kind() == T![']'] { + if AnyCssRule::can_cast(element.kind()) { + slots.mark_present(); + current_element = elements.next(); + } + } + slots.next_slot(); + if let Some(element) = ¤t_element { + if element.kind() == T!['}'] { slots.mark_present(); current_element = elements.next(); } @@ -574,58 +699,46 @@ impl SyntaxFactory for CssSyntaxFactory { slots.next_slot(); if current_element.is_some() { return RawSyntaxNode::new( - CSS_ATTRIBUTE_SELECTOR.to_bogus(), + CSS_MEDIA_AT_RULE.to_bogus(), children.into_iter().map(Some), ); } - slots.into_node(CSS_ATTRIBUTE_SELECTOR, children) + slots.into_node(CSS_MEDIA_AT_RULE, children) } - CSS_BLOCK => { + CSS_MEDIA_QUERY => { let mut elements = (&children).into_iter(); - let mut slots: RawNodeSlots<3usize> = RawNodeSlots::default(); + let mut slots: RawNodeSlots<5usize> = RawNodeSlots::default(); let mut current_element = elements.next(); if let Some(element) = ¤t_element { - if element.kind() == T!['{'] { + if element.kind() == T![not] { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if CssDeclarationList::can_cast(element.kind()) { + if element.kind() == T![or] { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if element.kind() == T!['}'] { + if element.kind() == T![only] { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); - if current_element.is_some() { - return RawSyntaxNode::new( - CSS_BLOCK.to_bogus(), - children.into_iter().map(Some), - ); - } - slots.into_node(CSS_BLOCK, children) - } - CSS_CLASS_SELECTOR => { - 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 { - if element.kind() == T ! [.] { + if AnyCssMediaQueryType::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if CssIdentifier::can_cast(element.kind()) { + if CssMediaQueryConsequent::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -633,35 +746,32 @@ impl SyntaxFactory for CssSyntaxFactory { slots.next_slot(); if current_element.is_some() { return RawSyntaxNode::new( - CSS_CLASS_SELECTOR.to_bogus(), + CSS_MEDIA_QUERY.to_bogus(), children.into_iter().map(Some), ); } - slots.into_node(CSS_CLASS_SELECTOR, children) + slots.into_node(CSS_MEDIA_QUERY, children) } - CSS_COMPLEX_SELECTOR => { + CSS_MEDIA_QUERY_CONSEQUENT => { 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 { - if AnyCssSelector::can_cast(element.kind()) { + if element.kind() == T![and] { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if matches!( - element.kind(), - T ! [>] | T ! [+] | T ! [~] | T ! [||] | CSS_SPACE_LITERAL - ) { + if element.kind() == T![not] { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if AnyCssSelector::can_cast(element.kind()) { + if AnyCssMediaQueryType::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -669,32 +779,32 @@ impl SyntaxFactory for CssSyntaxFactory { slots.next_slot(); if current_element.is_some() { return RawSyntaxNode::new( - CSS_COMPLEX_SELECTOR.to_bogus(), + CSS_MEDIA_QUERY_CONSEQUENT.to_bogus(), children.into_iter().map(Some), ); } - slots.into_node(CSS_COMPLEX_SELECTOR, children) + slots.into_node(CSS_MEDIA_QUERY_CONSEQUENT, children) } - CSS_COMPOUND_SELECTOR => { + CSS_MEDIA_QUERY_FEATURE => { 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 { - if element.kind() == T ! [&] { + if element.kind() == T!['('] { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if AnyCssSimpleSelector::can_cast(element.kind()) { + if AnyCssMediaQueryFeatureType::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if CssSubSelectorList::can_cast(element.kind()) { + if element.kind() == T![')'] { slots.mark_present(); current_element = elements.next(); } @@ -702,18 +812,18 @@ impl SyntaxFactory for CssSyntaxFactory { slots.next_slot(); if current_element.is_some() { return RawSyntaxNode::new( - CSS_COMPOUND_SELECTOR.to_bogus(), + CSS_MEDIA_QUERY_FEATURE.to_bogus(), children.into_iter().map(Some), ); } - slots.into_node(CSS_COMPOUND_SELECTOR, children) + slots.into_node(CSS_MEDIA_QUERY_FEATURE, children) } - CSS_CUSTOM_PROPERTY => { + CSS_MEDIA_QUERY_FEATURE_BOOLEAN => { let mut elements = (&children).into_iter(); let mut slots: RawNodeSlots<1usize> = RawNodeSlots::default(); let mut current_element = elements.next(); if let Some(element) = ¤t_element { - if element.kind() == CSS_CUSTOM_PROPERTY { + if CssIdentifier::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -721,15 +831,15 @@ impl SyntaxFactory for CssSyntaxFactory { slots.next_slot(); if current_element.is_some() { return RawSyntaxNode::new( - CSS_CUSTOM_PROPERTY.to_bogus(), + CSS_MEDIA_QUERY_FEATURE_BOOLEAN.to_bogus(), children.into_iter().map(Some), ); } - slots.into_node(CSS_CUSTOM_PROPERTY, children) + slots.into_node(CSS_MEDIA_QUERY_FEATURE_BOOLEAN, children) } - CSS_DECLARATION => { + CSS_MEDIA_QUERY_FEATURE_COMPARE => { let mut elements = (&children).into_iter(); - let mut slots: RawNodeSlots<5usize> = RawNodeSlots::default(); + let mut slots: RawNodeSlots<3usize> = RawNodeSlots::default(); let mut current_element = elements.next(); if let Some(element) = ¤t_element { if CssIdentifier::can_cast(element.kind()) { @@ -739,14 +849,7 @@ impl SyntaxFactory for CssSyntaxFactory { } slots.next_slot(); if let Some(element) = ¤t_element { - if CssCustomProperty::can_cast(element.kind()) { - slots.mark_present(); - current_element = elements.next(); - } - } - slots.next_slot(); - if let Some(element) = ¤t_element { - if element.kind() == T ! [:] { + if CssMediaQueryRange::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -759,58 +862,18 @@ impl SyntaxFactory for CssSyntaxFactory { } } slots.next_slot(); - if let Some(element) = ¤t_element { - if CssDeclarationImportant::can_cast(element.kind()) { - slots.mark_present(); - current_element = elements.next(); - } - } - slots.next_slot(); if current_element.is_some() { return RawSyntaxNode::new( - CSS_DECLARATION.to_bogus(), + CSS_MEDIA_QUERY_FEATURE_COMPARE.to_bogus(), children.into_iter().map(Some), ); } - slots.into_node(CSS_DECLARATION, children) + slots.into_node(CSS_MEDIA_QUERY_FEATURE_COMPARE, children) } - CSS_DECLARATION_IMPORTANT => { + CSS_MEDIA_QUERY_FEATURE_PLAIN => { 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 { - if element.kind() == T![!] { - slots.mark_present(); - current_element = elements.next(); - } - } - slots.next_slot(); - if let Some(element) = ¤t_element { - if element.kind() == T![important] { - slots.mark_present(); - current_element = elements.next(); - } - } - slots.next_slot(); - if current_element.is_some() { - return RawSyntaxNode::new( - CSS_DECLARATION_IMPORTANT.to_bogus(), - children.into_iter().map(Some), - ); - } - slots.into_node(CSS_DECLARATION_IMPORTANT, children) - } - CSS_DIMENSION => { - let mut elements = (&children).into_iter(); - let mut slots: RawNodeSlots<2usize> = RawNodeSlots::default(); + let mut slots: RawNodeSlots<3usize> = RawNodeSlots::default(); let mut current_element = elements.next(); - if let Some(element) = ¤t_element { - if CssNumber::can_cast(element.kind()) { - slots.mark_present(); - current_element = elements.next(); - } - } - slots.next_slot(); if let Some(element) = ¤t_element { if CssIdentifier::can_cast(element.kind()) { slots.mark_present(); @@ -818,27 +881,15 @@ impl SyntaxFactory for CssSyntaxFactory { } } slots.next_slot(); - if current_element.is_some() { - return RawSyntaxNode::new( - CSS_DIMENSION.to_bogus(), - children.into_iter().map(Some), - ); - } - slots.into_node(CSS_DIMENSION, children) - } - CSS_ID_SELECTOR => { - 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 { - if element.kind() == T ! [#] { + if element.kind() == T ! [:] { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if CssIdentifier::can_cast(element.kind()) { + if AnyCssValue::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -846,58 +897,46 @@ impl SyntaxFactory for CssSyntaxFactory { slots.next_slot(); if current_element.is_some() { return RawSyntaxNode::new( - CSS_ID_SELECTOR.to_bogus(), + CSS_MEDIA_QUERY_FEATURE_PLAIN.to_bogus(), children.into_iter().map(Some), ); } - slots.into_node(CSS_ID_SELECTOR, children) + slots.into_node(CSS_MEDIA_QUERY_FEATURE_PLAIN, children) } - CSS_IDENTIFIER => { + CSS_MEDIA_QUERY_FEATURE_RANGE => { let mut elements = (&children).into_iter(); - let mut slots: RawNodeSlots<1usize> = RawNodeSlots::default(); + let mut slots: RawNodeSlots<5usize> = RawNodeSlots::default(); let mut current_element = elements.next(); if let Some(element) = ¤t_element { - if element.kind() == IDENT { + if AnyCssValue::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); - if current_element.is_some() { - return RawSyntaxNode::new( - CSS_IDENTIFIER.to_bogus(), - children.into_iter().map(Some), - ); - } - slots.into_node(CSS_IDENTIFIER, children) - } - CSS_KEYFRAMES_BLOCK => { - 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 { - if CssKeyframesSelectorList::can_cast(element.kind()) { + if CssMediaQueryRange::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if element.kind() == T!['{'] { + if CssIdentifier::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if CssDeclarationList::can_cast(element.kind()) { + if AnyCssValue::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if element.kind() == T!['}'] { + if CssMediaQueryRange::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -905,32 +944,39 @@ impl SyntaxFactory for CssSyntaxFactory { slots.next_slot(); if current_element.is_some() { return RawSyntaxNode::new( - CSS_KEYFRAMES_BLOCK.to_bogus(), + CSS_MEDIA_QUERY_FEATURE_RANGE.to_bogus(), children.into_iter().map(Some), ); } - slots.into_node(CSS_KEYFRAMES_BLOCK, children) + slots.into_node(CSS_MEDIA_QUERY_FEATURE_RANGE, children) } - CSS_KEYFRAMES_SELECTOR => { + CSS_MEDIA_QUERY_RANGE => { let mut elements = (&children).into_iter(); - let mut slots: RawNodeSlots<3usize> = RawNodeSlots::default(); + let mut slots: RawNodeSlots<4usize> = RawNodeSlots::default(); let mut current_element = elements.next(); if let Some(element) = ¤t_element { - if element.kind() == T![from] { + if element.kind() == T ! [>] { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if element.kind() == T![to] { + if element.kind() == T ! [<] { slots.mark_present(); current_element = elements.next(); } } slots.next_slot(); if let Some(element) = ¤t_element { - if CssPercentage::can_cast(element.kind()) { + if element.kind() == T ! [>=] { + slots.mark_present(); + current_element = elements.next(); + } + } + slots.next_slot(); + if let Some(element) = ¤t_element { + if element.kind() == T ! [<=] { slots.mark_present(); current_element = elements.next(); } @@ -938,11 +984,11 @@ impl SyntaxFactory for CssSyntaxFactory { slots.next_slot(); if current_element.is_some() { return RawSyntaxNode::new( - CSS_KEYFRAMES_SELECTOR.to_bogus(), + CSS_MEDIA_QUERY_RANGE.to_bogus(), children.into_iter().map(Some), ); } - slots.into_node(CSS_KEYFRAMES_SELECTOR, children) + slots.into_node(CSS_MEDIA_QUERY_RANGE, children) } CSS_NAMED_NAMESPACE_PREFIX => { let mut elements = (&children).into_iter(); @@ -2014,16 +2060,6 @@ impl SyntaxFactory for CssSyntaxFactory { } slots.into_node(CSS_VAR_FUNCTION_VALUE, children) } - CSS_AT_KEYFRAMES_ITEM_LIST => { - Self::make_node_list_syntax(kind, children, CssKeyframesBlock::can_cast) - } - CSS_AT_MEDIA_QUERY_LIST => Self::make_separated_list_syntax( - kind, - children, - CssAtMediaQuery::can_cast, - T ! [,], - false, - ), CSS_COMPOUND_SELECTOR_LIST => Self::make_separated_list_syntax( kind, children, @@ -2034,6 +2070,9 @@ impl SyntaxFactory for CssSyntaxFactory { CSS_DECLARATION_LIST => { Self::make_node_list_syntax(kind, children, CssDeclaration::can_cast) } + CSS_KEYFRAMES_ITEM_LIST => { + Self::make_node_list_syntax(kind, children, CssKeyframesBlock::can_cast) + } CSS_KEYFRAMES_SELECTOR_LIST => Self::make_separated_list_syntax( kind, children, @@ -2041,6 +2080,13 @@ impl SyntaxFactory for CssSyntaxFactory { T ! [,], false, ), + CSS_MEDIA_QUERY_LIST => Self::make_separated_list_syntax( + kind, + children, + CssMediaQuery::can_cast, + T ! [,], + false, + ), CSS_PARAMETER_LIST => { Self::make_node_list_syntax(kind, children, CssParameter::can_cast) } diff --git a/crates/biome_css_parser/src/lexer/mod.rs b/crates/biome_css_parser/src/lexer/mod.rs index 2bbd979e1193..fb5fdd9de3bf 100644 --- a/crates/biome_css_parser/src/lexer/mod.rs +++ b/crates/biome_css_parser/src/lexer/mod.rs @@ -483,6 +483,7 @@ impl<'src> CssLexer<'src> { CRT => self.consume_ctr(), COL => self.consume_col(), AT_ => self.consume_byte(T![@]), + SEM => self.consume_byte(T![;]), HAS => self.consume_byte(T![#]), PNO => self.consume_byte(T!['(']), PNC => self.consume_byte(T![')']), @@ -764,6 +765,7 @@ impl<'src> CssLexer<'src> { b"nth-last-col" => NTHLASTCOL_KW, b"ltr" => LTR_KW, b"rtl" => RTL_KW, + b"charset" => CHARSET_KW, _ => IDENT, } } diff --git a/crates/biome_css_parser/src/syntax/at_rule/charset.rs b/crates/biome_css_parser/src/syntax/at_rule/charset.rs new file mode 100644 index 000000000000..090b24da5afd --- /dev/null +++ b/crates/biome_css_parser/src/syntax/at_rule/charset.rs @@ -0,0 +1,70 @@ +use crate::parser::CssParser; +use crate::syntax::parse_error::expected_string; +use crate::syntax::parse_string; +use biome_css_syntax::CssSyntaxKind::*; +use biome_css_syntax::{CssSyntaxKind, TextRange, T}; +use biome_parser::parse_recovery::ParseRecovery; +use biome_parser::parsed_syntax::ParsedSyntax::Present; +use biome_parser::prelude::ParsedSyntax::Absent; +use biome_parser::prelude::*; +use biome_rowan::SyntaxKind; + +#[inline] +pub(crate) fn is_at_charset_rule(p: &mut CssParser) -> bool { + p.at(T![charset]) +} + +#[inline] +pub(crate) fn parse_at_charset_rule(p: &mut CssParser) -> ParsedSyntax { + if !is_at_charset_rule(p) { + return Absent; + } + + let m = p.start(); + + p.bump(T![charset]); + + let kind = match parse_string(p).or_recover( + p, + &ParseRecovery::new(CSS_BOGUS, CHARTSET_RECOVERY_SET).enable_recovery_on_line_break(), + expected_string, + ) { + Ok(encoding) if !encoding.kind(p).is_bogus() => { + if eat_or_recover_close_token(p, encoding) { + CSS_CHARSET_AT_RULE + } else { + CSS_BOGUS_AT_RULE + } + } + _ => { + p.expect(T![;]); + CSS_BOGUS_AT_RULE + } + }; + + Present(m.complete(p, kind)) +} + +const CHARTSET_RECOVERY_SET: TokenSet = token_set![T![;]]; + +#[inline] +fn eat_or_recover_close_token(p: &mut CssParser, encoding: CompletedMarker) -> bool { + if p.eat(T![;]) { + true + } else { + if let Ok(m) = ParseRecovery::new(CSS_BOGUS, CHARTSET_RECOVERY_SET) + .enable_recovery_on_line_break() + .recover(p) + { + let diagnostic = expected_string( + p, + TextRange::new(encoding.range(p).start(), m.range(p).end()), + ); + p.error(diagnostic); + } + + p.expect(T![;]); + + false + } +} diff --git a/crates/biome_css_parser/src/syntax/at_rule/mod.rs b/crates/biome_css_parser/src/syntax/at_rule/mod.rs new file mode 100644 index 000000000000..8fd32bd1f722 --- /dev/null +++ b/crates/biome_css_parser/src/syntax/at_rule/mod.rs @@ -0,0 +1,45 @@ +mod charset; + +use crate::parser::CssParser; +use crate::syntax::at_rule::charset::{is_at_charset_rule, parse_at_charset_rule}; +use crate::syntax::parse_error::expected_any_at_rule; +use biome_css_syntax::CssSyntaxKind::*; +use biome_css_syntax::T; +use biome_parser::prelude::ParsedSyntax::{Absent, Present}; +use biome_parser::prelude::*; + +#[inline] +pub(crate) fn at_at_rule(p: &mut CssParser) -> bool { + p.at(T![@]) +} + +#[inline] +pub(crate) fn parse_at_rule(p: &mut CssParser) -> ParsedSyntax { + if !at_at_rule(p) { + return Absent; + } + + let m = p.start(); + + p.bump(T![@]); + + let kind = if parse_any_at_rule(p) + .or_add_diagnostic(p, expected_any_at_rule) + .is_some() + { + CSS_AT_RULE + } else { + CSS_BOGUS_RULE + }; + + Present(m.complete(p, kind)) +} + +#[inline] +pub(crate) fn parse_any_at_rule(p: &mut CssParser) -> ParsedSyntax { + if is_at_charset_rule(p) { + parse_at_charset_rule(p) + } else { + Absent + } +} diff --git a/crates/biome_css_parser/src/syntax/mod.rs b/crates/biome_css_parser/src/syntax/mod.rs index 50d89db33b09..e5ed99e6adcc 100644 --- a/crates/biome_css_parser/src/syntax/mod.rs +++ b/crates/biome_css_parser/src/syntax/mod.rs @@ -1,8 +1,10 @@ +mod at_rule; mod parse_error; mod selector; use crate::lexer::CssLexContext; use crate::parser::CssParser; +use crate::syntax::at_rule::{at_at_rule, parse_at_rule}; use crate::syntax::parse_error::expected_block; use crate::syntax::selector::CssSelectorList; use biome_css_syntax::CssSyntaxKind::*; @@ -36,7 +38,11 @@ pub(crate) fn parse_rule_list(p: &mut CssParser) { while !p.at(EOF) { progress.assert_progressing(p); - parse_rule(p); + if at_at_rule(p) { + parse_at_rule(p).ok(); + } else { + parse_rule(p); + } } rules.complete(p, CSS_RULE_LIST); @@ -120,7 +126,7 @@ pub(crate) fn parse_number(p: &mut CssParser, context: CssLexContext) -> ParsedS } #[inline] -pub(crate) fn parse_css_string(p: &mut CssParser) -> ParsedSyntax { +pub(crate) fn parse_string(p: &mut CssParser) -> ParsedSyntax { if !p.at(CSS_STRING_LITERAL) { return Absent; } diff --git a/crates/biome_css_parser/src/syntax/parse_error.rs b/crates/biome_css_parser/src/syntax/parse_error.rs index 750cb2dc144e..2aab631f08d2 100644 --- a/crates/biome_css_parser/src/syntax/parse_error.rs +++ b/crates/biome_css_parser/src/syntax/parse_error.rs @@ -11,6 +11,10 @@ pub(crate) fn expected_number(p: &CssParser, range: TextRange) -> ParseDiagnosti expected_node("number", range, p) } +pub(crate) fn expected_string(p: &CssParser, range: TextRange) -> ParseDiagnostic { + expected_node("string", range, p) +} + pub(crate) fn expected_any_pseudo_class_nth(p: &CssParser, range: TextRange) -> ParseDiagnostic { expected_any(&["even", "odd", "n", "", "number"], range, p) } @@ -130,6 +134,33 @@ pub(crate) fn expected_any_pseudo_class(p: &CssParser, range: TextRange) -> Pars .into_diagnostic(p) } +pub(crate) fn expected_any_at_rule(p: &CssParser, range: TextRange) -> ParseDiagnostic { + expect_one_of( + &[ + "charset", + "color-profile", + "container", + "counter-style", + "document", + "font-face", + "font-feature-values", + "font-palette-values", + "import", + "keyframes", + "layer", + "media", + "namespace", + "page", + "property", + "supports", + "viewport", + "scope", + ], + range, + ) + .into_diagnostic(p) +} + pub(crate) fn expected_block(p: &CssParser, range: TextRange) -> ParseDiagnostic { expected_node("body", range, p) } diff --git a/crates/biome_css_parser/src/syntax/selector/attribute.rs b/crates/biome_css_parser/src/syntax/selector/attribute.rs index e0a32b620fa3..a98905ffd35b 100644 --- a/crates/biome_css_parser/src/syntax/selector/attribute.rs +++ b/crates/biome_css_parser/src/syntax/selector/attribute.rs @@ -3,7 +3,7 @@ use crate::syntax::parse_error::{ expected_any_attribute_matcher_name, expected_any_attribute_modifier, expected_identifier, }; use crate::syntax::selector::{is_at_namespace, parse_namespace, selector_lex_context}; -use crate::syntax::{is_at_identifier, parse_css_string, parse_regular_identifier}; +use crate::syntax::{is_at_identifier, parse_regular_identifier, parse_string}; use biome_css_syntax::CssSyntaxKind::*; use biome_css_syntax::{CssSyntaxKind, T}; use biome_parser::diagnostic::expected_token; @@ -103,7 +103,7 @@ fn parse_attribute_matcher_value(p: &mut CssParser) -> ParsedSyntax { let m = p.start(); if p.at(CSS_STRING_LITERAL) { - parse_css_string(p).ok(); + parse_string(p).ok(); } else { parse_regular_identifier(p).ok(); } diff --git a/crates/biome_css_parser/src/syntax/selector/mod.rs b/crates/biome_css_parser/src/syntax/selector/mod.rs index 4199f82e5e70..fa566fe9303f 100644 --- a/crates/biome_css_parser/src/syntax/selector/mod.rs +++ b/crates/biome_css_parser/src/syntax/selector/mod.rs @@ -338,7 +338,10 @@ where if p.eat_with_context(T![')'], context) { true } else { - if let Ok(m) = ParseRecovery::new(CSS_BOGUS, SELECTOR_FUNCTION_RECOVERY_SET).recover(p) { + if let Ok(m) = ParseRecovery::new(CSS_BOGUS, SELECTOR_FUNCTION_RECOVERY_SET) + .enable_recovery_on_line_break() + .recover(p) + { let diagnostic = error_builder( p, TextRange::new(parameter.range(p).start(), m.range(p).end()), @@ -362,6 +365,7 @@ where let start = p.cur_range().start(); let range = ParseRecovery::new(CSS_BOGUS, SELECTOR_FUNCTION_RECOVERY_SET) + .enable_recovery_on_line_break() .recover(p) .map(|m| m.range(p)) .unwrap_or_else(|_| p.cur_range()); diff --git a/crates/biome_css_parser/src/syntax/selector/pseudo_class/function_value_list.rs b/crates/biome_css_parser/src/syntax/selector/pseudo_class/function_value_list.rs index 3f89bb38b5ff..06e753d4b149 100644 --- a/crates/biome_css_parser/src/syntax/selector/pseudo_class/function_value_list.rs +++ b/crates/biome_css_parser/src/syntax/selector/pseudo_class/function_value_list.rs @@ -1,7 +1,7 @@ use crate::parser::CssParser; use crate::syntax::parse_error::expected_identifier; use crate::syntax::selector::eat_or_recover_selector_function_close_token; -use crate::syntax::{is_at_identifier, parse_css_string, parse_regular_identifier}; +use crate::syntax::{is_at_identifier, parse_regular_identifier, parse_string}; use biome_css_syntax::CssSyntaxKind::*; use biome_css_syntax::{CssSyntaxKind, T}; use biome_parser::parse_lists::ParseSeparatedList; @@ -89,7 +89,7 @@ fn parse_pseudo_value(p: &mut CssParser) -> ParsedSyntax { } if p.at(CSS_STRING_LITERAL) { - parse_css_string(p) + parse_string(p) } else { parse_regular_identifier(p) } diff --git a/crates/biome_css_parser/src/syntax/selector/pseudo_class/mod.rs b/crates/biome_css_parser/src/syntax/selector/pseudo_class/mod.rs index 2f833277af43..48d9adaa15c8 100644 --- a/crates/biome_css_parser/src/syntax/selector/pseudo_class/mod.rs +++ b/crates/biome_css_parser/src/syntax/selector/pseudo_class/mod.rs @@ -52,9 +52,13 @@ pub(crate) fn parse_pseudo_class_selector(p: &mut CssParser) -> ParsedSyntax { p.bump(T![:]); - let kind = match parse_pseudo_class(p).or_add_diagnostic(p, expected_any_pseudo_class) { - Some(_) => CSS_PSEUDO_CLASS_SELECTOR, - None => CSS_BOGUS_SUB_SELECTOR, + let kind = if parse_pseudo_class(p) + .or_add_diagnostic(p, expected_any_pseudo_class) + .is_some() + { + CSS_PSEUDO_CLASS_SELECTOR + } else { + CSS_BOGUS_SUB_SELECTOR }; Present(m.complete(p, kind)) diff --git a/crates/biome_css_parser/tests/css_test_suite/error/at_rule/at_rule_charset_error.css b/crates/biome_css_parser/tests/css_test_suite/error/at_rule/at_rule_charset_error.css new file mode 100644 index 000000000000..d3690760c9a4 --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/error/at_rule/at_rule_charset_error.css @@ -0,0 +1,7 @@ +@charset dsadsa; +@charset ; +@charset "iso-8859-15" +@charset "UTF-8" 12321321; +@charset "UTF-8" 12321321 +@charset + diff --git a/crates/biome_css_parser/tests/css_test_suite/error/at_rule/at_rule_charset_error.css.snap b/crates/biome_css_parser/tests/css_test_suite/error/at_rule/at_rule_charset_error.css.snap new file mode 100644 index 000000000000..469912cee4ab --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/error/at_rule/at_rule_charset_error.css.snap @@ -0,0 +1,275 @@ +--- +source: crates/biome_css_parser/tests/spec_test.rs +expression: snapshot +--- + +## Input + +```css +@charset dsadsa; +@charset ; +@charset "iso-8859-15" +@charset "UTF-8" 12321321; +@charset "UTF-8" 12321321 +@charset + + +``` + + +## AST + +``` +CssRoot { + bom_token: missing (optional), + rules: CssRuleList [ + CssAtRule { + at_token: AT@0..1 "@" [] [], + rule: CssBogusAtRule { + items: [ + CHARSET_KW@1..9 "charset" [] [Whitespace(" ")], + CssBogus { + items: [ + IDENT@9..15 "dsadsa" [] [], + ], + }, + SEMICOLON@15..16 ";" [] [], + ], + }, + }, + CssAtRule { + at_token: AT@16..18 "@" [Newline("\n")] [], + rule: CssBogusAtRule { + items: [ + CHARSET_KW@18..26 "charset" [] [Whitespace(" ")], + SEMICOLON@26..27 ";" [] [], + ], + }, + }, + CssAtRule { + at_token: AT@27..29 "@" [Newline("\n")] [], + rule: CssBogusAtRule { + items: [ + CHARSET_KW@29..37 "charset" [] [Whitespace(" ")], + CssString { + value_token: CSS_STRING_LITERAL@37..50 "\"iso-8859-15\"" [] [], + }, + ], + }, + }, + CssAtRule { + at_token: AT@50..52 "@" [Newline("\n")] [], + rule: CssBogusAtRule { + items: [ + CHARSET_KW@52..60 "charset" [] [Whitespace(" ")], + CssString { + value_token: CSS_STRING_LITERAL@60..68 "\"UTF-8\"" [] [Whitespace(" ")], + }, + CssBogus { + items: [ + CSS_NUMBER_LITERAL@68..76 "12321321" [] [], + ], + }, + SEMICOLON@76..77 ";" [] [], + ], + }, + }, + CssAtRule { + at_token: AT@77..79 "@" [Newline("\n")] [], + rule: CssBogusAtRule { + items: [ + CHARSET_KW@79..87 "charset" [] [Whitespace(" ")], + CssString { + value_token: CSS_STRING_LITERAL@87..95 "\"UTF-8\"" [] [Whitespace(" ")], + }, + CssBogus { + items: [ + CSS_NUMBER_LITERAL@95..103 "12321321" [] [], + ], + }, + ], + }, + }, + CssAtRule { + at_token: AT@103..105 "@" [Newline("\n")] [], + rule: CssBogusAtRule { + items: [ + CHARSET_KW@105..112 "charset" [] [], + ], + }, + }, + ], + eof_token: EOF@112..114 "" [Newline("\n"), Newline("\n")] [], +} +``` + +## CST + +``` +0: CSS_ROOT@0..114 + 0: (empty) + 1: CSS_RULE_LIST@0..112 + 0: CSS_AT_RULE@0..16 + 0: AT@0..1 "@" [] [] + 1: CSS_BOGUS_AT_RULE@1..16 + 0: CHARSET_KW@1..9 "charset" [] [Whitespace(" ")] + 1: CSS_BOGUS@9..15 + 0: IDENT@9..15 "dsadsa" [] [] + 2: SEMICOLON@15..16 ";" [] [] + 1: CSS_AT_RULE@16..27 + 0: AT@16..18 "@" [Newline("\n")] [] + 1: CSS_BOGUS_AT_RULE@18..27 + 0: CHARSET_KW@18..26 "charset" [] [Whitespace(" ")] + 1: SEMICOLON@26..27 ";" [] [] + 2: CSS_AT_RULE@27..50 + 0: AT@27..29 "@" [Newline("\n")] [] + 1: CSS_BOGUS_AT_RULE@29..50 + 0: CHARSET_KW@29..37 "charset" [] [Whitespace(" ")] + 1: CSS_STRING@37..50 + 0: CSS_STRING_LITERAL@37..50 "\"iso-8859-15\"" [] [] + 3: CSS_AT_RULE@50..77 + 0: AT@50..52 "@" [Newline("\n")] [] + 1: CSS_BOGUS_AT_RULE@52..77 + 0: CHARSET_KW@52..60 "charset" [] [Whitespace(" ")] + 1: CSS_STRING@60..68 + 0: CSS_STRING_LITERAL@60..68 "\"UTF-8\"" [] [Whitespace(" ")] + 2: CSS_BOGUS@68..76 + 0: CSS_NUMBER_LITERAL@68..76 "12321321" [] [] + 3: SEMICOLON@76..77 ";" [] [] + 4: CSS_AT_RULE@77..103 + 0: AT@77..79 "@" [Newline("\n")] [] + 1: CSS_BOGUS_AT_RULE@79..103 + 0: CHARSET_KW@79..87 "charset" [] [Whitespace(" ")] + 1: CSS_STRING@87..95 + 0: CSS_STRING_LITERAL@87..95 "\"UTF-8\"" [] [Whitespace(" ")] + 2: CSS_BOGUS@95..103 + 0: CSS_NUMBER_LITERAL@95..103 "12321321" [] [] + 5: CSS_AT_RULE@103..112 + 0: AT@103..105 "@" [Newline("\n")] [] + 1: CSS_BOGUS_AT_RULE@105..112 + 0: CHARSET_KW@105..112 "charset" [] [] + 2: EOF@112..114 "" [Newline("\n"), Newline("\n")] [] + +``` + +## Diagnostics + +``` +at_rule_charset_error.css:1:10 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected a string but instead found 'dsadsa'. + + > 1 │ @charset dsadsa; + │ ^^^^^^ + 2 │ @charset ; + 3 │ @charset "iso-8859-15" + + i Expected a string here. + + > 1 │ @charset dsadsa; + │ ^^^^^^ + 2 │ @charset ; + 3 │ @charset "iso-8859-15" + +at_rule_charset_error.css:2:10 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected a string but instead found ';'. + + 1 │ @charset dsadsa; + > 2 │ @charset ; + │ ^ + 3 │ @charset "iso-8859-15" + 4 │ @charset "UTF-8" 12321321; + + i Expected a string here. + + 1 │ @charset dsadsa; + > 2 │ @charset ; + │ ^ + 3 │ @charset "iso-8859-15" + 4 │ @charset "UTF-8" 12321321; + +at_rule_charset_error.css:4:1 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × expected `;` but instead found `@` + + 2 │ @charset ; + 3 │ @charset "iso-8859-15" + > 4 │ @charset "UTF-8" 12321321; + │ ^ + 5 │ @charset "UTF-8" 12321321 + 6 │ @charset + + i Remove @ + +at_rule_charset_error.css:4:10 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected a string but instead found '"UTF-8" 12321321'. + + 2 │ @charset ; + 3 │ @charset "iso-8859-15" + > 4 │ @charset "UTF-8" 12321321; + │ ^^^^^^^^^^^^^^^^ + 5 │ @charset "UTF-8" 12321321 + 6 │ @charset + + i Expected a string here. + + 2 │ @charset ; + 3 │ @charset "iso-8859-15" + > 4 │ @charset "UTF-8" 12321321; + │ ^^^^^^^^^^^^^^^^ + 5 │ @charset "UTF-8" 12321321 + 6 │ @charset + +at_rule_charset_error.css:5:10 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected a string but instead found '"UTF-8" 12321321'. + + 3 │ @charset "iso-8859-15" + 4 │ @charset "UTF-8" 12321321; + > 5 │ @charset "UTF-8" 12321321 + │ ^^^^^^^^^^^^^^^^ + 6 │ @charset + 7 │ + + i Expected a string here. + + 3 │ @charset "iso-8859-15" + 4 │ @charset "UTF-8" 12321321; + > 5 │ @charset "UTF-8" 12321321 + │ ^^^^^^^^^^^^^^^^ + 6 │ @charset + 7 │ + +at_rule_charset_error.css:6:1 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × expected `;` but instead found `@` + + 4 │ @charset "UTF-8" 12321321; + 5 │ @charset "UTF-8" 12321321 + > 6 │ @charset + │ ^ + 7 │ + + i Remove @ + +at_rule_charset_error.css:8:1 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Expected a string but instead found the end of the file. + + 6 │ @charset + 7 │ + > 8 │ + │ + + i Expected a string here. + + 6 │ @charset + 7 │ + > 8 │ + │ + +``` + + diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/at_rule/at_rule_charset.css b/crates/biome_css_parser/tests/css_test_suite/ok/at_rule/at_rule_charset.css new file mode 100644 index 000000000000..8dfd39c45a8f --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/ok/at_rule/at_rule_charset.css @@ -0,0 +1,2 @@ +@charset "UTF-8"; +@charset "iso-8859-15"; diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/at_rule/at_rule_charset.css.snap b/crates/biome_css_parser/tests/css_test_suite/ok/at_rule/at_rule_charset.css.snap new file mode 100644 index 000000000000..3223a84efc4b --- /dev/null +++ b/crates/biome_css_parser/tests/css_test_suite/ok/at_rule/at_rule_charset.css.snap @@ -0,0 +1,70 @@ +--- +source: crates/biome_css_parser/tests/spec_test.rs +expression: snapshot +--- + +## Input + +```css +@charset "UTF-8"; +@charset "iso-8859-15"; + +``` + + +## AST + +``` +CssRoot { + bom_token: missing (optional), + rules: CssRuleList [ + CssAtRule { + at_token: AT@0..1 "@" [] [], + rule: CssCharsetAtRule { + charset_token: CHARSET_KW@1..9 "charset" [] [Whitespace(" ")], + encoding: CssString { + value_token: CSS_STRING_LITERAL@9..16 "\"UTF-8\"" [] [], + }, + semicolon_token: SEMICOLON@16..17 ";" [] [], + }, + }, + CssAtRule { + at_token: AT@17..19 "@" [Newline("\n")] [], + rule: CssCharsetAtRule { + charset_token: CHARSET_KW@19..27 "charset" [] [Whitespace(" ")], + encoding: CssString { + value_token: CSS_STRING_LITERAL@27..40 "\"iso-8859-15\"" [] [], + }, + semicolon_token: SEMICOLON@40..41 ";" [] [], + }, + }, + ], + eof_token: EOF@41..42 "" [Newline("\n")] [], +} +``` + +## CST + +``` +0: CSS_ROOT@0..42 + 0: (empty) + 1: CSS_RULE_LIST@0..41 + 0: CSS_AT_RULE@0..17 + 0: AT@0..1 "@" [] [] + 1: CSS_CHARSET_AT_RULE@1..17 + 0: CHARSET_KW@1..9 "charset" [] [Whitespace(" ")] + 1: CSS_STRING@9..16 + 0: CSS_STRING_LITERAL@9..16 "\"UTF-8\"" [] [] + 2: SEMICOLON@16..17 ";" [] [] + 1: CSS_AT_RULE@17..41 + 0: AT@17..19 "@" [Newline("\n")] [] + 1: CSS_CHARSET_AT_RULE@19..41 + 0: CHARSET_KW@19..27 "charset" [] [Whitespace(" ")] + 1: CSS_STRING@27..40 + 0: CSS_STRING_LITERAL@27..40 "\"iso-8859-15\"" [] [] + 2: SEMICOLON@40..41 ";" [] [] + 2: EOF@41..42 "" [Newline("\n")] [] + +``` + + diff --git a/crates/biome_css_parser/tests/spec_test.rs b/crates/biome_css_parser/tests/spec_test.rs index 858999be5bfe..707f865d4392 100644 --- a/crates/biome_css_parser/tests/spec_test.rs +++ b/crates/biome_css_parser/tests/spec_test.rs @@ -134,7 +134,8 @@ pub fn run(test_case: &str, _snapshot_name: &str, test_directory: &str, outcome_ #[test] pub fn quick_test() { let code = r#" - |h1 {} + @charset dsadsa; + "#; let root = parse_css( code, diff --git a/crates/biome_css_syntax/src/generated/kind.rs b/crates/biome_css_syntax/src/generated/kind.rs index 318aa144b6cf..ab22a7f95ded 100644 --- a/crates/biome_css_syntax/src/generated/kind.rs +++ b/crates/biome_css_syntax/src/generated/kind.rs @@ -227,6 +227,7 @@ pub enum CssSyntaxKind { NTHLASTOFTYPE_KW, NTHCOL_KW, NTHLASTCOL_KW, + CHARSET_KW, LTR_KW, RTL_KW, N_KW, @@ -251,17 +252,6 @@ pub enum CssSyntaxKind { CSS_RULE, CSS_SELECTOR_LIST, CSS_ANY_FUNCTION, - CSS_AT_KEYFRAMES, - CSS_AT_KEYFRAMES_BODY, - CSS_AT_MEDIA, - CSS_AT_MEDIA_QUERY, - CSS_AT_MEDIA_QUERY_CONSEQUENT, - CSS_AT_MEDIA_QUERY_FEATURE, - CSS_AT_MEDIA_QUERY_FEATURE_BOOLEAN, - CSS_AT_MEDIA_QUERY_FEATURE_COMPARE, - CSS_AT_MEDIA_QUERY_FEATURE_PLAIN, - CSS_AT_MEDIA_QUERY_FEATURE_RANGE, - CSS_AT_MEDIA_QUERY_RANGE, CSS_BLOCK, CSS_DECLARATION, CSS_DIMENSION, @@ -276,8 +266,6 @@ pub enum CssSyntaxKind { CSS_STRING, CSS_VAR_FUNCTION, CSS_VAR_FUNCTION_VALUE, - CSS_AT_KEYFRAMES_ITEM_LIST, - CSS_AT_MEDIA_QUERY_LIST, CSS_ATTRIBUTE_LIST, CSS_DECLARATION_LIST, CSS_KEYFRAMES_SELECTOR_LIST, @@ -324,6 +312,21 @@ pub enum CssSyntaxKind { CSS_ATTRIBUTE_NAME, CSS_ATTRIBUTE_MATCHER, CSS_ATTRIBUTE_MATCHER_VALUE, + CSS_AT_RULE, + CSS_CHARSET_AT_RULE, + CSS_KEYFRAMES_AT_RULE, + CSS_KEYFRAMES_BODY, + CSS_MEDIA_AT_RULE, + CSS_MEDIA_QUERY, + CSS_MEDIA_QUERY_CONSEQUENT, + CSS_MEDIA_QUERY_FEATURE, + CSS_MEDIA_QUERY_FEATURE_BOOLEAN, + CSS_MEDIA_QUERY_FEATURE_COMPARE, + CSS_MEDIA_QUERY_FEATURE_PLAIN, + CSS_MEDIA_QUERY_FEATURE_RANGE, + CSS_MEDIA_QUERY_RANGE, + CSS_KEYFRAMES_ITEM_LIST, + CSS_MEDIA_QUERY_LIST, CSS_BOGUS, CSS_BOGUS_BODY, CSS_BOGUS_RULE, @@ -331,6 +334,7 @@ pub enum CssSyntaxKind { CSS_BOGUS_SUB_SELECTOR, CSS_BOGUS_PSEUDO_CLASS, CSS_BOGUS_PSEUDO_ELEMENT, + CSS_BOGUS_AT_RULE, #[doc(hidden)] __LAST, } @@ -358,8 +362,6 @@ impl CssSyntaxKind { match self { CSS_RULE_LIST | CSS_SELECTOR_LIST - | CSS_AT_KEYFRAMES_ITEM_LIST - | CSS_AT_MEDIA_QUERY_LIST | CSS_ATTRIBUTE_LIST | CSS_DECLARATION_LIST | CSS_KEYFRAMES_SELECTOR_LIST @@ -372,7 +374,9 @@ impl CssSyntaxKind { | CSS_PSEUDO_CLASS_FUNCTION_RELATIVE_SELECTOR_LIST | CSS_RELATIVE_SELECTOR_LIST | CSS_PSEUDO_CLASS_FUNCTION_VALUE_LIST - | CSS_PSEUDO_VALUE_LIST => true, + | CSS_PSEUDO_VALUE_LIST + | CSS_KEYFRAMES_ITEM_LIST + | CSS_MEDIA_QUERY_LIST => true, _ => false, } } @@ -551,6 +555,7 @@ impl CssSyntaxKind { "nthlastoftype" => NTHLASTOFTYPE_KW, "nthcol" => NTHCOL_KW, "nthlastcol" => NTHLASTCOL_KW, + "charset" => CHARSET_KW, "ltr" => LTR_KW, "rtl" => RTL_KW, "n" => N_KW, @@ -780,6 +785,7 @@ impl CssSyntaxKind { NTHLASTOFTYPE_KW => "nthlastoftype", NTHCOL_KW => "nthcol", NTHLASTCOL_KW => "nthlastcol", + CHARSET_KW => "charset", LTR_KW => "ltr", RTL_KW => "rtl", N_KW => "n", @@ -797,4 +803,4 @@ impl CssSyntaxKind { } #[doc = r" Utility macro for creating a SyntaxKind through simple macro syntax"] #[macro_export] -macro_rules ! T { [;] => { $ crate :: CssSyntaxKind :: SEMICOLON } ; [,] => { $ crate :: CssSyntaxKind :: COMMA } ; ['('] => { $ crate :: CssSyntaxKind :: L_PAREN } ; [')'] => { $ crate :: CssSyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: CssSyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: CssSyntaxKind :: R_CURLY } ; ['['] => { $ crate :: CssSyntaxKind :: L_BRACK } ; [']'] => { $ crate :: CssSyntaxKind :: R_BRACK } ; [<] => { $ crate :: CssSyntaxKind :: L_ANGLE } ; [>] => { $ crate :: CssSyntaxKind :: R_ANGLE } ; [~] => { $ crate :: CssSyntaxKind :: TILDE } ; [#] => { $ crate :: CssSyntaxKind :: HASH } ; [&] => { $ crate :: CssSyntaxKind :: AMP } ; [|] => { $ crate :: CssSyntaxKind :: PIPE } ; [||] => { $ crate :: CssSyntaxKind :: PIPE2 } ; [+] => { $ crate :: CssSyntaxKind :: PLUS } ; [*] => { $ crate :: CssSyntaxKind :: STAR } ; [/] => { $ crate :: CssSyntaxKind :: SLASH } ; [^] => { $ crate :: CssSyntaxKind :: CARET } ; [%] => { $ crate :: CssSyntaxKind :: PERCENT } ; [.] => { $ crate :: CssSyntaxKind :: DOT } ; [:] => { $ crate :: CssSyntaxKind :: COLON } ; [::] => { $ crate :: CssSyntaxKind :: COLON2 } ; [=] => { $ crate :: CssSyntaxKind :: EQ } ; [!] => { $ crate :: CssSyntaxKind :: BANG } ; [!=] => { $ crate :: CssSyntaxKind :: NEQ } ; [-] => { $ crate :: CssSyntaxKind :: MINUS } ; [<=] => { $ crate :: CssSyntaxKind :: LTEQ } ; [>=] => { $ crate :: CssSyntaxKind :: GTEQ } ; [+=] => { $ crate :: CssSyntaxKind :: PLUSEQ } ; [|=] => { $ crate :: CssSyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: CssSyntaxKind :: AMPEQ } ; [^=] => { $ crate :: CssSyntaxKind :: CARETEQ } ; [/=] => { $ crate :: CssSyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: CssSyntaxKind :: STAREQ } ; [%=] => { $ crate :: CssSyntaxKind :: PERCENTEQ } ; [@] => { $ crate :: CssSyntaxKind :: AT } ; ["$="] => { $ crate :: CssSyntaxKind :: DOLLAR_EQ } ; [~=] => { $ crate :: CssSyntaxKind :: TILDE_EQ } ; [-->] => { $ crate :: CssSyntaxKind :: CDC } ; [] => { $ crate :: CssSyntaxKind :: CDC } ; [