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"
/>
This commit is contained in:
Philipp Spiess 2025-02-25 17:00:55 +01:00 • committed by GitHub
parent 294952f170
commit b56f12e6e7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 60 additions and 1 deletions

View file

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

View file

@ -77,6 +77,60 @@ describe('parse', () => {
},
])
})
it('parses &:has(.child:nth-child(2))', () => {
expect(parse('&:has(.child:nth-child(2))')).toEqual([
{
kind: 'selector',
value: '&',
},
{
kind: 'function',
value: ':has',
nodes: [
{
kind: 'selector',
value: '.child',
},
{
kind: 'function',
value: ':nth-child',
nodes: [
{
kind: 'value',
value: '2',
},
],
},
],
},
])
})
it('parses &:has(:nth-child(2))', () => {
expect(parse('&:has(:nth-child(2))')).toEqual([
{
kind: 'selector',
value: '&',
},
{
kind: 'function',
value: ':has',
nodes: [
{
kind: 'function',
value: ':nth-child',
nodes: [
{
kind: 'value',
value: '2',
},
],
},
],
},
])
})
})
describe('toCss', () => {

View file

@ -300,7 +300,11 @@ export function parse(input: string) {
buffer = ''
i = end
ast.push(node)
if (parent) {
parent.nodes.push(node)
} else {
ast.push(node)
}
break
}