From 224fcde821db43fb22e27c7559dbcf63803a0f91 Mon Sep 17 00:00:00 2001 From: "Ahmad S." Date: Wed, 30 Oct 2024 19:37:31 +0300 Subject: [PATCH] fix: preserve the separator between selectors when an unused selector is in between (#13954) fixes #13945 --- .changeset/eighty-icons-fold.md | 5 +++++ .../compiler/phases/3-transform/css/index.js | 16 +++++++++++---- .../unused-selector-in-between/_config.js | 20 +++++++++++++++++++ .../unused-selector-in-between/expected.css | 7 +++++++ .../unused-selector-in-between/input.svelte | 14 +++++++++++++ .../_expected.html | 2 +- .../_expected_head.html | 2 +- .../css-injected-options-minify/main.svelte | 6 ++++++ 8 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 .changeset/eighty-icons-fold.md create mode 100644 packages/svelte/tests/css/samples/unused-selector-in-between/_config.js create mode 100644 packages/svelte/tests/css/samples/unused-selector-in-between/expected.css create mode 100644 packages/svelte/tests/css/samples/unused-selector-in-between/input.svelte diff --git a/.changeset/eighty-icons-fold.md b/.changeset/eighty-icons-fold.md new file mode 100644 index 0000000000..2d8f0d57bf --- /dev/null +++ b/.changeset/eighty-icons-fold.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: preserve the separator between selectors when an unused selector is in between diff --git a/packages/svelte/src/compiler/phases/3-transform/css/index.js b/packages/svelte/src/compiler/phases/3-transform/css/index.js index 5b40867aab..ce682edd52 100644 --- a/packages/svelte/src/compiler/phases/3-transform/css/index.js +++ b/packages/svelte/src/compiler/phases/3-transform/css/index.js @@ -196,12 +196,13 @@ const visitors = { SelectorList(node, { state, next, path }) { // Only add comments if we're not inside a complex selector that itself is unused if (!path.find((n) => n.type === 'ComplexSelector' && !n.metadata.used)) { + const children = node.children; let pruning = false; - let prune_start = node.children[0].start; + let prune_start = children[0].start; let last = prune_start; - for (let i = 0; i < node.children.length; i += 1) { - const selector = node.children[i]; + for (let i = 0; i < children.length; i += 1) { + const selector = children[i]; if (selector.metadata.used === pruning) { if (pruning) { @@ -221,10 +222,17 @@ const visitors = { state.code.prependRight(selector.start, '/* (unused) '); } } else { + // If this is not the last selector add a separator + const separator = i !== children.length - 1 ? ',' : ''; + if (state.minify) { prune_start = last; + if (separator) { + while (state.code.original[prune_start - 1] !== ',') prune_start++; + state.code.update(last, prune_start, separator); + } } else { - state.code.overwrite(last, selector.start, ' /* (unused) '); + state.code.overwrite(last, selector.start, `${separator} /* (unused) `); } } } diff --git a/packages/svelte/tests/css/samples/unused-selector-in-between/_config.js b/packages/svelte/tests/css/samples/unused-selector-in-between/_config.js new file mode 100644 index 0000000000..43747eb0c1 --- /dev/null +++ b/packages/svelte/tests/css/samples/unused-selector-in-between/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + warnings: [ + { + code: 'css_unused_selector', + end: { + character: 72, + column: 3, + line: 10 + }, + message: 'Unused CSS selector "h4"', + start: { + character: 70, + column: 1, + line: 10 + } + } + ] +}); diff --git a/packages/svelte/tests/css/samples/unused-selector-in-between/expected.css b/packages/svelte/tests/css/samples/unused-selector-in-between/expected.css new file mode 100644 index 0000000000..5a93aa53b7 --- /dev/null +++ b/packages/svelte/tests/css/samples/unused-selector-in-between/expected.css @@ -0,0 +1,7 @@ + + h1.svelte-xyz, + h2.svelte-xyz, + h3.svelte-xyz, /* (unused) h4*/ + p.svelte-xyz { + color: red; + } diff --git a/packages/svelte/tests/css/samples/unused-selector-in-between/input.svelte b/packages/svelte/tests/css/samples/unused-selector-in-between/input.svelte new file mode 100644 index 0000000000..c1e149ba76 --- /dev/null +++ b/packages/svelte/tests/css/samples/unused-selector-in-between/input.svelte @@ -0,0 +1,14 @@ +

h1

+

h2

+

h3

+

p

+ + diff --git a/packages/svelte/tests/server-side-rendering/samples/css-injected-options-minify/_expected.html b/packages/svelte/tests/server-side-rendering/samples/css-injected-options-minify/_expected.html index caa872be9b..60e974bd1a 100644 --- a/packages/svelte/tests/server-side-rendering/samples/css-injected-options-minify/_expected.html +++ b/packages/svelte/tests/server-side-rendering/samples/css-injected-options-minify/_expected.html @@ -1 +1 @@ -
foo
\ No newline at end of file +
foo
\ No newline at end of file diff --git a/packages/svelte/tests/server-side-rendering/samples/css-injected-options-minify/_expected_head.html b/packages/svelte/tests/server-side-rendering/samples/css-injected-options-minify/_expected_head.html index 8d6e42d979..5350e77a49 100644 --- a/packages/svelte/tests/server-side-rendering/samples/css-injected-options-minify/_expected_head.html +++ b/packages/svelte/tests/server-side-rendering/samples/css-injected-options-minify/_expected_head.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/packages/svelte/tests/server-side-rendering/samples/css-injected-options-minify/main.svelte b/packages/svelte/tests/server-side-rendering/samples/css-injected-options-minify/main.svelte index 13e01788e2..6d9ecba8df 100644 --- a/packages/svelte/tests/server-side-rendering/samples/css-injected-options-minify/main.svelte +++ b/packages/svelte/tests/server-side-rendering/samples/css-injected-options-minify/main.svelte @@ -20,4 +20,10 @@ .foo, .unused { color: green; } + .unused, .foo { + color: green; + } + .foo, .unused, .foo { + color: green; + }