From 5189045562d6e17ac6f229e87ec829adb66a01d0 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Wed, 15 Oct 2025 10:33:29 +0200 Subject: [PATCH 1/4] add failing tests --- packages/tailwindcss/src/css-parser.test.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/tailwindcss/src/css-parser.test.ts b/packages/tailwindcss/src/css-parser.test.ts index c63597af7511..e4183278ee53 100644 --- a/packages/tailwindcss/src/css-parser.test.ts +++ b/packages/tailwindcss/src/css-parser.test.ts @@ -723,6 +723,18 @@ describe.each(['Unix', 'Windows'])('Line endings: %s', (lineEndings) => { ).toEqual([{ kind: 'at-rule', name: '@charset', params: '"UTF-8"', nodes: [] }]) }) + it('should parse an at-rule with tabs in the params', () => { + expect(parse('@apply\tbg-red-500;')).toEqual([ + { kind: 'at-rule', name: '@apply', params: 'bg-red-500', nodes: [] }, + ]) + }) + + it('should parse an at-rule with tabs and newlines in the params', () => { + expect(parse('@apply\n\tbg-red-500;')).toEqual([ + { kind: 'at-rule', name: '@apply', params: 'bg-red-500', nodes: [] }, + ]) + }) + it('should parse an at-rule without a block or semicolon', () => { expect( parse(` From 97e91913f374fe357c08a83b750c757a029a1306 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Wed, 15 Oct 2025 10:31:14 +0200 Subject: [PATCH 2/4] properly handle `\t` when parsing at-rules --- packages/tailwindcss/src/css-parser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tailwindcss/src/css-parser.ts b/packages/tailwindcss/src/css-parser.ts index e38f64b33582..1653c3789b28 100644 --- a/packages/tailwindcss/src/css-parser.ts +++ b/packages/tailwindcss/src/css-parser.ts @@ -571,7 +571,7 @@ export function parseAtRule(buffer: string, nodes: AstNode[] = []): AtRule { // behavior if necessary. for (let i = 5 /* '@page'.length */; i < buffer.length; i++) { let currentChar = buffer.charCodeAt(i) - if (currentChar === SPACE || currentChar === OPEN_PAREN) { + if (currentChar === SPACE || currentChar === TAB || currentChar === OPEN_PAREN) { name = buffer.slice(0, i) params = buffer.slice(i) break From d7cdd67ba98d01872f782bf6525c5daa8c830a93 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Wed, 15 Oct 2025 10:36:26 +0200 Subject: [PATCH 3/4] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56d453605f9c..a0bed774ea42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Allow named groups in combination with `not-*`, `has-*`, and `in-*` ([#19100](https://github.com/tailwindlabs/tailwindcss/pull/19100)) - Prevent important utilities from affecting other utilities ([#19110](https://github.com/tailwindlabs/tailwindcss/pull/19110)) - Don’t index into strings with the `theme(…)` function ([#19111](https://github.com/tailwindlabs/tailwindcss/pull/19111)) +- Fix parsing issue when `\t` is used in at-rules ([#19130](https://github.com/tailwindlabs/tailwindcss/pull/19130)) - Upgrade: Canonicalize utilities containing `0` values ([#19095](https://github.com/tailwindlabs/tailwindcss/pull/19095)) ## [4.1.14] - 2025-10-01 From 46a5a5b68fd044256af5f4a4ec01d570c7e355a4 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Wed, 15 Oct 2025 10:40:32 +0200 Subject: [PATCH 4/4] add various whitespace combinations in tests --- packages/tailwindcss/src/css-parser.test.ts | 24 ++++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/tailwindcss/src/css-parser.test.ts b/packages/tailwindcss/src/css-parser.test.ts index e4183278ee53..25657d9db770 100644 --- a/packages/tailwindcss/src/css-parser.test.ts +++ b/packages/tailwindcss/src/css-parser.test.ts @@ -723,14 +723,22 @@ describe.each(['Unix', 'Windows'])('Line endings: %s', (lineEndings) => { ).toEqual([{ kind: 'at-rule', name: '@charset', params: '"UTF-8"', nodes: [] }]) }) - it('should parse an at-rule with tabs in the params', () => { - expect(parse('@apply\tbg-red-500;')).toEqual([ - { kind: 'at-rule', name: '@apply', params: 'bg-red-500', nodes: [] }, - ]) - }) - - it('should parse an at-rule with tabs and newlines in the params', () => { - expect(parse('@apply\n\tbg-red-500;')).toEqual([ + it.each([ + [' '], // space + [' '], // multiple spaces + ['\t'], // tab + [' \t'], // space + tab + ['\t '], // tab + space + ['\t\t'], // multiple tabs + ['\n'], // newline + [' \n'], // space + newline + ['\n '], // newline + space + ['\n\n'], // multiple newlines + ['\r\n'], // windows newline + [' \r\n'], // space + windows newline + ['\r\n '], // windows newline + space + ])('should parse an at-rule with whitespace %s in the params', (whitespace) => { + expect(parse(`@apply${whitespace}bg-red-500;`)).toEqual([ { kind: 'at-rule', name: '@apply', params: 'bg-red-500', nodes: [] }, ]) })