fix: keep a reactive assignment with no dependencies when `migrate` cannot turn it into a declaration (#18817)

`migrate()` dropped a reactive assignment that has no dependencies and
put nothing in its place:

```svelte
$: count = 7;          →  (gone, `{count}` now undeclared)
$: obj.x = 1;          →  (gone)
```

A binding the statement declares now always gets its `let`, and the
statement is only removed once every target has one; otherwise it
becomes `run()`:

```svelte
let count = $state(7);
run(() => { obj.x = 1; });
```
main
Nic Polumeyv 2 days ago committed by GitHub
parent 8ef693e94e
commit 5b44f26bc2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: keep a reactive assignment with no dependencies when `migrate` cannot turn it into a declaration

@ -989,8 +989,11 @@ const instance_script = {
return; return;
} }
let declared = 0;
for (const binding of bindings) { for (const binding of bindings) {
if (binding.reassigned && (ids.includes(binding.node) || expression_ids.length === 0)) { // a binding this statement declares needs its `let` whether or not it is reassigned
if (ids.includes(binding.node) || (binding.reassigned && expression_ids.length === 0)) {
declared++;
check_rune_binding('state'); check_rune_binding('state');
const init = const init =
binding.kind === 'state' binding.kind === 'state'
@ -1006,7 +1009,13 @@ const instance_script = {
} }
} }
if (expression_ids.length === 0 && bindings.every((b) => b.kind !== 'store_sub')) { // the statement goes only once every target has a declaration standing in for it
if (
expression_ids.length === 0 &&
bindings.length > 0 &&
declared === bindings.length &&
bindings.every((b) => b.kind !== 'store_sub')
) {
state.str.remove(/** @type {number} */ (node.start), /** @type {number} */ (node.end)); state.str.remove(/** @type {number} */ (node.start), /** @type {number} */ (node.end));
return; return;
} }

@ -0,0 +1,8 @@
<script>
$: count = 7;
$: other = 8;
let obj = {};
$: obj.x = 1;
</script>
<p>{count} {other} {obj.x}</p>

@ -0,0 +1,14 @@
<script>
import { run } from 'svelte/legacy';
let count = $state(7);
let other = $state(8);
let obj = $state({});
run(() => {
obj.x = 1;
});
</script>
<p>{count} {other} {obj.x}</p>
Loading…
Cancel
Save