Skip to content

fix(parse/css): parse tailwind @utility with slash in the name#9043

Merged
dyc3 merged 1 commit intomainfrom
dyc3/tw-slash-utility-name
Mar 9, 2026
Merged

fix(parse/css): parse tailwind @utility with slash in the name#9043
dyc3 merged 1 commit intomainfrom
dyc3/tw-slash-utility-name

Conversation

@dyc3
Copy link
Copy Markdown
Contributor

@dyc3 dyc3 commented Feb 12, 2026

Summary

Allows the css parser to parse @utility a/b {}.

fixes #8897

Test Plan

snapshots

Docs

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Feb 12, 2026

🦋 Changeset detected

Latest commit: b6f8a3d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 13 packages
Name Type
@biomejs/biome Patch
@biomejs/cli-win32-x64 Patch
@biomejs/cli-win32-arm64 Patch
@biomejs/cli-darwin-x64 Patch
@biomejs/cli-darwin-arm64 Patch
@biomejs/cli-linux-x64 Patch
@biomejs/cli-linux-arm64 Patch
@biomejs/cli-linux-x64-musl Patch
@biomejs/cli-linux-arm64-musl Patch
@biomejs/wasm-web Patch
@biomejs/wasm-bundler Patch
@biomejs/wasm-nodejs Patch
@biomejs/backend-jsonrpc Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions bot added A-Parser Area: parser L-CSS Language: CSS and super languages labels Feb 12, 2026
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Feb 12, 2026

Merging this PR will not alter performance

✅ 29 untouched benchmarks
⏩ 187 skipped benchmarks1


Comparing dyc3/tw-slash-utility-name (b6f8a3d) with main (f2581b8)2

Open in CodSpeed

Footnotes

  1. 187 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on main (725e6bb) during the generation of this report, so f2581b8 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@dyc3 dyc3 force-pushed the dyc3/tw-slash-utility-name branch from 1bfb213 to 12f0722 Compare February 22, 2026 17:00
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 22, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d107b5c2-01e5-44f7-8a40-0f9bb00eab80

📥 Commits

Reviewing files that changed from the base of the PR and between 51d7636 and b6f8a3d.

⛔ Files ignored due to path filters (2)
  • crates/biome_css_parser/tests/css_test_suite/error/tailwind/when-disabled/utility-with-slash.css.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_parser/tests/css_test_suite/ok/tailwind/utility/with-slash.css.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (5)
  • .changeset/fix-tailwind-utility-slash.md
  • crates/biome_css_parser/src/lexer/mod.rs
  • crates/biome_css_parser/src/syntax/at_rule/tailwind.rs
  • crates/biome_css_parser/tests/css_test_suite/error/tailwind/when-disabled/utility-with-slash.css
  • crates/biome_css_parser/tests/css_test_suite/ok/tailwind/utility/with-slash.css
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/biome_css_parser/src/syntax/at_rule/tailwind.rs

Walkthrough

Adds support for Tailwind @utility names that include a forward slash by introducing a new lexical context TailwindUtilityName and threading an allow_slash flag through identifier-consumption routines in the CSS lexer. The at-rule parser now requests the Tailwind-specific lexing context for utility names. New tests cover ok and error cases for utility names containing /. A public lexer enum variant CssLexContext::TailwindUtilityName and new lexer methods for tailwind utility name consumption were added.

Possibly related PRs

Suggested labels

L-Tailwind

Suggested reviewers

  • ematipico
  • siketyan
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: fixing CSS parser to handle Tailwind @utility directives with slashes in names.
Description check ✅ Passed The description is directly related to the changeset, explaining the motivation (parsing @utility a/b), linking to issue #8897, and mentioning test snapshots.
Linked Issues check ✅ Passed The PR fully addresses issue #8897's objective by implementing lexer and parser changes to accept forward slashes in Tailwind @utility names, with appropriate test coverage.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the objective: lexer modifications for slash handling, parser context updates, and test files—no unrelated changes detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dyc3/tw-slash-utility-name

