mirror of https://github.com/sveltejs/svelte
breaking: scope `:has(...)` selectors (#13567)
The main part of #13395 This implements scoping for selectors inside `:has(...)`. The approach is to first descend into the contents of a `:has(...)` selector, then in case of a match, try to match the rest of the selector ignoring the `:has(...)` part. In other words, `.x:has(y)` is essentially treated as `x y` with `y` being matched first, then walking up the selector chain taking into account combinators. This is a breaking change because people could've used `:has(.unknown)` with `.unknown` not appearing in the HTML, and so they need to do `:has(:global(.unknown))` insteadpull/13606/head
parent
a6c97b378f
commit
eb6488cd90
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
breaking: scope `:has(...)` selectors
|
@ -0,0 +1,90 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
warnings: [
|
||||
{
|
||||
code: 'css_unused_selector',
|
||||
message: 'Unused CSS selector ".unused:has(y)"',
|
||||
start: {
|
||||
character: 269,
|
||||
column: 1,
|
||||
line: 27
|
||||
},
|
||||
end: {
|
||||
character: 283,
|
||||
column: 15,
|
||||
line: 27
|
||||
}
|
||||
},
|
||||
{
|
||||
code: 'css_unused_selector',
|
||||
message: 'Unused CSS selector ".unused:has(:global(y))"',
|
||||
start: {
|
||||
character: 304,
|
||||
column: 1,
|
||||
line: 30
|
||||
},
|
||||
end: {
|
||||
character: 327,
|
||||
column: 24,
|
||||
line: 30
|
||||
}
|
||||
},
|
||||
{
|
||||
code: 'css_unused_selector',
|
||||
message: 'Unused CSS selector "x:has(.unused)"',
|
||||
start: {
|
||||
character: 348,
|
||||
column: 1,
|
||||
line: 33
|
||||
},
|
||||
end: {
|
||||
character: 362,
|
||||
column: 15,
|
||||
line: 33
|
||||
}
|
||||
},
|
||||
{
|
||||
code: 'css_unused_selector',
|
||||
message: 'Unused CSS selector "x:has(y):has(.unused)"',
|
||||
start: {
|
||||
character: 517,
|
||||
column: 1,
|
||||
line: 46
|
||||
},
|
||||
end: {
|
||||
character: 538,
|
||||
column: 22,
|
||||
line: 46
|
||||
}
|
||||
},
|
||||
{
|
||||
code: 'css_unused_selector',
|
||||
message: 'Unused CSS selector ".unused"',
|
||||
start: {
|
||||
character: 743,
|
||||
column: 2,
|
||||
line: 65
|
||||
},
|
||||
end: {
|
||||
character: 750,
|
||||
column: 9,
|
||||
line: 65
|
||||
}
|
||||
},
|
||||
{
|
||||
code: 'css_unused_selector',
|
||||
message: 'Unused CSS selector ".unused x:has(y)"',
|
||||
start: {
|
||||
character: 897,
|
||||
column: 1,
|
||||
line: 81
|
||||
},
|
||||
end: {
|
||||
character: 913,
|
||||
column: 17,
|
||||
line: 81
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
@ -0,0 +1,77 @@
|
||||
|
||||
x.svelte-xyz:has(y:where(.svelte-xyz)) {
|
||||
color: green;
|
||||
}
|
||||
x.svelte-xyz:has(z:where(.svelte-xyz)) {
|
||||
color: green;
|
||||
}
|
||||
x.svelte-xyz:has(y) {
|
||||
color: green;
|
||||
}
|
||||
x.svelte-xyz:has(z) {
|
||||
color: green;
|
||||
}
|
||||
x.svelte-xyz:has(.foo) {
|
||||
color: green;
|
||||
}
|
||||
.foo:has(y.svelte-xyz) {
|
||||
color: green;
|
||||
}
|
||||
|
||||
/* (unused) .unused:has(y) {
|
||||
color: red;
|
||||
}*/
|
||||
/* (unused) .unused:has(:global(y)) {
|
||||
color: red;
|
||||
}*/
|
||||
/* (unused) x:has(.unused) {
|
||||
color: red;
|
||||
}*/
|
||||
.foo:has(.unused.svelte-xyz) {
|
||||
color: red;
|
||||
}
|
||||
|
||||
x.svelte-xyz:has(y:where(.svelte-xyz) /* (unused) .unused*/) {
|
||||
color: green;
|
||||
}
|
||||
x.svelte-xyz:has(y:where(.svelte-xyz), .foo) {
|
||||
color: green;
|
||||
}
|
||||
/* (unused) x:has(y):has(.unused) {
|
||||
color: red;
|
||||
}*/
|
||||
x.svelte-xyz:has(y:where(.svelte-xyz)):has(.foo) {
|
||||
color: green;
|
||||
}
|
||||
|
||||
x.svelte-xyz:has(y:where(.svelte-xyz)) z:where(.svelte-xyz) {
|
||||
color: green;
|
||||
}
|
||||
x.svelte-xyz:has(y:where(.svelte-xyz)) {
|
||||
z:where(.svelte-xyz) {
|
||||
color: green;
|
||||
}
|
||||
}
|
||||
x.svelte-xyz:has(y:where(.svelte-xyz)) .foo {
|
||||
color: green;
|
||||
}
|
||||
/* (empty) x:has(y) {
|
||||
.unused {
|
||||
color: red;
|
||||
}
|
||||
}*/
|
||||
|
||||
x.svelte-xyz y:where(.svelte-xyz):has(z:where(.svelte-xyz)) {
|
||||
color: green;
|
||||
}
|
||||
x.svelte-xyz {
|
||||
y:where(.svelte-xyz):has(z:where(.svelte-xyz)) {
|
||||
color: green;
|
||||
}
|
||||
}
|
||||
.foo x.svelte-xyz:has(y:where(.svelte-xyz)) {
|
||||
color: green;
|
||||
}
|
||||
/* (unused) .unused x:has(y) {
|
||||
color: red;
|
||||
}*/
|
@ -0,0 +1,84 @@
|
||||
<x>
|
||||
<y>
|
||||
<z></z>
|
||||
</y>
|
||||
</x>
|
||||
|
||||
<style>
|
||||
x:has(y) {
|
||||
color: green;
|
||||
}
|
||||
x:has(z) {
|
||||
color: green;
|
||||
}
|
||||
x:has(:global(y)) {
|
||||
color: green;
|
||||
}
|
||||
x:has(:global(z)) {
|
||||
color: green;
|
||||
}
|
||||
x:has(:global(.foo)) {
|
||||
color: green;
|
||||
}
|
||||
:global(.foo):has(y) {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.unused:has(y) {
|
||||
color: red;
|
||||
}
|
||||
.unused:has(:global(y)) {
|
||||
color: red;
|
||||
}
|
||||
x:has(.unused) {
|
||||
color: red;
|
||||
}
|
||||
:global(.foo):has(.unused) {
|
||||
color: red;
|
||||
}
|
||||
|
||||
x:has(y, .unused) {
|
||||
color: green;
|
||||
}
|
||||
x:has(y, :global(.foo)) {
|
||||
color: green;
|
||||
}
|
||||
x:has(y):has(.unused) {
|
||||
color: red;
|
||||
}
|
||||
x:has(y):has(:global(.foo)) {
|
||||
color: green;
|
||||
}
|
||||
|
||||
x:has(y) z {
|
||||
color: green;
|
||||
}
|
||||
x:has(y) {
|
||||
z {
|
||||
color: green;
|
||||
}
|
||||
}
|
||||
x:has(y) :global(.foo) {
|
||||
color: green;
|
||||
}
|
||||
x:has(y) {
|
||||
.unused {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
||||
x y:has(z) {
|
||||
color: green;
|
||||
}
|
||||
x {
|
||||
y:has(z) {
|
||||
color: green;
|
||||
}
|
||||
}
|
||||
:global(.foo) x:has(y) {
|
||||
color: green;
|
||||
}
|
||||
.unused x:has(y) {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
Loading…
Reference in new issue