svelte icon indicating copy to clipboard operation
svelte copied to clipboard

fix: snapshot destructured values in #each blocks to prevent mutation…

Open AyushCoder9 opened this issue 1 month ago • 5 comments

… issues

Fixes #17227

When using destructuring in #each blocks (e.g., {#each gen() as [item]}), if the generator mutates the yielded object, all items would end up with the same final value because they all reference the same object.

This fix adds snapshotting for destructured patterns in each blocks, ensuring that each iteration gets a snapshot of the value at the time it was yielded, matching the behavior of a standard for...of loop.

  • Add snapshot_each_value, snapshot_array, and snapshot_object utilities
  • Apply snapshotting in both client and server EachBlock visitors
  • Add test case to prevent regression

Before submitting the PR, please make sure you do the following

  • [ ] It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • [ ] Prefix your PR title with feat:, fix:, chore:, or docs:.
  • [ ] This message body should clearly illustrate what problems it solves.
  • [ ] Ideally, include a test that fails without this PR but passes with it.
  • [ ] If this PR changes code within packages/svelte/src, add a changeset (npx changeset).

Tests and linting

  • [ ] Run the tests with pnpm test and lint the project with pnpm lint

AyushCoder9 avatar Nov 24 '25 20:11 AyushCoder9

⚠️ No Changeset found

Latest commit: 8348132c9c1d6bf5b9c916a634742c15a17e0bd1

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

changeset-bot[bot] avatar Nov 24 '25 20:11 changeset-bot[bot]

Why would you want this behaviour? It's wrong. If you don't want the array to be mutated, don't mutate it.

Rich-Harris avatar Nov 24 '25 21:11 Rich-Harris

Playground

pnpm add https://pkg.pr.new/svelte@17232

github-actions[bot] avatar Nov 24 '25 21:11 github-actions[bot]

Preview: https://svelte-dev-git-preview-svelte-17232-svelte.vercel.app/

svelte-docs-bot[bot] avatar Nov 25 '25 04:11 svelte-docs-bot[bot]

Why would you want this behaviour? It's wrong. If you don't want the array to be mutated, don't mutate it.

I've updated the fix to match for...of behavior. Instead of snapshotting, array destructuring now happens immediately during iteration, capturing values at the time they are yielded. Changes Made

  1. New to_array_destructured utility function Destructures array elements immediately during iteration (not after) When a generator yields the same array object multiple times (mutating it), we extract the values at iteration time Returns an array of arrays so extract_paths can process them correctly
  2. Updated EachBlock visitors (client & server) Detects when array destructuring patterns are used (e.g., [item]) Calls to_array_destructured to destructure immediately during collection conversion This ensures each iteration gets the value at that moment, matching for...of behavior
  3. Object destructuring unchanged Object destructuring still uses snapshotting (shallow copy) since objects need to be copied Only array destructuring uses immediate destructuring How it works Before (incorrect behavior): // Generator yields same array object, mutating itgen() → [arr, arr, arr, arr, arr] // all reference same object// Later destructuring reads from same object → all get final value (4) After (matches for...of): // Destructure immediately during iterationgen() → extract [0] at yield 0, [1] at yield 1, etc.// Result: [0, 1, 2, 3, 4] captured at iteration time This matches for...of behavior where destructuring happens immediately, not by preventing mutation. The fix ensures values are captured at the time they're yielded, regardless of later mutations. Test case added to prevent regression. Ready for review.

AyushCoder9 avatar Nov 25 '25 04:11 AyushCoder9