fix: wrap `:id`, `:where``:not` and `:has` with `:global` during migration (#13850)

Closes #13765
pull/14064/head
Paolo Ricciuti 5 days ago committed by GitHub
parent 217ef2062d
commit e47ee22628
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: wrap `:id`, `:where``:not` and `:has` with `:global` during migration

@ -34,6 +34,61 @@ class MigrationError extends Error {
}
}
/**
*
* @param {State} state
*/
function migrate_css(state) {
if (!state.analysis.css.ast?.start) return;
let code = state.str
.snip(state.analysis.css.ast.start, /** @type {number} */ (state.analysis.css.ast?.end))
.toString();
let starting = 0;
// since we already blank css we can't work directly on `state.str` so we will create a copy that we can update
const str = new MagicString(code);
while (code) {
if (
code.startsWith(':has') ||
code.startsWith(':not') ||
code.startsWith(':is') ||
code.startsWith(':where')
) {
let start = code.indexOf('(') + 1;
let is_global = false;
const global_str = ':global';
const next_global = code.indexOf(global_str);
const str_between = code.substring(start, next_global);
if (!str_between.trim()) {
is_global = true;
start += global_str.length;
}
let parenthesis = 1;
let end = start;
let char = code[end];
// find the closing parenthesis
while (parenthesis !== 0 && char) {
if (char === '(') parenthesis++;
if (char === ')') parenthesis--;
end++;
char = code[end];
}
if (start && end) {
if (!is_global) {
str.prependLeft(starting + start, ':global(');
str.appendRight(starting + end - 1, ')');
}
starting += end - 1;
code = code.substring(end - 1);
continue;
}
}
starting++;
code = code.substring(1);
}
state.str.update(state.analysis.css.ast?.start, state.analysis.css.ast?.end, str.toString());
}
/**
* Does a best-effort migration of Svelte code towards using runes, event attributes and render tags.
* May throw an error if the code is too complex to migrate automatically.
@ -320,7 +375,10 @@ export function migrate(source, { filename, use_ts } = {}) {
if (!parsed.instance && need_script) {
str.appendRight(insertion_point, '\n</script>\n\n');
}
return { code: str.toString() };
migrate_css(state);
return {
code: str.toString()
};
} catch (e) {
if (!(e instanceof MigrationError)) {
// eslint-disable-next-line no-console

@ -0,0 +1,58 @@
<script>
function is(){}
function where(){}
function not(){}
function has(){}
// looks like css but it's not in style tag
const x = {
div:is(42),
span:where(42),
form:not(42),
input:has(42),
}
</script>
what if i'm talking about `:has()` in my blog?
```css
:has(.is_cool)
```
<style lang="postcss">
div:has(span){}
div > :not(span){}
div > :is(span){}
div > :where(span){}
div:has(:is(span)){}
div > :not(:is(span)){}
div > :is(:is(span)){}
div > :where(:is(span)){}
div:has(.class:is(span)){}
div > :not(.class:is(span)){}
div > :is(.class:is(span)){}
div > :where(.class:is(span)){}
div :has(.class:is(span:where(:focus))){}
div :not(.class:is(span:where(:focus-within))){}
div :is(.class:is(span:is(:hover))){}
div :where(.class:is(span:has(* > *))){}
div :is(.class:is(span:is(:hover)), .x){}
div :has( :global(.class:is(span:where(:focus)))){}
div :not(:global(.class:is(span:where(:focus-within)))){}
div :is(:global(.class:is(span:is(:hover)))){}
div :where(:global(.class:is(span:has(* > *)))){}
div :is(:global(.class:is(span:is(:hover)), .x)){}
div{
p:has(&){
}
:not(span > *){
:where(form){}
}
}
</style>

@ -0,0 +1,58 @@
<script>
function is(){}
function where(){}
function not(){}
function has(){}
// looks like css but it's not in style tag
const x = {
div:is(42),
span:where(42),
form:not(42),
input:has(42),
}
</script>
what if i'm talking about `:has()` in my blog?
```css
:has(.is_cool)
```
<style lang="postcss">
div:has(:global(span)){}
div > :not(:global(span)){}
div > :is(:global(span)){}
div > :where(:global(span)){}
div:has(:global(:is(span))){}
div > :not(:global(:is(span))){}
div > :is(:global(:is(span))){}
div > :where(:global(:is(span))){}
div:has(:global(.class:is(span))){}
div > :not(:global(.class:is(span))){}
div > :is(:global(.class:is(span))){}
div > :where(:global(.class:is(span))){}
div :has(:global(.class:is(span:where(:focus)))){}
div :not(:global(.class:is(span:where(:focus-within)))){}
div :is(:global(.class:is(span:is(:hover)))){}
div :where(:global(.class:is(span:has(* > *)))){}
div :is(:global(.class:is(span:is(:hover)), .x)){}
div :has( :global(.class:is(span:where(:focus)))){}
div :not(:global(.class:is(span:where(:focus-within)))){}
div :is(:global(.class:is(span:is(:hover)))){}
div :where(:global(.class:is(span:has(* > *)))){}
div :is(:global(.class:is(span:is(:hover)), .x)){}
div{
p:has(:global(&)){
}
:not(:global(span > *)){
:where(:global(form)){}
}
}
</style>
Loading…
Cancel
Save