-
Notifications
You must be signed in to change notification settings - Fork 1
feat: add key-based reordering support for keyed object arrays #41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Conversation
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
This was referenced Jun 4, 2025
Contributor
Author
fc6ce17 to
20fd215
Compare
2ad2ec4 to
2777c18
Compare
20fd215 to
1654acc
Compare
2777c18 to
a40879b
Compare
This was referenced Jun 4, 2025
1654acc to
8f32025
Compare
a40879b to
f7bcff7
Compare
8f32025 to
c5e2f7f
Compare
f7bcff7 to
131e5bd
Compare
c5e2f7f to
e35e767
Compare
131e5bd to
8a9f9ed
Compare
e35e767 to
7c922f7
Compare
8a9f9ed to
efa4722
Compare
rexxars
approved these changes
Jun 9, 2025
Comment on lines
+229
to
+233
| if (isUniquelyKeyed(itemA) && isUniquelyKeyed(itemB)) { | ||
| return diffArrayByKey(itemA, itemB, path, patches) | ||
| } | ||
|
|
||
| return diffArrayByIndex(itemA, itemB, path, patches) |
Member
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggested change
| if (isUniquelyKeyed(itemA) && isUniquelyKeyed(itemB)) { | |
| return diffArrayByKey(itemA, itemB, path, patches) | |
| } | |
| return diffArrayByIndex(itemA, itemB, path, patches) | |
| return isUniquelyKeyed(itemA) && isUniquelyKeyed(itemB) | |
| ? diffArrayByKey(itemA, itemB, path, patches) | |
| : diffArrayByIndex(itemA, itemB, path, patches) |
Contributor
Author
Merge activity
|
- Implement ReorderPatch type for handling array reordering operations - Add sophisticated diffArrayByKey algorithm that detects reordering, insertions, and deletions - Use two-phase reordering strategy with temporary keys to avoid key collisions - Update InsertPatch to support position-based insertion (before/after/replace) - Add set operations utilities with fallbacks for older JS environments - Enhance serialization to handle complex reorder scenarios safely - Add comprehensive test coverage for various reordering scenarios This enables more collaborative-editing-friendly patches for arrays of keyed objects, generating patches that are more resilient to concurrent modifications.
efa4722 to
b9d0b98
Compare
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.

This PR introduces a significant enhancement to how keyed object arrays are diffed and patched: support for key-based reordering.
Previously,
diffArrayByKeywould fall back to index-based diffing if the order of keys changed between the source and target arrays. This could lead to less precise or less conflict-resistant patches when items were simply moved around.With this change,
diffArrayByKeynow:ReorderPatchtype when items change position.insertandunsetpatches for items added or removed.The
serializePatchesfunction has been updated to handle the newReorderPatch. It employs a two-phase reordering strategy to avoid key collisions during the patch application:__temp_reorder_<originalKey>__) while applying their final content._keyproperty of these temporary items to restore their intended final keys.This two-phase approach ensures that direct key swaps (e.g., A ↔ B) are handled correctly without data loss.
Key Changes:
diffArrayByKeyOverhaul:diffArrayByIndexif key order changes.Mapfor efficient key-based lookups.differenceandintersectionset operations (fromsetOperations.ts) to categorize keys (removed, added, common).ReorderPatchis pushed to thepatchesarray, containing the original arraysnapshotand the specificreorders(sourceKey → targetKey).position: 'before'orposition: 'after'based on the surrounding existing keys.diffItem.ReorderPatchType (Internal):ReorderPatchto the internalPatchunion inpatches.ts.ReorderPatchincludesop: 'reorder',path,snapshot(the original array), andreorders(an array of{sourceKey, targetKey}pairs).serializePatchesHandling ofReorderPatch:ReorderPatchis encountered:setpatch operations._key: sourceKey) to be the final content of the item that will occupy that position, but with a temporary_key(e.g.,_key: "__temp_reorder_sourceKey__")._keyproperty of these temporary items (e.g.,path: 'array[_key=="__temp_reorder_sourceKey__"]._key') to their finaltargetKey.setOperations.ts:differenceandintersectionutility functions forSet<T>. These use nativeSet.prototype.difference/intersectionif available (ESNext) or provide fallbacks for older JS environments.KeyedSanityObjectandisKeyedObjectinpaths.ts:KeyedSanityObjecttype definition fromdiffPatch.tstopaths.ts.isKeyedObjecttype guard for robustness.getIndexForKeyUtility:diffPatch.tsto efficiently get the index of an item in a keyed array.diffArrayLogic Update:diffArrayByKey. Otherwise, it falls back todiffArrayByIndex.position: 'after'andpath: path.concat([-1]).InsertPatchType:InsertPatch(previouslyInsertAfterPatch) now includes aposition: 'before' | 'after' | 'replace'property and usespathinstead of justafter.serializePatchesupdated to usepatch.positionwhen creating theSanityInsertPatchOperation.test/fixtures/object-array-reorder.tswith various reordering scenarios (simple swap, complete reverse, reorder with content change, reorder with insertions/deletions).test/object-arrays.test.tsto verify these scenarios.Benefits:
This is a foundational improvement for generating robust patches for keyed arrays, crucial for collaborative environments.