From 8d0114b76ff8827189a74b226c5695cbbd270f45 Mon Sep 17 00:00:00 2001 From: paoloricciuti Date: Sun, 25 May 2025 19:54:27 +0200 Subject: [PATCH] fix: only use iterator destructuring logic if there's an array pattern --- .changeset/smooth-cameras-repair.md | 5 ++ .../client/visitors/VariableDeclaration.js | 63 +++++++++++++++---- .../_expected/client/index.svelte.js | 60 ++++++++++++++++++ .../_expected/server/index.svelte.js | 8 +++ .../destructure-derived-arrays/index.svelte | 7 +++ 5 files changed, 130 insertions(+), 13 deletions(-) create mode 100644 .changeset/smooth-cameras-repair.md create mode 100644 packages/svelte/tests/snapshot/samples/destructure-derived-arrays/_expected/client/index.svelte.js create mode 100644 packages/svelte/tests/snapshot/samples/destructure-derived-arrays/_expected/server/index.svelte.js create mode 100644 packages/svelte/tests/snapshot/samples/destructure-derived-arrays/index.svelte diff --git a/.changeset/smooth-cameras-repair.md b/.changeset/smooth-cameras-repair.md new file mode 100644 index 0000000000..4cf8b5cb2f --- /dev/null +++ b/.changeset/smooth-cameras-repair.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: only use iterator destructuring logic if there's an array pattern diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index 84c205d163..161725fddc 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -1,4 +1,4 @@ -/** @import { CallExpression, Expression, Identifier, Literal, VariableDeclaration, VariableDeclarator } from 'estree' */ +/** @import { CallExpression, Expression, Identifier, Literal, VariableDeclaration, VariableDeclarator, ObjectPattern, ArrayPattern } from 'estree' */ /** @import { Binding } from '#compiler' */ /** @import { ComponentClientTransformState, ComponentContext } from '../types' */ import { dev } from '../../../../state.js'; @@ -8,6 +8,7 @@ import * as assert from '../../../../utils/assert.js'; import { get_rune } from '../../../scope.js'; import { get_prop_source, is_prop_source, is_state_source, should_proxy } from '../utils.js'; import { is_hoisted_function } from '../../utils.js'; +import { walk } from 'zimmerframe'; /** * @param {VariableDeclaration} node @@ -170,9 +171,7 @@ export function VariableDeclaration(node, context) { ) ); } else { - const [pattern, replacements] = build_pattern(declarator.id, context.state.scope); const init = /** @type {CallExpression} */ (declarator.init); - /** @type {Identifier} */ let id; let rhs = value; @@ -188,17 +187,55 @@ export function VariableDeclaration(node, context) { ); } - for (let i = 0; i < replacements.size; i++) { - const [original, replacement] = [...replacements][i]; - declarations.push( - b.declarator( - original, - b.call( - '$.derived', - b.arrow([], b.block([b.let(pattern, rhs), b.return(replacement)])) - ) - ) + /** + * + * @param {ObjectPattern} object_pattern + * @returns + */ + function has_destructured_array(object_pattern) { + let has_array = false; + walk( + /** @type {ObjectPattern | ArrayPattern} */ (object_pattern), + {}, + { + ArrayPattern(_, context) { + has_array = true; + context.stop(); + } + } ); + return has_array; + } + + if ( + // if the declarator is an array patter or if it's an object pattern with an array pattern inside + // we want to use this method to account for possible iterators in the derived value + declarator.id.type === 'ArrayPattern' || + (declarator.id.type === 'ObjectPattern' && has_destructured_array(declarator.id)) + ) { + const [pattern, replacements] = build_pattern(declarator.id, context.state.scope); + + for (let i = 0; i < replacements.size; i++) { + const [original, replacement] = [...replacements][i]; + declarations.push( + b.declarator( + original, + b.call( + '$.derived', + b.arrow([], b.block([b.let(pattern, rhs), b.return(replacement)])) + ) + ) + ); + } + } else { + const bindings = extract_paths(declarator.id); + + for (let i = 0; i < bindings.length; i++) { + const binding = bindings[i]; + declarations.push( + b.declarator(binding.node, b.call('$.derived', b.thunk(binding.expression(rhs)))) + ); + } } } continue; diff --git a/packages/svelte/tests/snapshot/samples/destructure-derived-arrays/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/destructure-derived-arrays/_expected/client/index.svelte.js new file mode 100644 index 0000000000..ac1d353d12 --- /dev/null +++ b/packages/svelte/tests/snapshot/samples/destructure-derived-arrays/_expected/client/index.svelte.js @@ -0,0 +1,60 @@ +import 'svelte/internal/disclose-version'; +import * as $ from 'svelte/internal/client'; + +export default function Destructure_derived_arrays($$anchor) { + let $$d = $.derived(() => ({})), + a = $.derived(() => $.get($$d).a), + b = $.derived(() => $.get($$d).b), + c = $.derived(() => $.get($$d).c); + + let $$d_1 = $.derived(() => []), + d = $.derived(() => { + let [$$1, $$2, $$3] = $.get($$d_1); + + return $$1; + }), + e = $.derived(() => { + let [$$1, $$2, $$3] = $.get($$d_1); + + return $$2; + }), + f = $.derived(() => { + let [$$1, $$2, $$3] = $.get($$d_1); + + return $$3; + }); + + let $$d_2 = $.derived(() => []), + g = $.derived(() => { + let { g: $$4, h: $$5, i: [$$6] } = $.get($$d_2); + + return $$4; + }), + h = $.derived(() => { + let { g: $$4, h: $$5, i: [$$6] } = $.get($$d_2); + + return $$5; + }), + j = $.derived(() => { + let { g: $$4, h: $$5, i: [$$6] } = $.get($$d_2); + + return $$6; + }); + + let $$d_3 = $.derived(() => []), + k = $.derived(() => { + let { k: $$7, l: $$8, m: { n: [$$9] } } = $.get($$d_3); + + return $$7; + }), + l = $.derived(() => { + let { k: $$7, l: $$8, m: { n: [$$9] } } = $.get($$d_3); + + return $$8; + }), + o = $.derived(() => { + let { k: $$7, l: $$8, m: { n: [$$9] } } = $.get($$d_3); + + return $$9; + }); +} \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/destructure-derived-arrays/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/destructure-derived-arrays/_expected/server/index.svelte.js new file mode 100644 index 0000000000..1a5561e2fc --- /dev/null +++ b/packages/svelte/tests/snapshot/samples/destructure-derived-arrays/_expected/server/index.svelte.js @@ -0,0 +1,8 @@ +import * as $ from 'svelte/internal/server'; + +export default function Destructure_derived_arrays($$payload) { + let { a, b, c } = {}; + let [d, e, f] = []; + let { g, h, i: [j] } = []; + let { k, l, m: { n: [o] } } = []; +} \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/destructure-derived-arrays/index.svelte b/packages/svelte/tests/snapshot/samples/destructure-derived-arrays/index.svelte new file mode 100644 index 0000000000..106e88e3d3 --- /dev/null +++ b/packages/svelte/tests/snapshot/samples/destructure-derived-arrays/index.svelte @@ -0,0 +1,7 @@ + +