Skip to content

Commit 01ea8c2

Browse files
committed
handle :has
1 parent 8e3a529 commit 01ea8c2

File tree

4 files changed

+61
-9
lines changed

4 files changed

+61
-9
lines changed

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

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -335,10 +335,12 @@ function relative_selector_might_apply_to_node(relative_selector, rule, element)
335335
descendant_elements.push(element);
336336
}
337337

338-
walk(
339-
/** @type {Compiler.SvelteNode} */ (element.fragment),
340-
{ is_child: true },
341-
{
338+
/**
339+
* @param {Compiler.SvelteNode} node
340+
* @param {{ is_child: boolean }} state
341+
*/
342+
function walk_children(node, state) {
343+
walk(node, state, {
342344
_(node, context) {
343345
if (node.type === 'RegularElement' || node.type === 'SvelteElement') {
344346
descendant_elements.push(node);
@@ -351,12 +353,18 @@ function relative_selector_might_apply_to_node(relative_selector, rule, element)
351353
} else {
352354
context.next();
353355
}
356+
} else if (node.type === 'RenderTag') {
357+
for (const snippet of node.metadata.snippets) {
358+
walk_children(snippet.body, context.state);
359+
}
354360
} else {
355361
context.next();
356362
}
357363
}
358-
}
359-
);
364+
});
365+
}
366+
367+
walk_children(element.fragment, { is_child: true });
360368

361369
// :has(...) is special in that it means "look downwards in the CSS tree". Since our matching algorithm goes
362370
// upwards and back-to-front, we need to first check the selectors inside :has(...), then check the rest of the
@@ -609,17 +617,28 @@ function get_following_sibling_elements(element, include_self) {
609617

610618
// ...then walk them, starting from the node after the one
611619
// containing the element in question
612-
for (const node of nodes.slice(nodes.indexOf(start) + 1)) {
620+
621+
/** @param {Compiler.SvelteNode} node */
622+
function get_siblings(node) {
613623
walk(node, null, {
614624
RegularElement(node) {
615625
siblings.push(node);
616626
},
617627
SvelteElement(node) {
618628
siblings.push(node);
629+
},
630+
RenderTag(node) {
631+
for (const snippet of node.metadata.snippets) {
632+
get_siblings(snippet.body);
633+
}
619634
}
620635
});
621636
}
622637

638+
for (const node of nodes.slice(nodes.indexOf(start) + 1)) {
639+
get_siblings(node);
640+
}
641+
623642
if (include_self) {
624643
siblings.push(element);
625644
}
Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
import { test } from '../../test';
22

33
export default test({
4-
// TODO unskip
5-
skip: true
4+
warnings: [
5+
{
6+
code: 'css_unused_selector',
7+
message: 'Unused CSS selector "z:has(+ y)"',
8+
start: {
9+
line: 23,
10+
column: 1,
11+
character: 217
12+
},
13+
end: {
14+
line: 23,
15+
column: 11,
16+
character: 227
17+
}
18+
}
19+
]
620
});

packages/svelte/tests/css/samples/has-with-render-tag/expected.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,10 @@
22
x.svelte-xyz:has(y:where(.svelte-xyz)) {
33
color: green;
44
}
5+
p.svelte-xyz:has(+ y:where(.svelte-xyz)) {
6+
color: green;
7+
}
8+
9+
/* (unused) z:has(+ y) {
10+
color: red;
11+
}*/

packages/svelte/tests/css/samples/has-with-render-tag/input.svelte

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,20 @@
77
{@render foo()}
88
</x>
99

10+
<z>
11+
<p>this should be green</p>
12+
{@render foo()}
13+
</z>
14+
1015
<style>
1116
x:has(y) {
1217
color: green;
1318
}
19+
p:has(+ y) {
20+
color: green;
21+
}
22+
23+
z:has(+ y) {
24+
color: red;
25+
}
1426
</style>

0 commit comments

Comments
 (0)