diff --git a/.github/labeler.yml b/.github/labeler.yml index 5de15fb4b680..1de9de90acad 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -110,3 +110,8 @@ L-Grit: - changed-files: - any-glob-to-any-file: - crates/biome_grit_*/** + +L-Tailwind: +- changed-files: + - any-glob-to-any-file: + - crates/biome_tailwind_*/** diff --git a/crates/biome_parser/src/lexer.rs b/crates/biome_parser/src/lexer.rs index af08fdbe47ca..83ce0b3a0a9d 100644 --- a/crates/biome_parser/src/lexer.rs +++ b/crates/biome_parser/src/lexer.rs @@ -201,6 +201,8 @@ pub trait Lexer<'src> { } /// Returns the byte at position `self.position + offset` or `None` if it is out of bounds. + /// + /// See also: [`Self::prev_byte_at`] #[inline] fn byte_at(&self, offset: usize) -> Option { self.source() @@ -218,6 +220,18 @@ pub trait Lexer<'src> { } } + /// Returns the byte at position `self.position - offset` or `None` if it is out of bounds. Looks backwards instead of forwards. + #[inline] + fn prev_byte_at(&self, offset: usize) -> Option { + if offset > self.position() { + return None; + } + self.source() + .as_bytes() + .get(self.position() - offset) + .copied() + } + #[inline] fn text_position(&self) -> TextSize { TextSize::try_from(self.position()).expect("Input to be smaller than 4 GB") diff --git a/crates/biome_tailwind_factory/src/generated/node_factory.rs b/crates/biome_tailwind_factory/src/generated/node_factory.rs index bfde2e40baab..76f7868ee2ac 100644 --- a/crates/biome_tailwind_factory/src/generated/node_factory.rs +++ b/crates/biome_tailwind_factory/src/generated/node_factory.rs @@ -99,15 +99,21 @@ pub fn tw_full_candidate( TwFullCandidateBuilder { variants, candidate, + negative_token: None, excl_token: None, } } pub struct TwFullCandidateBuilder { variants: TwVariantList, candidate: AnyTwCandidate, + negative_token: Option, excl_token: Option, } impl TwFullCandidateBuilder { + pub fn with_negative_token(mut self, negative_token: SyntaxToken) -> Self { + self.negative_token = Some(negative_token); + self + } pub fn with_excl_token(mut self, excl_token: SyntaxToken) -> Self { self.excl_token = Some(excl_token); self @@ -117,6 +123,7 @@ impl TwFullCandidateBuilder { TailwindSyntaxKind::TW_FULL_CANDIDATE, [ Some(SyntaxElement::Node(self.variants.into_syntax())), + self.negative_token.map(|token| SyntaxElement::Token(token)), Some(SyntaxElement::Node(self.candidate.into_syntax())), self.excl_token.map(|token| SyntaxElement::Token(token)), ], diff --git a/crates/biome_tailwind_factory/src/generated/syntax_factory.rs b/crates/biome_tailwind_factory/src/generated/syntax_factory.rs index 6a58941ea683..2af41f08ddaf 100644 --- a/crates/biome_tailwind_factory/src/generated/syntax_factory.rs +++ b/crates/biome_tailwind_factory/src/generated/syntax_factory.rs @@ -171,7 +171,7 @@ impl SyntaxFactory for TailwindSyntaxFactory { } TW_FULL_CANDIDATE => { 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 && TwVariantList::can_cast(element.kind()) @@ -180,6 +180,13 @@ impl SyntaxFactory for TailwindSyntaxFactory { 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 && AnyTwCandidate::can_cast(element.kind()) { diff --git a/crates/biome_tailwind_parser/src/lexer/mod.rs b/crates/biome_tailwind_parser/src/lexer/mod.rs index d8f13072b5e5..8841e454f872 100644 --- a/crates/biome_tailwind_parser/src/lexer/mod.rs +++ b/crates/biome_tailwind_parser/src/lexer/mod.rs @@ -71,6 +71,21 @@ impl<'src> TailwindLexer<'src> { } } + fn consume_token_saw_negative(&mut self, current: u8) -> TailwindSyntaxKind { + match current { + b'\n' | b'\r' | b'\t' | b' ' => self.consume_newline_or_whitespaces(), + bracket @ (b'[' | b']' | b'(' | b')') => self.consume_bracket(bracket), + _ if self.current_kind == T!['['] => self.consume_bracketed_thing(TW_SELECTOR, b']'), + _ if self.current_kind == T!['('] => self.consume_bracketed_thing(TW_VALUE, b')'), + b':' => self.consume_byte(T![:]), + b'-' => self.consume_byte(T![-]), + b'!' => self.consume_byte(T![!]), + b'/' => self.consume_byte(T![/]), + _ if current.is_ascii_alphabetic() => self.consume_base(), + _ => self.consume_unexpected_character(), + } + } + /// Consume a token in the arbitrary context fn consume_token_arbitrary(&mut self, current: u8) -> TailwindSyntaxKind { match current { @@ -252,6 +267,7 @@ impl<'src> Lexer<'src> for TailwindLexer<'src> { match self.current_byte() { Some(current) => match context { TailwindLexContext::Regular => self.consume_token(current), + TailwindLexContext::SawNegative => self.consume_token_saw_negative(current), TailwindLexContext::Arbitrary => self.consume_token_arbitrary(current), TailwindLexContext::ArbitraryVariant => { self.consume_token_arbitrary_variant(current) diff --git a/crates/biome_tailwind_parser/src/lexer/tests.rs b/crates/biome_tailwind_parser/src/lexer/tests.rs index b34a1df15dc3..a6e2cf6a7c7d 100644 --- a/crates/biome_tailwind_parser/src/lexer/tests.rs +++ b/crates/biome_tailwind_parser/src/lexer/tests.rs @@ -191,3 +191,13 @@ fn variant_multiple_full() { TW_VALUE:7 ); } + +#[test] +fn negative() { + assert_lex!( + TailwindLexContext::SawNegative, + "-mt", + DASH:1, + TW_BASE:2, + ); +} diff --git a/crates/biome_tailwind_parser/src/syntax/mod.rs b/crates/biome_tailwind_parser/src/syntax/mod.rs index 8184f24b911e..12f2c50f34d6 100644 --- a/crates/biome_tailwind_parser/src/syntax/mod.rs +++ b/crates/biome_tailwind_parser/src/syntax/mod.rs @@ -56,7 +56,8 @@ impl ParseSeparatedList for CandidateList { ) -> biome_parser::parse_recovery::RecoveryResult { parsed_element.or_recover_with_token_set( p, - &ParseRecoveryTokenSet::new(TW_BOGUS_CANDIDATE, token_set![WHITESPACE, NEWLINE, EOF]), + &ParseRecoveryTokenSet::new(TW_BOGUS_CANDIDATE, token_set![WHITESPACE]) + .enable_recovery_on_line_break(), expected_candidate, ) } @@ -68,11 +69,16 @@ fn parse_full_candidate(p: &mut TailwindParser) -> ParsedSyntax { VariantList.parse_list(p); + if p.at(T![-]) { + p.bump_with_context(T![-], TailwindLexContext::SawNegative); + } + let candidate = parse_arbitrary_candidate(p) .or_else(|| parse_functional_or_static_candidate(p)) .or_recover_with_token_set( p, - &ParseRecoveryTokenSet::new(TW_BOGUS_CANDIDATE, token_set![WHITESPACE, NEWLINE, EOF]), + &ParseRecoveryTokenSet::new(TW_BOGUS_CANDIDATE, token_set![WHITESPACE]) + .enable_recovery_on_line_break(), expected_candidate, ); @@ -112,10 +118,11 @@ fn parse_functional_or_static_candidate(p: &mut TailwindParser) -> ParsedSyntax return Present(m.complete(p, TW_STATIC_CANDIDATE)); } - p.bump(DASH); + p.expect(T![-]); match parse_value(p).or_recover_with_token_set( p, - &ParseRecoveryTokenSet::new(TW_BOGUS_VALUE, token_set![WHITESPACE, NEWLINE, T![!], EOF]), + &ParseRecoveryTokenSet::new(TW_BOGUS_VALUE, token_set![WHITESPACE, T![!]]) + .enable_recovery_on_line_break(), expected_value, ) { Ok(_) => {} @@ -192,10 +199,7 @@ fn parse_modifier(p: &mut TailwindParser) -> ParsedSyntax { } match parse_value(p).or_recover_with_token_set( p, - &ParseRecoveryTokenSet::new( - TW_BOGUS_MODIFIER, - token_set![WHITESPACE, NEWLINE, T![!], EOF], - ), + &ParseRecoveryTokenSet::new(TW_BOGUS_MODIFIER, token_set![WHITESPACE, NEWLINE, T![!]]), expected_value, ) { Ok(_) => {} diff --git a/crates/biome_tailwind_parser/src/syntax/variant.rs b/crates/biome_tailwind_parser/src/syntax/variant.rs index 6aa89da59d07..dc0ef0389357 100644 --- a/crates/biome_tailwind_parser/src/syntax/variant.rs +++ b/crates/biome_tailwind_parser/src/syntax/variant.rs @@ -79,6 +79,10 @@ impl ParseSeparatedList for VariantList { } pub(crate) fn parse_variant(p: &mut TailwindParser) -> ParsedSyntax { + if p.at(T![-]) { + // variants can't start with a negative sign + return Absent; + } if p.at(T!['[']) { return parse_arbitrary_variant(p); } diff --git a/crates/biome_tailwind_parser/src/token_source.rs b/crates/biome_tailwind_parser/src/token_source.rs index da7ac0bc8422..f276099a2cda 100644 --- a/crates/biome_tailwind_parser/src/token_source.rs +++ b/crates/biome_tailwind_parser/src/token_source.rs @@ -22,6 +22,8 @@ pub(crate) enum TailwindLexContext { /// The default state. #[default] Regular, + /// The parser just encountered a `-` before a basename, e.g. in `-mt-4`. That meant that the next token should be a basename. + SawNegative, /// The lexer has encountered a `[` and the parser has yet to encounter the matching `]`. Arbitrary, /// Like Arbitrary, but specifically for arbitrary variants. diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/error/arbitrary-candidate/missing-property.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/error/arbitrary-candidate/missing-property.txt.snap index d09c3a057d1e..a083fe702dc7 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/error/arbitrary-candidate/missing-property.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/error/arbitrary-candidate/missing-property.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwBogusCandidate { items: [ L_BRACKET@0..1 "[" [] [], @@ -30,6 +31,7 @@ TwRoot { WHITESPACE@7..8 " " [] [], TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@8..9 "w" [] [], minus_token: DASH@9..10 "-" [] [], @@ -53,21 +55,23 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..12 0: TW_FULL_CANDIDATE@0..7 0: TW_VARIANT_LIST@0..0 - 1: TW_BOGUS_CANDIDATE@0..7 + 1: (empty) + 2: TW_BOGUS_CANDIDATE@0..7 0: L_BRACKET@0..1 "[" [] [] 1: TW_SELECTOR@1..6 ":40px" [] [] 2: R_BRACKET@6..7 "]" [] [] - 2: (empty) + 3: (empty) 1: WHITESPACE@7..8 " " [] [] 2: TW_FULL_CANDIDATE@8..12 0: TW_VARIANT_LIST@8..8 - 1: TW_FUNCTIONAL_CANDIDATE@8..12 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@8..12 0: TW_BASE@8..9 "w" [] [] 1: DASH@9..10 "-" [] [] 2: TW_NAMED_VALUE@10..12 0: TW_VALUE@10..12 "5" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@12..12 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/error/arbitrary-candidate/missing-value-in-arbitrary.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/error/arbitrary-candidate/missing-value-in-arbitrary.txt.snap index 295894003103..773859a0cae4 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/error/arbitrary-candidate/missing-value-in-arbitrary.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/error/arbitrary-candidate/missing-value-in-arbitrary.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwBogusCandidate { items: [ L_BRACKET@0..1 "[" [] [], @@ -30,6 +31,7 @@ TwRoot { WHITESPACE@8..9 " " [] [], TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@9..10 "w" [] [], minus_token: DASH@10..11 "-" [] [], @@ -53,21 +55,23 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..13 0: TW_FULL_CANDIDATE@0..8 0: TW_VARIANT_LIST@0..0 - 1: TW_BOGUS_CANDIDATE@0..8 + 1: (empty) + 2: TW_BOGUS_CANDIDATE@0..8 0: L_BRACKET@0..1 "[" [] [] 1: TW_SELECTOR@1..7 "width:" [] [] 2: R_BRACKET@7..8 "]" [] [] - 2: (empty) + 3: (empty) 1: WHITESPACE@8..9 " " [] [] 2: TW_FULL_CANDIDATE@9..13 0: TW_VARIANT_LIST@9..9 - 1: TW_FUNCTIONAL_CANDIDATE@9..13 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@9..13 0: TW_BASE@9..10 "w" [] [] 1: DASH@10..11 "-" [] [] 2: TW_NAMED_VALUE@11..13 0: TW_VALUE@11..13 "5" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@13..13 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/error/incomplete-arbitrary-value-0.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/error/incomplete-arbitrary-value-0.txt.snap index ec2d4256242d..930d559eaf17 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/error/incomplete-arbitrary-value-0.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/error/incomplete-arbitrary-value-0.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@0..4 "text" [] [], minus_token: DASH@4..5 "-" [] [], @@ -43,13 +44,14 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..7 0: TW_FULL_CANDIDATE@0..7 0: TW_VARIANT_LIST@0..0 - 1: TW_FUNCTIONAL_CANDIDATE@0..7 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@0..7 0: TW_BASE@0..4 "text" [] [] 1: DASH@4..5 "-" [] [] 2: TW_BOGUS_VALUE@5..7 0: L_BRACKET@5..7 "[" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@7..7 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/error/incomplete-arbitrary-value-1.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/error/incomplete-arbitrary-value-1.txt.snap index a217f8322630..7fe70d5f14c9 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/error/incomplete-arbitrary-value-1.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/error/incomplete-arbitrary-value-1.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@0..4 "text" [] [], minus_token: DASH@4..5 "-" [] [], @@ -44,14 +45,15 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..14 0: TW_FULL_CANDIDATE@0..14 0: TW_VARIANT_LIST@0..0 - 1: TW_FUNCTIONAL_CANDIDATE@0..14 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@0..14 0: TW_BASE@0..4 "text" [] [] 1: DASH@4..5 "-" [] [] 2: TW_BOGUS_VALUE@5..14 0: L_BRACKET@5..6 "[" [] [] 1: TW_SELECTOR@6..14 "#ff0000" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@14..14 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/error/incomplete-arbitrary-value-2.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/error/incomplete-arbitrary-value-2.txt.snap index 73d171cb21db..d112e2fbff89 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/error/incomplete-arbitrary-value-2.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/error/incomplete-arbitrary-value-2.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@0..4 "text" [] [], minus_token: DASH@4..5 "-" [] [], @@ -33,6 +34,7 @@ TwRoot { WHITESPACE@6..7 " " [] [], TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@7..11 "text" [] [], minus_token: DASH@11..12 "-" [] [], @@ -46,6 +48,7 @@ TwRoot { WHITESPACE@14..15 " " [] [], TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@15..17 "bg" [] [], minus_token: DASH@17..18 "-" [] [], @@ -69,33 +72,36 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..26 0: TW_FULL_CANDIDATE@0..6 0: TW_VARIANT_LIST@0..0 - 1: TW_FUNCTIONAL_CANDIDATE@0..6 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@0..6 0: TW_BASE@0..4 "text" [] [] 1: DASH@4..5 "-" [] [] 2: TW_BOGUS_VALUE@5..6 0: L_BRACKET@5..6 "[" [] [] 3: (empty) - 2: (empty) + 3: (empty) 1: WHITESPACE@6..7 " " [] [] 2: TW_FULL_CANDIDATE@7..14 0: TW_VARIANT_LIST@7..7 - 1: TW_FUNCTIONAL_CANDIDATE@7..14 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@7..14 0: TW_BASE@7..11 "text" [] [] 1: DASH@11..12 "-" [] [] 2: TW_NAMED_VALUE@12..14 0: TW_VALUE@12..14 "sm" [] [] 3: (empty) - 2: (empty) + 3: (empty) 3: WHITESPACE@14..15 " " [] [] 4: TW_FULL_CANDIDATE@15..26 0: TW_VARIANT_LIST@15..15 - 1: TW_FUNCTIONAL_CANDIDATE@15..26 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@15..26 0: TW_BASE@15..17 "bg" [] [] 1: DASH@17..18 "-" [] [] 2: TW_NAMED_VALUE@18..26 0: TW_VALUE@18..26 "red-500" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@26..26 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/error/incomplete-arbitrary-variant.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/error/incomplete-arbitrary-variant.txt.snap index 7fabfafdbb65..7a7ff4417cac 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/error/incomplete-arbitrary-variant.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/error/incomplete-arbitrary-variant.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@0..4 "aria" [] [], minus_token: DASH@4..5 "-" [] [], @@ -44,14 +45,15 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..18 0: TW_FULL_CANDIDATE@0..18 0: TW_VARIANT_LIST@0..0 - 1: TW_FUNCTIONAL_CANDIDATE@0..18 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@0..18 0: TW_BASE@0..4 "aria" [] [] 1: DASH@4..5 "-" [] [] 2: TW_BOGUS_VALUE@5..18 0: L_BRACKET@5..6 "[" [] [] 1: TW_SELECTOR@6..18 "foo:text-sm" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@18..18 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/error/missing-modifier-value-1.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/error/missing-modifier-value-1.txt.snap index 483d49e72d8c..3bd3131d7425 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/error/missing-modifier-value-1.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/error/missing-modifier-value-1.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@0..2 "bg" [] [], minus_token: DASH@2..3 "-" [] [], @@ -50,7 +51,8 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..15 0: TW_FULL_CANDIDATE@0..15 0: TW_VARIANT_LIST@0..0 - 1: TW_FUNCTIONAL_CANDIDATE@0..13 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@0..13 0: TW_BASE@0..2 "bg" [] [] 1: DASH@2..3 "-" [] [] 2: TW_NAMED_VALUE@3..12 @@ -59,7 +61,7 @@ TwRoot { 0: SLASH@12..13 "/" [] [] 1: TW_BOGUS_MODIFIER@13..13 0: ERROR_TOKEN@13..13 "" [] [] - 2: BANG@13..15 "!" [] [Newline("\n")] + 3: BANG@13..15 "!" [] [Newline("\n")] 2: EOF@15..15 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/error/missing-modifier-value.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/error/missing-modifier-value.txt.snap index dfeb32e079fc..1fc6168553ab 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/error/missing-modifier-value.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/error/missing-modifier-value.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwBogusCandidate { items: [ TW_BASE@0..2 "bg" [] [], @@ -43,13 +44,14 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..14 0: TW_FULL_CANDIDATE@0..14 0: TW_VARIANT_LIST@0..0 - 1: TW_BOGUS_CANDIDATE@0..14 + 1: (empty) + 2: TW_BOGUS_CANDIDATE@0..14 0: TW_BASE@0..2 "bg" [] [] 1: DASH@2..3 "-" [] [] 2: TW_NAMED_VALUE@3..12 0: TW_VALUE@3..12 "green-500" [] [] 3: SLASH@12..14 "/" [] [Newline("\n")] - 2: (empty) + 3: (empty) 2: EOF@14..14 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/error/missing-value.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/error/missing-value.txt.snap index 8cf05b9fcfb3..bbb65d587b15 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/error/missing-value.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/error/missing-value.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwBogusCandidate { items: [ TW_BASE@0..4 "text" [] [], @@ -39,10 +40,11 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..6 0: TW_FULL_CANDIDATE@0..6 0: TW_VARIANT_LIST@0..0 - 1: TW_BOGUS_CANDIDATE@0..6 + 1: (empty) + 2: TW_BOGUS_CANDIDATE@0..6 0: TW_BASE@0..4 "text" [] [] 1: DASH@4..6 "-" [] [Newline("\n")] - 2: (empty) + 3: (empty) 2: EOF@6..6 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/brackets/gradient.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/brackets/gradient.txt.snap index de101155a6e4..bf12572d1f42 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/brackets/gradient.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/brackets/gradient.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@0..9 "bg-radial" [] [], minus_token: DASH@9..10 "-" [] [], @@ -33,6 +34,7 @@ TwRoot { WHITESPACE@22..23 " " [] [], TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@23..27 "from" [] [], minus_token: DASH@27..28 "-" [] [], @@ -46,6 +48,7 @@ TwRoot { WHITESPACE@35..36 " " [] [], TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@36..39 "via" [] [], minus_token: DASH@39..40 "-" [] [], @@ -59,6 +62,7 @@ TwRoot { WHITESPACE@48..49 " " [] [], TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@49..51 "to" [] [], minus_token: DASH@51..52 "-" [] [], @@ -72,6 +76,7 @@ TwRoot { WHITESPACE@62..63 " " [] [], TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@63..65 "to" [] [], minus_token: DASH@65..66 "-" [] [], @@ -95,7 +100,8 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..70 0: TW_FULL_CANDIDATE@0..22 0: TW_VARIANT_LIST@0..0 - 1: TW_FUNCTIONAL_CANDIDATE@0..22 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@0..22 0: TW_BASE@0..9 "bg-radial" [] [] 1: DASH@9..10 "-" [] [] 2: TW_ARBITRARY_VALUE@10..22 @@ -103,47 +109,51 @@ TwRoot { 1: TW_VALUE@11..21 "at_50%_75%" [] [] 2: R_BRACKET@21..22 "]" [] [] 3: (empty) - 2: (empty) + 3: (empty) 1: WHITESPACE@22..23 " " [] [] 2: TW_FULL_CANDIDATE@23..35 0: TW_VARIANT_LIST@23..23 - 1: TW_FUNCTIONAL_CANDIDATE@23..35 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@23..35 0: TW_BASE@23..27 "from" [] [] 1: DASH@27..28 "-" [] [] 2: TW_NAMED_VALUE@28..35 0: TW_VALUE@28..35 "sky-200" [] [] 3: (empty) - 2: (empty) + 3: (empty) 3: WHITESPACE@35..36 " " [] [] 4: TW_FULL_CANDIDATE@36..48 0: TW_VARIANT_LIST@36..36 - 1: TW_FUNCTIONAL_CANDIDATE@36..48 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@36..48 0: TW_BASE@36..39 "via" [] [] 1: DASH@39..40 "-" [] [] 2: TW_NAMED_VALUE@40..48 0: TW_VALUE@40..48 "blue-400" [] [] 3: (empty) - 2: (empty) + 3: (empty) 5: WHITESPACE@48..49 " " [] [] 6: TW_FULL_CANDIDATE@49..62 0: TW_VARIANT_LIST@49..49 - 1: TW_FUNCTIONAL_CANDIDATE@49..62 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@49..62 0: TW_BASE@49..51 "to" [] [] 1: DASH@51..52 "-" [] [] 2: TW_NAMED_VALUE@52..62 0: TW_VALUE@52..62 "indigo-900" [] [] 3: (empty) - 2: (empty) + 3: (empty) 7: WHITESPACE@62..63 " " [] [] 8: TW_FULL_CANDIDATE@63..70 0: TW_VARIANT_LIST@63..63 - 1: TW_FUNCTIONAL_CANDIDATE@63..70 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@63..70 0: TW_BASE@63..65 "to" [] [] 1: DASH@65..66 "-" [] [] 2: TW_NAMED_VALUE@66..70 0: TW_VALUE@66..70 "90%" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@70..70 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/brackets/image-url.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/brackets/image-url.txt.snap index ae06e8007250..155c11cb4f08 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/brackets/image-url.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/brackets/image-url.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@0..2 "bg" [] [], minus_token: DASH@2..3 "-" [] [], @@ -43,7 +44,8 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..29 0: TW_FULL_CANDIDATE@0..29 0: TW_VARIANT_LIST@0..0 - 1: TW_FUNCTIONAL_CANDIDATE@0..29 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@0..29 0: TW_BASE@0..2 "bg" [] [] 1: DASH@2..3 "-" [] [] 2: TW_ARBITRARY_VALUE@3..29 @@ -51,7 +53,7 @@ TwRoot { 1: TW_VALUE@4..27 "url(/img/mountains.jpg)" [] [] 2: R_BRACKET@27..29 "]" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@29..29 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/brackets/shadow.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/brackets/shadow.txt.snap index 227a1adaf772..e2a6268df1d4 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/brackets/shadow.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/brackets/shadow.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@0..6 "shadow" [] [], minus_token: DASH@6..7 "-" [] [], @@ -43,7 +44,8 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..21 0: TW_FULL_CANDIDATE@0..21 0: TW_VARIANT_LIST@0..0 - 1: TW_FUNCTIONAL_CANDIDATE@0..21 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@0..21 0: TW_BASE@0..6 "shadow" [] [] 1: DASH@6..7 "-" [] [] 2: TW_ARBITRARY_VALUE@7..21 @@ -51,7 +53,7 @@ TwRoot { 1: TW_VALUE@8..19 "0px_2px_4px" [] [] 2: R_BRACKET@19..21 "]" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@21..21 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/candidates/arbitrary-candidate-0.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/candidates/arbitrary-candidate-0.txt.snap index 493c2c67864d..a45acd338dd6 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/candidates/arbitrary-candidate-0.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/candidates/arbitrary-candidate-0.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwArbitraryCandidate { l_brack_token: L_BRACKET@0..1 "[" [] [], property_token: TW_PROPERTY@1..6 "color" [] [], @@ -46,7 +47,8 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..15 0: TW_FULL_CANDIDATE@0..15 0: TW_VARIANT_LIST@0..0 - 1: TW_ARBITRARY_CANDIDATE@0..15 + 1: (empty) + 2: TW_ARBITRARY_CANDIDATE@0..15 0: L_BRACKET@0..1 "[" [] [] 1: TW_PROPERTY@1..6 "color" [] [] 2: COLON@6..7 ":" [] [] @@ -56,7 +58,7 @@ TwRoot { 0: SLASH@11..12 "/" [] [] 1: TW_NAMED_VALUE@12..15 0: TW_VALUE@12..15 "50" [] [Newline("\n")] - 2: (empty) + 3: (empty) 2: EOF@15..15 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/candidates/arbitrary-candidate-1.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/candidates/arbitrary-candidate-1.txt.snap index 4bc19687b076..c55493fde44e 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/candidates/arbitrary-candidate-1.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/candidates/arbitrary-candidate-1.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwArbitraryCandidate { l_brack_token: L_BRACKET@0..1 "[" [] [], property_token: TW_PROPERTY@1..13 "--pattern-fg" [] [], @@ -46,7 +47,8 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..39 0: TW_FULL_CANDIDATE@0..39 0: TW_VARIANT_LIST@0..0 - 1: TW_ARBITRARY_CANDIDATE@0..39 + 1: (empty) + 2: TW_ARBITRARY_CANDIDATE@0..39 0: L_BRACKET@0..1 "[" [] [] 1: TW_PROPERTY@1..13 "--pattern-fg" [] [] 2: COLON@13..14 ":" [] [] @@ -56,7 +58,7 @@ TwRoot { 0: SLASH@36..37 "/" [] [] 1: TW_NAMED_VALUE@37..39 0: TW_VALUE@37..39 "5" [] [Newline("\n")] - 2: (empty) + 3: (empty) 2: EOF@39..39 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/candidates/arbitrary-candidate-2.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/candidates/arbitrary-candidate-2.txt.snap index 89c1ac51779e..84dfc7aa3edf 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/candidates/arbitrary-candidate-2.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/candidates/arbitrary-candidate-2.txt.snap @@ -23,6 +23,7 @@ TwRoot { }, COLON@4..5 ":" [] [], ], + negative_token: missing (optional), candidate: TwArbitraryCandidate { l_brack_token: L_BRACKET@5..6 "[" [] [], property_token: TW_PROPERTY@6..18 "--pattern-fg" [] [], @@ -54,7 +55,8 @@ TwRoot { 0: TW_STATIC_VARIANT@0..4 0: TW_BASE@0..4 "dark" [] [] 1: COLON@4..5 ":" [] [] - 1: TW_ARBITRARY_CANDIDATE@5..42 + 1: (empty) + 2: TW_ARBITRARY_CANDIDATE@5..42 0: L_BRACKET@5..6 "[" [] [] 1: TW_PROPERTY@6..18 "--pattern-fg" [] [] 2: COLON@18..19 ":" [] [] @@ -64,7 +66,7 @@ TwRoot { 0: SLASH@38..39 "/" [] [] 1: TW_NAMED_VALUE@39..42 0: TW_VALUE@39..42 "10" [] [Newline("\n")] - 2: (empty) + 3: (empty) 2: EOF@42..42 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/candidates/arbitrary-candidate-3.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/candidates/arbitrary-candidate-3.txt.snap index a0f4f5bb50d6..95c25206ef15 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/candidates/arbitrary-candidate-3.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/candidates/arbitrary-candidate-3.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwArbitraryCandidate { l_brack_token: L_BRACKET@0..1 "[" [] [], property_token: TW_PROPERTY@1..11 "background" [] [], @@ -41,14 +42,15 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..18 0: TW_FULL_CANDIDATE@0..18 0: TW_VARIANT_LIST@0..0 - 1: TW_ARBITRARY_CANDIDATE@0..18 + 1: (empty) + 2: TW_ARBITRARY_CANDIDATE@0..18 0: L_BRACKET@0..1 "[" [] [] 1: TW_PROPERTY@1..11 "background" [] [] 2: COLON@11..12 ":" [] [] 3: TW_VALUE@12..16 "blue" [] [] 4: R_BRACKET@16..18 "]" [] [Newline("\n")] 5: (empty) - 2: (empty) + 3: (empty) 2: EOF@18..18 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/gradients/precise-control.txt b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/gradients/precise-control.txt new file mode 100644 index 000000000000..74eed4fca729 --- /dev/null +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/gradients/precise-control.txt @@ -0,0 +1 @@ +bg-gradient-to-r from-indigo-500 from-10% via-sky-500 via-30% to-emerald-500 to-90% diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/gradients/precise-control.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/gradients/precise-control.txt.snap new file mode 100644 index 000000000000..2885e7b8e43a --- /dev/null +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/gradients/precise-control.txt.snap @@ -0,0 +1,205 @@ +--- +source: crates/biome_tailwind_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```text +bg-gradient-to-r from-indigo-500 from-10% via-sky-500 via-30% to-emerald-500 to-90% + +``` + + +## AST + +``` +TwRoot { + bom_token: missing (optional), + candidates: TwCandidateList [ + TwFullCandidate { + variants: TwVariantList [], + negative_token: missing (optional), + candidate: TwFunctionalCandidate { + base_token: TW_BASE@0..2 "bg" [] [], + minus_token: DASH@2..3 "-" [] [], + value: TwNamedValue { + value_token: TW_VALUE@3..16 "gradient-to-r" [] [], + }, + modifier: missing (optional), + }, + excl_token: missing (optional), + }, + WHITESPACE@16..17 " " [] [], + TwFullCandidate { + variants: TwVariantList [], + negative_token: missing (optional), + candidate: TwFunctionalCandidate { + base_token: TW_BASE@17..21 "from" [] [], + minus_token: DASH@21..22 "-" [] [], + value: TwNamedValue { + value_token: TW_VALUE@22..32 "indigo-500" [] [], + }, + modifier: missing (optional), + }, + excl_token: missing (optional), + }, + WHITESPACE@32..33 " " [] [], + TwFullCandidate { + variants: TwVariantList [], + negative_token: missing (optional), + candidate: TwFunctionalCandidate { + base_token: TW_BASE@33..37 "from" [] [], + minus_token: DASH@37..38 "-" [] [], + value: TwNamedValue { + value_token: TW_VALUE@38..41 "10%" [] [], + }, + modifier: missing (optional), + }, + excl_token: missing (optional), + }, + WHITESPACE@41..42 " " [] [], + TwFullCandidate { + variants: TwVariantList [], + negative_token: missing (optional), + candidate: TwFunctionalCandidate { + base_token: TW_BASE@42..45 "via" [] [], + minus_token: DASH@45..46 "-" [] [], + value: TwNamedValue { + value_token: TW_VALUE@46..53 "sky-500" [] [], + }, + modifier: missing (optional), + }, + excl_token: missing (optional), + }, + WHITESPACE@53..54 " " [] [], + TwFullCandidate { + variants: TwVariantList [], + negative_token: missing (optional), + candidate: TwFunctionalCandidate { + base_token: TW_BASE@54..57 "via" [] [], + minus_token: DASH@57..58 "-" [] [], + value: TwNamedValue { + value_token: TW_VALUE@58..61 "30%" [] [], + }, + modifier: missing (optional), + }, + excl_token: missing (optional), + }, + WHITESPACE@61..62 " " [] [], + TwFullCandidate { + variants: TwVariantList [], + negative_token: missing (optional), + candidate: TwFunctionalCandidate { + base_token: TW_BASE@62..64 "to" [] [], + minus_token: DASH@64..65 "-" [] [], + value: TwNamedValue { + value_token: TW_VALUE@65..76 "emerald-500" [] [], + }, + modifier: missing (optional), + }, + excl_token: missing (optional), + }, + WHITESPACE@76..77 " " [] [], + TwFullCandidate { + variants: TwVariantList [], + negative_token: missing (optional), + candidate: TwFunctionalCandidate { + base_token: TW_BASE@77..79 "to" [] [], + minus_token: DASH@79..80 "-" [] [], + value: TwNamedValue { + value_token: TW_VALUE@80..84 "90%" [] [Newline("\n")], + }, + modifier: missing (optional), + }, + excl_token: missing (optional), + }, + ], + eof_token: EOF@84..84 "" [] [], +} +``` + +## CST + +``` +0: TW_ROOT@0..84 + 0: (empty) + 1: TW_CANDIDATE_LIST@0..84 + 0: TW_FULL_CANDIDATE@0..16 + 0: TW_VARIANT_LIST@0..0 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@0..16 + 0: TW_BASE@0..2 "bg" [] [] + 1: DASH@2..3 "-" [] [] + 2: TW_NAMED_VALUE@3..16 + 0: TW_VALUE@3..16 "gradient-to-r" [] [] + 3: (empty) + 3: (empty) + 1: WHITESPACE@16..17 " " [] [] + 2: TW_FULL_CANDIDATE@17..32 + 0: TW_VARIANT_LIST@17..17 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@17..32 + 0: TW_BASE@17..21 "from" [] [] + 1: DASH@21..22 "-" [] [] + 2: TW_NAMED_VALUE@22..32 + 0: TW_VALUE@22..32 "indigo-500" [] [] + 3: (empty) + 3: (empty) + 3: WHITESPACE@32..33 " " [] [] + 4: TW_FULL_CANDIDATE@33..41 + 0: TW_VARIANT_LIST@33..33 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@33..41 + 0: TW_BASE@33..37 "from" [] [] + 1: DASH@37..38 "-" [] [] + 2: TW_NAMED_VALUE@38..41 + 0: TW_VALUE@38..41 "10%" [] [] + 3: (empty) + 3: (empty) + 5: WHITESPACE@41..42 " " [] [] + 6: TW_FULL_CANDIDATE@42..53 + 0: TW_VARIANT_LIST@42..42 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@42..53 + 0: TW_BASE@42..45 "via" [] [] + 1: DASH@45..46 "-" [] [] + 2: TW_NAMED_VALUE@46..53 + 0: TW_VALUE@46..53 "sky-500" [] [] + 3: (empty) + 3: (empty) + 7: WHITESPACE@53..54 " " [] [] + 8: TW_FULL_CANDIDATE@54..61 + 0: TW_VARIANT_LIST@54..54 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@54..61 + 0: TW_BASE@54..57 "via" [] [] + 1: DASH@57..58 "-" [] [] + 2: TW_NAMED_VALUE@58..61 + 0: TW_VALUE@58..61 "30%" [] [] + 3: (empty) + 3: (empty) + 9: WHITESPACE@61..62 " " [] [] + 10: TW_FULL_CANDIDATE@62..76 + 0: TW_VARIANT_LIST@62..62 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@62..76 + 0: TW_BASE@62..64 "to" [] [] + 1: DASH@64..65 "-" [] [] + 2: TW_NAMED_VALUE@65..76 + 0: TW_VALUE@65..76 "emerald-500" [] [] + 3: (empty) + 3: (empty) + 11: WHITESPACE@76..77 " " [] [] + 12: TW_FULL_CANDIDATE@77..84 + 0: TW_VARIANT_LIST@77..77 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@77..84 + 0: TW_BASE@77..79 "to" [] [] + 1: DASH@79..80 "-" [] [] + 2: TW_NAMED_VALUE@80..84 + 0: TW_VALUE@80..84 "90%" [] [Newline("\n")] + 3: (empty) + 3: (empty) + 2: EOF@84..84 "" [] [] + +``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/gradients/simple.txt b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/gradients/simple.txt new file mode 100644 index 000000000000..d7be3eb2cd0b --- /dev/null +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/gradients/simple.txt @@ -0,0 +1 @@ +bg-gradient-to-r from-indigo-500 via-purple-500 to-pink-500 diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/gradients/simple.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/gradients/simple.txt.snap new file mode 100644 index 000000000000..a959815ac7b6 --- /dev/null +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/gradients/simple.txt.snap @@ -0,0 +1,130 @@ +--- +source: crates/biome_tailwind_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```text +bg-gradient-to-r from-indigo-500 via-purple-500 to-pink-500 + +``` + + +## AST + +``` +TwRoot { + bom_token: missing (optional), + candidates: TwCandidateList [ + TwFullCandidate { + variants: TwVariantList [], + negative_token: missing (optional), + candidate: TwFunctionalCandidate { + base_token: TW_BASE@0..2 "bg" [] [], + minus_token: DASH@2..3 "-" [] [], + value: TwNamedValue { + value_token: TW_VALUE@3..16 "gradient-to-r" [] [], + }, + modifier: missing (optional), + }, + excl_token: missing (optional), + }, + WHITESPACE@16..17 " " [] [], + TwFullCandidate { + variants: TwVariantList [], + negative_token: missing (optional), + candidate: TwFunctionalCandidate { + base_token: TW_BASE@17..21 "from" [] [], + minus_token: DASH@21..22 "-" [] [], + value: TwNamedValue { + value_token: TW_VALUE@22..32 "indigo-500" [] [], + }, + modifier: missing (optional), + }, + excl_token: missing (optional), + }, + WHITESPACE@32..33 " " [] [], + TwFullCandidate { + variants: TwVariantList [], + negative_token: missing (optional), + candidate: TwFunctionalCandidate { + base_token: TW_BASE@33..36 "via" [] [], + minus_token: DASH@36..37 "-" [] [], + value: TwNamedValue { + value_token: TW_VALUE@37..47 "purple-500" [] [], + }, + modifier: missing (optional), + }, + excl_token: missing (optional), + }, + WHITESPACE@47..48 " " [] [], + TwFullCandidate { + variants: TwVariantList [], + negative_token: missing (optional), + candidate: TwFunctionalCandidate { + base_token: TW_BASE@48..50 "to" [] [], + minus_token: DASH@50..51 "-" [] [], + value: TwNamedValue { + value_token: TW_VALUE@51..60 "pink-500" [] [Newline("\n")], + }, + modifier: missing (optional), + }, + excl_token: missing (optional), + }, + ], + eof_token: EOF@60..60 "" [] [], +} +``` + +## CST + +``` +0: TW_ROOT@0..60 + 0: (empty) + 1: TW_CANDIDATE_LIST@0..60 + 0: TW_FULL_CANDIDATE@0..16 + 0: TW_VARIANT_LIST@0..0 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@0..16 + 0: TW_BASE@0..2 "bg" [] [] + 1: DASH@2..3 "-" [] [] + 2: TW_NAMED_VALUE@3..16 + 0: TW_VALUE@3..16 "gradient-to-r" [] [] + 3: (empty) + 3: (empty) + 1: WHITESPACE@16..17 " " [] [] + 2: TW_FULL_CANDIDATE@17..32 + 0: TW_VARIANT_LIST@17..17 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@17..32 + 0: TW_BASE@17..21 "from" [] [] + 1: DASH@21..22 "-" [] [] + 2: TW_NAMED_VALUE@22..32 + 0: TW_VALUE@22..32 "indigo-500" [] [] + 3: (empty) + 3: (empty) + 3: WHITESPACE@32..33 " " [] [] + 4: TW_FULL_CANDIDATE@33..47 + 0: TW_VARIANT_LIST@33..33 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@33..47 + 0: TW_BASE@33..36 "via" [] [] + 1: DASH@36..37 "-" [] [] + 2: TW_NAMED_VALUE@37..47 + 0: TW_VALUE@37..47 "purple-500" [] [] + 3: (empty) + 3: (empty) + 5: WHITESPACE@47..48 " " [] [] + 6: TW_FULL_CANDIDATE@48..60 + 0: TW_VARIANT_LIST@48..48 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@48..60 + 0: TW_BASE@48..50 "to" [] [] + 1: DASH@50..51 "-" [] [] + 2: TW_NAMED_VALUE@51..60 + 0: TW_VALUE@51..60 "pink-500" [] [Newline("\n")] + 3: (empty) + 3: (empty) + 2: EOF@60..60 "" [] [] + +``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/arbitrary-value-0.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/arbitrary-value-0.txt.snap index 4cb649da5da1..32e3c7a0e620 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/arbitrary-value-0.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/arbitrary-value-0.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@0..2 "bg" [] [], minus_token: DASH@2..3 "-" [] [], @@ -43,7 +44,8 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..13 0: TW_FULL_CANDIDATE@0..13 0: TW_VARIANT_LIST@0..0 - 1: TW_FUNCTIONAL_CANDIDATE@0..13 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@0..13 0: TW_BASE@0..2 "bg" [] [] 1: DASH@2..3 "-" [] [] 2: TW_ARBITRARY_VALUE@3..13 @@ -51,7 +53,7 @@ TwRoot { 1: TW_VALUE@4..11 "#ff0000" [] [] 2: R_BRACKET@11..13 "]" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@13..13 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/arbitrary-value-1.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/arbitrary-value-1.txt.snap index 07a53bd0ddb3..de0d76a7758e 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/arbitrary-value-1.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/arbitrary-value-1.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@0..2 "px" [] [], minus_token: DASH@2..3 "-" [] [], @@ -43,7 +44,8 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..10 0: TW_FULL_CANDIDATE@0..10 0: TW_VARIANT_LIST@0..0 - 1: TW_FUNCTIONAL_CANDIDATE@0..10 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@0..10 0: TW_BASE@0..2 "px" [] [] 1: DASH@2..3 "-" [] [] 2: TW_ARBITRARY_VALUE@3..10 @@ -51,7 +53,7 @@ TwRoot { 1: TW_VALUE@4..8 "16px" [] [] 2: R_BRACKET@8..10 "]" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@10..10 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/base-has-dash-0.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/base-has-dash-0.txt.snap index 3a803c97f65e..dbcb57ae55bd 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/base-has-dash-0.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/base-has-dash-0.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@0..11 "drop-shadow" [] [], minus_token: DASH@11..12 "-" [] [], @@ -41,13 +42,14 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..20 0: TW_FULL_CANDIDATE@0..20 0: TW_VARIANT_LIST@0..0 - 1: TW_FUNCTIONAL_CANDIDATE@0..20 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@0..20 0: TW_BASE@0..11 "drop-shadow" [] [] 1: DASH@11..12 "-" [] [] 2: TW_NAMED_VALUE@12..20 0: TW_VALUE@12..20 "red-500" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@20..20 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/base-has-dash-1.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/base-has-dash-1.txt.snap index d1d95962acc6..aad8b03d5f83 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/base-has-dash-1.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/base-has-dash-1.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@0..11 "drop-shadow" [] [], minus_token: DASH@11..12 "-" [] [], @@ -43,7 +44,8 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..22 0: TW_FULL_CANDIDATE@0..22 0: TW_VARIANT_LIST@0..0 - 1: TW_FUNCTIONAL_CANDIDATE@0..22 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@0..22 0: TW_BASE@0..11 "drop-shadow" [] [] 1: DASH@11..12 "-" [] [] 2: TW_ARBITRARY_VALUE@12..22 @@ -51,7 +53,7 @@ TwRoot { 1: TW_VALUE@13..20 "#000000" [] [] 2: R_BRACKET@20..22 "]" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@22..22 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/base-has-dash-2.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/base-has-dash-2.txt.snap index 1a395d2644b7..95028e1b39d3 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/base-has-dash-2.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/base-has-dash-2.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@0..16 "border-spacing-y" [] [], minus_token: DASH@16..17 "-" [] [], @@ -43,7 +44,8 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..23 0: TW_FULL_CANDIDATE@0..23 0: TW_VARIANT_LIST@0..0 - 1: TW_FUNCTIONAL_CANDIDATE@0..23 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@0..23 0: TW_BASE@0..16 "border-spacing-y" [] [] 1: DASH@16..17 "-" [] [] 2: TW_ARBITRARY_VALUE@17..23 @@ -51,7 +53,7 @@ TwRoot { 1: TW_VALUE@18..21 "2px" [] [] 2: R_BRACKET@21..23 "]" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@23..23 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/basic-0.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/basic-0.txt.snap index d10281aa4f9e..688f5acecf1a 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/basic-0.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/basic-0.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@0..4 "text" [] [], minus_token: DASH@4..5 "-" [] [], @@ -41,13 +42,14 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..8 0: TW_FULL_CANDIDATE@0..8 0: TW_VARIANT_LIST@0..0 - 1: TW_FUNCTIONAL_CANDIDATE@0..8 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@0..8 0: TW_BASE@0..4 "text" [] [] 1: DASH@4..5 "-" [] [] 2: TW_NAMED_VALUE@5..8 0: TW_VALUE@5..8 "md" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@8..8 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/basic-1.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/basic-1.txt.snap index 84d170c49a6d..7aa39c40738d 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/basic-1.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/basic-1.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@0..2 "bg" [] [], minus_token: DASH@2..3 "-" [] [], @@ -41,13 +42,14 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..11 0: TW_FULL_CANDIDATE@0..11 0: TW_VARIANT_LIST@0..0 - 1: TW_FUNCTIONAL_CANDIDATE@0..11 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@0..11 0: TW_BASE@0..2 "bg" [] [] 1: DASH@2..3 "-" [] [] 2: TW_NAMED_VALUE@3..11 0: TW_VALUE@3..11 "red-500" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@11..11 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/css-value.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/css-value.txt.snap index ac574f9c8fb2..108c8b725804 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/css-value.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/css-value.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@0..4 "text" [] [], minus_token: DASH@4..5 "-" [] [], @@ -43,7 +44,8 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..18 0: TW_FULL_CANDIDATE@0..18 0: TW_VARIANT_LIST@0..0 - 1: TW_FUNCTIONAL_CANDIDATE@0..18 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@0..18 0: TW_BASE@0..4 "text" [] [] 1: DASH@4..5 "-" [] [] 2: TW_CSS_VARIABLE_VALUE@5..18 @@ -51,7 +53,7 @@ TwRoot { 1: TW_VALUE@6..16 "--my-color" [] [] 2: R_PAREN@16..18 ")" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@18..18 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/important.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/important.txt.snap index 4bf4cfcd6878..2717163ae7b2 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/important.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/important.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@0..4 "text" [] [], minus_token: DASH@4..5 "-" [] [], @@ -41,13 +42,14 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..9 0: TW_FULL_CANDIDATE@0..9 0: TW_VARIANT_LIST@0..0 - 1: TW_FUNCTIONAL_CANDIDATE@0..7 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@0..7 0: TW_BASE@0..4 "text" [] [] 1: DASH@4..5 "-" [] [] 2: TW_NAMED_VALUE@5..7 0: TW_VALUE@5..7 "lg" [] [] 3: (empty) - 2: BANG@7..9 "!" [] [Newline("\n")] + 3: BANG@7..9 "!" [] [Newline("\n")] 2: EOF@9..9 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/modifier.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/modifier.txt.snap index f1486f6692c4..8f90fe8c295f 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/modifier.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/modifier.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@0..2 "bg" [] [], minus_token: DASH@2..3 "-" [] [], @@ -46,7 +47,8 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..14 0: TW_FULL_CANDIDATE@0..14 0: TW_VARIANT_LIST@0..0 - 1: TW_FUNCTIONAL_CANDIDATE@0..14 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@0..14 0: TW_BASE@0..2 "bg" [] [] 1: DASH@2..3 "-" [] [] 2: TW_NAMED_VALUE@3..10 @@ -55,7 +57,7 @@ TwRoot { 0: SLASH@10..11 "/" [] [] 1: TW_NAMED_VALUE@11..14 0: TW_VALUE@11..14 "10" [] [Newline("\n")] - 2: (empty) + 3: (empty) 2: EOF@14..14 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/multiple-spaces.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/multiple-spaces.txt.snap index 913bd9abb148..3ff3091e52b3 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/multiple-spaces.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/multiple-spaces.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwStaticCandidate { base_token: TW_BASE@0..6 "border" [] [], }, @@ -31,6 +32,7 @@ TwRoot { }, COLON@25..26 ":" [] [], ], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@26..33 "outline" [] [], minus_token: DASH@33..34 "-" [] [], @@ -54,22 +56,24 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..39 0: TW_FULL_CANDIDATE@0..6 0: TW_VARIANT_LIST@0..0 - 1: TW_STATIC_CANDIDATE@0..6 + 1: (empty) + 2: TW_STATIC_CANDIDATE@0..6 0: TW_BASE@0..6 "border" [] [] - 2: (empty) + 3: (empty) 1: WHITESPACE@6..20 " " [] [] 2: TW_FULL_CANDIDATE@20..39 0: TW_VARIANT_LIST@20..26 0: TW_STATIC_VARIANT@20..25 0: TW_BASE@20..25 "focus" [] [] 1: COLON@25..26 ":" [] [] - 1: TW_FUNCTIONAL_CANDIDATE@26..39 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@26..39 0: TW_BASE@26..33 "outline" [] [] 1: DASH@33..34 "-" [] [] 2: TW_NAMED_VALUE@34..39 0: TW_VALUE@34..39 "none" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@39..39 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/multiple.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/multiple.txt.snap index 4093add2ae10..fc14b3eb6da4 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/multiple.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/multiple.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwStaticCandidate { base_token: TW_BASE@0..6 "border" [] [], }, @@ -31,6 +32,7 @@ TwRoot { }, COLON@12..13 ":" [] [], ], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@13..20 "outline" [] [], minus_token: DASH@20..21 "-" [] [], @@ -54,22 +56,24 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..26 0: TW_FULL_CANDIDATE@0..6 0: TW_VARIANT_LIST@0..0 - 1: TW_STATIC_CANDIDATE@0..6 + 1: (empty) + 2: TW_STATIC_CANDIDATE@0..6 0: TW_BASE@0..6 "border" [] [] - 2: (empty) + 3: (empty) 1: WHITESPACE@6..7 " " [] [] 2: TW_FULL_CANDIDATE@7..26 0: TW_VARIANT_LIST@7..13 0: TW_STATIC_VARIANT@7..12 0: TW_BASE@7..12 "focus" [] [] 1: COLON@12..13 ":" [] [] - 1: TW_FUNCTIONAL_CANDIDATE@13..26 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@13..26 0: TW_BASE@13..20 "outline" [] [] 1: DASH@20..21 "-" [] [] 2: TW_NAMED_VALUE@21..26 0: TW_VALUE@21..26 "none" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@26..26 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/negative.txt b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/negative.txt new file mode 100644 index 000000000000..d2624cde50bb --- /dev/null +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/negative.txt @@ -0,0 +1 @@ +-top-4 -mb-2 hover:-mt-2 diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/negative.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/negative.txt.snap new file mode 100644 index 000000000000..3e146ba1409b --- /dev/null +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/negative.txt.snap @@ -0,0 +1,113 @@ +--- +source: crates/biome_tailwind_parser/tests/spec_test.rs +expression: snapshot +--- +## Input + +```text +-top-4 -mb-2 hover:-mt-2 + +``` + + +## AST + +``` +TwRoot { + bom_token: missing (optional), + candidates: TwCandidateList [ + TwFullCandidate { + variants: TwVariantList [], + negative_token: DASH@0..1 "-" [] [], + candidate: TwFunctionalCandidate { + base_token: TW_BASE@1..4 "top" [] [], + minus_token: DASH@4..5 "-" [] [], + value: TwNamedValue { + value_token: TW_VALUE@5..6 "4" [] [], + }, + modifier: missing (optional), + }, + excl_token: missing (optional), + }, + WHITESPACE@6..7 " " [] [], + TwFullCandidate { + variants: TwVariantList [], + negative_token: DASH@7..8 "-" [] [], + candidate: TwFunctionalCandidate { + base_token: TW_BASE@8..10 "mb" [] [], + minus_token: DASH@10..11 "-" [] [], + value: TwNamedValue { + value_token: TW_VALUE@11..12 "2" [] [], + }, + modifier: missing (optional), + }, + excl_token: missing (optional), + }, + WHITESPACE@12..13 " " [] [], + TwFullCandidate { + variants: TwVariantList [ + TwStaticVariant { + base_token: TW_BASE@13..18 "hover" [] [], + }, + COLON@18..19 ":" [] [], + ], + negative_token: DASH@19..20 "-" [] [], + candidate: TwFunctionalCandidate { + base_token: TW_BASE@20..22 "mt" [] [], + minus_token: DASH@22..23 "-" [] [], + value: TwNamedValue { + value_token: TW_VALUE@23..25 "2" [] [Newline("\n")], + }, + modifier: missing (optional), + }, + excl_token: missing (optional), + }, + ], + eof_token: EOF@25..25 "" [] [], +} +``` + +## CST + +``` +0: TW_ROOT@0..25 + 0: (empty) + 1: TW_CANDIDATE_LIST@0..25 + 0: TW_FULL_CANDIDATE@0..6 + 0: TW_VARIANT_LIST@0..0 + 1: DASH@0..1 "-" [] [] + 2: TW_FUNCTIONAL_CANDIDATE@1..6 + 0: TW_BASE@1..4 "top" [] [] + 1: DASH@4..5 "-" [] [] + 2: TW_NAMED_VALUE@5..6 + 0: TW_VALUE@5..6 "4" [] [] + 3: (empty) + 3: (empty) + 1: WHITESPACE@6..7 " " [] [] + 2: TW_FULL_CANDIDATE@7..12 + 0: TW_VARIANT_LIST@7..7 + 1: DASH@7..8 "-" [] [] + 2: TW_FUNCTIONAL_CANDIDATE@8..12 + 0: TW_BASE@8..10 "mb" [] [] + 1: DASH@10..11 "-" [] [] + 2: TW_NAMED_VALUE@11..12 + 0: TW_VALUE@11..12 "2" [] [] + 3: (empty) + 3: (empty) + 3: WHITESPACE@12..13 " " [] [] + 4: TW_FULL_CANDIDATE@13..25 + 0: TW_VARIANT_LIST@13..19 + 0: TW_STATIC_VARIANT@13..18 + 0: TW_BASE@13..18 "hover" [] [] + 1: COLON@18..19 ":" [] [] + 1: DASH@19..20 "-" [] [] + 2: TW_FUNCTIONAL_CANDIDATE@20..25 + 0: TW_BASE@20..22 "mt" [] [] + 1: DASH@22..23 "-" [] [] + 2: TW_NAMED_VALUE@23..25 + 0: TW_VALUE@23..25 "2" [] [Newline("\n")] + 3: (empty) + 3: (empty) + 2: EOF@25..25 "" [] [] + +``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/static.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/static.txt.snap index c5dd4bfb56d2..d5032f29718b 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/static.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/simple/static.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwStaticCandidate { base_token: TW_BASE@0..10 "underline" [] [Newline("\n")], }, @@ -36,9 +37,10 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..10 0: TW_FULL_CANDIDATE@0..10 0: TW_VARIANT_LIST@0..0 - 1: TW_STATIC_CANDIDATE@0..10 + 1: (empty) + 2: TW_STATIC_CANDIDATE@0..10 0: TW_BASE@0..10 "underline" [] [Newline("\n")] - 2: (empty) + 3: (empty) 2: EOF@10..10 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/stress/stress-1.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/stress/stress-1.txt.snap index 072af66f2c14..c3361fb8c813 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/stress/stress-1.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/stress/stress-1.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@0..4 "text" [] [], minus_token: DASH@4..5 "-" [] [], @@ -31,6 +32,7 @@ TwRoot { WHITESPACE@7..8 " " [] [], TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@8..15 "leading" [] [], minus_token: DASH@15..16 "-" [] [], @@ -51,6 +53,7 @@ TwRoot { }, COLON@28..29 ":" [] [], ], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@29..33 "text" [] [], minus_token: DASH@33..34 "-" [] [], @@ -90,6 +93,7 @@ TwRoot { }, COLON@71..72 ":" [] [], ], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@72..76 "text" [] [], minus_token: DASH@76..77 "-" [] [], @@ -103,6 +107,7 @@ TwRoot { WHITESPACE@84..85 " " [] [], TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwStaticCandidate { base_token: TW_BASE@85..89 "flex" [] [], }, @@ -111,6 +116,7 @@ TwRoot { WHITESPACE@89..90 " " [] [], TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@90..95 "items" [] [], minus_token: DASH@95..96 "-" [] [], @@ -124,6 +130,7 @@ TwRoot { WHITESPACE@102..103 " " [] [], TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@103..106 "gap" [] [], minus_token: DASH@106..107 "-" [] [], @@ -148,6 +155,7 @@ TwRoot { }, COLON@124..125 ":" [] [], ], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@125..132 "opacity" [] [], minus_token: DASH@132..133 "-" [] [], @@ -172,6 +180,7 @@ TwRoot { }, COLON@154..155 ":" [] [], ], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@155..161 "cursor" [] [], minus_token: DASH@161..162 "-" [] [], @@ -195,17 +204,19 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..174 0: TW_FULL_CANDIDATE@0..7 0: TW_VARIANT_LIST@0..0 - 1: TW_FUNCTIONAL_CANDIDATE@0..7 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@0..7 0: TW_BASE@0..4 "text" [] [] 1: DASH@4..5 "-" [] [] 2: TW_NAMED_VALUE@5..7 0: TW_VALUE@5..7 "sm" [] [] 3: (empty) - 2: (empty) + 3: (empty) 1: WHITESPACE@7..8 " " [] [] 2: TW_FULL_CANDIDATE@8..22 0: TW_VARIANT_LIST@8..8 - 1: TW_FUNCTIONAL_CANDIDATE@8..22 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@8..22 0: TW_BASE@8..15 "leading" [] [] 1: DASH@15..16 "-" [] [] 2: TW_ARBITRARY_VALUE@16..22 @@ -213,14 +224,15 @@ TwRoot { 1: TW_VALUE@17..21 "10px" [] [] 2: R_BRACKET@21..22 "]" [] [] 3: (empty) - 2: (empty) + 3: (empty) 3: WHITESPACE@22..23 " " [] [] 4: TW_FULL_CANDIDATE@23..44 0: TW_VARIANT_LIST@23..29 0: TW_STATIC_VARIANT@23..28 0: TW_BASE@23..28 "hover" [] [] 1: COLON@28..29 ":" [] [] - 1: TW_FUNCTIONAL_CANDIDATE@29..44 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@29..44 0: TW_BASE@29..33 "text" [] [] 1: DASH@33..34 "-" [] [] 2: TW_NAMED_VALUE@34..36 @@ -231,7 +243,7 @@ TwRoot { 0: L_BRACKET@37..38 "[" [] [] 1: TW_VALUE@38..43 "100px" [] [] 2: R_BRACKET@43..44 "]" [] [] - 2: (empty) + 3: (empty) 5: WHITESPACE@44..45 " " [] [] 6: TW_FULL_CANDIDATE@45..84 0: TW_VARIANT_LIST@45..72 @@ -249,39 +261,43 @@ TwRoot { 1: TW_VALUE@63..70 "checked" [] [] 2: R_BRACKET@70..71 "]" [] [] 5: COLON@71..72 ":" [] [] - 1: TW_FUNCTIONAL_CANDIDATE@72..84 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@72..84 0: TW_BASE@72..76 "text" [] [] 1: DASH@76..77 "-" [] [] 2: TW_NAMED_VALUE@77..84 0: TW_VALUE@77..84 "red-500" [] [] 3: (empty) - 2: (empty) + 3: (empty) 7: WHITESPACE@84..85 " " [] [] 8: TW_FULL_CANDIDATE@85..89 0: TW_VARIANT_LIST@85..85 - 1: TW_STATIC_CANDIDATE@85..89 + 1: (empty) + 2: TW_STATIC_CANDIDATE@85..89 0: TW_BASE@85..89 "flex" [] [] - 2: (empty) + 3: (empty) 9: WHITESPACE@89..90 " " [] [] 10: TW_FULL_CANDIDATE@90..102 0: TW_VARIANT_LIST@90..90 - 1: TW_FUNCTIONAL_CANDIDATE@90..102 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@90..102 0: TW_BASE@90..95 "items" [] [] 1: DASH@95..96 "-" [] [] 2: TW_NAMED_VALUE@96..102 0: TW_VALUE@96..102 "center" [] [] 3: (empty) - 2: (empty) + 3: (empty) 11: WHITESPACE@102..103 " " [] [] 12: TW_FULL_CANDIDATE@103..108 0: TW_VARIANT_LIST@103..103 - 1: TW_FUNCTIONAL_CANDIDATE@103..108 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@103..108 0: TW_BASE@103..106 "gap" [] [] 1: DASH@106..107 "-" [] [] 2: TW_NAMED_VALUE@107..108 0: TW_VALUE@107..108 "2" [] [] 3: (empty) - 2: (empty) + 3: (empty) 13: WHITESPACE@108..109 " " [] [] 14: TW_FULL_CANDIDATE@109..135 0: TW_VARIANT_LIST@109..125 @@ -293,13 +309,14 @@ TwRoot { 1: TW_VALUE@114..123 ":disabled" [] [] 2: R_BRACKET@123..124 "]" [] [] 1: COLON@124..125 ":" [] [] - 1: TW_FUNCTIONAL_CANDIDATE@125..135 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@125..135 0: TW_BASE@125..132 "opacity" [] [] 1: DASH@132..133 "-" [] [] 2: TW_NAMED_VALUE@133..135 0: TW_VALUE@133..135 "50" [] [] 3: (empty) - 2: (empty) + 3: (empty) 15: WHITESPACE@135..136 " " [] [] 16: TW_FULL_CANDIDATE@136..174 0: TW_VARIANT_LIST@136..155 @@ -311,13 +328,14 @@ TwRoot { 2: TW_STATIC_VARIANT@146..154 0: TW_BASE@146..154 "disabled" [] [] 3: COLON@154..155 ":" [] [] - 1: TW_FUNCTIONAL_CANDIDATE@155..174 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@155..174 0: TW_BASE@155..161 "cursor" [] [] 1: DASH@161..162 "-" [] [] 2: TW_NAMED_VALUE@162..174 0: TW_VALUE@162..174 "not-allowed" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@174..174 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/stress/stress-2.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/stress/stress-2.txt.snap index db2a94817939..a108e34170de 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/stress/stress-2.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/stress/stress-2.txt.snap @@ -18,6 +18,7 @@ TwRoot { candidates: TwCandidateList [ TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@0..6 "border" [] [], minus_token: DASH@6..7 "-" [] [], @@ -31,6 +32,7 @@ TwRoot { WHITESPACE@17..18 " " [] [], TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@18..22 "text" [] [], minus_token: DASH@22..23 "-" [] [], @@ -44,6 +46,7 @@ TwRoot { WHITESPACE@33..34 " " [] [], TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@34..45 "ring-offset" [] [], minus_token: DASH@45..46 "-" [] [], @@ -66,6 +69,7 @@ TwRoot { }, COLON@70..71 ":" [] [], ], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@71..75 "ring" [] [], minus_token: DASH@75..76 "-" [] [], @@ -79,6 +83,7 @@ TwRoot { WHITESPACE@80..81 " " [] [], TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@81..87 "aspect" [] [], minus_token: DASH@87..88 "-" [] [], @@ -92,6 +97,7 @@ TwRoot { WHITESPACE@94..95 " " [] [], TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@95..99 "size" [] [], minus_token: DASH@99..100 "-" [] [], @@ -105,6 +111,7 @@ TwRoot { WHITESPACE@101..102 " " [] [], TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@102..109 "rounded" [] [], minus_token: DASH@109..110 "-" [] [], @@ -118,6 +125,7 @@ TwRoot { WHITESPACE@114..115 " " [] [], TwFullCandidate { variants: TwVariantList [], + negative_token: missing (optional), candidate: TwStaticCandidate { base_token: TW_BASE@115..121 "border" [] [], }, @@ -131,6 +139,7 @@ TwRoot { }, COLON@127..128 ":" [] [], ], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@128..135 "outline" [] [], minus_token: DASH@135..136 "-" [] [], @@ -153,6 +162,7 @@ TwRoot { }, COLON@154..155 ":" [] [], ], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@155..159 "ring" [] [], minus_token: DASH@159..160 "-" [] [], @@ -175,6 +185,7 @@ TwRoot { }, COLON@175..176 ":" [] [], ], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@176..187 "ring-offset" [] [], minus_token: DASH@187..188 "-" [] [], @@ -193,6 +204,7 @@ TwRoot { }, COLON@198..199 ":" [] [], ], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@199..205 "cursor" [] [], minus_token: DASH@205..206 "-" [] [], @@ -211,6 +223,7 @@ TwRoot { }, COLON@226..227 ":" [] [], ], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@227..234 "opacity" [] [], minus_token: DASH@234..235 "-" [] [], @@ -234,33 +247,36 @@ TwRoot { 1: TW_CANDIDATE_LIST@0..238 0: TW_FULL_CANDIDATE@0..17 0: TW_VARIANT_LIST@0..0 - 1: TW_FUNCTIONAL_CANDIDATE@0..17 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@0..17 0: TW_BASE@0..6 "border" [] [] 1: DASH@6..7 "-" [] [] 2: TW_NAMED_VALUE@7..17 0: TW_VALUE@7..17 "foreground" [] [] 3: (empty) - 2: (empty) + 3: (empty) 1: WHITESPACE@17..18 " " [] [] 2: TW_FULL_CANDIDATE@18..33 0: TW_VARIANT_LIST@18..18 - 1: TW_FUNCTIONAL_CANDIDATE@18..33 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@18..33 0: TW_BASE@18..22 "text" [] [] 1: DASH@22..23 "-" [] [] 2: TW_NAMED_VALUE@23..33 0: TW_VALUE@23..33 "foreground" [] [] 3: (empty) - 2: (empty) + 3: (empty) 3: WHITESPACE@33..34 " " [] [] 4: TW_FULL_CANDIDATE@34..56 0: TW_VARIANT_LIST@34..34 - 1: TW_FUNCTIONAL_CANDIDATE@34..56 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@34..56 0: TW_BASE@34..45 "ring-offset" [] [] 1: DASH@45..46 "-" [] [] 2: TW_NAMED_VALUE@46..56 0: TW_VALUE@46..56 "background" [] [] 3: (empty) - 2: (empty) + 3: (empty) 5: WHITESPACE@56..57 " " [] [] 6: TW_FULL_CANDIDATE@57..80 0: TW_VARIANT_LIST@57..71 @@ -270,62 +286,68 @@ TwRoot { 2: TW_NAMED_VALUE@63..70 0: TW_VALUE@63..70 "visible" [] [] 1: COLON@70..71 ":" [] [] - 1: TW_FUNCTIONAL_CANDIDATE@71..80 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@71..80 0: TW_BASE@71..75 "ring" [] [] 1: DASH@75..76 "-" [] [] 2: TW_NAMED_VALUE@76..80 0: TW_VALUE@76..80 "ring" [] [] 3: (empty) - 2: (empty) + 3: (empty) 7: WHITESPACE@80..81 " " [] [] 8: TW_FULL_CANDIDATE@81..94 0: TW_VARIANT_LIST@81..81 - 1: TW_FUNCTIONAL_CANDIDATE@81..94 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@81..94 0: TW_BASE@81..87 "aspect" [] [] 1: DASH@87..88 "-" [] [] 2: TW_NAMED_VALUE@88..94 0: TW_VALUE@88..94 "square" [] [] 3: (empty) - 2: (empty) + 3: (empty) 9: WHITESPACE@94..95 " " [] [] 10: TW_FULL_CANDIDATE@95..101 0: TW_VARIANT_LIST@95..95 - 1: TW_FUNCTIONAL_CANDIDATE@95..101 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@95..101 0: TW_BASE@95..99 "size" [] [] 1: DASH@99..100 "-" [] [] 2: TW_NAMED_VALUE@100..101 0: TW_VALUE@100..101 "4" [] [] 3: (empty) - 2: (empty) + 3: (empty) 11: WHITESPACE@101..102 " " [] [] 12: TW_FULL_CANDIDATE@102..114 0: TW_VARIANT_LIST@102..102 - 1: TW_FUNCTIONAL_CANDIDATE@102..114 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@102..114 0: TW_BASE@102..109 "rounded" [] [] 1: DASH@109..110 "-" [] [] 2: TW_NAMED_VALUE@110..114 0: TW_VALUE@110..114 "full" [] [] 3: (empty) - 2: (empty) + 3: (empty) 13: WHITESPACE@114..115 " " [] [] 14: TW_FULL_CANDIDATE@115..121 0: TW_VARIANT_LIST@115..115 - 1: TW_STATIC_CANDIDATE@115..121 + 1: (empty) + 2: TW_STATIC_CANDIDATE@115..121 0: TW_BASE@115..121 "border" [] [] - 2: (empty) + 3: (empty) 15: WHITESPACE@121..122 " " [] [] 16: TW_FULL_CANDIDATE@122..140 0: TW_VARIANT_LIST@122..128 0: TW_STATIC_VARIANT@122..127 0: TW_BASE@122..127 "focus" [] [] 1: COLON@127..128 ":" [] [] - 1: TW_FUNCTIONAL_CANDIDATE@128..140 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@128..140 0: TW_BASE@128..135 "outline" [] [] 1: DASH@135..136 "-" [] [] 2: TW_NAMED_VALUE@136..140 0: TW_VALUE@136..140 "none" [] [] 3: (empty) - 2: (empty) + 3: (empty) 17: WHITESPACE@140..141 " " [] [] 18: TW_FULL_CANDIDATE@141..161 0: TW_VARIANT_LIST@141..155 @@ -335,13 +357,14 @@ TwRoot { 2: TW_NAMED_VALUE@147..154 0: TW_VALUE@147..154 "visible" [] [] 1: COLON@154..155 ":" [] [] - 1: TW_FUNCTIONAL_CANDIDATE@155..161 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@155..161 0: TW_BASE@155..159 "ring" [] [] 1: DASH@159..160 "-" [] [] 2: TW_NAMED_VALUE@160..161 0: TW_VALUE@160..161 "2" [] [] 3: (empty) - 2: (empty) + 3: (empty) 19: WHITESPACE@161..162 " " [] [] 20: TW_FULL_CANDIDATE@162..189 0: TW_VARIANT_LIST@162..176 @@ -351,39 +374,42 @@ TwRoot { 2: TW_NAMED_VALUE@168..175 0: TW_VALUE@168..175 "visible" [] [] 1: COLON@175..176 ":" [] [] - 1: TW_FUNCTIONAL_CANDIDATE@176..189 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@176..189 0: TW_BASE@176..187 "ring-offset" [] [] 1: DASH@187..188 "-" [] [] 2: TW_NAMED_VALUE@188..189 0: TW_VALUE@188..189 "2" [] [] 3: (empty) - 2: (empty) + 3: (empty) 21: WHITESPACE@189..190 " " [] [] 22: TW_FULL_CANDIDATE@190..217 0: TW_VARIANT_LIST@190..199 0: TW_STATIC_VARIANT@190..198 0: TW_BASE@190..198 "disabled" [] [] 1: COLON@198..199 ":" [] [] - 1: TW_FUNCTIONAL_CANDIDATE@199..217 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@199..217 0: TW_BASE@199..205 "cursor" [] [] 1: DASH@205..206 "-" [] [] 2: TW_NAMED_VALUE@206..217 0: TW_VALUE@206..217 "not-allowed" [] [] 3: (empty) - 2: (empty) + 3: (empty) 23: WHITESPACE@217..218 " " [] [] 24: TW_FULL_CANDIDATE@218..238 0: TW_VARIANT_LIST@218..227 0: TW_STATIC_VARIANT@218..226 0: TW_BASE@218..226 "disabled" [] [] 1: COLON@226..227 ":" [] [] - 1: TW_FUNCTIONAL_CANDIDATE@227..238 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@227..238 0: TW_BASE@227..234 "opacity" [] [] 1: DASH@234..235 "-" [] [] 2: TW_NAMED_VALUE@235..238 0: TW_VALUE@235..238 "50" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@238..238 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/variants/arbitrary-variant.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/variants/arbitrary-variant.txt.snap index 7bbd506cc15d..ad551bd528ea 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/variants/arbitrary-variant.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/variants/arbitrary-variant.txt.snap @@ -25,6 +25,7 @@ TwRoot { }, COLON@5..6 ":" [] [], ], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@6..10 "text" [] [], minus_token: DASH@10..11 "-" [] [], @@ -53,13 +54,14 @@ TwRoot { 1: TW_SELECTOR@1..4 "&_p" [] [] 2: R_BRACKET@4..5 "]" [] [] 1: COLON@5..6 ":" [] [] - 1: TW_FUNCTIONAL_CANDIDATE@6..19 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@6..19 0: TW_BASE@6..10 "text" [] [] 1: DASH@10..11 "-" [] [] 2: TW_NAMED_VALUE@11..19 0: TW_VALUE@11..19 "red-500" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@19..19 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/variants/functional-arbirary-param.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/variants/functional-arbirary-param.txt.snap index 610509d9a814..5fd9ec1f99c4 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/variants/functional-arbirary-param.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/variants/functional-arbirary-param.txt.snap @@ -29,6 +29,7 @@ TwRoot { }, COLON@15..16 ":" [] [], ], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@16..20 "text" [] [], minus_token: DASH@20..21 "-" [] [], @@ -60,13 +61,14 @@ TwRoot { 1: TW_VALUE@6..14 "disabled" [] [] 2: R_BRACKET@14..15 "]" [] [] 1: COLON@15..16 ":" [] [] - 1: TW_FUNCTIONAL_CANDIDATE@16..29 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@16..29 0: TW_BASE@16..20 "text" [] [] 1: DASH@20..21 "-" [] [] 2: TW_NAMED_VALUE@21..29 0: TW_VALUE@21..29 "red-500" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@29..29 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/variants/functional-named-param.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/variants/functional-named-param.txt.snap index 34ba50e9e7a6..dcd579dbddeb 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/variants/functional-named-param.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/variants/functional-named-param.txt.snap @@ -27,6 +27,7 @@ TwRoot { }, COLON@13..14 ":" [] [], ], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@14..18 "text" [] [], minus_token: DASH@18..19 "-" [] [], @@ -56,13 +57,14 @@ TwRoot { 2: TW_NAMED_VALUE@5..13 0: TW_VALUE@5..13 "disabled" [] [] 1: COLON@13..14 ":" [] [] - 1: TW_FUNCTIONAL_CANDIDATE@14..27 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@14..27 0: TW_BASE@14..18 "text" [] [] 1: DASH@18..19 "-" [] [] 2: TW_NAMED_VALUE@19..27 0: TW_VALUE@19..27 "red-500" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@27..27 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/variants/hover.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/variants/hover.txt.snap index 4f83aedd3288..890331b6280c 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/variants/hover.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/variants/hover.txt.snap @@ -23,6 +23,7 @@ TwRoot { }, COLON@5..6 ":" [] [], ], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@6..10 "text" [] [], minus_token: DASH@10..11 "-" [] [], @@ -49,13 +50,14 @@ TwRoot { 0: TW_STATIC_VARIANT@0..5 0: TW_BASE@0..5 "hover" [] [] 1: COLON@5..6 ":" [] [] - 1: TW_FUNCTIONAL_CANDIDATE@6..19 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@6..19 0: TW_BASE@6..10 "text" [] [] 1: DASH@10..11 "-" [] [] 2: TW_NAMED_VALUE@11..19 0: TW_VALUE@11..19 "red-500" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@19..19 "" [] [] ``` diff --git a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/variants/hover_focus.txt.snap b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/variants/hover_focus.txt.snap index 002b97fef495..c4e98aa17f5e 100644 --- a/crates/biome_tailwind_parser/tests/tailwind_specs/ok/variants/hover_focus.txt.snap +++ b/crates/biome_tailwind_parser/tests/tailwind_specs/ok/variants/hover_focus.txt.snap @@ -27,6 +27,7 @@ TwRoot { }, COLON@11..12 ":" [] [], ], + negative_token: missing (optional), candidate: TwFunctionalCandidate { base_token: TW_BASE@12..16 "text" [] [], minus_token: DASH@16..17 "-" [] [], @@ -56,13 +57,14 @@ TwRoot { 2: TW_STATIC_VARIANT@6..11 0: TW_BASE@6..11 "focus" [] [] 3: COLON@11..12 ":" [] [] - 1: TW_FUNCTIONAL_CANDIDATE@12..25 + 1: (empty) + 2: TW_FUNCTIONAL_CANDIDATE@12..25 0: TW_BASE@12..16 "text" [] [] 1: DASH@16..17 "-" [] [] 2: TW_NAMED_VALUE@17..25 0: TW_VALUE@17..25 "red-500" [] [Newline("\n")] 3: (empty) - 2: (empty) + 3: (empty) 2: EOF@25..25 "" [] [] ``` diff --git a/crates/biome_tailwind_syntax/src/generated/nodes.rs b/crates/biome_tailwind_syntax/src/generated/nodes.rs index b095df66fed4..c9d58e2abf05 100644 --- a/crates/biome_tailwind_syntax/src/generated/nodes.rs +++ b/crates/biome_tailwind_syntax/src/generated/nodes.rs @@ -232,6 +232,7 @@ impl TwFullCandidate { pub fn as_fields(&self) -> TwFullCandidateFields { TwFullCandidateFields { variants: self.variants(), + negative_token: self.negative_token(), candidate: self.candidate(), excl_token: self.excl_token(), } @@ -239,11 +240,14 @@ impl TwFullCandidate { pub fn variants(&self) -> TwVariantList { support::list(&self.syntax, 0usize) } + pub fn negative_token(&self) -> Option { + support::token(&self.syntax, 1usize) + } pub fn candidate(&self) -> SyntaxResult { - support::required_node(&self.syntax, 1usize) + support::required_node(&self.syntax, 2usize) } pub fn excl_token(&self) -> Option { - support::token(&self.syntax, 2usize) + support::token(&self.syntax, 3usize) } } impl Serialize for TwFullCandidate { @@ -257,6 +261,7 @@ impl Serialize for TwFullCandidate { #[derive(Serialize)] pub struct TwFullCandidateFields { pub variants: TwVariantList, + pub negative_token: Option, pub candidate: SyntaxResult, pub excl_token: Option, } @@ -952,6 +957,10 @@ impl std::fmt::Debug for TwFullCandidate { DEPTH.set(current_depth + 1); f.debug_struct("TwFullCandidate") .field("variants", &self.variants()) + .field( + "negative_token", + &support::DebugOptionalElement(self.negative_token()), + ) .field("candidate", &support::DebugSyntaxResult(self.candidate())) .field( "excl_token", diff --git a/crates/biome_tailwind_syntax/src/generated/nodes_mut.rs b/crates/biome_tailwind_syntax/src/generated/nodes_mut.rs index fe61a4bf4b70..94e3652c400c 100644 --- a/crates/biome_tailwind_syntax/src/generated/nodes_mut.rs +++ b/crates/biome_tailwind_syntax/src/generated/nodes_mut.rs @@ -108,16 +108,22 @@ impl TwFullCandidate { .splice_slots(0usize..=0usize, once(Some(element.into_syntax().into()))), ) } + pub fn with_negative_token(self, element: Option) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(element.map(|element| element.into()))), + ) + } pub fn with_candidate(self, element: AnyTwCandidate) -> Self { Self::unwrap_cast( self.syntax - .splice_slots(1usize..=1usize, once(Some(element.into_syntax().into()))), + .splice_slots(2usize..=2usize, once(Some(element.into_syntax().into()))), ) } pub fn with_excl_token(self, element: Option) -> Self { Self::unwrap_cast( self.syntax - .splice_slots(2usize..=2usize, once(element.map(|element| element.into()))), + .splice_slots(3usize..=3usize, once(element.map(|element| element.into()))), ) } } diff --git a/xtask/codegen/tailwind.ungram b/xtask/codegen/tailwind.ungram index 974fa6898b60..2eedcb30f852 100644 --- a/xtask/codegen/tailwind.ungram +++ b/xtask/codegen/tailwind.ungram @@ -59,6 +59,7 @@ AnyTwFullCandidate = TwFullCandidate | TwBogusCandidate // A Candidate is essentially a CSS class from an end user perspective. It's what the end user puts inside the `class` attribute in their HTML, separated by spaces. TwFullCandidate = variants: TwVariantList + negative: '-'? candidate: AnyTwCandidate '!'?