Skip to content

Commit

Permalink
Prevent mutable structures when merging Immutable objects
Browse files Browse the repository at this point in the history
  • Loading branch information
Methuselah96 committed Sep 8, 2021
1 parent 678b802 commit 0f4bab4
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 2 deletions.
39 changes: 38 additions & 1 deletion __tests__/issues.ts
@@ -1,4 +1,13 @@
import { List, OrderedMap, OrderedSet, Record, Seq, Set } from 'immutable';
import {
fromJS,
List,
Map,
OrderedMap,
OrderedSet,
Record,
Seq,
Set,
} from 'immutable';

describe('Issue #1175', () => {
it('invalid hashCode() response should not infinitly recurse', () => {
Expand Down Expand Up @@ -121,3 +130,31 @@ describe('Issue #1785', () => {

expect(emptyRecord.merge({ id: 1 })).toBe(emptyRecord);
});

describe('Issue #1475', () => {
it('complex case should return first value on mergeDeep when types are incompatible', () => {
const a = fromJS({
ch: [
{
code: 8,
},
],
}) as Map<unknown, unknown>;
const b = fromJS({
ch: {
code: 8,
},
});
expect(a.mergeDeep(b).equals(b)).toBe(true);
});

it('simple case should return first value on mergeDeep when types are incompatible', () => {
const a = fromJS({
ch: [],
}) as Map<unknown, unknown>;
const b = fromJS({
ch: { code: 8 },
});
expect(a.mergeDeep(b).equals(b)).toBe(true);
});
});
14 changes: 13 additions & 1 deletion src/functional/merge.js
@@ -1,7 +1,10 @@
import { isImmutable } from '../predicates/isImmutable';
import { isIndexed } from '../predicates/isIndexed';
import { isKeyed } from '../predicates/isKeyed';
import { IndexedCollection, KeyedCollection } from '../Collection';
import hasOwnProperty from '../utils/hasOwnProperty';
import isDataStructure from '../utils/isDataStructure';
import isPlainObject from '../utils/isPlainObj';
import shallowCopy from '../utils/shallowCopy';

export function merge(collection, ...sources) {
Expand Down Expand Up @@ -69,10 +72,19 @@ export function mergeWithSources(collection, sources, merger) {
function deepMergerWith(merger) {
function deepMerger(oldValue, newValue, key) {
return isDataStructure(oldValue) && isDataStructure(newValue)
? mergeWithSources(oldValue, [newValue], deepMerger)
? areMergeable(oldValue, newValue)
? mergeWithSources(oldValue, [newValue], deepMerger)
: newValue
: merger
? merger(oldValue, newValue, key)
: newValue;
}
return deepMerger;
}

function areMergeable(oldValue, newValue) {
return !(
(isIndexed(oldValue) || Array.isArray(oldValue)) &&
(isKeyed(newValue) || isPlainObject(newValue))
);
}

0 comments on commit 0f4bab4

Please sign in to comment.