Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,21 @@ function _mergeIntoObservable<T extends ObservableParam<Record<string, any>>>(
const targetChild = (target as Record<string, any>)[key];

if ((isObj || isArr) && targetChild) {
if (levelsDeep > 0 && isEmpty(sourceValue)) {
if (isArr) {
// Replace dense arrays entirely, merge sparse arrays
const sourceArr = sourceValue as any[];
const isSparseArray = Object.keys(sourceArr).length < sourceArr.length;

if (isSparseArray) {
_mergeIntoObservable(targetChild, sourceValue, levelsDeep + 1);
} else {
targetChild.set(sourceValue);
}
} else if (levelsDeep > 0 && isEmpty(sourceValue)) {
targetChild.set(sourceValue);
} else {
_mergeIntoObservable(targetChild, sourceValue, levelsDeep + 1);
}
_mergeIntoObservable(targetChild, sourceValue, levelsDeep + 1);
} else {
targetChild.set(sourceValue);
}
Expand Down
26 changes: 26 additions & 0 deletions tests/helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,32 @@ describe('mergeIntoObservable', () => {
const merged = mergeIntoObservable(target, source);
expect(merged.get()).toEqual({});
});
// Tests for https://github.com/LegendApp/legend-state/issues/468
// Array elements should be removed when source array is shorter than target
test('should remove array elements when source is shorter', () => {
const target = observable({ arr: ['a', 'b', 'c'] });
const source = { arr: ['a'] };
const merged = mergeIntoObservable(target, source);
expect(merged.arr.get()).toEqual(['a']);
});
test('should remove array elements when merging nested object', () => {
const target = observable({ data: { items: [1, 2, 3, 4, 5] } });
const source = { data: { items: [1, 2] } };
const merged = mergeIntoObservable(target, source);
expect(merged.data.items.get()).toEqual([1, 2]);
});
test('should handle array with single element removal', () => {
const target = observable({ tags: ['tag1', 'tag2'] });
const source = { tags: ['tag1'] };
const merged = mergeIntoObservable(target, source);
expect(merged.tags.get()).toEqual(['tag1']);
});
test('should handle complete array replacement with different values', () => {
const target = observable({ ids: ['a', 'b', 'c'] });
const source = { ids: ['x', 'y'] };
const merged = mergeIntoObservable(target, source);
expect(merged.ids.get()).toEqual(['x', 'y']);
});
});

describe('isObservableValueReady', () => {
Expand Down