Skip to content

Commit 924dd69

Browse files
authored
Ensure @custom-variant foo () has a non-empty selector list (#16009)
This PR fixes an issue where an empty selector list was valid when defining a `@custom-variant`. Given this input: ```css @custom-variant foo (); ``` If you then use it with a utility such as `foo:flex`, then the following (incorrect) CSS was generated: ```css .foo\:flex { { display: flex; } } ``` Which is invalid CSS. This PR will now validate that that we have at least _something_ and show an error accordingly.
1 parent 965048c commit 924dd69

File tree

3 files changed

+26
-0
lines changed

3 files changed

+26
-0
lines changed

Diff for: CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2727
- Find utilities when using functions inside arrays ([#15974](https://github.com/tailwindlabs/tailwindcss/pull/15974))
2828
- Ensure that `@tailwindcss/browser` does not pollute the global namespace ([#15978](https://github.com/tailwindlabs/tailwindcss/pull/15978))
2929
- Fix crash when project lives in the `/` directory ([#15988](https://github.com/tailwindlabs/tailwindcss/pull/15988))
30+
- Ensure `@custom-variant` has a non-empty selector list ([#16009](https://github.com/tailwindlabs/tailwindcss/pull/16009))
3031
- _Upgrade_: Ensure JavaScript config files on different drives are correctly migrated ([#15927](https://github.com/tailwindlabs/tailwindcss/pull/15927))
3132
- _Upgrade_: Migrate `leading-[1]` to `leading-none` ([#16004](https://github.com/tailwindlabs/tailwindcss/pull/16004))
3233
- _Upgrade_: Do not migrate arbitrary leading utilities to bare utilities ([#16004](https://github.com/tailwindlabs/tailwindcss/pull/16004))

Diff for: packages/tailwindcss/src/index.test.ts

+20
Original file line numberDiff line numberDiff line change
@@ -2514,6 +2514,26 @@ describe('@custom-variant', () => {
25142514
).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: \`@custom-variant\` cannot be nested.]`)
25152515
})
25162516

2517+
test('@custom-variant must not have an empty selector', () => {
2518+
return expect(
2519+
compileCss(css`
2520+
@custom-variant foo ();
2521+
`),
2522+
).rejects.toThrowErrorMatchingInlineSnapshot(
2523+
`[Error: \`@custom-variant foo ()\` selector is invalid.]`,
2524+
)
2525+
})
2526+
2527+
test('@custom-variant with multiple selectors, cannot be empty', () => {
2528+
return expect(
2529+
compileCss(css`
2530+
@custom-variant foo (.foo, .bar, );
2531+
`),
2532+
).rejects.toThrowErrorMatchingInlineSnapshot(
2533+
`[Error: \`@custom-variant foo (.foo, .bar, )\` selector is invalid.]`,
2534+
)
2535+
})
2536+
25172537
test('@custom-variant with no body must include a selector', () => {
25182538
return expect(
25192539
compileCss(css`

Diff for: packages/tailwindcss/src/index.ts

+5
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,11 @@ async function parseCss(
281281
}
282282

283283
let selectors = segment(selector.slice(1, -1), ',')
284+
if (selectors.length === 0 || selectors.some((selector) => selector.trim() === '')) {
285+
throw new Error(
286+
`\`@custom-variant ${name} (${selectors.join(',')})\` selector is invalid.`,
287+
)
288+
}
284289

285290
let atRuleParams: string[] = []
286291
let styleRuleSelectors: string[] = []

0 commit comments

Comments
 (0)