Skip to content

Commit c1ec87e

Browse files
committed
fix: handle leading combinators within :has(...)
We need to ignore the leading combinator within a `:has(...)`, else it would not stop matching, assuming there are more parent selectors (which there aren't) and always fail. #13567 (comment)
1 parent eb6488c commit c1ec87e

File tree

4 files changed

+39
-1
lines changed

4 files changed

+39
-1
lines changed

packages/svelte/src/compiler/phases/2-analyze/css/css-prune.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,16 @@ function relative_selector_might_apply_to_node(
371371

372372
for (const complex_selector of complex_selectors) {
373373
const selectors = truncate(complex_selector);
374+
const left_most_combinator = selectors[0]?.combinator ?? descendant_combinator;
375+
// In .x:has(> y), we want to search for y, ignoring the left-most combinator
376+
// (else it would try to walk further up and fail because there are no selectors left)
377+
if (selectors.length > 0) {
378+
selectors[0] = {
379+
...selectors[0],
380+
combinator: null
381+
};
382+
}
383+
374384
if (
375385
selectors.length === 0 /* is :global(...) */ ||
376386
apply_selector(selectors, rule, element, stylesheet, check_has)
@@ -379,7 +389,7 @@ function relative_selector_might_apply_to_node(
379389
// and now looking upwards for the .x part.
380390
if (
381391
apply_combinator(
382-
selectors[0]?.combinator ?? descendant_combinator,
392+
left_most_combinator,
383393
selectors[0] ?? [],
384394
[relative_selector],
385395
rule,

packages/svelte/tests/css/samples/has/_config.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,20 @@ export default test({
8585
column: 17,
8686
line: 81
8787
}
88+
},
89+
{
90+
code: 'css_unused_selector',
91+
message: 'Unused CSS selector "x:has(> z)"',
92+
start: {
93+
line: 88,
94+
column: 1,
95+
character: 968
96+
},
97+
end: {
98+
line: 88,
99+
column: 11,
100+
character: 978
101+
}
88102
}
89103
]
90104
});

packages/svelte/tests/css/samples/has/expected.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,10 @@
7575
/* (unused) .unused x:has(y) {
7676
color: red;
7777
}*/
78+
79+
x.svelte-xyz:has(> y:where(.svelte-xyz)) {
80+
color: green;
81+
}
82+
/* (unused) x:has(> z) {
83+
color: red;
84+
}*/

packages/svelte/tests/css/samples/has/input.svelte

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,11 @@
8181
.unused x:has(y) {
8282
color: red;
8383
}
84+
85+
x:has(> y) {
86+
color: green;
87+
}
88+
x:has(> z) {
89+
color: red;
90+
}
8491
</style>

0 commit comments

Comments
 (0)