From 07662d4aa7623e45ebee04c3894ca1bbf80bc0c2 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Tue, 25 Jun 2024 14:46:05 +0200 Subject: [PATCH] fix: correctly serialize object assignment expressions fixes #12174 #12109 didn't take into account actual object assignments and couldn't differentiate them from our "fake" assignments, this fixes that --- .changeset/eleven-avocados-walk.md | 5 +++++ .../src/compiler/phases/3-transform/client/utils.js | 3 ++- .../phases/3-transform/client/visitors/global.js | 2 +- .../phases/3-transform/client/visitors/template.js | 10 ++++------ .../runtime-runes/samples/state-update/_config.js | 2 +- .../runtime-runes/samples/state-update/main.svelte | 2 ++ 6 files changed, 15 insertions(+), 9 deletions(-) create mode 100644 .changeset/eleven-avocados-walk.md diff --git a/.changeset/eleven-avocados-walk.md b/.changeset/eleven-avocados-walk.md new file mode 100644 index 000000000000..af50fb60b2a6 --- /dev/null +++ b/.changeset/eleven-avocados-walk.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: correctly serialize object assignment expressions diff --git a/packages/svelte/src/compiler/phases/3-transform/client/utils.js b/packages/svelte/src/compiler/phases/3-transform/client/utils.js index c716bb83b694..595c8db13c35 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/utils.js @@ -120,7 +120,7 @@ export function serialize_get_binding(node, state) { * @param {import('estree').AssignmentExpression} node * @param {import('zimmerframe').Context} context * @param {() => any} fallback - * @param {boolean} prefix + * @param {boolean | null} [prefix] - If the assignment is a transformed update expression, set this. Else `null` * @param {{skip_proxy_and_freeze?: boolean}} [options] * @returns {import('estree').Expression} */ @@ -419,6 +419,7 @@ export function serialize_set_binding(node, context, fallback, prefix, options) } } else if ( node.right.type === 'Literal' && + prefix != null && (node.operator === '+=' || node.operator === '-=') ) { return b.update( diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/global.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/global.js index 2834e9ff060c..37dd02855f23 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/global.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/global.js @@ -32,7 +32,7 @@ export const global_visitors = { next(); }, AssignmentExpression(node, context) { - return serialize_set_binding(node, context, context.next, false); + return serialize_set_binding(node, context, context.next); }, UpdateExpression(node, context) { const { state, next, visit } = context; diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js index 3134409b85cc..6a426db0d419 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js @@ -791,9 +791,7 @@ function serialize_inline_component(node, component_name, context) { const assignment = b.assignment('=', attribute.expression, b.id('$$value')); push_prop( b.set(attribute.name, [ - b.stmt( - serialize_set_binding(assignment, context, () => context.visit(assignment), false) - ) + b.stmt(serialize_set_binding(assignment, context, () => context.visit(assignment))) ]) ); } @@ -1025,7 +1023,7 @@ function serialize_bind_this(bind_this, context, node) { const bind_this_id = /** @type {import('estree').Expression} */ (context.visit(bind_this)); const ids = Array.from(each_ids.values()).map((id) => b.id('$$value_' + id[0])); const assignment = b.assignment('=', bind_this, b.id('$$value')); - const update = serialize_set_binding(assignment, context, () => context.visit(assignment), false); + const update = serialize_set_binding(assignment, context, () => context.visit(assignment)); for (const [binding, [, , expression]] of each_ids) { // reset expressions to what they were before @@ -2399,7 +2397,7 @@ export const template_visitors = { if (assignment.left.type !== 'Identifier' && assignment.left.type !== 'MemberExpression') { // serialize_set_binding turns other patterns into IIFEs and separates the assignments // into separate expressions, at which point this is called again with an identifier or member expression - return serialize_set_binding(assignment, context, () => assignment, false); + return serialize_set_binding(assignment, context, () => assignment); } const left = object(assignment.left); const value = get_assignment_value(assignment, context); @@ -2780,7 +2778,7 @@ export const template_visitors = { assignment, context, () => /** @type {import('estree').Expression} */ (visit(assignment)), - false, + null, { skip_proxy_and_freeze: true } diff --git a/packages/svelte/tests/runtime-runes/samples/state-update/_config.js b/packages/svelte/tests/runtime-runes/samples/state-update/_config.js index 9d183557f9fa..4adf2095b8b6 100644 --- a/packages/svelte/tests/runtime-runes/samples/state-update/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/state-update/_config.js @@ -2,6 +2,6 @@ import { test } from '../../test'; export default test({ test({ assert, logs }) { - assert.deepEqual(logs, [1, 1, 1, 1]); + assert.deepEqual(logs, [1, 1, 1, 1, 4, 4]); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/state-update/main.svelte b/packages/svelte/tests/runtime-runes/samples/state-update/main.svelte index 011a3f693106..c0012c74ec27 100644 --- a/packages/svelte/tests/runtime-runes/samples/state-update/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/state-update/main.svelte @@ -6,4 +6,6 @@ console.log(x++); console.log(++o.x); console.log(o.x++); + console.log((o.x += 2)); + console.log((x += 2));