immutable 3.7.2 → 3.7.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -86,7 +86,7 @@ Just add a reference with a relative path to the type declarations at the top
86
86
  of your file.
87
87
 
88
88
  ```javascript
89
- ///<reference path='./node_modules/immutable/dist/Immutable.d.ts'/>
89
+ ///<reference path='./node_modules/immutable/dist/immutable.d.ts'/>
90
90
  import Immutable = require('immutable');
91
91
  var map1: Immutable.Map<string, number>;
92
92
  map1 = Immutable.Map({a:1, b:2, c:3});
@@ -116,18 +116,31 @@ and especially well with an application designed using the ideas of [Flux][].
116
116
 
117
117
  When data is passed from above rather than being subscribed to, and you're only
118
118
  interested in doing work when something has changed, you can use equality.
119
- `Immutable` always returns itself when a mutation results in an identical
120
- collection, allowing for using `===` equality to determine if something
121
- has changed.
119
+
120
+ Immutable collections should be treated as *values* rather than *objects*. While
121
+ objects represents some thing which could change over time, a value represents
122
+ the state of that thing at a particular instance of time. This principle is most
123
+ important to understanding the appropriate use of immutable data. In order to
124
+ treat Immutable.js collections as values, it's important to use the
125
+ `Immutable.is()` function or `.equals()` method to determine value equality
126
+ instead of the `===` operator which determines object reference identity.
122
127
 
123
128
  ```javascript
124
129
  var map1 = Immutable.Map({a:1, b:2, c:3});
125
130
  var map2 = map1.set('b', 2);
126
- assert(map1 === map2); // no change
131
+ assert(map1.equals(map2) === true);
127
132
  var map3 = map1.set('b', 50);
128
- assert(map1 !== map3); // change
133
+ assert(map1.equals(map3) === false);
129
134
  ```
130
135
 
136
+ Note: As a performance optimization `Immutable` attempts to return the existing
137
+ collection when an operation would result in an identical collection, allowing
138
+ for using `===` reference equality to determine if something definitely has not
139
+ changed. This can be extremely useful when used within memoization function
140
+ which would prefer to re-run the function if a deeper equality check could
141
+ potentially be more costly. The `===` equality check is also used internally by
142
+ `Immutable.is` and `.equals()` as a performance optimization.
143
+
131
144
  If an object is immutable, it can be "copied" simply by making another reference
132
145
  to it instead of copying the entire object. Because a reference is much smaller
133
146
  than the object itself, this results in memory savings and a potential boost in
@@ -209,6 +222,26 @@ Immutable.Seq(myObject).map(x => x * x).toObject();
209
222
  // { a: 1, b: 4, c: 9 }
210
223
  ```
211
224
 
225
+ Keep in mind, when using JS objects to construct Immutable Maps, that
226
+ JavaScript Object properties are always strings, even if written in a quote-less
227
+ shorthand, while Immutable Maps accept keys of any type.
228
+
229
+ ```js
230
+ var obj = { 1: "one" };
231
+ Object.keys(obj); // [ "1" ]
232
+ obj["1"]; // "one"
233
+ obj[1]; // "one"
234
+
235
+ var map = Immutable.fromJS(obj);
236
+ map.get("1"); // "one"
237
+ map.get(1); // undefined
238
+ ```
239
+
240
+ Property access for JavaScript Objects first converts the key to a string, but
241
+ since Immutable Map keys can be of any type the argument to `get()` is
242
+ not altered.
243
+
244
+
212
245
  ### Converts back to raw JavaScript objects.
213
246
 
214
247
  All `immutable` Iterables can be converted to plain JavaScript Arrays and
@@ -337,8 +370,9 @@ data, performing a deep equality check if necessary.
337
370
  ```javascript
338
371
  var map1 = Immutable.Map({a:1, b:1, c:1});
339
372
  var map2 = Immutable.Map({a:1, b:1, c:1});
340
- assert(map1 !== map2);
341
- assert(Immutable.is(map1, map2) === true);
373
+ assert(map1 !== map2); // two different instances
374
+ assert(Immutable.is(map1, map2)); // have equivalent values
375
+ assert(map1.equals(map2)); // alternatively use the equals method
342
376
  ```
343
377
 
344
378
  `Immutable.is()` uses the same measure of equality as [Object.is][]
@@ -359,9 +393,9 @@ Batching Mutations
359
393
  > — Rich Hickey, Clojure
360
394
 
361
395
  Applying a mutation to create a new immutable object results in some overhead,
362
- which can add up to a performance penalty. If you need to apply a series of
363
- mutations locally before returning, `Immutable` gives you the ability to create
364
- a temporary mutable (transient) copy of a collection and apply a batch of
396
+ which can add up to a minor performance penalty. If you need to apply a series
397
+ of mutations locally before returning, `Immutable` gives you the ability to
398
+ create a temporary mutable (transient) copy of a collection and apply a batch of
365
399
  mutations in a performant manner by using `withMutations`. In fact, this is
366
400
  exactly how `Immutable` applies complex mutations itself.
367
401
 
