Skip to content

Commit b56f12e

Browse files
Ensure nested functions in selectors used with JavaScript plugins are not truncated (#16802)
Fixes #16799 This was caused by a wrong condition in the CSS value parser that put child function arguments into the parent function by accident. ## Test plan - Added a unit test to guard against regressions - Validated against the repro: <img width="914" alt="Screenshot 2025-02-25 at 16 31 14" src="https://github.com/user-attachments/assets/f5fdf2e7-9c1b-4b04-89a8-1fa78a27f0f5" />
1 parent 294952f commit b56f12e

File tree

3 files changed

+60
-1
lines changed

3 files changed

+60
-1
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2121
- Fix an issue where `@reference "…"` would sometimes omit keyframe animations ([#16774](https://github.com/tailwindlabs/tailwindcss/pull/16774))
2222
- Ensure `z-*!` utilities are property marked as `!important` ([#16795](https://github.com/tailwindlabs/tailwindcss/pull/16795))
2323
- Read UTF-8 CSS files that start with a byte-order mark (BOM) ([#16796](https://github.com/tailwindlabs/tailwindcss/pull/16796))
24+
- Ensure nested functions in selectors used with JavaScript plugins are not truncated ([#16802](https://github.com/tailwindlabs/tailwindcss/pull/16802))
2425

2526
## [4.0.8] - 2025-02-21
2627

packages/tailwindcss/src/compat/selector-parser.test.ts

+54
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,60 @@ describe('parse', () => {
7777
},
7878
])
7979
})
80+
81+
it('parses &:has(.child:nth-child(2))', () => {
82+
expect(parse('&:has(.child:nth-child(2))')).toEqual([
83+
{
84+
kind: 'selector',
85+
value: '&',
86+
},
87+
{
88+
kind: 'function',
89+
value: ':has',
90+
nodes: [
91+
{
92+
kind: 'selector',
93+
value: '.child',
94+
},
95+
{
96+
kind: 'function',
97+
value: ':nth-child',
98+
nodes: [
99+
{
100+
kind: 'value',
101+
value: '2',
102+
},
103+
],
104+
},
105+
],
106+
},
107+
])
108+
})
109+
110+
it('parses &:has(:nth-child(2))', () => {
111+
expect(parse('&:has(:nth-child(2))')).toEqual([
112+
{
113+
kind: 'selector',
114+
value: '&',
115+
},
116+
{
117+
kind: 'function',
118+
value: ':has',
119+
nodes: [
120+
{
121+
kind: 'function',
122+
value: ':nth-child',
123+
nodes: [
124+
{
125+
kind: 'value',
126+
value: '2',
127+
},
128+
],
129+
},
130+
],
131+
},
132+
])
133+
})
80134
})
81135

82136
describe('toCss', () => {

packages/tailwindcss/src/compat/selector-parser.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,11 @@ export function parse(input: string) {
300300
buffer = ''
301301
i = end
302302

303-
ast.push(node)
303+
if (parent) {
304+
parent.nodes.push(node)
305+
} else {
306+
ast.push(node)
307+
}
304308

305309
break
306310
}

0 commit comments

Comments
 (0)