8000 BREAKING: Alias `merge` as `concat` for Set and Map collections by leebyron · Pull Request #1373 · immutable-js/immutable-js · GitHub
[go: up one dir, main page]

Skip to content

BREAKING: Alias merge as concat for Set and Map collections #1373

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
merged 2 commits into from
Oct 11, 2017
Merged
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
26 changes: 25 additions & 1 deletion __tests__/List.ts
Original file line number Diff line number Diff line change
Expand Up @@ -642,12 +642,36 @@ describe('List', () => {
});

it('concat works like Array.prototype.concat', () => {
const v1 = List.of(1, 2, 3);
const v1 = List([1, 2, 3]);
const v2 = v1.concat(4, List([ 5, 6 ]), [7, 8], Seq([ 9, 10 ]), Set.of(11, 12), null as any);
expect(v1.toArray()).toEqual([1, 2, 3]);
expect(v2.toArray()).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, null]);
});

it('concat returns self when no changes', () => {
const v1 = List([1, 2, 3]);
expect(v1.concat([])).toBe(v1);
});

it('concat returns arg when concat to empty', () => {
const v1 = List([1, 2, 3]);
expect(List().concat(v1)).toBe(v1);
});

it('concats a single value', () => {
const v1 = List([1, 2, 3]);
expect(v1.concat(4)).toEqual(List([1, 2, 3, 4]));
});

it('concat returns List-coerced arg when concat to empty', () => {
expect(List().concat([1, 2, 3])).toEqual(List([1, 2, 3]));
});

it('concat does not spread in string characters', () => {
const v1 = List([1, 2, 3]);
expect(v1.concat('abcdef')).toEqual(List([1, 2, 3, 'abcdef']));
});

