diff --git a/.changeset/weak-doors-yell.md b/.changeset/weak-doors-yell.md
new file mode 100644
index 000000000000..1b21783435a4
--- /dev/null
+++ b/.changeset/weak-doors-yell.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: don't transform reassigned state in labeled statement in `$derived`
diff --git a/packages/svelte/src/compiler/migrate/index.js b/packages/svelte/src/compiler/migrate/index.js
index 9d79d88b2397..523389a25aef 100644
--- a/packages/svelte/src/compiler/migrate/index.js
+++ b/packages/svelte/src/compiler/migrate/index.js
@@ -944,54 +944,53 @@ const instance_script = {
node.body.type === 'ExpressionStatement' &&
node.body.expression.type === 'AssignmentExpression'
) {
- const ids = extract_identifiers(node.body.expression.left);
- const [, expression_ids] = extract_all_identifiers_from_expression(
- node.body.expression.right
- );
- const bindings = ids.map((id) => state.scope.get(id.name));
- const reassigned_bindings = bindings.filter((b) => b?.reassigned);
+ const { left, right } = node.body.expression;
- if (
- node.body.expression.right.type !== 'Literal' &&
- !bindings.some((b) => b?.kind === 'store_sub') &&
- node.body.expression.left.type !== 'MemberExpression'
- ) {
- let { start, end } = /** @type {{ start: number, end: number }} */ (
- node.body.expression.right
- );
+ const ids = extract_identifiers(left);
+ const [, expression_ids] = extract_all_identifiers_from_expression(right);
+ const bindings = ids.map((id) => /** @type {Binding} */ (state.scope.get(id.name)));
- check_rune_binding('derived');
+ if (bindings.every((b) => b.kind === 'legacy_reactive')) {
+ if (
+ right.type !== 'Literal' &&
+ bindings.every((b) => b.kind !== 'store_sub') &&
+ left.type !== 'MemberExpression'
+ ) {
+ let { start, end } = /** @type {{ start: number, end: number }} */ (right);
- // $derived
- state.str.update(
- /** @type {number} */ (node.start),
- /** @type {number} */ (node.body.expression.start),
- 'let '
- );
+ check_rune_binding('derived');
- if (node.body.expression.right.type === 'SequenceExpression') {
- while (state.str.original[start] !== '(') start -= 1;
- while (state.str.original[end - 1] !== ')') end += 1;
- }
+ // $derived
+ state.str.update(
+ /** @type {number} */ (node.start),
+ /** @type {number} */ (node.body.expression.start),
+ 'let '
+ );
+
+ if (right.type === 'SequenceExpression') {
+ while (state.str.original[start] !== '(') start -= 1;
+ while (state.str.original[end - 1] !== ')') end += 1;
+ }
+
+ state.str.prependRight(start, `$derived(`);
- state.str.prependRight(start, `$derived(`);
+ // in a case like `$: ({ a } = b())`, there's already a trailing parenthesis.
+ // otherwise, we need to add one
+ if (state.str.original[/** @type {number} */ (node.body.start)] !== '(') {
+ state.str.appendLeft(end, `)`);
+ }
- // in a case like `$: ({ a } = b())`, there's already a trailing parenthesis.
- // otherwise, we need to add one
- if (state.str.original[/** @type {number} */ (node.body.start)] !== '(') {
- state.str.appendLeft(end, `)`);
+ return;
}
- return;
- } else {
- for (const binding of reassigned_bindings) {
- if (binding && (ids.includes(binding.node) || expression_ids.length === 0)) {
+ for (const binding of bindings) {
+ if (binding.reassigned && (ids.includes(binding.node) || expression_ids.length === 0)) {
check_rune_binding('state');
const init =
binding.kind === 'state'
? ' = $state()'
: expression_ids.length === 0
- ? ` = $state(${state.str.original.substring(/** @type {number} */ (node.body.expression.right.start), node.body.expression.right.end)})`
+ ? ` = $state(${state.str.original.substring(/** @type {number} */ (right.start), right.end)})`
: '';
// implicitly-declared variable which we need to make explicit
state.str.prependLeft(
@@ -1000,7 +999,8 @@ const instance_script = {
);
}
}
- if (expression_ids.length === 0 && !bindings.some((b) => b?.kind === 'store_sub')) {
+
+ if (expression_ids.length === 0 && bindings.every((b) => b.kind !== 'store_sub')) {
state.str.remove(/** @type {number} */ (node.start), /** @type {number} */ (node.end));
return;
}
diff --git a/packages/svelte/tests/migrate/samples/labeled-statement-reassign-state/input.svelte b/packages/svelte/tests/migrate/samples/labeled-statement-reassign-state/input.svelte
new file mode 100644
index 000000000000..0b5c13d8898b
--- /dev/null
+++ b/packages/svelte/tests/migrate/samples/labeled-statement-reassign-state/input.svelte
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/packages/svelte/tests/migrate/samples/labeled-statement-reassign-state/output.svelte b/packages/svelte/tests/migrate/samples/labeled-statement-reassign-state/output.svelte
new file mode 100644
index 000000000000..c2b36a6e3028
--- /dev/null
+++ b/packages/svelte/tests/migrate/samples/labeled-statement-reassign-state/output.svelte
@@ -0,0 +1,10 @@
+
\ No newline at end of file