fix: preserve Set/Map order when restoring referential equalities - #357
Open
spokodev wants to merge 1 commit into
Open
fix: preserve Set/Map order when restoring referential equalities#357spokodev wants to merge 1 commit into
spokodev wants to merge 1 commit into
Conversation
setDeep replaced Set members and Map keys with delete + add, which moves the entry to the end of the container. When more than one referentially equal value lives in the same Set (or is used as a key in the same Map), each replacement shifted the positional indices that the remaining referential-equality annotations rely on, so getNthKey resolved the wrong entry. The result was silent data loss: entries were dropped and others duplicated. Rebuild the container in place instead, keeping every entry at its original index.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
setDeepreplacedSetmembers andMapkeys withdelete+add, which moves the entry to the end of the container. When more than one referentially equal value lives in the sameSet(or is used as a key in the sameMap), each replacement shifts the positional indices that the remaining referential-equality annotations rely on, sogetNthKeyresolves the wrong entry. The result is silent data loss — entries are dropped and others duplicated — with default options, on bothserialize/deserializeandstringify/parse.Rebuild the container in place so every entry keeps its original index. Adds regression tests for the Set and Map-key cases.
Greptile Summary
This PR fixes a silent data-loss bug where
setDeepuseddelete+add(orset+delete) to replace a Set member or Map key, moving the entry to the end of the container and corrupting the positional indices that subsequent referential-equality annotations rely on. The fix rebuilds the Set/Map in-place, preserving original insertion order throughout the restoration walk.src/accessDeep.ts: Both the Set branch and the Map-key branch now snapshot entries into a temporary array, clear the container, then re-insert everything in original order — substituting only the one entry that changed.src/index.test.ts: Two new regression tests are added covering the multi-referential-equal-values-in-Set case and the multi-referential-equal-keys-in-Map case that triggered the original bug.Confidence Score: 5/5
The change is a targeted, well-reasoned fix to a reproducible data-loss bug in Set/Map referential-equality restoration, with no regressions to other code paths.
Both the Set and Map-key branches now correctly snapshot-then-rebuild the container, preserving insertion order across multiple sequential annotations. The Map value path (which was already order-safe) is untouched. Two focused regression tests confirm the previously broken cases now work. No new error paths or behavioural changes are introduced beyond the bug fix.
No files require special attention — the change is self-contained within src/accessDeep.ts and src/index.test.ts.
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[setDeep called] --> B{parent type?} B -- Array --> C[Direct index assignment] B -- PlainObject --> D[Direct key assignment] B -- Set --> E[oldValue = getNthKey] B -- Map --> F{annotation type?} E --> G[newValue = mapper oldValue] G --> H{oldValue !== newValue?} H -- No --> I[no-op] H -- Yes --> J[Snapshot to array\nReplace at index\nClear + re-add all] J --> K[Set order preserved] F -- key --> L[newKey = mapper keyToRow] F -- value --> M[parent.set in-place\norder unchanged] L --> N{newKey !== keyToRow?} N -- No --> O[no-op] N -- Yes --> P[Snapshot entries\nClear\nRe-insert substituting old key] P --> Q[Map order preserved]%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% flowchart TD A[setDeep called] --> B{parent type?} B -- Array --> C[Direct index assignment] B -- PlainObject --> D[Direct key assignment] B -- Set --> E[oldValue = getNthKey] B -- Map --> F{annotation type?} E --> G[newValue = mapper oldValue] G --> H{oldValue !== newValue?} H -- No --> I[no-op] H -- Yes --> J[Snapshot to array\nReplace at index\nClear + re-add all] J --> K[Set order preserved] F -- key --> L[newKey = mapper keyToRow] F -- value --> M[parent.set in-place\norder unchanged] L --> N{newKey !== keyToRow?} N -- No --> O[no-op] N -- Yes --> P[Snapshot entries\nClear\nRe-insert substituting old key] P --> Q[Map order preserved]Reviews (1): Last reviewed commit: "fix: preserve Set/Map order when restori..." | Re-trigger Greptile