Skip to content

Commit a08f063

Browse files
dummdidummOcean-OS
andauthored
fix: more accurately detect $derived migration use cases (#13740)
- detect store mutations and not use `$derived` in that case, fixes #13723 - better detect `let x` that can be folded into `$derived`, fixes #13727 --------- Co-authored-by: ComputerGuy <[email protected]>
1 parent 8a06d05 commit a08f063

File tree

6 files changed

+43
-7
lines changed

6 files changed

+43
-7
lines changed

.changeset/nasty-geese-turn.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: more accurately detect `$derived` migration opportunities

packages/svelte/src/compiler/migrate/index.js

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -569,14 +569,22 @@ const instance_script = {
569569
const declaration = reference.path.find((el) => el.type === 'VariableDeclaration');
570570
const assignment = reference.path.find((el) => el.type === 'AssignmentExpression');
571571
const update = reference.path.find((el) => el.type === 'UpdateExpression');
572-
const labeled = reference.path.find(
573-
(el) => el.type === 'LabeledStatement' && el.label.name === '$'
572+
const labeled = /** @type {LabeledStatement | undefined} */ (
573+
reference.path.find((el) => el.type === 'LabeledStatement' && el.label.name === '$')
574574
);
575575

576-
if (assignment && labeled) {
576+
if (
577+
assignment &&
578+
labeled &&
579+
// ensure that $: foo = bar * 2 is not counted as a reassignment of bar
580+
(labeled.body.type !== 'ExpressionStatement' ||
581+
labeled.body.expression !== assignment ||
582+
(assignment.left.type === 'Identifier' &&
583+
assignment.left.name === binding.node.name))
584+
) {
577585
if (assignment_in_labeled) return false;
578586
assignment_in_labeled = /** @type {AssignmentExpression} */ (assignment);
579-
labeled_statement = /** @type {LabeledStatement} */ (labeled);
587+
labeled_statement = labeled;
580588
}
581589

582590
return (
@@ -750,7 +758,12 @@ const instance_script = {
750758
);
751759
const bindings = ids.map((id) => state.scope.get(id.name));
752760
const reassigned_bindings = bindings.filter((b) => b?.reassigned);
753-
if (reassigned_bindings.length === 0 && !bindings.some((b) => b?.kind === 'store_sub')) {
761+
762+
if (
763+
reassigned_bindings.length === 0 &&
764+
!bindings.some((b) => b?.kind === 'store_sub') &&
765+
node.body.expression.left.type !== 'MemberExpression'
766+
) {
754767
let { start, end } = /** @type {{ start: number, end: number }} */ (
755768
node.body.expression.right
756769
);

packages/svelte/tests/migrate/samples/derivations/input.svelte

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66
// no semicolon at the end
77
$: time_8 = count * 8
88
$: ({ time_16 } = { time_16: count * 16 })
9+
// preceeding let that doesn't do anything
10+
let time_32;
11+
$: time_32 = count * doubled;
12+
let very_high;
13+
$: very_high = time_32 * count;
914
</script>
1015

1116
{count} / {doubled} / {quadrupled} / {time_8} / {time_16}

packages/svelte/tests/migrate/samples/derivations/output.svelte

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66
// no semicolon at the end
77
let time_8 = $derived(count * 8)
88
let { time_16 } = $derived({ time_16: count * 16 })
9+
// preceeding let that doesn't do anything
10+
let time_32 = $derived(count * doubled);
11+
12+
let very_high = $derived(time_32 * count);
13+
914
</script>
1015

1116
{count} / {doubled} / {quadrupled} / {time_8} / {time_16}

packages/svelte/tests/migrate/samples/effects/input.svelte

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,7 @@
1010
console.log('bar');
1111
}
1212
$: $count = 1;
13+
$: foo.x = count;
1314
</script>
15+
16+
<button onclick={() => count++}>increment</button>

packages/svelte/tests/migrate/samples/effects/output.svelte

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<script>
22
import { run } from 'svelte/legacy';
33
4-
let count = 0;
4+
let count = $state(0);
55
run(() => {
66
console.log(count);
77
});
@@ -18,4 +18,9 @@
1818
run(() => {
1919
$count = 1;
2020
});
21-
</script>
21+
run(() => {
22+
foo.x = count;
23+
});
24+
</script>
25+
26+
<button onclick={() => count++}>increment</button>

0 commit comments

Comments
 (0)