Skip to content

feat: allow objects/arrays for class attribute #14714

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Dec 24, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
implement CSS pruning for array/object expressions
  • Loading branch information
dummdidumm committed Dec 18, 2024
commit 7840a2ce86b7972d753b22493a97df19972d3373
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,7 @@ function attribute_matches(node, name, expected_value, operator, case_insensitiv
/** @type {string[]} */
let prev_values = [];
for (const chunk of chunks) {
const current_possible_values = get_possible_values(chunk);
const current_possible_values = get_possible_values(chunk, name === 'class');

// impossible to find out all combinations
if (!current_possible_values) return true;
Expand Down
34 changes: 29 additions & 5 deletions packages/svelte/src/compiler/phases/2-analyze/css/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,54 @@ const UNKNOWN = {};

/**
* @param {Node} node
* @param {boolean} is_class
* @param {Set<any>} set
*/
function gather_possible_values(node, set) {
function gather_possible_values(node, is_class, set) {
if (node.type === 'Literal') {
set.add(String(node.value));
} else if (node.type === 'ConditionalExpression') {
gather_possible_values(node.consequent, set);
gather_possible_values(node.alternate, set);
gather_possible_values(node.consequent, is_class, set);
gather_possible_values(node.alternate, is_class, set);
} else if (is_class && node.type === 'ArrayExpression') {
for (const entry of node.elements) {
if (entry) {
gather_possible_values(entry, is_class, set);
} else {
set.add(UNKNOWN);
}
}
} else if (is_class && node.type === 'ObjectExpression') {
for (const property of node.properties) {
if (
property.type === 'Property' &&
!property.computed &&
(property.key.type === 'Identifier' || property.key.type === 'Literal')
) {
set.add(
property.key.type === 'Identifier' ? property.key.name : String(property.key.value)
);
} else {
set.add(UNKNOWN);
}
}
} else {
set.add(UNKNOWN);
}
}

/**
* @param {AST.Text | AST.ExpressionTag} chunk
* @param {boolean} is_class
* @returns {Set<string> | null}
*/
export function get_possible_values(chunk) {
export function get_possible_values(chunk, is_class) {
const values = new Set();

if (chunk.type === 'Text') {
values.add(chunk.data);
} else {
gather_possible_values(chunk.expression, values);
gather_possible_values(chunk.expression, is_class, values);
}

if (values.has(UNKNOWN)) return null;
Expand Down
20 changes: 20 additions & 0 deletions packages/svelte/tests/css/samples/clsx-can-prune/_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { test } from '../../test';

export default test({
warnings: [
{
code: 'css_unused_selector',
message: 'Unused CSS selector ".unused"\nhttps://svelte.dev/e/css_unused_selector',
start: {
line: 15,
column: 1,
character: 325
},
end: {
line: 15,
column: 8,
character: 332
}
}
]
});
9 changes: 9 additions & 0 deletions packages/svelte/tests/css/samples/clsx-can-prune/expected.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

.used1.svelte-xyz { color: green; }
.used2.svelte-xyz { color: green; }
.used3.svelte-xyz { color: green; }
.used4.svelte-xyz { color: green; }
.used5.svelte-xyz { color: green; }
.used6.svelte-xyz { color: green; }

/* (unused) .unused { color: red; }*/
16 changes: 16 additions & 0 deletions packages/svelte/tests/css/samples/clsx-can-prune/input.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<p class={['used1']}></p>
<p class={[{ used2: true }]}></p>
<p class={{ used3: true }}></p>
<p class={{ 'used4 used5': true }}></p>
<p class={{ used6 }}></p>

<style>
.used1 { color: green; }
.used2 { color: green; }
.used3 { color: green; }
.used4 { color: green; }
.used5 { color: green; }
.used6 { color: green; }

.unused { color: red; }
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

.x.svelte-xyz { color: green; }
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<h1 class={[foo]}>hello world</h1>

<style>
.x { color: green; }
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

.x.svelte-xyz { color: green; }
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<h1 class={{ foo: true, ...rest }}>hello world</h1>

<style>
.x { color: green; }
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

.x.svelte-xyz { color: green; }
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<h1 class={{ [foo]: true }}>hello world</h1>

<style>
.x { color: green; }
</style>
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy