From 659198a95c0f547061600487c45131b00368bd2a Mon Sep 17 00:00:00 2001 From: 7nik Date: Thu, 19 Jun 2025 13:19:51 +0300 Subject: [PATCH] fix: address css class matching regression (#16204) * fix: address css class matching regression * address feedback --------- Co-authored-by: 7nik --- .changeset/big-carpets-stare.md | 5 +++++ .../phases/2-analyze/css/css-prune.js | 21 +++++++++++++------ .../css/samples/class-directive/_config.js | 10 ++++----- .../css/samples/class-directive/expected.css | 6 ++++-- .../css/samples/class-directive/input.svelte | 8 ++++--- 5 files changed, 34 insertions(+), 16 deletions(-) create mode 100644 .changeset/big-carpets-stare.md diff --git a/.changeset/big-carpets-stare.md b/.changeset/big-carpets-stare.md new file mode 100644 index 0000000000..eabe29bb88 --- /dev/null +++ b/.changeset/big-carpets-stare.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: address css class matching regression 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 b9a5688a87..79e8fbb02c 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 @@ -628,10 +628,11 @@ function attribute_matches(node, name, expected_value, operator, case_insensitiv if (attribute.type === 'SpreadAttribute') return true; if (attribute.type === 'BindDirective' && attribute.name === name) return true; + const name_lower = name.toLowerCase(); // match attributes against the corresponding directive but bail out on exact matching - if (attribute.type === 'StyleDirective' && name.toLowerCase() === 'style') return true; - if (attribute.type === 'ClassDirective' && name.toLowerCase() === 'class') { - if (operator == '~=') { + if (attribute.type === 'StyleDirective' && name_lower === 'style') return true; + if (attribute.type === 'ClassDirective' && name_lower === 'class') { + if (operator === '~=') { if (attribute.name === expected_value) return true; } else { return true; @@ -639,13 +640,21 @@ function attribute_matches(node, name, expected_value, operator, case_insensitiv } if (attribute.type !== 'Attribute') continue; - if (attribute.name.toLowerCase() !== name.toLowerCase()) continue; + if (attribute.name.toLowerCase() !== name_lower) continue; if (attribute.value === true) return operator === null; if (expected_value === null) return true; if (is_text_attribute(attribute)) { - return test_attribute(operator, expected_value, case_insensitive, attribute.value[0].data); + const matches = test_attribute( + operator, + expected_value, + case_insensitive, + attribute.value[0].data + ); + // continue if we still may match against a class/style directive + if (!matches && (name_lower === 'class' || name_lower === 'style')) continue; + return matches; } const chunks = get_attribute_chunks(attribute.value); @@ -654,7 +663,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, name === 'class'); + const current_possible_values = get_possible_values(chunk, name_lower === 'class'); // impossible to find out all combinations if (!current_possible_values) return true; diff --git a/packages/svelte/tests/css/samples/class-directive/_config.js b/packages/svelte/tests/css/samples/class-directive/_config.js index 28e9fbc815..abeb8b6329 100644 --- a/packages/svelte/tests/css/samples/class-directive/_config.js +++ b/packages/svelte/tests/css/samples/class-directive/_config.js @@ -4,16 +4,16 @@ export default test({ warnings: [ { code: 'css_unused_selector', - message: 'Unused CSS selector ".third"\nhttps://svelte.dev/e/css_unused_selector', + message: 'Unused CSS selector ".forth"\nhttps://svelte.dev/e/css_unused_selector', start: { - line: 6, + line: 8, column: 2, - character: 115 + character: 190 }, end: { - line: 6, + line: 8, column: 8, - character: 121 + character: 196 } } ] diff --git a/packages/svelte/tests/css/samples/class-directive/expected.css b/packages/svelte/tests/css/samples/class-directive/expected.css index 1d7d3d4dee..b3a74baee5 100644 --- a/packages/svelte/tests/css/samples/class-directive/expected.css +++ b/packages/svelte/tests/css/samples/class-directive/expected.css @@ -1,3 +1,5 @@ - .first.svelte-xyz { color: green } + + .zero.first.svelte-xyz { color: green } .second.svelte-xyz { color: green } - /* (unused) .third { color: red }*/ + .third.svelte-xyz { color: green } + /* (unused) .forth { color: red }*/ diff --git a/packages/svelte/tests/css/samples/class-directive/input.svelte b/packages/svelte/tests/css/samples/class-directive/input.svelte index cf00335964..70075f89d4 100644 --- a/packages/svelte/tests/css/samples/class-directive/input.svelte +++ b/packages/svelte/tests/css/samples/class-directive/input.svelte @@ -1,7 +1,9 @@ -
+
+
\ No newline at end of file