Skip to content

Conversation

@dyc3
Copy link
Contributor

@dyc3 dyc3 commented Oct 24, 2025

Summary

The css parser will now accept @source not "foo.css";

See also: https://tailwindcss.com/docs/detecting-classes-in-source-files#ignoring-specific-paths

fixes #7848

Test Plan

added snapshot tests

Docs

@changeset-bot
Copy link

changeset-bot bot commented Oct 24, 2025

🦋 Changeset detected

Latest commit: 3c60b2f

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 A-Formatter Area: formatter A-Tooling Area: internal tools L-CSS Language: CSS labels Oct 24, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Oct 24, 2025

Parser conformance results on

js/262

Test result main count This PR count Difference
Total 50762 50762 0
Passed 49558 49558 0
Failed 1162 1162 0
Panics 42 42 0
Coverage 97.63% 97.63% 0.00%

jsx/babel

Test result main count This PR count Difference
Total 40 40 0
Passed 37 37 0
Failed 3 3 0
Panics 0 0 0
Coverage 92.50% 92.50% 0.00%

symbols/microsoft

Test result main count This PR count Difference
Total 6316 6316 0
Passed 2105 2105 0
Failed 4211 4211 0
Panics 0 0 0
Coverage 33.33% 33.33% 0.00%

ts/babel

Test result main count This PR count Difference
Total 835 835 0
Passed 742 742 0
Failed 93 93 0
Panics 0 0 0
Coverage 88.86% 88.86% 0.00%

ts/microsoft

Test result main count This PR count Difference
Total 18805 18805 0
Passed 14057 14057 0
Failed 4747 4747 0
Panics 1 1 0
Coverage 74.75% 74.75% 0.00%

@dyc3 dyc3 requested review from a team October 24, 2025 17:48
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 24, 2025

Walkthrough

Adds support for Tailwind's @source not syntax across parser, formatter and grammar. The parser optionally consumes a not token in source at-rules, the ungrammar is updated to allow an optional not, and the formatter conditionally emits not when present. Tests and a formatter options file were added to validate the change.

Suggested reviewers

  • ematipico
  • siketyan

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "fix(parse/css): fix parsing tailwind source exclude syntax" accurately summarizes the main change in the changeset. It's concise, specific about the area of change (CSS parsing), and clearly communicates that this fixes parsing of Tailwind's source exclude syntax. The title directly corresponds to the implementation of support for @source not "..." statements across the parser, formatter, and grammar definitions.
Linked Issues Check ✅ Passed Issue #7848 requires that the parser accept @source not "..." statements without error. The PR implements this requirement across all necessary components: the ungram grammar now allows an optional 'not' keyword, the CSS parser optionally consumes the 'not' token, the formatter handles optional emission of the not_token, and snapshot tests validate the new syntax works correctly. All coding-related requirements from the issue are met.
Out of Scope Changes Check ✅ Passed All changes are directly scoped to implementing support for the @source not syntax. The parser, formatter, and grammar files are all modified to handle the new optional 'not' keyword, test files validate the syntax, and a changeset documents the patch. The formatter changes are necessarily in-scope because the formatter must know how to handle the newly parsed syntax. No extraneous or unrelated changes were introduced.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dyc3/fix-tw-source-not

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f94466e and 3c60b2f.

⛔ Files ignored due to path filters (8)
  • crates/biome_css_factory/src/generated/node_factory.rs is excluded by !**/generated/**, !**/generated/** and included by **
  • crates/biome_css_factory/src/generated/syntax_factory.rs is excluded by !**/generated/**, !**/generated/** and included by **
  • crates/biome_css_formatter/tests/specs/css/atrule/tailwind/source-not.css.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_parser/tests/css_test_suite/ok/tailwind/simple.css.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_parser/tests/css_test_suite/ok/tailwind/source-not.css.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_parser/tests/css_test_suite/ok/tailwind/source.css.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_syntax/src/generated/nodes.rs is excluded by !**/generated/**, !**/generated/** and included by **
  • crates/biome_css_syntax/src/generated/nodes_mut.rs is excluded by !**/generated/**, !**/generated/** and included by **
📒 Files selected for processing (7)
  • .changeset/soft-rules-feel.md (1 hunks)
  • crates/biome_css_formatter/src/tailwind/statements/source_at_rule.rs (1 hunks)
  • crates/biome_css_formatter/tests/specs/css/atrule/tailwind/options.json (1 hunks)
  • crates/biome_css_formatter/tests/specs/css/atrule/tailwind/source-not.css (1 hunks)
  • crates/biome_css_parser/src/syntax/at_rule/tailwind.rs (1 hunks)
  • crates/biome_css_parser/tests/css_test_suite/ok/tailwind/source-not.css (1 hunks)
  • xtask/codegen/css.ungram (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • crates/biome_css_formatter/tests/specs/css/atrule/tailwind/source-not.css
  • crates/biome_css_formatter/tests/specs/css/atrule/tailwind/options.json
  • crates/biome_css_formatter/src/tailwind/statements/source_at_rule.rs
  • xtask/codegen/css.ungram
  • crates/biome_css_parser/tests/css_test_suite/ok/tailwind/source-not.css
🧰 Additional context used
📓 Path-based instructions (4)
crates/biome_*_{syntax,parser,formatter,analyze,factory,semantic}/**

📄 CodeRabbit inference engine (CLAUDE.md)

Maintain the per-language crate structure: biome_{lang}_{syntax,parser,formatter,analyze,factory,semantic}

Files:

  • crates/biome_css_parser/src/syntax/at_rule/tailwind.rs
crates/biome_*/**

