From 5675067e2ba392bb4a54cbfd086a92cb1c9db8d1 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Thu, 3 Oct 2024 14:12:08 +0200 Subject: [PATCH] fix: allow combinator at start of nested CSS selector (#13440) * fix: allow combinator at start of nested CSS selector Solved by moving the combinator positioning validation into the analysis phase Fixes #13433 * highlight the combinator, not the start of the combinator * fix --------- Co-authored-by: Rich Harris --- .changeset/young-ducks-punch.md | 5 +++++ .../src/compiler/phases/1-parse/read/style.js | 6 +----- .../phases/2-analyze/css/css-analyze.js | 11 ++++++++++ .../samples/nested-css-combinator/_config.js | 20 +++++++++++++++++++ .../nested-css-combinator/expected.css | 10 ++++++++++ .../nested-css-combinator/input.svelte | 15 ++++++++++++++ .../errors.json | 2 +- .../errors.json | 2 +- .../errors.json | 2 +- 9 files changed, 65 insertions(+), 8 deletions(-) create mode 100644 .changeset/young-ducks-punch.md create mode 100644 packages/svelte/tests/css/samples/nested-css-combinator/_config.js create mode 100644 packages/svelte/tests/css/samples/nested-css-combinator/expected.css create mode 100644 packages/svelte/tests/css/samples/nested-css-combinator/input.svelte diff --git a/.changeset/young-ducks-punch.md b/.changeset/young-ducks-punch.md new file mode 100644 index 0000000000..8db05e8099 --- /dev/null +++ b/.changeset/young-ducks-punch.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: allow combinator at start of nested CSS selector diff --git a/packages/svelte/src/compiler/phases/1-parse/read/style.js b/packages/svelte/src/compiler/phases/1-parse/read/style.js index f6acd577c5..aa835a1d96 100644 --- a/packages/svelte/src/compiler/phases/1-parse/read/style.js +++ b/packages/svelte/src/compiler/phases/1-parse/read/style.js @@ -351,11 +351,7 @@ function read_selector(parser, inside_pseudo_class = false) { const combinator = read_combinator(parser); if (combinator) { - if (relative_selector.selectors.length === 0) { - if (!inside_pseudo_class) { - e.css_selector_invalid(start); - } - } else { + if (relative_selector.selectors.length > 0) { relative_selector.end = index; children.push(relative_selector); } diff --git a/packages/svelte/src/compiler/phases/2-analyze/css/css-analyze.js b/packages/svelte/src/compiler/phases/2-analyze/css/css-analyze.js index 88ba86cc82..ec36e1ce64 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/css/css-analyze.js +++ b/packages/svelte/src/compiler/phases/2-analyze/css/css-analyze.js @@ -129,6 +129,17 @@ const css_visitors = { } }, RelativeSelector(node, context) { + const parent = /** @type {Css.ComplexSelector} */ (context.path.at(-1)); + + if ( + node.combinator != null && + !context.state.rule?.metadata.parent_rule && + parent.children[0] === node && + context.path.at(-3)?.type !== 'PseudoClassSelector' + ) { + e.css_selector_invalid(node.combinator); + } + node.metadata.is_global = node.selectors.length >= 1 && is_global(node); if (node.selectors.length === 1) { diff --git a/packages/svelte/tests/css/samples/nested-css-combinator/_config.js b/packages/svelte/tests/css/samples/nested-css-combinator/_config.js new file mode 100644 index 0000000000..e239029aa9 --- /dev/null +++ b/packages/svelte/tests/css/samples/nested-css-combinator/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + warnings: [ + { + code: 'css_unused_selector', + end: { + character: 109, + column: 11, + line: 11 + }, + message: 'Unused CSS selector "~ .unused"', + start: { + character: 100, + column: 2, + line: 11 + } + } + ] +}); diff --git a/packages/svelte/tests/css/samples/nested-css-combinator/expected.css b/packages/svelte/tests/css/samples/nested-css-combinator/expected.css new file mode 100644 index 0000000000..d934073e2b --- /dev/null +++ b/packages/svelte/tests/css/samples/nested-css-combinator/expected.css @@ -0,0 +1,10 @@ + + .foo.svelte-xyz { + > .bar:where(.svelte-xyz) { + color: red; + } + + /* (unused) ~ .unused { + color: red; + }*/ + } diff --git a/packages/svelte/tests/css/samples/nested-css-combinator/input.svelte b/packages/svelte/tests/css/samples/nested-css-combinator/input.svelte new file mode 100644 index 0000000000..843d788d0b --- /dev/null +++ b/packages/svelte/tests/css/samples/nested-css-combinator/input.svelte @@ -0,0 +1,15 @@ +
+
+
+ + diff --git a/packages/svelte/tests/validator/samples/css-invalid-combinator-selector-1/errors.json b/packages/svelte/tests/validator/samples/css-invalid-combinator-selector-1/errors.json index 421c747518..cdd6d0f703 100644 --- a/packages/svelte/tests/validator/samples/css-invalid-combinator-selector-1/errors.json +++ b/packages/svelte/tests/validator/samples/css-invalid-combinator-selector-1/errors.json @@ -8,7 +8,7 @@ }, "end": { "line": 10, - "column": 1 + "column": 2 } } ] diff --git a/packages/svelte/tests/validator/samples/css-invalid-combinator-selector-2/errors.json b/packages/svelte/tests/validator/samples/css-invalid-combinator-selector-2/errors.json index 0c1d24ee3b..18aa7ef807 100644 --- a/packages/svelte/tests/validator/samples/css-invalid-combinator-selector-2/errors.json +++ b/packages/svelte/tests/validator/samples/css-invalid-combinator-selector-2/errors.json @@ -8,7 +8,7 @@ }, "end": { "line": 8, - "column": 1 + "column": 2 } } ] diff --git a/packages/svelte/tests/validator/samples/css-invalid-combinator-selector-3/errors.json b/packages/svelte/tests/validator/samples/css-invalid-combinator-selector-3/errors.json index 5f5552b498..81f4a348b7 100644 --- a/packages/svelte/tests/validator/samples/css-invalid-combinator-selector-3/errors.json +++ b/packages/svelte/tests/validator/samples/css-invalid-combinator-selector-3/errors.json @@ -8,7 +8,7 @@ }, "end": { "line": 5, - "column": 2 + "column": 3 } } ]