diff --git a/.changeset/beige-mirrors-listen.md b/.changeset/beige-mirrors-listen.md new file mode 100644 index 000000000000..896268149061 --- /dev/null +++ b/.changeset/beige-mirrors-listen.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: correctly scope CSS selectors with descendant combinators 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 dc08c8115102..5cde3bc3c6fe 100644 --- a/packages/svelte/src/compiler/phases/1-parse/read/style.js +++ b/packages/svelte/src/compiler/phases/1-parse/read/style.js @@ -114,7 +114,8 @@ function read_rule(parser) { start, end: parser.index, metadata: { - parent_rule: null + parent_rule: null, + has_local_selectors: false } }; } 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 7da86538b771..c299612fd140 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 @@ -11,10 +11,6 @@ import { error } from '../../../errors.js'; */ /** @typedef {NODE_PROBABLY_EXISTS | NODE_DEFINITELY_EXISTS} NodeExistsValue */ -const NO_MATCH = 'NO_MATCH'; -const POSSIBLE_MATCH = 'POSSIBLE_MATCH'; -const UNKNOWN_SELECTOR = 'UNKNOWN_SELECTOR'; - const NODE_PROBABLY_EXISTS = 0; const NODE_DEFINITELY_EXISTS = 1; @@ -66,6 +62,7 @@ export function prune(stylesheet, element) { const visitors = { ComplexSelector(node, context) { const selectors = truncate(node); + const inner = selectors[selectors.length - 1]; if (node.metadata.rule?.metadata.parent_rule) { const has_explicit_nesting_selector = selectors.some((selector) => @@ -90,6 +87,7 @@ const visitors = { context.state.stylesheet ) ) { + mark(inner, context.state.element); node.metadata.used = true; } @@ -114,124 +112,96 @@ 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(); - const relative_selector = relative_selectors.pop(); if (!relative_selector) return false; - const applies = relative_selector_might_apply_to_node( + const possible_match = relative_selector_might_apply_to_node( relative_selector, rule, element, stylesheet ); - if (applies === NO_MATCH) { + if (!possible_match) { return false; } - if (applies === UNKNOWN_SELECTOR) { - return mark(relative_selector, element); - } - if (relative_selector.combinator) { - if ( - relative_selector.combinator.type === 'Combinator' && - relative_selector.combinator.name === ' ' - ) { - // TODO this is incorrect, it will match `.this-matches .this-does-not .this-does {...}` - for (const ancestor_selector of relative_selectors) { - if (ancestor_selector.metadata.is_global) { - continue; - } + const name = relative_selector.combinator.name; - if (ancestor_selector.metadata.is_host) { - return mark(relative_selector, element); - } + switch (name) { + case ' ': + case '>': { + let parent = /** @type {import('#compiler').TemplateNode | null} */ (element.parent); - /** @type {import('#compiler').RegularElement | import('#compiler').SvelteElement | null} */ - let parent = element; - let matched = false; - while ((parent = get_element_parent(parent))) { - if ( - relative_selector_might_apply_to_node(ancestor_selector, rule, parent, stylesheet) !== - NO_MATCH - ) { - mark(ancestor_selector, parent); - matched = true; + let parent_matched = false; + let crossed_component_boundary = false; + + while (parent) { + if (parent.type === 'Component' || parent.type === 'SvelteComponent') { + crossed_component_boundary = true; } - } - if (matched) { - return mark(relative_selector, element); - } - } + if (parent.type === 'RegularElement' || parent.type === 'SvelteElement') { + if (apply_selector(parent_selectors, rule, parent, stylesheet)) { + // TODO the `name === ' '` causes false positives, but removing it causes false negatives... + if (name === ' ' || crossed_component_boundary) { + mark(parent_selectors[parent_selectors.length - 1], parent); + } - if (relative_selectors.every((relative_selector) => relative_selector.metadata.is_global)) { - return mark(relative_selector, element); - } + parent_matched = true; + } - return false; - } + if (name === '>') return parent_matched; + } - if (relative_selector.combinator.name === '>') { - const has_global_parent = relative_selectors.every( - (relative_selector) => relative_selector.metadata.is_global - ); + parent = /** @type {import('#compiler').TemplateNode | null} */ (parent.parent); + } - if ( - has_global_parent || - apply_selector(relative_selectors, rule, get_element_parent(element), stylesheet) - ) { - return mark(relative_selector, element); + return parent_matched || parent_selectors.every((selector) => is_global(selector, rule)); } - return false; - } - - if (relative_selector.combinator.name === '+' || relative_selector.combinator.name === '~') { - const siblings = get_possible_element_siblings( - element, - relative_selector.combinator.name === '+' - ); + case '+': + case '~': { + 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 - // css-tree limitation that does not parse the inner selector of :global - // so unless we are sure there will be no sibling to match, we will consider it as matched - const has_global = relative_selectors.some( - (relative_selector) => relative_selector.metadata.is_global - ); + let sibling_matched = false; - if (has_global) { - if (siblings.size === 0 && get_element_parent(element) !== null) { - return false; + for (const possible_sibling of siblings.keys()) { + if (apply_selector(parent_selectors, rule, possible_sibling, stylesheet)) { + mark(relative_selector, element); + sibling_matched = true; + } } - return mark(relative_selector, element); - } - for (const possible_sibling of siblings.keys()) { - if (apply_selector(relative_selectors.slice(), rule, possible_sibling, stylesheet)) { - mark(relative_selector, element); - has_match = true; - } + return ( + sibling_matched || + (get_element_parent(element) === null && + parent_selectors.every((selector) => is_global(selector, rule))) + ); } - return has_match; + default: + // TODO other combinators + return true; } + } - // TODO other combinators - return mark(relative_selector, element); + // if this is the left-most non-global selector, mark it — we want + // `x y z {...}` to become `x.blah y z.blah {...}` + const parent = parent_selectors[parent_selectors.length - 1]; + if (!parent || is_global(parent, rule)) { + mark(relative_selector, element); } - return mark(relative_selector, element); + return true; } /** @@ -243,25 +213,64 @@ function apply_selector(relative_selectors, rule, element, stylesheet) { function mark(relative_selector, element) { relative_selector.metadata.scoped = true; element.metadata.scoped = true; +} + +/** + * Returns `true` if the relative selector is global, meaning + * it's a `:global(...)` or `:host` or `:root` selector, or + * is an `:is(...)` or `:where(...)` selector that contains + * a global selector + * @param {import('#compiler').Css.RelativeSelector} selector + * @param {import('#compiler').Css.Rule} rule + */ +function is_global(selector, rule) { + if (selector.metadata.is_global || selector.metadata.is_host || selector.metadata.is_root) { + return true; + } + + for (const s of selector.selectors) { + /** @type {import('#compiler').Css.SelectorList | null} */ + let selector_list = null; + let owner = rule; + + if (s.type === 'PseudoClassSelector') { + if ((s.name === 'is' || s.name === 'where') && s.args) { + selector_list = s.args; + } + } + + if (s.type === 'NestingSelector') { + owner = /** @type {import('#compiler').Css.Rule} */ (rule.metadata.parent_rule); + selector_list = owner.prelude; + } + + const has_global_selectors = selector_list?.children.some((complex_selector) => { + return complex_selector.children.every((relative_selector) => + is_global(relative_selector, owner) + ); + }); + + if (!has_global_selectors) { + return false; + } + } + return true; } const regex_backslash_and_following_character = /\\(.)/g; /** + * Ensure that `element` satisfies each simple selector in `relative_selector` + * * @param {import('#compiler').Css.RelativeSelector} relative_selector * @param {import('#compiler').Css.Rule} rule - * @param {import('#compiler').RegularElement | import('#compiler').SvelteElement} node + * @param {import('#compiler').RegularElement | import('#compiler').SvelteElement} element * @param {import('#compiler').Css.StyleSheet} stylesheet - * @returns {NO_MATCH | POSSIBLE_MATCH | UNKNOWN_SELECTOR} + * @returns {boolean} */ -function relative_selector_might_apply_to_node(relative_selector, rule, node, stylesheet) { - if (relative_selector.metadata.is_host || relative_selector.metadata.is_root) return NO_MATCH; - - let i = relative_selector.selectors.length; - while (i--) { - const selector = relative_selector.selectors[i]; - +function relative_selector_might_apply_to_node(relative_selector, rule, element, stylesheet) { + for (const selector of relative_selector.selectors) { if (selector.type === 'Percentage' || selector.type === 'Nth') continue; const name = selector.name.replace(regex_backslash_and_following_character, '$1'); @@ -269,25 +278,27 @@ function relative_selector_might_apply_to_node(relative_selector, rule, node, st switch (selector.type) { case 'PseudoClassSelector': { if (name === 'host' || name === 'root') { - return NO_MATCH; + return false; } if (name === 'global' && relative_selector.selectors.length === 1) { - return NO_MATCH; + 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) { let matched = false; for (const complex_selector of selector.args.children) { - if (apply_selector(truncate(complex_selector), rule, node, stylesheet)) { + if (apply_selector(truncate(complex_selector), rule, element, stylesheet)) { complex_selector.metadata.used = true; matched = true; } } if (!matched) { - return NO_MATCH; + return false; } } @@ -299,38 +310,38 @@ function relative_selector_might_apply_to_node(relative_selector, rule, node, st } case 'AttributeSelector': { - const whitelisted = whitelist_attribute_selector.get(node.name.toLowerCase()); + const whitelisted = whitelist_attribute_selector.get(element.name.toLowerCase()); if ( !whitelisted?.includes(selector.name.toLowerCase()) && !attribute_matches( - node, + element, selector.name, selector.value && unquote(selector.value), selector.matcher, selector.flags?.includes('i') ?? false ) ) { - return NO_MATCH; + return false; } break; } case 'ClassSelector': { if ( - !attribute_matches(node, 'class', name, '~=', false) && - !node.attributes.some( + !attribute_matches(element, 'class', name, '~=', false) && + !element.attributes.some( (attribute) => attribute.type === 'ClassDirective' && attribute.name === name ) ) { - return NO_MATCH; + return false; } break; } case 'IdSelector': { - if (!attribute_matches(node, 'id', name, '=', false)) { - return NO_MATCH; + if (!attribute_matches(element, 'id', name, '=', false)) { + return false; } break; @@ -338,11 +349,11 @@ function relative_selector_might_apply_to_node(relative_selector, rule, node, st case 'TypeSelector': { if ( - node.name.toLowerCase() !== name.toLowerCase() && + element.name.toLowerCase() !== name.toLowerCase() && name !== '*' && - node.type !== 'SvelteElement' + element.type !== 'SvelteElement' ) { - return NO_MATCH; + return false; } break; @@ -354,25 +365,23 @@ function relative_selector_might_apply_to_node(relative_selector, rule, node, st const parent = /** @type {import('#compiler').Css.Rule} */ (rule.metadata.parent_rule); for (const complex_selector of parent.prelude.children) { - if (apply_selector(truncate(complex_selector), parent, node, stylesheet)) { + if (apply_selector(truncate(complex_selector), parent, element, stylesheet)) { complex_selector.metadata.used = true; matched = true; } } if (!matched) { - return NO_MATCH; + return false; } break; } - - default: - return UNKNOWN_SELECTOR; } } - return POSSIBLE_MATCH; + // possible match + return true; } /** 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 f873c5d3a93a..ebb65a768c1a 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/child-combinator/expected.css b/packages/svelte/tests/css/samples/child-combinator/expected.css index 3143c231be9f..4d7a2096cae8 100644 --- a/packages/svelte/tests/css/samples/child-combinator/expected.css +++ b/packages/svelte/tests/css/samples/child-combinator/expected.css @@ -2,6 +2,6 @@ background-color: red; } - main.svelte-xyz div:where(.svelte-xyz) > button:where(.svelte-xyz) { + main.svelte-xyz div > button:where(.svelte-xyz) { background-color: blue; } diff --git a/packages/svelte/tests/css/samples/descendant-selector-unmatched/expected.css b/packages/svelte/tests/css/samples/descendant-selector-unmatched/expected.css new file mode 100644 index 000000000000..52c8c72109e8 --- /dev/null +++ b/packages/svelte/tests/css/samples/descendant-selector-unmatched/expected.css @@ -0,0 +1,4 @@ + + /* (unused) x y z { + color: red; + }*/ diff --git a/packages/svelte/tests/css/samples/descendant-selector-unmatched/input.svelte b/packages/svelte/tests/css/samples/descendant-selector-unmatched/input.svelte new file mode 100644 index 000000000000..c31ae21efcad --- /dev/null +++ b/packages/svelte/tests/css/samples/descendant-selector-unmatched/input.svelte @@ -0,0 +1,9 @@ + + + + + diff --git a/packages/svelte/tests/css/samples/dynamic-element-tag/expected.css b/packages/svelte/tests/css/samples/dynamic-element-tag/expected.css index 87d8325df18a..80f7facd5a81 100644 --- a/packages/svelte/tests/css/samples/dynamic-element-tag/expected.css +++ b/packages/svelte/tests/css/samples/dynamic-element-tag/expected.css @@ -7,10 +7,10 @@ h2.svelte-xyz span:where(.svelte-xyz) { color: red; } - h2.svelte-xyz > span:where(.svelte-xyz) > b:where(.svelte-xyz) { + h2.svelte-xyz > span > b:where(.svelte-xyz) { color: red; } - h2.svelte-xyz span b:where(.svelte-xyz) { + h2.svelte-xyz span:where(.svelte-xyz) b:where(.svelte-xyz) { color: red; } h2.svelte-xyz b:where(.svelte-xyz) { diff --git a/packages/svelte/tests/css/samples/general-siblings-combinator-star/expected.css b/packages/svelte/tests/css/samples/general-siblings-combinator-star/expected.css index 530213faac1c..7ec653d1beb9 100644 --- a/packages/svelte/tests/css/samples/general-siblings-combinator-star/expected.css +++ b/packages/svelte/tests/css/samples/general-siblings-combinator-star/expected.css @@ -1,4 +1,4 @@ - .match.svelte-xyz > :where(.svelte-xyz) ~ :where(.svelte-xyz) { + .match.svelte-xyz > * ~ :where(.svelte-xyz) { margin-left: 4px; } /* (unused) .not-match > * ~ * { diff --git a/packages/svelte/tests/css/samples/general-siblings-combinator-star/expected.html b/packages/svelte/tests/css/samples/general-siblings-combinator-star/expected.html index 1cfae6e6f7ff..c97af84a65e5 100644 --- a/packages/svelte/tests/css/samples/general-siblings-combinator-star/expected.html +++ b/packages/svelte/tests/css/samples/general-siblings-combinator-star/expected.html @@ -2,6 +2,6 @@
+
-
-
\ No newline at end of file + diff --git a/packages/svelte/tests/css/samples/general-siblings-combinator/expected.css b/packages/svelte/tests/css/samples/general-siblings-combinator/expected.css index ff9874b9e45e..ffdd14f5c44b 100644 --- a/packages/svelte/tests/css/samples/general-siblings-combinator/expected.css +++ b/packages/svelte/tests/css/samples/general-siblings-combinator/expected.css @@ -1,6 +1,6 @@ div.svelte-xyz ~ article:where(.svelte-xyz) { color: green; } span.svelte-xyz ~ b:where(.svelte-xyz) { color: green; } - div.svelte-xyz span:where(.svelte-xyz) ~ b:where(.svelte-xyz) { color: green; } + div.svelte-xyz span ~ b:where(.svelte-xyz) { color: green; } .a.svelte-xyz ~ article:where(.svelte-xyz) { color: green; } div.svelte-xyz ~ .b:where(.svelte-xyz) { color: green; } .a.svelte-xyz ~ .c:where(.svelte-xyz) { color: green; } 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 cbffb98fdc8b..292c6c49ac9d 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 8b0a7637aea0..a7938255785f 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 32ff99e34f39..a956085c56eb 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 8cd223842213..146f302633cd 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 292c6c49ac9d..000000000000 --- 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 a7938255785f..000000000000 --- 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 32ff99e34f39..000000000000 --- 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 146f302633cd..000000000000 --- 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 diff --git a/packages/svelte/tests/css/samples/omit-scoping-attribute-whitespace-multiple/expected.css b/packages/svelte/tests/css/samples/omit-scoping-attribute-whitespace-multiple/expected.css index 772529431050..9fc102a2d0e7 100644 --- a/packages/svelte/tests/css/samples/omit-scoping-attribute-whitespace-multiple/expected.css +++ b/packages/svelte/tests/css/samples/omit-scoping-attribute-whitespace-multiple/expected.css @@ -1,3 +1,3 @@ - div.svelte-xyz section p:where(.svelte-xyz) { + div.svelte-xyz section:where(.svelte-xyz) p:where(.svelte-xyz) { color: red; } diff --git a/packages/svelte/tests/css/samples/omit-scoping-attribute-whitespace-multiple/expected.html b/packages/svelte/tests/css/samples/omit-scoping-attribute-whitespace-multiple/expected.html index 53c470b0c197..d6ee64cfb46c 100644 --- a/packages/svelte/tests/css/samples/omit-scoping-attribute-whitespace-multiple/expected.html +++ b/packages/svelte/tests/css/samples/omit-scoping-attribute-whitespace-multiple/expected.html @@ -1 +1 @@ -

this is styled

\ No newline at end of file +

this is styled

diff --git a/packages/svelte/tests/css/samples/preserve-specificity/expected.css b/packages/svelte/tests/css/samples/preserve-specificity/expected.css index 897ce85faaa9..4e179e066f24 100644 --- a/packages/svelte/tests/css/samples/preserve-specificity/expected.css +++ b/packages/svelte/tests/css/samples/preserve-specificity/expected.css @@ -1,4 +1,4 @@ - a.svelte-xyz b c span:where(.svelte-xyz) { + a.svelte-xyz b:where(.svelte-xyz) c:where(.svelte-xyz) span:where(.svelte-xyz) { color: red; font-size: 2em; font-family: 'Comic Sans MS'; diff --git a/packages/svelte/tests/css/samples/preserve-specificity/expected.html b/packages/svelte/tests/css/samples/preserve-specificity/expected.html index 171d90d362ba..3ad77eebb664 100644 --- a/packages/svelte/tests/css/samples/preserve-specificity/expected.html +++ b/packages/svelte/tests/css/samples/preserve-specificity/expected.html @@ -1,12 +1,12 @@ - - + + Big red Comic Sans - + Big red Comic Sans - \ No newline at end of file + diff --git a/packages/svelte/tests/css/samples/siblings-combinator-star/expected.css b/packages/svelte/tests/css/samples/siblings-combinator-star/expected.css index 4986c4f715c2..1de61b6842d0 100644 --- a/packages/svelte/tests/css/samples/siblings-combinator-star/expected.css +++ b/packages/svelte/tests/css/samples/siblings-combinator-star/expected.css @@ -1,4 +1,4 @@ - .match.svelte-xyz > :where(.svelte-xyz) + :where(.svelte-xyz) { + .match.svelte-xyz > * + :where(.svelte-xyz) { margin-left: 4px; } /* (unused) .not-match > * + * { diff --git a/packages/svelte/tests/css/samples/siblings-combinator-star/expected.html b/packages/svelte/tests/css/samples/siblings-combinator-star/expected.html index 1cfae6e6f7ff..c97af84a65e5 100644 --- a/packages/svelte/tests/css/samples/siblings-combinator-star/expected.html +++ b/packages/svelte/tests/css/samples/siblings-combinator-star/expected.html @@ -2,6 +2,6 @@
+
-
-
\ No newline at end of file + diff --git a/packages/svelte/tests/css/samples/siblings-combinator/expected.css b/packages/svelte/tests/css/samples/siblings-combinator/expected.css index 97a7a4689793..5622a66a303f 100644 --- a/packages/svelte/tests/css/samples/siblings-combinator/expected.css +++ b/packages/svelte/tests/css/samples/siblings-combinator/expected.css @@ -16,7 +16,7 @@ span.svelte-xyz + b:where(.svelte-xyz) { color: green; } - div.svelte-xyz span:where(.svelte-xyz) + b:where(.svelte-xyz) { + div.svelte-xyz span + b:where(.svelte-xyz) { color: green; } .a.svelte-xyz + article:where(.svelte-xyz) { diff --git a/playgrounds/sandbox/run.js b/playgrounds/sandbox/run.js index 1dca76e867bb..9163ef0cb701 100644 --- a/playgrounds/sandbox/run.js +++ b/playgrounds/sandbox/run.js @@ -30,6 +30,7 @@ const svelte_modules = glob('**/*.svelte', { cwd: `${cwd}/input` }); const js_modules = glob('**/*.js', { cwd: `${cwd}/input` }); for (const generate of ['client', 'server']) { + console.error(`\n--- generating ${generate} ---\n`); for (const file of svelte_modules) { const input = `${cwd}/input/${file}`; const source = fs.readFileSync(input, 'utf-8');