📄 CodeRabbit inference engine (CLAUDE.md)

Place core crates under /crates/biome_*/

Files:

  • crates/biome_css_parser/src/syntax/at_rule/tailwind.rs
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Format Rust files before committing (e.g., via just f which formats Rust)
Document rules, assists, and options with inline rustdoc in source

Files:

  • crates/biome_css_parser/src/syntax/at_rule/tailwind.rs
.changeset/*.md

📄 CodeRabbit inference engine (CONTRIBUTING.md)

.changeset/*.md: In changesets, only use #### or ##### headers; other header levels are not allowed
Changesets should cover user-facing changes only; internal changes do not need changesets
Use past tense for what you did and present tense for current Biome behavior in changesets
When fixing a bug in a changeset, start with an issue link (e.g., “Fixed #1234: …”)
When referencing a rule or assist in a changeset, include a link to its page on the website
Include code blocks in changesets when applicable to illustrate changes
End every sentence in a changeset with a period

Files:

  • .changeset/soft-rules-feel.md
🧠 Learnings (1)
📚 Learning: 2025-10-15T09:19:01.347Z
Learnt from: CR
PR: biomejs/biome#0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:19:01.347Z
Learning: Applies to .changeset/*.md : When fixing a bug in a changeset, start with an issue link (e.g., “Fixed #1234: …”)

Applied to files:

  • .changeset/soft-rules-feel.md
🪛 LanguageTool
.changeset/soft-rules-feel.md

[grammar] ~5-~5: There seems to be a noun/verb agreement error. Did you mean “excludes” or “excluded”?
Context: ...l now correctly parse tailwind's source exclude syntax: @source not "foo.css";

(SINGULAR_NOUN_VERB_AGREEMENT)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: Documentation
  • GitHub Check: Parser conformance
  • GitHub Check: Bench (biome_css_parser)
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: Bench (biome_css_analyze)
  • GitHub Check: Bench (biome_css_formatter)
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Check Dependencies
  • GitHub Check: Test Node.js API
  • GitHub Check: autofix
🔇 Additional comments (1)
crates/biome_css_parser/src/syntax/at_rule/tailwind.rs (1)

218-220: LGTM!

The optional not token handling is straightforward and correct. Fits perfectly with the existing parser patterns.


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

Copy link
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

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72afdfa and f94466e.

⛔ Files ignored due to path filters (8)
  • crates/biome_css_factory/src/generated/node_factory.rs is excluded by !**/generated/**, !**/generated/** and included by **
  • crates/biome_css_factory/src/generated/syntax_factory.rs is excluded by !**/generated/**, !**/generated/** and included by **
  • crates/biome_css_formatter/tests/specs/css/atrule/tailwind/source-not.css.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_parser/tests/css_test_suite/ok/tailwind/simple.css.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_parser/tests/css_test_suite/ok/tailwind/source-not.css.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_parser/tests/css_test_suite/ok/tailwind/source.css.snap is excluded by !**/*.snap and included by **
  • crates/biome_css_syntax/src/generated/nodes.rs is excluded by !**/generated/**, !**/generated/** and included by **
  • crates/biome_css_syntax/src/generated/nodes_mut.rs is excluded by !**/generated/**, !**/generated/** and included by **
📒 Files selected for processing (7)
  • .changeset/soft-rules-feel.md (1 hunks)
  • crates/biome_css_formatter/src/tailwind/statements/source_at_rule.rs (1 hunks)
  • crates/biome_css_formatter/tests/specs/css/atrule/tailwind/options.json (1 hunks)
  • crates/biome_css_formatter/tests/specs/css/atrule/tailwind/source-not.css (1 hunks)
  • crates/biome_css_parser/src/syntax/at_rule/tailwind.rs (1 hunks)
  • crates/biome_css_parser/tests/css_test_suite/ok/tailwind/source-not.css (1 hunks)
  • xtask/codegen/css.ungram (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
crates/biome_*_{syntax,parser,formatter,analyze,factory,semantic}/**

📄 CodeRabbit inference engine (CLAUDE.md)

Maintain the per-language crate structure: biome_{lang}_{syntax,parser,formatter,analyze,factory,semantic}

Files:

  • crates/biome_css_parser/src/syntax/at_rule/tailwind.rs
  • crates/biome_css_formatter/tests/specs/css/atrule/tailwind/options.json
  • crates/biome_css_parser/tests/css_test_suite/ok/tailwind/source-not.css
  • crates/biome_css_formatter/src/tailwind/statements/source_at_rule.rs
  • crates/biome_css_formatter/tests/specs/css/atrule/tailwind/source-not.css
crates/biome_*/**

