From 29687e01838dd4ddf0ce158eb119724365918608 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 22 Oct 2025 06:14:43 -0400 Subject: [PATCH] Discard candidates with an empty data type (#19172) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/tailwindlabs/tailwindcss-intellisense/issues/1479 Maybe should close https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1480 — perhaps we can find a workaround there for older versions? We're building up a class name in code to validate if something is a valid variant: `{variant}:[color:red]` if `{variant}` got replaced with `bg-[` then we'd produce `bg-[:[color:red]` and this parsed as a valid candidate: ``` bg-[:[color:red] ^^ root: `bg` ^ data type: `` (empty string) — this should be invalid ^^^^^^^^^^ value: `[color:red` ``` The value isn't valid _but_ the syntax for arbitrary values is pretty lax in core. Oxide already won't pick something like this up though so no problem there. Only a problem for something like IntelliSense or clients using the compile() API directly. --- CHANGELOG.md | 4 ++++ packages/tailwindcss/src/candidate.test.ts | 8 ++++++++ packages/tailwindcss/src/candidate.ts | 4 +++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5292d918c..375288258 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - _Experimental_: Add `@container-size` utility ([#18901](https://github.com/tailwindlabs/tailwindcss/pull/18901)) +### Fixed + +- Discard candidates with an empty data type ([#19172](https://github.com/tailwindlabs/tailwindcss/pull/19172)) + ## [4.1.15] - 2025-10-20 ### Fixed diff --git a/packages/tailwindcss/src/candidate.test.ts b/packages/tailwindcss/src/candidate.test.ts index 3d4aa983b..53d21dda6 100644 --- a/packages/tailwindcss/src/candidate.test.ts +++ b/packages/tailwindcss/src/candidate.test.ts @@ -1776,6 +1776,14 @@ it('should not parse compound group with a non-compoundable variant', () => { expect(run('group-*:flex', { utilities, variants })).toMatchInlineSnapshot(`[]`) }) +it('empty data types are invalid', () => { + let utilities = new Utilities() + utilities.functional('bg', () => []) + let variants = new Variants() + + expect(run('bg-[:foo]', { utilities, variants })).toMatchInlineSnapshot(`[]`) +}) + it('should parse a variant containing an arbitrary string with unbalanced parens, brackets, curlies and other quotes', () => { let utilities = new Utilities() utilities.static('flex', () => []) diff --git a/packages/tailwindcss/src/candidate.ts b/packages/tailwindcss/src/candidate.ts index c081c3b47..fa8cd3047 100644 --- a/packages/tailwindcss/src/candidate.ts +++ b/packages/tailwindcss/src/candidate.ts @@ -554,7 +554,7 @@ export function* parseCandidate(input: string, designSystem: DesignSystem): Iter if (!isValidArbitrary(arbitraryValue)) continue // Extract an explicit typehint if present, e.g. `bg-[color:var(--my-var)])` - let typehint = '' + let typehint: string | null = null for (let i = 0; i < arbitraryValue.length; i++) { let code = arbitraryValue.charCodeAt(i) @@ -580,6 +580,8 @@ export function* parseCandidate(input: string, designSystem: DesignSystem): Iter continue } + if (typehint === '') continue + candidate.value = { kind: 'arbitrary', dataType: typehint || null,