it('allows chained mutations', () => {
const v1 = List();
const v2 = v1.push(1);
Expand Down
27 changes: 24 additions & 3 deletions src/List.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
} from './TrieUtils';
import { IndexedCollection } from './Collection';
import { MapPrototype } from './Map';
import { Iterator, iteratorValue, iteratorDone } from './Iterator';
import { hasIterator, Iterator, iteratorValue, iteratorDone } from './Iterator';

import assertNotInfinite from './utils/assertNotInfinite';

Expand Down Expand Up @@ -135,8 +135,28 @@ export class List extends IndexedCollection {

// @pragma Composition

merge(/*...collections*/) {
return this.concat.apply(this, arguments);
concat(/*...collections*/) {
const seqs = [];
for (let i = 0; i < arguments.length; i++) {
const argument = arguments[i];
const seq = IndexedCollection(
typeof argument !== 'string' && hasIterator(argument)
? argument
: [argument]
);
if (seq.size !== 0) {
seqs.push(seq);
}
}
if (seqs.length === 0) {
return this;
}
if (this.size === 0 && !this.__ownerID && seqs.length === 1) {
return this.constructor(seqs[0]);
}
return this.withMutations(list => {
seqs.forEach(seq => seq.forEach(value => list.push(value)));
});
}

setSize(size) {
Expand Down Expand Up @@ -215,6 +235,7 @@ const IS_LIST_SENTINEL = '@@__IMMUTABLE_LIST__@@';
export const ListPrototype = List.prototype;
ListPrototype[IS_LIST_SENTINEL] = true;
ListPrototype[DELETE] = ListPrototype.remove;
ListPrototype.merge = ListPrototype.concat;
ListPrototype.setIn = MapPrototype.setIn;
ListPrototype.deleteIn = ListPrototype.removeIn = MapPrototype.removeIn;
ListPrototype.update = MapPrototype.update;
Expand Down
1 change: 1 addition & 0 deletions src/Map.js
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ MapPrototype[IS_MAP_SENTINEL] = true;
MapPrototype[DELETE] = MapPrototype.remove;
MapPrototype.removeIn = MapPrototype.deleteIn;
MapPrototype.removeAll = MapPrototype.deleteAll;
MapPrototype.concat = MapPrototype.merge;
MapPrototype['@@transducer/init'] = MapPrototype.asMutable;
MapPrototype['@@transducer/step'] = function(result, arr) {
return result.set(arr[0], arr[1]);
Expand Down
2 changes: 1 addition & 1 deletion src/Set.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ const IS_SET_SENTINEL = '@@__IMMUTABLE_SET__@@';
const SetPrototype = Set.prototype;
SetPrototype[IS_SET_SENTINEL] = true;
SetPrototype[DELETE] = SetPrototype.remove;
SetPrototype.merge = SetPrototype.union;
SetPrototype.merge = SetPrototype.concat = SetPrototype.union;
SetPrototype.withMutations = MapPrototype.withMutations;
SetPrototype.asMutable = MapPrototype.asMutable;
SetPrototype.asImmutable = MapPrototype.asImmutable;
Expand Down
75 changes: 49 additions & 26 deletions type-definitions/Immutable.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -787,7 +787,7 @@ declare module Immutable {
/**
* Returns a new List with other values or collections concatenated to this one.
*
* Note: `concat` *cannot* be safely used in `withMutations`.
* Note: `concat` can be used in `withMutations`.
*
* @alias merge
*/
Expand Down Expand Up @@ -1223,8 +1223,13 @@ declare module Immutable {
* ```
*
* Note: `merge` can be used in `withMutations`.
*
* @alias concat
*/
merge(...collections: Array<Iterable<[K, V]> | {[key: string]: V}>): this;
merge<KC, VC>(...collections: Array<Iterable<[KC, VC]>>): Map<K | KC, V | VC>;
merge<C>(...collections: Array<{[key: string]: C}>): Map<K | string, V | C>;
concat<KC, VC>(...collections: Array<Iterable<[KC, VC]>>): Map<K | KC, V | VC>;
concat<C>(...collections: Array<{[key: string]: C}>): Map<K | string, V | C>;

/**
* Like `merge()`, `mergeWith()` returns a new Map resulting from merging
Expand Down Expand Up @@ -1512,12 +1517,6 @@ declare module Immutable {

// Sequence algorithms

/**
* Returns a new Map with other collections concatenated to this one.
*/
concat<KC, VC>(...collections: Array<Iterable<[KC, VC]>>): Map<K | KC, V | VC>;
concat<C>(...collections: Array<{[key: string]: C}>): Map<K | string, V | C>;

/**
* Returns a new Map with values passed through a
* `mapper` function.
Expand Down Expand Up @@ -1628,14 +1627,34 @@ declare module Immutable {
*/
readonly size: number;

// Sequence algorithms

/**
* Returns a new OrderedMap with other collections concatenated to this one.
* Returns a new OrderedMap resulting from merging the provided Collections
* (or JS objects) into this OrderedMap. In other words, this takes each
* entry of each collection and sets it on this OrderedMap.
*
* Note: Values provided to `merge` are shallowly converted before being
* merged. No nested values are altered.
*
* <!-- runkit:activate -->
* ```js
* const { OrderedMap } = require('immutable@4.0.0-rc.7')
* const one = OrderedMap({ a: 10, b: 20, c: 30 })
* const two = OrderedMap({ b: 40, a: 50, d: 60 })
* one.merge(two) // OrderedMap { "a": 50, "b": 40, "c": 30, "d": 60 }
* two.merge(one) // OrderedMap { "b": 20, "a": 10, "d": 60, "c": 30 }
* ```
*
* Note: `merge` can be used in `withMutations`.
*
* @alias concat
*/
merge<KC, VC>(.. A93C .collections: Array<Iterable<[KC, VC]>>): OrderedMap<K | KC, V | VC>;
merge<C>(...collections: Array<{[key: string]: C}>): OrderedMap<K | string, V | C>;
concat<KC, VC>(...collections: Array<Iterable<[KC, VC]>>): OrderedMap<K | KC, V | VC>;
concat<C>(...collections: Array<{[key: string]: C}>): OrderedMap<K | string, V | C>;

// Sequence algorithms

/**
* Returns a new OrderedMap with values passed through a
* `mapper` function.
Expand Down Expand Up @@ -1811,24 +1830,26 @@ declare module Immutable {
*
* Note: `union` can be used in `withMutations`.
* @alias merge
* @alias concat
*/
union(...collections: Array<Iterable<T>>): this;
merge(...collections: Array<Iterable<T>>): this;
union<C>(...collections: Array<Iterable<C>>): Set<T | C>;
merge<C>(...collections: Array<Iterable<C>>): Set<T | C>;
concat<C>(...collections: Array<Iterable<C>>): Set<T | C>;

/**
* Returns a Set which has removed any values not also contained
* within `collections`.
*
* Note: `intersect` can be used in `withMutations`.
*/
intersect(...collections: Array<Collection<any, T> | Array<T>>): this;
intersect(...collections: Array<Iterable<T>>): this;

/**
* Returns a Set excluding any values contained within `collections`.
*
* Note: `subtract` can be used in `withMutations`.
*/
subtract(...collections: Array<Collection<any, T> | Array<T>>): this;
subtract(...collections: Array<Iterable<T>>): this;


// Transient changes
Expand Down Expand Up @@ -1863,11 +1884,6 @@ declare module Immutable {

// Sequence algorithms

/**
* Returns a new Set with other collections concatenated to this one.
*/
concat<C>(...valuesOrCollections: Array<Iterable<C> | C>): Set<T | C>;

/**
* Returns a new Set with values passed through a
* `mapper` function.
Expand Down Expand Up @@ -1956,12 +1972,19 @@ declare module Immutable {
*/
readonly size: number;

// Sequence algorithms

/**
* Returns a new OrderedSet with other collections concatenated to this one.
* Returns an OrderedSet including any value from `collections` that does
* not already exist in this OrderedSet.
*
* Note: `union` can be used in `withMutations`.
* @alias merge
* @alias concat
*/
concat<C>(...valuesOrCollections: Array<Iterable<C> | C>): OrderedSet<T | C>;
union<C>(...collections: Array<Iterable<C>>): OrderedSet<T | C>;
merge<C>(...collections: Array<Iterable<C>>): OrderedSet<T | C>;
concat<C>(...collections: Array<Iterable<C>>): OrderedSet<T | C>;

// Sequence algorithms

/**
* Returns a new Set with values passed through a
Expand Down Expand Up @@ -3013,7 +3036,7 @@ declare module Immutable {
* All entries will be present in the resulting Seq, even if they
* are duplicates.
*/
concat<C>(...valuesOrCollections: Array<Iterable<C> | C>): Seq.Set<T | C>;
concat<U>(...collections: Array<Iterable<U>>): Seq.Set<T | U>;

/**
* Returns a new Seq.Set with values passed through a
Expand Down Expand Up @@ -3717,7 +3740,7 @@ declare module Immutable {
/**
* Returns a new Collection with other collections concatenated to this one.
*/
concat<C>(...valuesOrCollections: Array<Iterable<C> | C>): Collection.Set<T | C>;
concat<U>(...collections: Array<Iterable<U>>): Collection.Set<T | U>;

/**
* Returns a new Collection.Set with values passed through a
Expand Down
22 changes: 10 additions & 12 deletions type-definitions/immutable.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ declare class SetCollection<+T> extends Collection<T, T> {
@@iterator(): Iterator<T>;
toSeq(): SetSeq<T>;

concat<C>(...iters: Array<Iterable<C> | C>): SetCollection<T | C>;
concat<U>(...collections: Iterable<U>[]): SetCollection<T | U>;

// `filter`, `map` and `flatMap` cannot be defined further up the hierarchy,
// because the implementation for `KeyedCollection` allows the value type to
Expand Down Expand Up @@ -619,7 +619,7 @@ declare class SetSeq<+T> extends Seq<T, T> mixins SetCollection<T> {

// Override specialized return types

concat<C>(...iters: Array<Iterable<C> | C>): SetSeq<T | C>;
concat<U>(...collections: Iterable<U>[]): SetSeq<T | U>;

filter(predicate: typeof Boolean): SetSeq<$NonMaybeType<T>>;
filter(
Expand Down Expand Up @@ -836,6 +836,9 @@ declare class Map<K, +V> extends KeyedCollection<K, V> {
merge<K_, V_>(
...collections: (Iterable<[K_, V_]> | PlainObjInput<K_, V_>)[]
): Map<K | K_, V | V_>;
concat<K_, V_>(
...collections: (Iterable<[K_, V_]> | PlainObjInput<K_, V_>)[]
): Map<K | K_, V | V_>;

mergeWith<K_, W, X>(
merger: (oldVal: V, newVal: W, key: K) => X,
Expand Down Expand Up @@ -883,9 +886,6 @@ declare class Map<K, +V> extends KeyedCollection<K, V> {

flip(): Map<V, K>;

concat<KC, VC>(...iters: Array<Iterable<[KC, VC]>>): Map<K | KC, V | VC>;
concat<KC, VC>(...iters: Array<PlainObjInput<KC, VC>>): Map<K | KC, V | VC>;

filter(predicate: typeof Boolean): Map<K, $NonMaybeType<V>>;
filter(
predicate: (value: V, key: K, iter: this) => mixed,
Expand Down Expand Up @@ -937,6 +937,9 @@ declare class OrderedMap<K, +V> extends Map<K, V> {
merge<K_, V_>(
...collections: (Iterable<[K_, V_]> | PlainObjInput<K_, V_>)[]
): OrderedMap<K | K_, V | V_>;
concat<K_, V_>(
...collections: (Iterable<[K_, V_]> | PlainObjInput<K_, V_>)[]
): OrderedMap<K | K_, V | V_>;

mergeWith<K_, W, X>(
merger: (oldVal: V, newVal: W, key: K) => X,
Expand Down Expand Up @@ -984,9 +987,6 @@ declare class OrderedMap<K, +V> extends Map<K, V> {

flip(): OrderedMap<V, K>;

concat<KC, VC>(...iters: Array<Iterable<[KC, VC]>>): OrderedMap<K | KC, V | VC>;
concat<KC, VC>(...iters: Array<PlainObjInput<KC, VC>>): OrderedMap<K | KC, V | VC>;

filter(predicate: typeof Boolean): OrderedMap<K, $NonMaybeType<V>>;
filter(
predicate: (value: V, key: K, iter: this) => mixed,
Expand Down Expand Up @@ -1038,6 +1038,7 @@ declare class Set<+T> extends SetCollection<T> {
clear(): this;
union<U>(...collections: Iterable<U>[]): Set<T | U>;
merge<U>(...collections: Iterable<U>[]): Set<T | U>;
concat<U>(...collections: Iterable<U>[]): Set<T | U>;
intersect<U>(...collections: Iterable<U>[]): Set<T & U>;
subtract(...collections: Iterable<mixed>[]): this;

Expand All @@ -1048,8 +1049,6 @@ declare class Set<+T> extends SetCollection<T> {

// Override specialized return types

concat<C>(...iters: Array<Iterable<C> | C>): Set<T | C>;

filter(predicate: typeof Boolean): Set<$NonMaybeType<T>>;
filter(
predicate: (value: T, value: T, iter: this) => mixed,
Expand Down Expand Up @@ -1087,10 +1086,9 @@ declare class OrderedSet<+T> extends Set<T> {
add<U>(value: U): OrderedSet<T | U>;
union<U>(...collections: Iterable<U>[]): OrderedSet<T | U>;
merge<U>(...collections: Iterable<U>[]): OrderedSet<T | U>;
concat<U>(...collections: Iterable<U>[]): OrderedSet<T | U>;
intersect<U>(...collections: Iterable<U>[]): OrderedSet<T & U>;

concat<C>(...iters: Array<Iterable<C> | C>): OrderedSet<T | C>;

filter(predicate: typeof Boolean): OrderedSet<$NonMaybeType<T>>;
filter(
predicate: (value: T, value: T, iter: this) => mixed,
Expand Down
4 changes: 2 additions & 2 deletions type-definitions/ts-tests/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,13 +252,13 @@ import { Map, List } from '../../';
// $ExpectType Map<string, number>
Map<string, number>().merge({ a: 1 });

// $ExpectError
// $ExpectType Map<string, number | { b: number; }>
Map<string, number>().merge({ a: { b: 1 } });

// $ExpectType Map<number, number>
Map<number, number>().merge(Map<number, number>());

// $ExpectError
// $ExpectType Map<number, string | number>
Map<number, number>().merge(Map<number, string>());

// $ExpectType Map<number, string | number>
Expand Down
4 changes: 2 additions & 2 deletions type-definitions/ts-tests/ordered-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,13 +252,13 @@ import { OrderedMap, List } from '../../';
// $ExpectType OrderedMap<string, number>
OrderedMap<string, number>().merge({ a: 1 });

// $ExpectError
// $ExpectType OrderedMap<string, number | { b: number; }>
OrderedMap<string, number>().merge({ a: { b: 1 } });

// $ExpectType OrderedMap<number, number>
OrderedMap<number, number>().merge(OrderedMap<number, number>());

// $ExpectError
// $ExpectType OrderedMap<number, string | number>
OrderedMap<number, number>().merge(OrderedMap<number, string>());

// $ExpectType OrderedMap<number, string | number>
Expand Down
4 changes: 2 additions & 2 deletions type-definitions/ts-tests/ordered-set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ import { OrderedSet, Map } from '../../';
// $ExpectType OrderedSet<number>
OrderedSet<number>().union(OrderedSet<number>());

// $ExpectError
// $ExpectType OrderedSet<string | number>
OrderedSet<number>().union(OrderedSet<string>());

// $ExpectType OrderedSet<string | number>
Expand All @@ -170,7 +170,7 @@ import { OrderedSet, Map } from '../../';
// $ExpectType OrderedSet<number>
OrderedSet<number>().merge(OrderedSet<number>());

// $ExpectError
// $ExpectType OrderedSet<string | number>
OrderedSet<number>().merge(OrderedSet<string>());

// $ExpectType OrderedSet<string | number>
Expand Down
Loading
0