📄 CodeRabbit inference engine (CLAUDE.md)

Place core crates under /crates/biome_*/

Files:

  • crates/biome_css_parser/src/syntax/at_rule/tailwind.rs
  • crates/biome_css_formatter/tests/specs/css/atrule/tailwind/options.json
  • crates/biome_css_parser/tests/css_test_suite/ok/tailwind/source-not.css
  • crates/biome_css_formatter/src/tailwind/statements/source_at_rule.rs
  • crates/biome_css_formatter/tests/specs/css/atrule/tailwind/source-not.css
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Format Rust files before committing (e.g., via just f which formats Rust)
Document rules, assists, and options with inline rustdoc in source

Files:

  • crates/biome_css_parser/src/syntax/at_rule/tailwind.rs
  • crates/biome_css_formatter/src/tailwind/statements/source_at_rule.rs
**/tests/**

📄 CodeRabbit inference engine (CLAUDE.md)

Place test files under a tests/ directory in each crate

Files:

  • crates/biome_css_formatter/tests/specs/css/atrule/tailwind/options.json
  • crates/biome_css_parser/tests/css_test_suite/ok/tailwind/source-not.css
  • crates/biome_css_formatter/tests/specs/css/atrule/tailwind/source-not.css
xtask/codegen/*.ungram

📄 CodeRabbit inference engine (CLAUDE.md)

Define and modify language grammars in .ungram files; ASTs are generated from these

Files:

  • xtask/codegen/css.ungram
.changeset/*.md

📄 CodeRabbit inference engine (CONTRIBUTING.md)

.changeset/*.md: In changesets, only use #### or ##### headers; other header levels are not allowed
Changesets should cover user-facing changes only; internal changes do not need changesets
Use past tense for what you did and present tense for current Biome behavior in changesets
When fixing a bug in a changeset, start with an issue link (e.g., “Fixed #1234: …”)
When referencing a rule or assist in a changeset, include a link to its page on the website
Include code blocks in changesets when applicable to illustrate changes
End every sentence in a changeset with a period

Files:

  • .changeset/soft-rules-feel.md
🧠 Learnings (1)
📚 Learning: 2025-10-15T09:22:15.851Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-10-15T09:22:15.851Z
Learning: Applies to crates/biome_formatter/tests/specs/**/options.json : Use options.json files colocated with test inputs to override formatting options for all files in that folder

Applied to files:

  • crates/biome_css_formatter/tests/specs/css/atrule/tailwind/options.json
🧬 Code graph analysis (1)
crates/biome_css_formatter/src/tailwind/statements/source_at_rule.rs (1)
crates/biome_css_syntax/src/generated/nodes.rs (23)
  • source_token (7227-7229)
  • not_token (820-822)
  • not_token (1085-1087)
  • not_token (3165-3167)
  • not_token (6042-6044)
  • not_token (7230-7232)
  • path (6954-6956)
  • path (7184-7186)
  • path (7233-7235)
  • semicolon_token (347-349)
  • semicolon_token (1553-1555)
  • semicolon_token (1684-1686)
  • semicolon_token (2234-2236)
  • semicolon_token (2788-2790)
  • semicolon_token (3444-3446)
  • semicolon_token (6489-6491)
  • semicolon_token (6624-6626)
  • semicolon_token (6912-6914)
  • semicolon_token (6957-6959)
  • semicolon_token (7051-7053)
  • semicolon_token (7142-7144)
  • semicolon_token (7187-7189)
  • semicolon_token (7236-7238)
🪛 LanguageTool
.changeset/soft-rules-feel.md

[grammar] ~5-~5: There seems to be a noun/verb agreement error. Did you mean “excludes” or “excluded”?
Context: ...l now correctly parse tailwind's source exclude syntax: @source not "foo.css";