@@ -381,6 +415,12 @@ Note: `immutable` also provides `asMutable` and `asImmutable`, but only
381
415
  encourages their use when `withMutations` will not suffice. Use caution to not
382
416
  return a mutable copy, which could result in undesired behavior.
383
417
 
418
+ *Important!*: Only a select few methods can be used in `withMutations` including
419
+ `set`, `push` and `pop`. These methods can be applied directly against a
420
+ persistent data-structure where other methods like `map`, `filter`, `sort`,
421
+ and `splice` will always return new immutable data-structures and never mutate
422
+ a mutable collection.
423
+
384
424
 
385
425
  Documentation
386
426
  -------------
@@ -354,4 +354,38 @@ describe('Cursor', () => {
354
354
  );
355
355
  });
356
356
 
357
+ it('can get Record value as a property', () => {
358
+ var User = Immutable.Record({ name: 'John' });
359
+ var users = Immutable.List.of(new User());
360
+ var data = Immutable.Map({'users': users});
361
+ var cursor = Cursor.from(data, ['users']);
362
+ expect(cursor.first().name).toBe('John');
363
+ });
364
+
365
+ it('can set value of a cursor directly', () => {
366
+ var onChange = jest.genMockFunction();
367
+ var data = Immutable.fromJS({a:1});
368
+ var c = Cursor.from(data, ['a'], onChange);
369
+ var c1 = c.set(2);
370
+ expect(c1.deref()).toBe(2);
371
+ expect(onChange).lastCalledWith(
372
+ Immutable.fromJS({a:2}),
373
+ data,
374
+ ['a']
375
+ );
376
+ });
377
+
378
+ it('can set value of a cursor to undefined directly', () => {
379
+ var onChange = jest.genMockFunction();
380
+ var data = Immutable.fromJS({a:1});
381
+ var c = Cursor.from(data, ['a'], onChange);
382
+ var c1 = c.set(undefined);
383
+ expect(c1.deref()).toBe(undefined);
384
+ expect(onChange).lastCalledWith(
385
+ Immutable.fromJS({a:undefined}),
386
+ data,
387
+ ['a']
388
+ );
389
+ });
390
+
357
391
  });
@@ -91,8 +91,11 @@ declare module 'immutable/contrib/cursor' {
91
91
  /**
92
92
  * Sets `value` at `key` in the cursor, returning a new cursor to the same
93
93
  * point in the new data.
94
+ *
95
+ * If only one parameter is provided, it is set directly as the cursor's value.
94
96
  */
95
97
  set(key: any, value: any): Cursor;
98
+ set(value: any): Cursor;
96
99
 
97
100
  /**
98
101
  * Deletes `key` from the cursor, returning a new cursor to the same
@@ -20,6 +20,7 @@ var Iterable = Immutable.Iterable;
20
20
  var Iterator = Iterable.Iterator;
21
21
  var Seq = Immutable.Seq;
22
22
  var Map = Immutable.Map;
23
+ var Record = Immutable.Record;
23
24
 
24
25
 
25
26
  function cursorFrom(rootData, keyPath, onChange) {
@@ -85,7 +86,11 @@ IndexedCursorPrototype.getIn = function(keyPath, notSetValue) {
85
86
 
86
87
  IndexedCursorPrototype.set =
87
88
  KeyedCursorPrototype.set = function(key, value) {
88
- return updateCursor(this, function (m) { return m.set(key, value); }, [key]);
89
+ if(arguments.length === 1) {
90
+ return updateCursor(this, function() { return key; }, []);
91
+ } else {
92
+ return updateCursor(this, function (m) { return m.set(key, value); }, [key]);
93
+ }
89
94
  }
90
95
 
91
96
  IndexedCursorPrototype.push = function(/* values */) {
@@ -251,7 +256,34 @@ function makeCursor(rootData, keyPath, onChange, value) {
251
256
  }
252
257
  var size = value && value.size;
253
258
  var CursorClass = Iterable.isIndexed(value) ? IndexedCursor : KeyedCursor;
254
- return new CursorClass(rootData, keyPath, onChange, size);
259
+ var cursor = new CursorClass(rootData, keyPath, onChange, size);
260
+
261
+ if (value instanceof Record) {
262
+ defineRecordProperties(cursor, value);
263
+ }
264
+
265
+ return cursor;
266
+ }
267
+
268
+ function defineRecordProperties(cursor, value) {
269
+ try {
270
+ value._keys.forEach(setProp.bind(undefined, cursor));
271
+ } catch (error) {
272
+ // Object.defineProperty failed. Probably IE8.
273
+ }
274
+ }
275
+
276
+ function setProp(prototype, name) {
277
+ Object.defineProperty(prototype, name, {
278
+ get: function() {
279
+ return this.get(name);
280
+ },
281
+ set: function(value) {
282
+ if (!this.__ownerID) {
283
+ throw new Error('Cannot set on an immutable record.');
284
+ }
285
+ }
286
+ });
255
287
  }
256
288
 
257
289
  function wrappedValue(cursor, keyPath, value) {