Comment @coderabbitai help to get the list of available commands and usage tips.

@ematipico
Copy link
Copy Markdown
Member

@dyc3 should this PR be merged?

@dyc3
Copy link
Copy Markdown
Contributor Author

dyc3 commented Mar 9, 2026

Ah, yes. Slipped through. I'll fix the ci

@dyc3 dyc3 force-pushed the dyc3/tw-slash-utility-name branch from 12f0722 to 51d7636 Compare March 9, 2026 17:50
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/biome_css_parser/src/lexer/mod.rs`:
- Around line 1098-1108: The lexer branch currently gates handling of sequences
like `--*` on self.options.is_tailwind_directives_enabled(), which makes token
emission option-dependent; remove that option check so the logic always runs:
whenever dispatched == MIN and peek_byte().map(lookup_byte) == Some(MUL) perform
the same handling — if prev_byte().map(lookup_byte) == Some(MIN) then call
advance(1) and return Some(current as char), otherwise return None — while
keeping the same uses of dispatched, MIN, MUL, peek_byte, prev_byte, advance,
and current so token emission no longer depends on
is_tailwind_directives_enabled().

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 069f830f-2d37-4c61-b60e-3edd57cfd92d

📥 Commits

Reviewing files that changed from the base of the PR and between 12f0722 and 51d7636.

📒 Files selected for processing (3)
  • .changeset/fix-tailwind-utility-slash.md
  • crates/biome_css_parser/src/lexer/mod.rs
  • crates/biome_css_parser/src/syntax/at_rule/tailwind.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • .changeset/fix-tailwind-utility-slash.md
  • crates/biome_css_parser/src/syntax/at_rule/tailwind.rs

Comment on lines 1098 to 1108
if self.options.is_tailwind_directives_enabled()
&& current == b'-'
&& self.peek_byte() == Some(b'*')
&& dispatched == MIN
&& self.peek_byte().map(lookup_byte) == Some(MUL)
{
// HACK: handle `--*`
if self.prev_byte() == Some(b'-') {
if self.prev_byte().map(lookup_byte) == Some(MIN) {
self.advance(1);
return Some(current as char);
}
// otherwise, handle cases like `--color-*`
return None;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Please don’t make lexer output depend on is_tailwind_directives_enabled().

This branch still tokenises the same bytes differently depending on a parser option. That’s a nasty way to make disabled-mode diagnostics go sideways.

Based on learnings: "In the Biome CSS parser, lexer token emission should not be gated behind parser options like is_tailwind_directives_enabled(). The lexer must emit correct tokens regardless of parser options to enable accurate diagnostics and error messages when the syntax is used incorrectly."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_css_parser/src/lexer/mod.rs` around lines 1098 - 1108, The lexer
branch currently gates handling of sequences like `--*` on
self.options.is_tailwind_directives_enabled(), which makes token emission
option-dependent; remove that option check so the logic always runs: whenever
dispatched == MIN and peek_byte().map(lookup_byte) == Some(MUL) perform the same
handling — if prev_byte().map(lookup_byte) == Some(MIN) then call advance(1) and
return Some(current as char), otherwise return None — while keeping the same
uses of dispatched, MIN, MUL, peek_byte, prev_byte, advance, and current so
token emission no longer depends on is_tailwind_directives_enabled().

@dyc3 dyc3 force-pushed the dyc3/tw-slash-utility-name branch from 51d7636 to b6f8a3d Compare March 9, 2026 18:44
@dyc3 dyc3 merged commit 61e2a02 into main Mar 9, 2026
17 checks passed
@dyc3 dyc3 deleted the dyc3/tw-slash-utility-name branch March 9, 2026 19:07
@github-actions github-actions bot mentioned this pull request Mar 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Parser Area: parser L-CSS Language: CSS and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

📝 parser error with forward slash in tailwind directive

3 participants