From c0363966d3010325b529cbbd3f7e03b2d3a46659 Mon Sep 17 00:00:00 2001 From: Nguyen Tran <88808276+ngtr6788@users.noreply.github.com> Date: Thu, 4 May 2023 09:48:05 -0400 Subject: [PATCH] fix: treat slots as if they don't exist when using CSS adjacent and general sibling combinators (#8422) Fixes #8284. The problem is that the element is treated as an actual element, and for this purpose, we have to treat them as if they don't exist. More specifically, we treat all slot fallback children nodes on the same level as the slot's non-slot siblings. --- src/compiler/compile/css/Selector.ts | 44 ++++++++++++++++++- src/compiler/compile/nodes/Slot.ts | 3 +- .../expected.css | 1 + .../input.svelte | 12 +++++ .../expected.css | 1 + .../input.svelte | 7 +++ .../expected.css | 1 + .../input.svelte | 18 ++++++++ .../expected.css | 1 + .../input.svelte | 12 +++++ .../expected.css | 1 + .../input.svelte | 22 ++++++++++ .../expected.css | 1 + .../input.svelte | 10 +++++ .../expected.css | 1 + .../input.svelte | 7 +++ .../expected.css | 1 + .../input.svelte | 18 ++++++++ .../expected.css | 1 + .../input.svelte | 10 +++++ .../expected.css | 1 + .../input.svelte | 11 +++++ .../_config.js | 3 ++ .../input.svelte | 20 +++++++++ .../warnings.json | 14 ++++++ .../_config.js | 3 ++ .../input.svelte | 18 ++++++++ .../warnings.json | 14 ++++++ 28 files changed, 254 insertions(+), 2 deletions(-) create mode 100644 test/css/samples/general-siblings-combinator-former-element-in-slot/expected.css create mode 100644 test/css/samples/general-siblings-combinator-former-element-in-slot/input.svelte create mode 100644 test/css/samples/general-siblings-combinator-nested-slots-flattened/expected.css create mode 100644 test/css/samples/general-siblings-combinator-nested-slots-flattened/input.svelte create mode 100644 test/css/samples/general-siblings-combinator-nested-slots/expected.css create mode 100644 test/css/samples/general-siblings-combinator-nested-slots/input.svelte create mode 100644 test/css/samples/general-siblings-combinator-selects-slot-fallback/expected.css create mode 100644 test/css/samples/general-siblings-combinator-selects-slot-fallback/input.svelte create mode 100644 test/css/samples/general-siblings-combinator-slots-between/expected.css create mode 100644 test/css/samples/general-siblings-combinator-slots-between/input.svelte create mode 100644 test/css/samples/siblings-combinator-former-element-in-slot/expected.css create mode 100644 test/css/samples/siblings-combinator-former-element-in-slot/input.svelte create mode 100644 test/css/samples/siblings-combinator-nested-slots-flattened/expected.css create mode 100644 test/css/samples/siblings-combinator-nested-slots-flattened/input.svelte create mode 100644 test/css/samples/siblings-combinator-nested-slots/expected.css create mode 100644 test/css/samples/siblings-combinator-nested-slots/input.svelte create mode 100644 test/css/samples/siblings-combinator-selects-slot-fallback/expected.css create mode 100644 test/css/samples/siblings-combinator-selects-slot-fallback/input.svelte create mode 100644 test/css/samples/siblings-combinator-slots-between/expected.css create mode 100644 test/css/samples/siblings-combinator-slots-between/input.svelte create mode 100644 test/validator/samples/general-siblings-combinator-in-custom-element-selects-slot-fallback/_config.js create mode 100644 test/validator/samples/general-siblings-combinator-in-custom-element-selects-slot-fallback/input.svelte create mode 100644 test/validator/samples/general-siblings-combinator-in-custom-element-selects-slot-fallback/warnings.json create mode 100644 test/validator/samples/siblings-combinator-in-custom-element-selects-slot-fallback/_config.js create mode 100644 test/validator/samples/siblings-combinator-in-custom-element-selects-slot-fallback/input.svelte create mode 100644 test/validator/samples/siblings-combinator-in-custom-element-selects-slot-fallback/warnings.json diff --git a/src/compiler/compile/css/Selector.ts b/src/compiler/compile/css/Selector.ts index c2ad450416..705e341601 100644 --- a/src/compiler/compile/css/Selector.ts +++ b/src/compiler/compile/css/Selector.ts @@ -470,10 +470,52 @@ function get_element_parent(node: Element): Element | null { return parent as Element | null; } +/** + * Finds the given node's previous sibling in the DOM + * + * Unless the component is a custom element (web component), which in this + * case, the element is actually real, the Svelte is just a + * placeholder and is not actually real. Any children nodes in + * are 'flattened' and considered as the same level as the 's siblings + * + * e.g. + *

