Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/curly-balloons-relate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: correctly look for sibling elements inside blocks and components when pruning CSS
25 changes: 16 additions & 9 deletions packages/svelte/src/compiler/phases/2-analyze/css/css-prune.js
Original file line number Diff line number Diff line change
Expand Up @@ -638,19 +638,30 @@ function get_following_sibling_elements(element, include_self) {
/** @type {Array<Compiler.AST.RegularElement | Compiler.AST.SvelteElement>} */
const siblings = [];

// ...then walk them, starting from the node after the one
// containing the element in question
// ...then walk them, starting from the node containing the element in question
// skipping nodes that appears before the element

const seen = new Set();
let skip = true;

/** @param {Compiler.AST.SvelteNode} node */
function get_siblings(node) {
walk(node, null, {
RegularElement(node) {
siblings.push(node);
if (node === element) {
skip = false;
if (include_self) siblings.push(node);
} else if (!skip) {
siblings.push(node);
}
},
SvelteElement(node) {
siblings.push(node);
if (node === element) {
skip = false;
if (include_self) siblings.push(node);
} else if (!skip) {
siblings.push(node);
}
},
RenderTag(node) {
for (const snippet of node.metadata.snippets) {
Expand All @@ -663,14 +674,10 @@ function get_following_sibling_elements(element, include_self) {
});
}

for (const node of nodes.slice(nodes.indexOf(start) + 1)) {
for (const node of nodes.slice(nodes.indexOf(start))) {
get_siblings(node);
}

if (include_self) {
siblings.push(element);
}

return siblings;
}

Expand Down
118 changes: 66 additions & 52 deletions packages/svelte/tests/css/samples/has/_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,182 +6,196 @@ export default test({
code: 'css_unused_selector',
message: 'Unused CSS selector ".unused:has(y)"',
start: {
line: 31,
line: 33,
column: 1,
character: 308
character: 330
},
end: {
line: 31,
line: 33,
column: 15,
character: 322
character: 344
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector ".unused:has(:global(y))"',
start: {
line: 34,
line: 36,
column: 1,
character: 343
character: 365
},
end: {
line: 34,
line: 36,
column: 24,
character: 366
character: 388
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "x:has(.unused)"',
start: {
line: 37,
line: 39,
column: 1,
character: 387
character: 409
},
end: {
line: 37,
line: 39,
column: 15,
character: 401
character: 423
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector ":global(.foo):has(.unused)"',
start: {
line: 40,
line: 42,
column: 1,
character: 422
character: 444
},
end: {
line: 40,
line: 42,
column: 27,
character: 448
character: 470
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "x:has(y):has(.unused)"',
start: {
line: 50,
line: 52,
column: 1,
character: 556
character: 578
},
end: {
line: 50,
line: 52,
column: 22,
character: 577
character: 599
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector ".unused"',
start: {
line: 69,
line: 71,
column: 2,
character: 782
character: 804
},
end: {
line: 69,
line: 71,
column: 9,
character: 789
character: 811
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector ".unused x:has(y)"',
start: {
line: 85,
line: 87,
column: 1,
character: 936
character: 958
},
end: {
line: 85,
line: 87,
column: 17,
character: 952
character: 974
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector ".unused:has(.unused)"',
start: {
line: 88,
line: 90,
column: 1,
character: 973
character: 995
},
end: {
line: 88,
line: 90,
column: 21,
character: 993
character: 1015
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "x:has(> z)"',
start: {
line: 98,
line: 100,
column: 1,
character: 1093
character: 1115
},
end: {
line: 98,
line: 100,
column: 11,
character: 1103
character: 1125
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "x:has(> d)"',
start: {
line: 101,
line: 103,
column: 1,
character: 1124
character: 1146
},
end: {
line: 101,
line: 103,
column: 11,
character: 1134
character: 1156
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "x:has(~ y)"',
start: {
line: 121,
line: 123,
column: 1,
character: 1326
character: 1348
},
end: {
line: 121,
line: 123,
column: 11,
character: 1336
character: 1358
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "f:has(~ d)"',
start: {
line: 133,
column: 1,
character: 1446
},
end: {
line: 133,
column: 11,
character: 1456
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector ":has(.unused)"',
start: {
line: 129,
line: 141,
column: 2,
character: 1409
character: 1529
},
end: {
line: 129,
line: 141,
column: 15,
character: 1422
character: 1542
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "&:has(.unused)"',
start: {
line: 135,
line: 147,
column: 2,
character: 1480
character: 1600
},
end: {
line: 135,
line: 147,
column: 16,
character: 1494
character: 1614
}
}
]
Expand Down
10 changes: 10 additions & 0 deletions packages/svelte/tests/css/samples/has/expected.css
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,16 @@
color: red;
}*/

d.svelte-xyz:has(+ e:where(.svelte-xyz)) {
color: green;
}
d.svelte-xyz:has(~ f:where(.svelte-xyz)) {
color: green;
}
/* (unused) f:has(~ d) {
color: red;
}*/

.foo {
.svelte-xyz:has(x:where(.svelte-xyz)) {
color: green;
Expand Down
12 changes: 12 additions & 0 deletions packages/svelte/tests/css/samples/has/input.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
<z></z>
{#if foo}
<d></d>
<e></e>
<f></f>
{/if}
</y>
</x>
Expand Down Expand Up @@ -122,6 +124,16 @@
color: red;
}

d:has(+ e) {
color: green;
}
d:has(~ f) {
color: green;
}
f:has(~ d) {
color: red;
}

:global(.foo) {
:has(x) {
color: green;
Expand Down