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,54 +944,53 @@ 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 bindings = ids.map((id) => state.scope.get(id.name));
const reassigned_bindings = bindings.filter((b) => b?.reassigned);
if ( const ids = extract_identifiers(left);
node.body.expression.right.type !== 'Literal' && const [, expression_ids] = extract_all_identifiers_from_expression(right);
!bindings.some((b) => b?.kind === 'store_sub') && const bindings = ids.map((id) => /** @type {Binding} */ (state.scope.get(id.name)));
node.body.expression.left.type !== 'MemberExpression'
) {
let { start, end } = /** @type {{ start: number, end: number }} */ (
node.body.expression.right
);
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 check_rune_binding('derived');
state.str.update(
/** @type {number} */ (node.start),
/** @type {number} */ (node.body.expression.start),
'let '
);
if (node.body.expression.right.type === 'SequenceExpression') { // $derived
while (state.str.original[start] !== '(') start -= 1; state.str.update(
while (state.str.original[end - 1] !== ')') end += 1; /** @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. return;
// otherwise, we need to add one
if (state.str.original[/** @type {number} */ (node.body.start)] !== '(') {
state.str.appendLeft(end, `)`);
} }
return; for (const binding of bindings) {
} else { if (binding.reassigned && (ids.includes(binding.node) || expression_ids.length === 0)) {
for (const binding of reassigned_bindings) {
if (binding && (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