diff --git a/__tests__/merge.ts b/__tests__/merge.ts index aab6d1d092..7795410be9 100644 --- a/__tests__/merge.ts +++ b/__tests__/merge.ts @@ -7,7 +7,7 @@ /// -import { fromJS, is, List, Map } from '../'; +import { fromJS, is, List, Map, Set } from '../'; describe('merge', () => { it('merges two maps', () => { @@ -108,7 +108,15 @@ describe('merge', () => { expect(m1.mergeDeep(m2).get('a')).toEqual(Map({x: 1, y: 1, z: 10})); }); - it('merges map entries with Vector values', () => { + it('merges map enties with List and Set values', () => { + const initial = Map({a: Map({x: 10, y: 20}), b: List([1, 2, 3]), c: Set([1, 2, 3])}); + const additions = Map({a: Map({y: 50, z: 100}), b: List([4, 5, 6]), c: Set([4, 5, 6])}); + expect(initial.mergeDeep(additions)).toEqual( + Map({a: Map({x: 10, y: 50, z: 100}), b: List([1, 2, 3, 4, 5, 6]), c: Set([1, 2, 3, 4, 5, 6])}), + ); + }); + + it('merges map entries with new values', () => { const initial = Map({a: List([1])}); // Note: merge and mergeDeep do not deeply coerce values, they only merge @@ -126,14 +134,14 @@ describe('merge', () => { }); it('maintains JS values inside immutable collections', () => { - let m1 = fromJS({a: {b: [{imm: 'map'}]}}); + let m1 = fromJS({a: {b: {imm: 'map'}}}); let m2 = m1.mergeDeep( - Map({a: Map({b: List.of( {plain: 'obj'} )})}), + Map({a: Map({b: {plain: 'obj'} })}), ); - expect(m1.getIn(['a', 'b', 0])).toEqual(Map([['imm', 'map']])); + expect(m1.getIn(['a', 'b'])).toEqual(Map([['imm', 'map']])); // However mergeDeep will merge that value into the inner Map - expect(m2.getIn(['a', 'b', 0])).toEqual(Map({imm: 'map', plain: 'obj'})); + expect(m2.getIn(['a', 'b'])).toEqual(Map({imm: 'map', plain: 'obj'})); }); }); diff --git a/src/List.js b/src/List.js index e2ec2d9c4e..4825962903 100644 --- a/src/List.js +++ b/src/List.js @@ -20,12 +20,7 @@ import { resolveEnd } from './TrieUtils'; import { IndexedCollection } from './Collection'; -import { - MapPrototype, - mergeIntoCollectionWith, - deepMerger, - deepMergerWith -} from './Map'; +import { MapPrototype } from './Map'; import { Iterator, iteratorValue, iteratorDone } from './Iterator'; import assertNotInfinite from './utils/assertNotInfinite'; @@ -140,20 +135,8 @@ export class List extends IndexedCollection { // @pragma Composition - merge(/*...iters*/) { - return mergeIntoListWith(this, undefined, arguments); - } - - mergeWith(merger, ...iters) { - return mergeIntoListWith(this, merger, iters); - } - - mergeDeep(/*...iters*/) { - return mergeIntoListWith(this, deepMerger, arguments); - } - - mergeDeepWith(merger, ...iters) { - return mergeIntoListWith(this, deepMergerWith(merger), iters); + merge(/*...collections*/) { + return this.concat.apply(this, arguments); } setSize(size) { @@ -652,22 +635,6 @@ function setListBounds(list, begin, end) { return makeList(newOrigin, newCapacity, newLevel, newRoot, newTail); } -function mergeIntoListWith(list, merger, collections) { - const iters = []; - let maxSize = 0; - for (let ii = 0; ii < collections.length; ii++) { - const iter = IndexedCollection(collections[ii]); - if (iter.size > maxSize) { - maxSize = iter.size; - } - iters.push(iter); - } - if (maxSize > list.size) { - list = list.setSize(maxSize); - } - return mergeIntoCollectionWith(list, merger, iters); -} - function getTailOffset(size) { return size < SIZE ? 0 : ((size - 1) >>> SHIFT) << SHIFT; } diff --git a/src/Map.js b/src/Map.js index 9ab3e6c72c..e354243da7 100644 --- a/src/Map.js +++ b/src/Map.js @@ -159,7 +159,7 @@ export class Map extends KeyedCollection { } mergeDeep(/*...iters*/) { - return mergeIntoMapWith(this, deepMerger, arguments); + return mergeIntoMapWith(this, deepMergerWith(alwaysNewVal), arguments); } mergeDeepWith(merger, ...iters) { @@ -839,21 +839,19 @@ function mergeIntoMapWith(map, merger, collections) { return mergeIntoCollectionWith(map, merger, iters); } -export function deepMerger(oldVal, newVal) { - return newVal && typeof newVal === 'object' && oldVal && oldVal.mergeDeep - ? oldVal.mergeDeep(newVal) - : is(oldVal, newVal) ? oldVal : newVal; +function alwaysNewVal(oldVal, newVal) { + return newVal; } export function deepMergerWith(merger) { - return (oldVal, newVal, key) => { - if ( - newVal && - typeof newVal === 'object' && - oldVal && - oldVal.mergeDeepWith - ) { - return oldVal.mergeDeepWith(merger, newVal); + return function(oldVal, newVal, key) { + if (oldVal && newVal && typeof newVal === 'object') { + if (oldVal.mergeDeepWith) { + return oldVal.mergeDeepWith(merger, newVal); + } + if (oldVal.merge) { + return oldVal.merge(newVal); + } } const nextValue = merger(oldVal, newVal, key); return is(oldVal, nextValue) ? oldVal : nextValue; diff --git a/src/Set.js b/src/Set.js index 8215930b9a..f1bfd74f6c 100644 --- a/src/Set.js +++ b/src/Set.js @@ -128,14 +128,6 @@ export class Set extends SetCollection { }); } - merge() { - return this.union.apply(this, arguments); - } - - mergeWith(merger, ...iters) { - return this.union.apply(this, iters); - } - sort(comparator) { // Late binding return OrderedSet(sortFactory(this, comparator)); @@ -186,8 +178,7 @@ const IS_SET_SENTINEL = '@@__IMMUTABLE_SET__@@'; const SetPrototype = Set.prototype; SetPrototype[IS_SET_SENTINEL] = true; SetPrototype[DELETE] = SetPrototype.remove; -SetPrototype.mergeDeep = SetPrototype.merge; -SetPrototype.mergeDeepWith = SetPrototype.mergeWith; +SetPrototype.merge = SetPrototype.union; SetPrototype.withMutations = MapPrototype.withMutations; SetPrototype.asMutable = MapPrototype.asMutable; SetPrototype.asImmutable = MapPrototype.asImmutable; diff --git a/type-definitions/Immutable.d.ts b/type-definitions/Immutable.d.ts index 95650b665c..91bbbce48a 100644 --- a/type-definitions/Immutable.d.ts +++ b/type-definitions/Immutable.d.ts @@ -675,39 +675,6 @@ declare module Immutable { update(index: number, updater: (value: T) => T): this; update(updater: (value: this) => R): R; - /** - * Note: `merge` can be used in `withMutations`. - * - * @see `Map#merge` - */ - merge(...collections: Array>): this; - - /** - * Note: `mergeWith` can be used in `withMutations`. - * - * @see `Map#mergeWith` - */ - mergeWith( - merger: (oldVal: T, newVal: T, key: number) => T, - ...collections: Array> - ): this; - - /** - * Note: `mergeDeep` can be used in `withMutations`. - * - * @see `Map#mergeDeep` - */ - mergeDeep(...collections: Array>): this; - - /** - * Note: `mergeDeepWith` can be used in `withMutations`. - * @see `Map#mergeDeepWith` - */ - mergeDeepWith( - merger: (oldVal: T, newVal: T, key: number) => T, - ...collections: Array> - ): this; - /** * Returns a new List with size `size`. If `size` is less than this * List's size, the new List will exclude values at the higher indices. @@ -819,8 +786,13 @@ declare module Immutable { /** * Returns a new List with other values or collections concatenated to this one. + * + * Note: `concat` *cannot* be safely used in `withMutations`. + * + * @alias merge */ concat(...valuesOrCollections: Array | C>): List; + merge(...collections: Array): List; /** * Returns a new List with values passed through a diff --git a/type-definitions/immutable.js.flow b/type-definitions/immutable.js.flow index 186cd8f614..50b909722a 100644 --- a/type-definitions/immutable.js.flow +++ b/type-definitions/immutable.js.flow @@ -636,18 +636,6 @@ declare class List<+T> extends IndexedCollection { merge(...collections: Iterable[]): List; - mergeWith( - merger: (oldVal: T, newVal: U, key: number) => V, - ...collections: Iterable[] - ): List; - - mergeDeep(...collections: Iterable[]): List; - - mergeDeepWith( - merger: (oldVal: T, newVal: U, key: number) => V, - ...collections: Iterable[] - ): List; - setSize(size: number): this; setIn(keyPath: Iterable, value: mixed): this; deleteIn(keyPath: Iterable, value: mixed): this; diff --git a/type-definitions/tests/immutable-flow.js b/type-definitions/tests/immutable-flow.js index b902b0edef..ebad3c0143 100644 --- a/type-definitions/tests/immutable-flow.js +++ b/type-definitions/tests/immutable-flow.js @@ -163,18 +163,6 @@ numberOrStringList = List.of('a').merge(List.of(1)) // $ExpectError numberList = List.of('a').merge(List.of(1)) -numberList = List.of(1).mergeWith((previous, next, key) => 1, [1]) -// $ExpectError -numberList = List.of(1).mergeWith((previous, next, key) => previous + next, ['a']) - -numberOrStringList = List.of(1).mergeDeep(['a']) -// $ExpectError -numberList = List.of(1).mergeDeep(['a']) - -numberList = List.of(1).mergeDeepWith((previous, next, key) => 1, [1]) -// $ExpectError -numberList = List.of(1).mergeDeepWith((previous, next, key) => previous + next, ['a']) - nullableNumberList = List.of(1).setSize(2) numberList = List.of(1).setIn([], 0) diff --git a/type-definitions/ts-tests/list.ts b/type-definitions/ts-tests/list.ts index 05e642c5c9..4023d4c684 100644 --- a/type-definitions/ts-tests/list.ts +++ b/type-definitions/ts-tests/list.ts @@ -288,7 +288,7 @@ import { List } from '../../'; // $ExpectType List List().merge(List()); - // $ExpectError + // $ExpectType List List().merge(List()); // $ExpectType List @@ -304,75 +304,12 @@ import { List } from '../../'; List().mergeIn([], []); } -{ // #mergeWith - - // $ExpectType List - List().mergeWith((prev: number, next: number, key: number) => 1, List()); - - // $ExpectError - List().mergeWith((prev: string, next: number, key: number) => 1, List()); - - // $ExpectError - List().mergeWith((prev: number, next: string, key: number) => 1, List()); - - // $ExpectError - List().mergeWith((prev: number, next: number, key: string) => 1, List()); - - // $ExpectError - List().mergeWith((prev: number, next: number, key: number) => 'a', List()); - - // $ExpectError - List().mergeWith((prev: number, next: number, key: number) => 1, List()); - - // $ExpectType List - List().mergeWith((prev: number, next: string, key: number) => 1, List()); -} - -{ // #mergeDeep - - // $ExpectType List - List().mergeDeep(List()); - - // $ExpectError - List().mergeDeep(List()); - - // $ExpectType List - List().mergeDeep(List()); - - // $ExpectType List - List().mergeDeep(List()); -} - { // #mergeDeepIn // $ExpectType List List().mergeDeepIn([], []); } -{ // #mergeDeepWith - - // $ExpectType List - List().mergeDeepWith((prev: number, next: number, key: number) => 1, List()); - - // $ExpectError - List().mergeDeepWith((prev: string, next: number, key: number) => 1, List()); - - // $ExpectError - List().mergeDeepWith((prev: number, next: string, key: number) => 1, List()); - - // $ExpectError - List().mergeDeepWith((prev: number, next: number, key: string) => 1, List()); - - // $ExpectError - List().mergeDeepWith((prev: number, next: number, key: number) => 'a', List()); - - // $ExpectError - List().mergeDeepWith((prev: number, next: number, key: number) => 1, List()); - - // $ExpectType List - List().mergeDeepWith((prev: number, next: string, key: number) => 1, List()); -} - { // #flatten // $ExpectType Collection