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 <rich.harris@vercel.com>
pull/15729/head
Paolo Ricciuti 5 months ago committed by GitHub
parent 73acf6e7f4
commit 0d233e58cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: don't transform reassigned state in labeled statement in `$derived`

@ -944,21 +944,19 @@ const instance_script = {
node.body.type === 'ExpressionStatement' && node.body.type === 'ExpressionStatement' &&
node.body.expression.type === 'AssignmentExpression' node.body.expression.type === 'AssignmentExpression'
) { ) {
const ids = extract_identifiers(node.body.expression.left); const { left, right } = node.body.expression;
const [, expression_ids] = extract_all_identifiers_from_expression(
node.body.expression.right const ids = extract_identifiers(left);
); const [, expression_ids] = extract_all_identifiers_from_expression(right);
const bindings = ids.map((id) => state.scope.get(id.name)); const bindings = ids.map((id) => /** @type {Binding} */ (state.scope.get(id.name)));
const reassigned_bindings = bindings.filter((b) => b?.reassigned);
if (bindings.every((b) => b.kind === 'legacy_reactive')) {
if ( if (
node.body.expression.right.type !== 'Literal' && right.type !== 'Literal' &&
!bindings.some((b) => b?.kind === 'store_sub') && bindings.every((b) => b.kind !== 'store_sub') &&
node.body.expression.left.type !== 'MemberExpression' left.type !== 'MemberExpression'
) { ) {
let { start, end } = /** @type {{ start: number, end: number }} */ ( let { start, end } = /** @type {{ start: number, end: number }} */ (right);
node.body.expression.right
);
check_rune_binding('derived'); check_rune_binding('derived');
@ -969,7 +967,7 @@ const instance_script = {
'let ' 'let '
); );
if (node.body.expression.right.type === 'SequenceExpression') { if (right.type === 'SequenceExpression') {
while (state.str.original[start] !== '(') start -= 1; while (state.str.original[start] !== '(') start -= 1;
while (state.str.original[end - 1] !== ')') end += 1; while (state.str.original[end - 1] !== ')') end += 1;
} }
@ -983,15 +981,16 @@ const instance_script = {
} }
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'); check_rune_binding('state');
const init = const init =
binding.kind === 'state' binding.kind === 'state'
? ' = $state()' ? ' = $state()'
: expression_ids.length === 0 : 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 // implicitly-declared variable which we need to make explicit
state.str.prependLeft( 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)); state.str.remove(/** @type {number} */ (node.start), /** @type {number} */ (node.end));
return; return;
} }

@ -0,0 +1,6 @@
<script>
let something = '123';
let foo = false;
$: foo = !!something;
</script>

@ -0,0 +1,10 @@
<script>
import { run } from 'svelte/legacy';
let something = '123';
let foo = $state(false);
run(() => {
foo = !!something;
});
</script>
Loading…
Cancel
Save