Skip to content

fix: preserve live Map iteration during draft mutations - #1332

Open
Marve10s wants to merge 1 commit into
immerjs:mainfrom
Marve10s:fix/map-live-iteration
Open

Marve10s wants to merge 1 commit into
immerjs:mainfrom
Marve10s:fix/map-live-iteration

Conversation

@Marve10s

Copy link
Copy Markdown

Mutating a draft Map during iteration can visit deleted entries and skip added entries when no earlier operation has created the draft's copy.

const seen = []
produce(new Map([["a", 1], ["b", 2]]), draft => {
  draft.forEach((value, key) => {
    seen.push([key, value])
    if (key === "a") {
      draft.delete("b")
      draft.set("c", 3)
    }
  })
})

Previously seen was [["a", 1], ["b", undefined]]; it now matches native Map behavior: [["a", 1], ["c", 3]].

Prepare the copy before forEach and keys start iterating, so iteration and subsequent mutations use the same backing Map. This also fixes values, entries, and Symbol.iterator, which use keys. Read-only iteration now creates a shallow copy, but an unmodified producer still returns the original state. The regression cases cover all five entry points in the existing configuration matrix.

This restores native live-iteration semantics: repeatedly deleting and re-adding the current key, or continually adding keys during traversal, can keep iteration running just as it would on a plain Map.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant