Skip to content

Commit 7840a2c

Browse files
committed
implement CSS pruning for array/object expressions
1 parent 9a28106 commit 7840a2c

File tree

11 files changed

+96
-6
lines changed

11 files changed

+96
-6
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -731,7 +731,7 @@ function attribute_matches(node, name, expected_value, operator, case_insensitiv
731731
/** @type {string[]} */
732732
let prev_values = [];
733733
for (const chunk of chunks) {
734-
const current_possible_values = get_possible_values(chunk);
734+
const current_possible_values = get_possible_values(chunk, name === 'class');
735735

736736
// impossible to find out all combinations
737737
if (!current_possible_values) return true;

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

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,54 @@ const UNKNOWN = {};
44

55
/**
66
* @param {Node} node
7+
* @param {boolean} is_class
78
* @param {Set<any>} set
89
*/
9-
function gather_possible_values(node, set) {
10+
function gather_possible_values(node, is_class, set) {
1011
if (node.type === 'Literal') {
1112
set.add(String(node.value));
1213
} else if (node.type === 'ConditionalExpression') {
13-
gather_possible_values(node.consequent, set);
14-
gather_possible_values(node.alternate, set);
14+
gather_possible_values(node.consequent, is_class, set);
15+
gather_possible_values(node.alternate, is_class, set);
16+
} else if (is_class && node.type === 'ArrayExpression') {
17+
for (const entry of node.elements) {
18+
if (entry) {
19+
gather_possible_values(entry, is_class, set);
20+
} else {
21+
set.add(UNKNOWN);
22+
}
23+
}
24+
} else if (is_class && node.type === 'ObjectExpression') {
25+
for (const property of node.properties) {
26+
if (
27+
property.type === 'Property' &&
28+
!property.computed &&
29+
(property.key.type === 'Identifier' || property.key.type === 'Literal')
30+
) {
31+
set.add(
32+
property.key.type === 'Identifier' ? property.key.name : String(property.key.value)
33+
);
34+
} else {
35+
set.add(UNKNOWN);
36+
}
37+
}
1538
} else {
1639
set.add(UNKNOWN);
1740
}
1841
}
1942

2043
/**
2144
* @param {AST.Text | AST.ExpressionTag} chunk
45+
* @param {boolean} is_class
2246
* @returns {Set<string> | null}
2347
*/
24-
export function get_possible_values(chunk) {
48+
export function get_possible_values(chunk, is_class) {
2549
const values = new Set();
2650

2751
if (chunk.type === 'Text') {
2852
values.add(chunk.data);
2953
} else {
30-
gather_possible_values(chunk.expression, values);
54+
gather_possible_values(chunk.expression, is_class, values);
3155
}
3256

3357
if (values.has(UNKNOWN)) return null;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
warnings: [
5+
{
6+
code: 'css_unused_selector',
7+
message: 'Unused CSS selector ".unused"\nhttps://svelte.dev/e/css_unused_selector',
8+
start: {
9+
line: 15,
10+
column: 1,
11+
character: 325
12+
},
13+
end: {
14+
line: 15,
15+
column: 8,
16+
character: 332
17+
}
18+
}
19+
]
20+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
.used1.svelte-xyz { color: green; }
3+
.used2.svelte-xyz { color: green; }
4+
.used3.svelte-xyz { color: green; }
5+
.used4.svelte-xyz { color: green; }
6+
.used5.svelte-xyz { color: green; }
7+
.used6.svelte-xyz { color: green; }
8+
9+
/* (unused) .unused { color: red; }*/
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<p class={['used1']}></p>
2+
<p class={[{ used2: true }]}></p>
3+
<p class={{ used3: true }}></p>
4+
<p class={{ 'used4 used5': true }}></p>
5+
<p class={{ used6 }}></p>
6+
7+
<style>
8+
.used1 { color: green; }
9+
.used2 { color: green; }
10+
.used3 { color: green; }
11+
.used4 { color: green; }
12+
.used5 { color: green; }
13+
.used6 { color: green; }
14+
15+
.unused { color: red; }
16+
</style>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
.x.svelte-xyz { color: green; }
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<h1 class={[foo]}>hello world</h1>
2+
3+
<style>
4+
.x { color: green; }
5+
</style>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
.x.svelte-xyz { color: green; }
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<h1 class={{ foo: true, ...rest }}>hello world</h1>
2+
3+
<style>
4+
.x { color: green; }
5+
</style>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
.x.svelte-xyz { color: green; }

0 commit comments

Comments
 (0)