Skip to content

Commit 0d233e5

Browse files
fix: don't transform reassigned state in labeled statement in $derived (#15725)
* fix: don't transform reassigned state in labeled statement in `$derived` * fix type so optional chaining is unnecessary * drive-by tidy up * drive-by tidy up --------- Co-authored-by: Rich Harris <[email protected]>
1 parent 73acf6e commit 0d233e5

File tree

4 files changed

+57
-36
lines changed

4 files changed

+57
-36
lines changed

.changeset/weak-doors-yell.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: don't transform reassigned state in labeled statement in `$derived`

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

+36-36
Original file line numberDiff line numberDiff line change
@@ -944,54 +944,53 @@ const instance_script = {
944944
node.body.type === 'ExpressionStatement' &&
945945
node.body.expression.type === 'AssignmentExpression'
946946
) {
947-
const ids = extract_identifiers(node.body.expression.left);
948-
const [, expression_ids] = extract_all_identifiers_from_expression(
949-
node.body.expression.right
950-
);
951-
const bindings = ids.map((id) => state.scope.get(id.name));
952-
const reassigned_bindings = bindings.filter((b) => b?.reassigned);
947+
const { left, right } = node.body.expression;
953948

954-
if (
955-
node.body.expression.right.type !== 'Literal' &&
956-
!bindings.some((b) => b?.kind === 'store_sub') &&
957-
node.body.expression.left.type !== 'MemberExpression'
958-
) {
959-
let { start, end } = /** @type {{ start: number, end: number }} */ (
960-
node.body.expression.right
961-
);
949+
const ids = extract_identifiers(left);
950+
const [, expression_ids] = extract_all_identifiers_from_expression(right);
951+
const bindings = ids.map((id) => /** @type {Binding} */ (state.scope.get(id.name)));
962952

963-
check_rune_binding('derived');
953+
if (bindings.every((b) => b.kind === 'legacy_reactive')) {
954+
if (
955+
right.type !== 'Literal' &&
956+
bindings.every((b) => b.kind !== 'store_sub') &&
957+
left.type !== 'MemberExpression'
958+
) {
959+
let { start, end } = /** @type {{ start: number, end: number }} */ (right);
964960

965-
// $derived
966-
state.str.update(
967-
/** @type {number} */ (node.start),
968-
/** @type {number} */ (node.body.expression.start),
969-
'let '
970-
);
961+
check_rune_binding('derived');
971962

972-
if (node.body.expression.right.type === 'SequenceExpression') {
973-
while (state.str.original[start] !== '(') start -= 1;
974-
while (state.str.original[end - 1] !== ')') end += 1;
975-
}
963+
// $derived
964+
state.str.update(
965+
/** @type {number} */ (node.start),
966+
/** @type {number} */ (node.body.expression.start),
967+
'let '
968+
);
969+
970+
if (right.type === 'SequenceExpression') {
971+
while (state.str.original[start] !== '(') start -= 1;
972+
while (state.str.original[end - 1] !== ')') end += 1;
973+
}
974+
975+
state.str.prependRight(start, `$derived(`);
976976

977-
state.str.prependRight(start, `$derived(`);
977+
// in a case like `$: ({ a } = b())`, there's already a trailing parenthesis.
978+
// otherwise, we need to add one
979+
if (state.str.original[/** @type {number} */ (node.body.start)] !== '(') {
980+
state.str.appendLeft(end, `)`);
981+
}
978982

979-
// in a case like `$: ({ a } = b())`, there's already a trailing parenthesis.
980-
// otherwise, we need to add one
981-
if (state.str.original[/** @type {number} */ (node.body.start)] !== '(') {
982-
state.str.appendLeft(end, `)`);
983+
return;
983984
}
984985

985-
return;
986-
} else {
987-
for (const binding of reassigned_bindings) {
988-
if (binding && (ids.includes(binding.node) || expression_ids.length === 0)) {
986+
for (const binding of bindings) {
987+
if (binding.reassigned && (ids.includes(binding.node) || expression_ids.length === 0)) {
989988
check_rune_binding('state');
990989
const init =
991990
binding.kind === 'state'
992991
? ' = $state()'
993992
: expression_ids.length === 0
994-
? ` = $state(${state.str.original.substring(/** @type {number} */ (node.body.expression.right.start), node.body.expression.right.end)})`
993+
? ` = $state(${state.str.original.substring(/** @type {number} */ (right.start), right.end)})`
995994
: '';
996995
// implicitly-declared variable which we need to make explicit
997996
state.str.prependLeft(
@@ -1000,7 +999,8 @@ const instance_script = {
1000999
);
10011000
}
10021001
}
1003-
if (expression_ids.length === 0 && !bindings.some((b) => b?.kind === 'store_sub')) {
1002+
1003+
if (expression_ids.length === 0 && bindings.every((b) => b.kind !== 'store_sub')) {
10041004
state.str.remove(/** @type {number} */ (node.start), /** @type {number} */ (node.end));
10051005
return;
10061006
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<script>
2+
let something = '123';
3+
4+
let foo = false;
5+
$: foo = !!something;
6+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<script>
2+
import { run } from 'svelte/legacy';
3+
4+
let something = '123';
5+
6+
let foo = $state(false);
7+
run(() => {
8+
foo = !!something;
9+
});
10+
</script>

0 commit comments

Comments
 (0)