fix: css pruning producing invalid css (#14448)

* fix: css pruning producing invalid css

* Update .changeset/big-hats-wonder.md

---------

Co-authored-by: Rich Harris <rich.harris@vercel.com>
pull/14457/head
Paolo Ricciuti 9 months ago committed by GitHub
parent 4f318e6ad6
commit 19d80ad63c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: correctly remove unused selectors in middle of selector lists

@ -200,6 +200,7 @@ const visitors = {
let pruning = false; let pruning = false;
let prune_start = children[0].start; let prune_start = children[0].start;
let last = prune_start; let last = prune_start;
let has_previous_used = false;
for (let i = 0; i < children.length; i += 1) { for (let i = 0; i < children.length; i += 1) {
const selector = children[i]; const selector = children[i];
@ -210,9 +211,9 @@ const visitors = {
while (state.code.original[i] !== ',') i--; while (state.code.original[i] !== ',') i--;
if (state.minify) { if (state.minify) {
state.code.remove(prune_start, i + 1); state.code.remove(prune_start, has_previous_used ? i : i + 1);
} else { } else {
state.code.overwrite(i, i + 1, '*/'); state.code.appendRight(has_previous_used ? i : i + 1, '*/');
} }
} else { } else {
if (i === 0) { if (i === 0) {
@ -222,17 +223,10 @@ const visitors = {
state.code.prependRight(selector.start, '/* (unused) '); state.code.prependRight(selector.start, '/* (unused) ');
} }
} else { } else {
// If this is not the last selector add a separator
const separator = i !== children.length - 1 ? ',' : '';
if (state.minify) { if (state.minify) {
prune_start = last; prune_start = last;
if (separator) {
while (state.code.original[prune_start - 1] !== ',') prune_start++;
state.code.update(last, prune_start, separator);
}
} else { } else {
state.code.overwrite(last, selector.start, `${separator} /* (unused) `); state.code.overwrite(last, selector.start, ` /* (unused) `);
} }
} }
} }
@ -240,6 +234,10 @@ const visitors = {
pruning = !pruning; pruning = !pruning;
} }
if (!pruning && selector.metadata.used) {
has_previous_used = true;
}
last = selector.end; last = selector.end;
} }

@ -75,7 +75,7 @@
/* (unused) .unused x:has(y) { /* (unused) .unused x:has(y) {
color: red; color: red;
}*/ }*/
/* (unused) .unused:has(.unused)*/ x.svelte-xyz:has(y:where(.svelte-xyz)) { /* (unused) .unused:has(.unused),*/ x.svelte-xyz:has(y:where(.svelte-xyz)) {
color: green; color: green;
} }

@ -1,7 +1,7 @@
h1.svelte-xyz, h1.svelte-xyz,
h2.svelte-xyz, h2.svelte-xyz,
h3.svelte-xyz, /* (unused) h4*/ h3.svelte-xyz /* (unused) h4*/,
p.svelte-xyz { p.svelte-xyz {
color: red; color: red;
} }

@ -1,3 +1,3 @@
/* (unused) .foo*/ .bar.svelte-xyz /* (unused) .baz*/ { /* (unused) .foo,*/ .bar.svelte-xyz /* (unused) .baz*/ {
color: red; color: red;
} }

@ -0,0 +1,160 @@
import { test } from '../../test';
export default test({
warnings: [
{
code: 'a11y_missing_content',
message: '`<h1>` element should contain text',
start: {
line: 1,
column: 0,
character: 0
},
end: {
line: 1,
column: 9,
character: 9
}
},
{
code: 'a11y_missing_content',
message: '`<h4>` element should contain text',
start: {
line: 2,
column: 0,
character: 10
},
end: {
line: 2,
column: 9,
character: 19
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "h2"',
start: {
line: 6,
column: 5,
character: 35
},
end: {
line: 6,
column: 7,
character: 37
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "h3"',
start: {
line: 6,
column: 9,
character: 39
},
end: {
line: 6,
column: 11,
character: 41
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "h2"',
start: {
line: 9,
column: 5,
character: 66
},
end: {
line: 9,
column: 7,
character: 68
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "h2"',
start: {
line: 13,
column: 5,
character: 110
},
end: {
line: 13,
column: 7,
character: 112
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "h3"',
start: {
line: 13,
column: 9,
character: 114
},
end: {
line: 13,
column: 11,
character: 116
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "h2"',
start: {
line: 17,
column: 5,
character: 161
},
end: {
line: 17,
column: 7,
character: 163
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "h3"',
start: {
line: 17,
column: 9,
character: 165
},
end: {
line: 17,
column: 11,
character: 167
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "h5"',
start: {
line: 17,
column: 17,
character: 173
},
end: {
line: 17,
column: 19,
character: 175
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector "h6"',
start: {
line: 17,
column: 21,
character: 177
},
end: {
line: 17,
column: 23,
character: 179
}
}
]
});

@ -0,0 +1,15 @@
h1.svelte-xyz /* (unused) h2, h3*/ {
color: red;
}
h1.svelte-xyz /* (unused) h2*/ {
text-decoration: underline;
}
h1.svelte-xyz /* (unused) h2, h3*/, h4.svelte-xyz {
text-transform: uppercase;
}
h1.svelte-xyz /* (unused) h2, h3*/, h4.svelte-xyz /* (unused) h5, h6*/ {
background-color: green;
}

@ -0,0 +1,20 @@
<h1></h1>
<h4></h4>
<style>
h1, h2, h3 {
color: red;
}
h1, h2 {
text-decoration: underline;
}
h1, h2, h3, h4 {
text-transform: uppercase;
}
h1, h2, h3, h4, h5, h6 {
background-color: green;
}
</style>
Loading…
Cancel
Save