From bcb0eb1070a3e8b6fee2e46b917b0dc9b8939c37 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 16 Feb 2024 15:52:52 -0500 Subject: [PATCH] progress --- .../phases/2-analyze/css/css-prune.js | 81 ++++++++----------- .../compiler/phases/3-transform/css/index.js | 1 + .../global-with-child-combinator-2/_config.js | 9 +-- .../expected.css | 2 +- .../expected.html | 4 +- .../input.svelte | 4 +- .../global-with-child-combinator-3/_config.js | 5 -- .../expected.css | 3 - .../expected.html | 3 - .../input.svelte | 9 --- 10 files changed, 41 insertions(+), 80 deletions(-) delete mode 100644 packages/svelte/tests/css/samples/global-with-child-combinator-3/_config.js delete mode 100644 packages/svelte/tests/css/samples/global-with-child-combinator-3/expected.css delete mode 100644 packages/svelte/tests/css/samples/global-with-child-combinator-3/expected.html delete mode 100644 packages/svelte/tests/css/samples/global-with-child-combinator-3/input.svelte 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 8bf7155ce3..eb63c345e3 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 @@ -113,15 +113,11 @@ function truncate(node) { /** * @param {import('#compiler').Css.RelativeSelector[]} relative_selectors * @param {import('#compiler').Css.Rule} rule - * @param {import('#compiler').RegularElement | import('#compiler').SvelteElement | null} element + * @param {import('#compiler').RegularElement | import('#compiler').SvelteElement} element * @param {import('#compiler').Css.StyleSheet} stylesheet * @returns {boolean} */ function apply_selector(relative_selectors, rule, element, stylesheet) { - if (!element) { - return relative_selectors.every(({ metadata }) => metadata.is_global || metadata.is_host); - } - const parent_selectors = relative_selectors.slice(); const relative_selector = parent_selectors.pop(); @@ -139,69 +135,47 @@ function apply_selector(relative_selectors, rule, element, stylesheet) { } if (relative_selector.combinator) { - switch (relative_selector.combinator.name) { - case ' ': { - if ( - parent_selectors.every( - ({ metadata }) => metadata.is_global || metadata.is_host || metadata.is_root - ) - ) { - return true; - } + const name = relative_selector.combinator.name; - /** @type {import('#compiler').TemplateNode | null} */ - let parent = element; + switch (name) { + case ' ': + case '>': { + let parent = /** @type {import('#compiler').TemplateNode | null} */ (element.parent); + + let parent_found = false; + let parent_matched = false; let crossed_component_boundary = false; - let matched = false; - while ((parent = /** @type {import('#compiler').TemplateNode | null} */ (parent.parent))) { + while (parent) { if (parent.type === 'Component' || parent.type === 'SvelteComponent') { crossed_component_boundary = true; - - // ensure that any _other_ elements that use this selector end up getting scoped - // e.g. if you have `` and ``, we need to make sure that the - // `y` selector gets scoped, otherwise it might falsely apply to `` - parent_selectors[parent_selectors.length - 1].metadata.scoped = true; } if (parent.type === 'RegularElement' || parent.type === 'SvelteElement') { + parent_found = true; + if (apply_selector(parent_selectors, rule, parent, stylesheet)) { - if (crossed_component_boundary) { + if (name === ' ' || crossed_component_boundary) { mark(parent_selectors[parent_selectors.length - 1], parent); } else { - mark(parent_selectors[parent_selectors.length - 1], parent); - // relative_selector.metadata.selected.add(element); + parent_selectors[parent_selectors.length - 1].metadata.selected.add(parent); } - matched = true; + parent_matched = true; } - } - } - return matched; - } - - case '>': { - const has_global_parent = parent_selectors.every( - (relative_selector) => relative_selector.metadata.is_global - ); + if (name === '>') return parent_matched; + } - if ( - has_global_parent || - apply_selector(parent_selectors, rule, get_element_parent(element), stylesheet) - ) { - return true; + parent = /** @type {import('#compiler').TemplateNode | null} */ (parent.parent); } - return false; + return parent_matched || parent_selectors.every(is_global); } case '+': case '~': { - const siblings = get_possible_element_siblings( - element, - relative_selector.combinator.name === '+' - ); + const siblings = get_possible_element_siblings(element, name === '+'); let has_match = false; // NOTE: if we have :global(), we couldn't figure out what is selected within `:global` due to the @@ -259,6 +233,17 @@ function mark(relative_selector, element) { relative_selector.metadata.selected.add(element); } +/** @param {import('#compiler').Css.RelativeSelector} selector */ +function is_global(selector) { + if (selector.metadata.is_global || selector.metadata.is_host || selector.metadata.is_root) { + return true; + } + + // TODO :is(...), :where(...) + + return false; +} + const regex_backslash_and_following_character = /\\(.)/g; /** @@ -283,7 +268,9 @@ function relative_selector_might_apply_to_node(relative_selector, rule, element, } if (name === 'global' && relative_selector.selectors.length === 1) { - return false; + const args = /** @type {import('#compiler').Css.SelectorList} */ (selector.args); + const complex_selector = args.children[0]; + return apply_selector(complex_selector.children, rule, element, stylesheet); } if ((name === 'is' || name === 'where') && selector.args) { diff --git a/packages/svelte/src/compiler/phases/3-transform/css/index.js b/packages/svelte/src/compiler/phases/3-transform/css/index.js index 11254e7fb8..a330303f98 100644 --- a/packages/svelte/src/compiler/phases/3-transform/css/index.js +++ b/packages/svelte/src/compiler/phases/3-transform/css/index.js @@ -201,6 +201,7 @@ const visitors = { for (const relative_selector of node.children) { if (relative_selector.metadata.is_global) { remove_global_pseudo_class(relative_selector.selectors[0]); + continue; } if (relative_selector.metadata.scoped) { diff --git a/packages/svelte/tests/css/samples/global-with-child-combinator-2/_config.js b/packages/svelte/tests/css/samples/global-with-child-combinator-2/_config.js index cbffb98fdc..292c6c49ac 100644 --- a/packages/svelte/tests/css/samples/global-with-child-combinator-2/_config.js +++ b/packages/svelte/tests/css/samples/global-with-child-combinator-2/_config.js @@ -1,12 +1,5 @@ import { test } from '../../test'; export default test({ - warnings: [ - { - code: 'css-unused-selector', - message: 'Unused CSS selector "a:global(.foo) > div"', - start: { character: 91, column: 1, line: 8 }, - end: { character: 111, column: 21, line: 8 } - } - ] + warnings: [] }); diff --git a/packages/svelte/tests/css/samples/global-with-child-combinator-2/expected.css b/packages/svelte/tests/css/samples/global-with-child-combinator-2/expected.css index 8b0a7637ae..a793825578 100644 --- a/packages/svelte/tests/css/samples/global-with-child-combinator-2/expected.css +++ b/packages/svelte/tests/css/samples/global-with-child-combinator-2/expected.css @@ -1,3 +1,3 @@ - div > div.svelte-xyz { + a > b > div.svelte-xyz { color: red; } diff --git a/packages/svelte/tests/css/samples/global-with-child-combinator-2/expected.html b/packages/svelte/tests/css/samples/global-with-child-combinator-2/expected.html index 32ff99e34f..a956085c56 100644 --- a/packages/svelte/tests/css/samples/global-with-child-combinator-2/expected.html +++ b/packages/svelte/tests/css/samples/global-with-child-combinator-2/expected.html @@ -1,3 +1,3 @@
-
-
\ No newline at end of file +
+ diff --git a/packages/svelte/tests/css/samples/global-with-child-combinator-2/input.svelte b/packages/svelte/tests/css/samples/global-with-child-combinator-2/input.svelte index 8cd2238422..146f302633 100644 --- a/packages/svelte/tests/css/samples/global-with-child-combinator-2/input.svelte +++ b/packages/svelte/tests/css/samples/global-with-child-combinator-2/input.svelte @@ -1,9 +1,9 @@
-
+
\ No newline at end of file diff --git a/packages/svelte/tests/css/samples/global-with-child-combinator-3/_config.js b/packages/svelte/tests/css/samples/global-with-child-combinator-3/_config.js deleted file mode 100644 index 292c6c49ac..0000000000 --- a/packages/svelte/tests/css/samples/global-with-child-combinator-3/_config.js +++ /dev/null @@ -1,5 +0,0 @@ -import { test } from '../../test'; - -export default test({ - warnings: [] -}); diff --git a/packages/svelte/tests/css/samples/global-with-child-combinator-3/expected.css b/packages/svelte/tests/css/samples/global-with-child-combinator-3/expected.css deleted file mode 100644 index a793825578..0000000000 --- a/packages/svelte/tests/css/samples/global-with-child-combinator-3/expected.css +++ /dev/null @@ -1,3 +0,0 @@ - a > b > div.svelte-xyz { - color: red; - } diff --git a/packages/svelte/tests/css/samples/global-with-child-combinator-3/expected.html b/packages/svelte/tests/css/samples/global-with-child-combinator-3/expected.html deleted file mode 100644 index 32ff99e34f..0000000000 --- a/packages/svelte/tests/css/samples/global-with-child-combinator-3/expected.html +++ /dev/null @@ -1,3 +0,0 @@ -
-
-
\ No newline at end of file diff --git a/packages/svelte/tests/css/samples/global-with-child-combinator-3/input.svelte b/packages/svelte/tests/css/samples/global-with-child-combinator-3/input.svelte deleted file mode 100644 index 146f302633..0000000000 --- a/packages/svelte/tests/css/samples/global-with-child-combinator-3/input.svelte +++ /dev/null @@ -1,9 +0,0 @@ - - -
-
-
\ No newline at end of file