diff --git a/.changeset/tidy-ravens-assign.md b/.changeset/tidy-ravens-assign.md new file mode 100644 index 0000000000..312adde9b5 --- /dev/null +++ b/.changeset/tidy-ravens-assign.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: preserve short-circuiting for logical assignments to private state fields diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/AssignmentExpression.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/AssignmentExpression.js index e66e3408e2..7ab148f0a3 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/AssignmentExpression.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/AssignmentExpression.js @@ -1,4 +1,4 @@ -/** @import { AssignmentExpression, AssignmentOperator, Expression, Identifier, Pattern } from 'estree' */ +/** @import { AssignmentExpression, AssignmentOperator, Expression, Identifier, LogicalOperator, Pattern } from 'estree' */ /** @import { AST } from '#compiler' */ /** @import { Context } from '../types.js' */ import * as b from '#compiler/builders'; @@ -79,8 +79,13 @@ function build_assignment(operator, left, right, context) { // special case — assignment to private state field if (left.property.type === 'PrivateIdentifier') { + const logical_operator = ['||=', '&&=', '??='].includes(operator) + ? /** @type {LogicalOperator} */ (operator.slice(0, -1)) + : null; let value = /** @type {Expression} */ ( - context.visit(build_assignment_value(operator, left, right)) + context.visit( + logical_operator === null ? build_assignment_value(operator, left, right) : right + ) ); const needs_proxy = @@ -88,7 +93,15 @@ function build_assignment(operator, left, right, context) { is_non_coercive_operator(operator) && should_proxy(value, context.state.scope); - return b.call('$.set', left, value, needs_proxy && b.true); + const assignment = b.call('$.set', left, value, needs_proxy && b.true); + + return logical_operator === null + ? assignment + : b.logical( + logical_operator, + /** @type {Expression} */ (context.visit(left)), + assignment + ); } } } diff --git a/packages/svelte/tests/runtime-runes/samples/class-private-fields-logical-assignment/_config.js b/packages/svelte/tests/runtime-runes/samples/class-private-fields-logical-assignment/_config.js new file mode 100644 index 0000000000..d919c18396 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/class-private-fields-logical-assignment/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: `

truthy||value

` +}); diff --git a/packages/svelte/tests/runtime-runes/samples/class-private-fields-logical-assignment/main.svelte b/packages/svelte/tests/runtime-runes/samples/class-private-fields-logical-assignment/main.svelte new file mode 100644 index 0000000000..cc74150b35 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/class-private-fields-logical-assignment/main.svelte @@ -0,0 +1,24 @@ + + +

{result.join('|')}