diff --git a/packages/svelte/src/compiler/phases/2-analyze/css/css-prune.js b/packages/svelte/src/compiler/phases/2-analyze/css/css-prune.js index f05cd7e4ae3d..83c50c73d029 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/css/css-prune.js +++ b/packages/svelte/src/compiler/phases/2-analyze/css/css-prune.js @@ -825,9 +825,10 @@ function get_element_parent(node) { /** * @param {Compiler.AST.RegularElement | Compiler.AST.SvelteElement | Compiler.AST.RenderTag | Compiler.AST.Component | Compiler.AST.SvelteComponent | Compiler.AST.SvelteSelf} node * @param {boolean} adjacent_only + * @param {Set} seen * @returns {Map} */ -function get_possible_element_siblings(node, adjacent_only) { +function get_possible_element_siblings(node, adjacent_only, seen = new Set()) { /** @type {Map} */ const result = new Map(); const path = node.metadata.path; @@ -886,8 +887,11 @@ function get_possible_element_siblings(node, adjacent_only) { } if (current.type === 'SnippetBlock') { + if (seen.has(current)) break; + seen.add(current); + for (const site of current.metadata.sites) { - const siblings = get_possible_element_siblings(site, adjacent_only); + const siblings = get_possible_element_siblings(site, adjacent_only, seen); add_to_map(siblings, result); if (adjacent_only && current.metadata.sites.size === 1 && has_definite_elements(siblings)) { diff --git a/packages/svelte/tests/css/samples/render-tag-loop/_config.js b/packages/svelte/tests/css/samples/render-tag-loop/_config.js new file mode 100644 index 000000000000..f623b92cc38b --- /dev/null +++ b/packages/svelte/tests/css/samples/render-tag-loop/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + warnings: [ + { + code: 'css_unused_selector', + message: 'Unused CSS selector "div + div"', + start: { + line: 19, + column: 1, + character: 185 + }, + end: { + line: 19, + column: 10, + character: 194 + } + } + ] +}); diff --git a/packages/svelte/tests/css/samples/render-tag-loop/expected.css b/packages/svelte/tests/css/samples/render-tag-loop/expected.css index 580c1f05fbbc..1f05ddb41cc7 100644 --- a/packages/svelte/tests/css/samples/render-tag-loop/expected.css +++ b/packages/svelte/tests/css/samples/render-tag-loop/expected.css @@ -1,7 +1,10 @@ - div.svelte-xyz div:where(.svelte-xyz) { + div div.svelte-xyz { color: green; } + /* (unused) div + div { + color: red; /* this is marked as unused, but only because we've written an infinite loop - worth fixing? *\/ + }*/ div.svelte-xyz:has(div:where(.svelte-xyz)) { color: green; } diff --git a/packages/svelte/tests/css/samples/render-tag-loop/input.svelte b/packages/svelte/tests/css/samples/render-tag-loop/input.svelte index 192eb3d2f127..ade8df574489 100644 --- a/packages/svelte/tests/css/samples/render-tag-loop/input.svelte +++ b/packages/svelte/tests/css/samples/render-tag-loop/input.svelte @@ -1,10 +1,12 @@ {#snippet a()} + {@render b()}
{@render b()}
{/snippet} {#snippet b()} + {@render a()}
{@render a()}
@@ -14,6 +16,9 @@ div div { color: green; } + div + div { + color: red; /* this is marked as unused, but only because we've written an infinite loop - worth fixing? */ + } div:has(div) { color: green; }