(SINGULAR_NOUN_VERB_AGREEMENT)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Documentation
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Check Dependencies
  • GitHub Check: Test Node.js API
  • GitHub Check: Bench (biome_css_parser)
  • GitHub Check: Bench (biome_css_formatter)
  • GitHub Check: Parser conformance
  • GitHub Check: Bench (biome_css_analyze)
  • GitHub Check: autofix
🔇 Additional comments (6)
crates/biome_css_formatter/tests/specs/css/atrule/tailwind/source-not.css (1)

1-1: LGTM! Intentional whitespace for formatter testing.

The excessive whitespace is appropriate for testing that the formatter correctly normalises the @source not directive.

crates/biome_css_parser/tests/css_test_suite/ok/tailwind/source-not.css (1)

1-1: LGTM! Clean test case for the new syntax.

The test correctly demonstrates the @source not exclusion syntax as documented in Tailwind.

crates/biome_css_parser/src/syntax/at_rule/tailwind.rs (1)

218-220: LGTM! Clean implementation of optional not token parsing.

The logic correctly handles the optional not keyword after the source token, matching the updated grammar definition.

crates/biome_css_formatter/tests/specs/css/atrule/tailwind/options.json (1)

1-7: LGTM! Proper test configuration for Tailwind directives.

The options file correctly enables tailwindDirectives parsing for the test suite, allowing the formatter to handle the new @source not syntax.

Based on learnings

crates/biome_css_formatter/src/tailwind/statements/source_at_rule.rs (1)

10-10: LGTM! Correct handling of optional not_token in formatting.

The formatter properly destructures and conditionally emits the not_token when present, maintaining correct spacing between tokens.

Also applies to: 16-18

xtask/codegen/css.ungram (1)

1944-1944: LGTM! Grammar correctly reflects the optional not token.

The updated TwSourceAtRule definition properly allows the not keyword to be optional after source, supporting both inclusion and exclusion syntax.

"@biomejs/biome": patch
---

The css parser with `tailwindDirectives` enabled will now correctly parse tailwind's source exclude syntax: `@source not "foo.css";`
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Grammar: Use "exclusion" instead of "exclude".

The phrase "source exclude syntax" is grammatically awkward.

Apply this diff:

-The css parser with `tailwindDirectives` enabled will now correctly parse tailwind's source exclude syntax: `@source not "foo.css";`
+The css parser with `tailwindDirectives` enabled will now correctly parse tailwind's source exclusion syntax: `@source not "foo.css";`
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
The css parser with `tailwindDirectives` enabled will now correctly parse tailwind's source exclude syntax: `@source not "foo.css";`
The css parser with `tailwindDirectives` enabled will now correctly parse tailwind's source exclusion syntax: `@source not "foo.css";`
🧰 Tools
🪛 LanguageTool

[grammar] ~5-~5: There seems to be a noun/verb agreement error. Did you mean “excludes” or “excluded”?
Context: ...l now correctly parse tailwind's source exclude syntax: @source not "foo.css";

(SINGULAR_NOUN_VERB_AGREEMENT)

🤖 Prompt for AI Agents
In .changeset/soft-rules-feel.md around line 5, change the phrase "source
exclude syntax" to "source exclusion syntax" so the sentence reads: "The css
parser with `tailwindDirectives` enabled will now correctly parse tailwind's
source exclusion syntax: `@source not \"foo.css\";`". Ensure only the wording is
updated and punctuation/formatting remains unchanged.

@codspeed-hq
Copy link

codspeed-hq bot commented Oct 24, 2025

CodSpeed Performance Report

Merging #7853 will not alter performance

Comparing dyc3/fix-tw-source-not (3c60b2f) with main (53ffa8b)1

Summary

✅ 29 untouched
⏩ 111 skipped2

Footnotes

  1. No successful run was found on main (72afdfa) during the generation of this report, so 53ffa8b was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

  2. 111 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.

@dyc3 dyc3 force-pushed the dyc3/fix-tw-source-not branch from f94466e to 3c60b2f Compare October 25, 2025 14:19
@dyc3 dyc3 merged commit fe90c78 into main Oct 25, 2025
18 checks passed
@dyc3 dyc3 deleted the dyc3/fix-tw-source-not branch October 25, 2025 14:51
@github-actions github-actions bot mentioned this pull request Oct 25, 2025
Jagget pushed a commit to Jagget/biome that referenced this pull request Oct 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Formatter Area: formatter A-Parser Area: parser A-Tooling Area: internal tools L-CSS Language: CSS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🐛 Tailwind path ignore syntax causes a parsing error

3 participants