Heading 1

+ * + *

Heading 2

+ *
+ * + * is considered to look like: + *

Heading 1

+ *

Heading 2

+ */ +function find_previous_sibling(node: INode): INode { + if (node.component.compile_options.customElement) { + return node.prev; + } + + let current_node: INode = node; + do { + if (current_node.type === 'Slot') { + const slot_children = current_node.children; + if (slot_children.length > 0) { + current_node = slot_children.slice(-1)[0]; // go to its last child first + continue; + } + } + + while (!current_node.prev && current_node.parent && current_node.parent.type === 'Slot') { + current_node = current_node.parent; + } + current_node = current_node.prev; + } while (current_node && current_node.type === 'Slot'); + + return current_node; +} + function get_possible_element_siblings(node: INode, adjacent_only: boolean): Map { const result: Map = new Map(); let prev: INode = node; - while (prev = prev.prev) { + while (prev = find_previous_sibling(prev)) { if (prev.type === 'Element') { if (!prev.attributes.find(attr => attr.type === 'Attribute' && attr.name.toLowerCase() === 'slot')) { result.set(prev, NodeExist.Definitely); diff --git a/src/compiler/compile/nodes/Slot.ts b/src/compiler/compile/nodes/Slot.ts index 9a0b1ea815..8dfcc09c03 100644 --- a/src/compiler/compile/nodes/Slot.ts +++ b/src/compiler/compile/nodes/Slot.ts @@ -7,7 +7,8 @@ import { TemplateNode } from '../../interfaces'; import compiler_errors from '../compiler_errors'; export default class Slot extends Element { - type: 'Element'; + // @ts-ignore Slot elements have the 'Slot' type, but TypeScript doesn't allow us to have 'Slot' when it extends Element + type: 'Slot'; name: string; children: INode[]; slot_name: string; diff --git a/test/css/samples/general-siblings-combinator-former-element-in-slot/expected.css b/test/css/samples/general-siblings-combinator-former-element-in-slot/expected.css new file mode 100644 index 0000000000..f365e3dc24 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-former-element-in-slot/expected.css @@ -0,0 +1 @@ +h1.svelte-xyz~p.svelte-xyz{color:red} \ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-former-element-in-slot/input.svelte b/test/css/samples/general-siblings-combinator-former-element-in-slot/input.svelte new file mode 100644 index 0000000000..66a8a09796 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-former-element-in-slot/input.svelte @@ -0,0 +1,12 @@ + +

Heading 1

+
+Span 1 +Span 2 +

Paragraph 2

+ + diff --git a/test/css/samples/general-siblings-combinator-nested-slots-flattened/expected.css b/test/css/samples/general-siblings-combinator-nested-slots-flattened/expected.css new file mode 100644 index 0000000000..f365e3dc24 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-nested-slots-flattened/expected.css @@ -0,0 +1 @@ +h1.svelte-xyz~p.svelte-xyz{color:red} \ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-nested-slots-flattened/input.svelte b/test/css/samples/general-siblings-combinator-nested-slots-flattened/input.svelte new file mode 100644 index 0000000000..0d521b8385 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-nested-slots-flattened/input.svelte @@ -0,0 +1,7 @@ +

Heading 1

Span 1Span 2

Paragraph 2

+ + diff --git a/test/css/samples/general-siblings-combinator-nested-slots/expected.css b/test/css/samples/general-siblings-combinator-nested-slots/expected.css new file mode 100644 index 0000000000..f365e3dc24 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-nested-slots/expected.css @@ -0,0 +1 @@ +h1.svelte-xyz~p.svelte-xyz{color:red} \ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-nested-slots/input.svelte b/test/css/samples/general-siblings-combinator-nested-slots/input.svelte new file mode 100644 index 0000000000..d820705782 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-nested-slots/input.svelte @@ -0,0 +1,18 @@ + + +

Heading 1

+
+
+Span 1 +Span 2 + + +

Paragraph 2

+
+
+ + diff --git a/test/css/samples/general-siblings-combinator-selects-slot-fallback/expected.css b/test/css/samples/general-siblings-combinator-selects-slot-fallback/expected.css new file mode 100644 index 0000000000..f365e3dc24 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-selects-slot-fallback/expected.css @@ -0,0 +1 @@ +h1.svelte-xyz~p.svelte-xyz{color:red} \ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-selects-slot-fallback/input.svelte b/test/css/samples/general-siblings-combinator-selects-slot-fallback/input.svelte new file mode 100644 index 0000000000..61d829d257 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-selects-slot-fallback/input.svelte @@ -0,0 +1,12 @@ +

Heading 1

+Span 1 +Span 2 + +

Paragraph 2

+
+ + diff --git a/test/css/samples/general-siblings-combinator-slots-between/expected.css b/test/css/samples/general-siblings-combinator-slots-between/expected.css new file mode 100644 index 0000000000..b6edba4ef7 --- /dev/null +++ b/test/css/samples/general-siblings-combinator-slots-between/expected.css @@ -0,0 +1 @@ +h1.svelte-xyz~span.svelte-xyz{color:green}h1.svelte-xyz~p.svelte-xyz{color:red}span.svelte-xyz~p.svelte-xyz{color:blue} \ No newline at end of file diff --git a/test/css/samples/general-siblings-combinator-slots-between/input.svelte b/test/css/samples/general-siblings-combinator-slots-between/input.svelte new file mode 100644 index 0000000000..8b80b4de3e --- /dev/null +++ b/test/css/samples/general-siblings-combinator-slots-between/input.svelte @@ -0,0 +1,22 @@ +

Heading 1

+ + Span 1 + + + Span 2 + +

Paragraph 2

+ + diff --git a/test/css/samples/siblings-combinator-former-element-in-slot/expected.css b/test/css/samples/siblings-combinator-former-element-in-slot/expected.css new file mode 100644 index 0000000000..d523f1d533 --- /dev/null +++ b/test/css/samples/siblings-combinator-former-element-in-slot/expected.css @@ -0,0 +1 @@ +h1.svelte-xyz+span.svelte-xyz{color:red} \ No newline at end of file diff --git a/test/css/samples/siblings-combinator-former-element-in-slot/input.svelte b/test/css/samples/siblings-combinator-former-element-in-slot/input.svelte new file mode 100644 index 0000000000..8cbf9bd709 --- /dev/null +++ b/test/css/samples/siblings-combinator-former-element-in-slot/input.svelte @@ -0,0 +1,10 @@ + +

test

+
+Hello + + diff --git a/test/css/samples/siblings-combinator-nested-slots-flattened/expected.css b/test/css/samples/siblings-combinator-nested-slots-flattened/expected.css new file mode 100644 index 0000000000..d523f1d533 --- /dev/null +++ b/test/css/samples/siblings-combinator-nested-slots-flattened/expected.css @@ -0,0 +1 @@ +h1.svelte-xyz+span.svelte-xyz{color:red} \ No newline at end of file diff --git a/test/css/samples/siblings-combinator-nested-slots-flattened/input.svelte b/test/css/samples/siblings-combinator-nested-slots-flattened/input.svelte new file mode 100644 index 0000000000..475aa85426 --- /dev/null +++ b/test/css/samples/siblings-combinator-nested-slots-flattened/input.svelte @@ -0,0 +1,7 @@ +

test

Hello + + diff --git a/test/css/samples/siblings-combinator-nested-slots/expected.css b/test/css/samples/siblings-combinator-nested-slots/expected.css new file mode 100644 index 0000000000..d523f1d533 --- /dev/null +++ b/test/css/samples/siblings-combinator-nested-slots/expected.css @@ -0,0 +1 @@ +h1.svelte-xyz+span.svelte-xyz{color:red} \ No newline at end of file diff --git a/test/css/samples/siblings-combinator-nested-slots/input.svelte b/test/css/samples/siblings-combinator-nested-slots/input.svelte new file mode 100644 index 0000000000..cb8cbbbe08 --- /dev/null +++ b/test/css/samples/siblings-combinator-nested-slots/input.svelte @@ -0,0 +1,18 @@ + + + +

test

+
+
+
+ + + Hello + + + + diff --git a/test/css/samples/siblings-combinator-selects-slot-fallback/expected.css b/test/css/samples/siblings-combinator-selects-slot-fallback/expected.css new file mode 100644 index 0000000000..d523f1d533 --- /dev/null +++ b/test/css/samples/siblings-combinator-selects-slot-fallback/expected.css @@ -0,0 +1 @@ +h1.svelte-xyz+span.svelte-xyz{color:red} \ No newline at end of file diff --git a/test/css/samples/siblings-combinator-selects-slot-fallback/input.svelte b/test/css/samples/siblings-combinator-selects-slot-fallback/input.svelte new file mode 100644 index 0000000000..7fa02c8305 --- /dev/null +++ b/test/css/samples/siblings-combinator-selects-slot-fallback/input.svelte @@ -0,0 +1,10 @@ +

test

+ + Hello + + + diff --git a/test/css/samples/siblings-combinator-slots-between/expected.css b/test/css/samples/siblings-combinator-slots-between/expected.css new file mode 100644 index 0000000000..d523f1d533 --- /dev/null +++ b/test/css/samples/siblings-combinator-slots-between/expected.css @@ -0,0 +1 @@ +h1.svelte-xyz+span.svelte-xyz{color:red} \ No newline at end of file diff --git a/test/css/samples/siblings-combinator-slots-between/input.svelte b/test/css/samples/siblings-combinator-slots-between/input.svelte new file mode 100644 index 0000000000..36219534fe --- /dev/null +++ b/test/css/samples/siblings-combinator-slots-between/input.svelte @@ -0,0 +1,11 @@ +

test

+ + + +Hello + + diff --git a/test/validator/samples/general-siblings-combinator-in-custom-element-selects-slot-fallback/_config.js b/test/validator/samples/general-siblings-combinator-in-custom-element-selects-slot-fallback/_config.js new file mode 100644 index 0000000000..6fc797bfd8 --- /dev/null +++ b/test/validator/samples/general-siblings-combinator-in-custom-element-selects-slot-fallback/_config.js @@ -0,0 +1,3 @@ +export default { + customElement: true +}; diff --git a/test/validator/samples/general-siblings-combinator-in-custom-element-selects-slot-fallback/input.svelte b/test/validator/samples/general-siblings-combinator-in-custom-element-selects-slot-fallback/input.svelte new file mode 100644 index 0000000000..ffaeb2c097 --- /dev/null +++ b/test/validator/samples/general-siblings-combinator-in-custom-element-selects-slot-fallback/input.svelte @@ -0,0 +1,20 @@ + + +

Heading 1

+Span 1 +Span 2 + +

Paragraph 2

+
+ + diff --git a/test/validator/samples/general-siblings-combinator-in-custom-element-selects-slot-fallback/warnings.json b/test/validator/samples/general-siblings-combinator-in-custom-element-selects-slot-fallback/warnings.json new file mode 100644 index 0000000000..0336660caf --- /dev/null +++ b/test/validator/samples/general-siblings-combinator-in-custom-element-selects-slot-fallback/warnings.json @@ -0,0 +1,14 @@ +[ + { + "code": "css-unused-selector", + "message": "Unused CSS selector \"h1 ~ p\"", + "start": { + "column": 1, + "line": 12 + }, + "end": { + "column": 7, + "line": 12 + } + } +] \ No newline at end of file diff --git a/test/validator/samples/siblings-combinator-in-custom-element-selects-slot-fallback/_config.js b/test/validator/samples/siblings-combinator-in-custom-element-selects-slot-fallback/_config.js new file mode 100644 index 0000000000..6fc797bfd8 --- /dev/null +++ b/test/validator/samples/siblings-combinator-in-custom-element-selects-slot-fallback/_config.js @@ -0,0 +1,3 @@ +export default { + customElement: true +}; diff --git a/test/validator/samples/siblings-combinator-in-custom-element-selects-slot-fallback/input.svelte b/test/validator/samples/siblings-combinator-in-custom-element-selects-slot-fallback/input.svelte new file mode 100644 index 0000000000..1d98415321 --- /dev/null +++ b/test/validator/samples/siblings-combinator-in-custom-element-selects-slot-fallback/input.svelte @@ -0,0 +1,18 @@ + + +

test

+ + Hello + + + diff --git a/test/validator/samples/siblings-combinator-in-custom-element-selects-slot-fallback/warnings.json b/test/validator/samples/siblings-combinator-in-custom-element-selects-slot-fallback/warnings.json new file mode 100644 index 0000000000..3ef66ebf60 --- /dev/null +++ b/test/validator/samples/siblings-combinator-in-custom-element-selects-slot-fallback/warnings.json @@ -0,0 +1,14 @@ +[ + { + "code": "css-unused-selector", + "end": { + "column": 11, + "line": 10 + }, + "message": "Unused CSS selector \"h1 + span\"", + "start": { + "column": 2, + "line": 10 + } + } +] \ No newline at end of file