immutable 4.0.0-rc.1 → 4.0.0-rc.14

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.
@@ -1,290 +0,0 @@
1
- /**
2
- * Copyright (c) 2014-2015, Facebook, Inc.
3
- * All rights reserved.
4
- *
5
- * This source code is licensed under the BSD-style license found in the
6
- * LICENSE file in the root directory of this source tree. An additional grant
7
- * of patent rights can be found in the PATENTS file in the same directory.
8
- */
9
-
10
-
11
- /**
12
- * Cursors
13
- * -------
14
- *
15
- * Cursors allow you to hold a reference to a path in a nested immutable data
16
- * structure, allowing you to pass smaller sections of a larger nested
17
- * collection to portions of your application while maintaining a central point
18
- * aware of changes to the entire data structure.
19
- *
20
- * This is particularly useful when used in conjuction with component-based UI
21
- * libraries like [React](http://facebook.github.io/react/) or to simulate
22
- * "state" throughout an application while maintaining a single flow of logic.
23
- *
24
- * Cursors provide a simple API for getting the value at that path
25
- * (the equivalent of `this.getIn(keyPath)`), updating the value at that path
26
- * (the equivalent of `this.updateIn(keyPath)`), and getting a sub-cursor
27
- * starting from that path.
28
- *
29
- * When updated, a new root collection is created and provided to the `onChange`
30
- * function provided to the first call to `Cursor(map, onChange)`.
31
- *
32
- * When this cursor's (or any of its sub-cursors') `update` method is called,
33
- * the resulting new data structure will be provided to the `onChange`
34
- * function. Use this callback to keep track of the most current value or
35
- * update the rest of your application.
36
- */
37
-
38
- import * as Immutable from '../../';
39
-
40
- export function from(
41
- collection: Immutable.Collection<any, any>,
42
- onChange?: (newValue: any, oldValue?: any, keyPath?: Array<any>) => any
43
- ): Cursor;
44
- export function from(
45
- collection: Immutable.Collection<any, any>,
46
- keyPath: Array<any>,
47
- onChange?: (newValue: any, oldValue?: any, keyPath?: Array<any>) => any
48
- ): Cursor;
49
- export function from(
50
- collection: Immutable.Collection<any, any>,
51
- key: any,
52
- onChange?: (newValue: any, oldValue?: any, keyPath?: Array<any>) => any
53
- ): Cursor;
54
-
55
-
56
- export interface Cursor extends Immutable.Iterable<any, any>, Immutable.Seq<any, any> {
57
-
58
- /**
59
- * Returns a sub-cursor following the key-path starting from this cursor.
60
- */
61
- cursor(subKeyPath: Array<any>): Cursor;
62
- cursor(subKey: any): Cursor;
63
-
64
- /**
65
- * Returns the value at the cursor, if the cursor path does not yet exist,
66
- * returns `notSetValue`.
67
- */
68
- deref(notSetValue?: any): any;
69
-
70
- /**
71
- * Returns the value at the `key` in the cursor, or `notSetValue` if it
72
- * does not exist.
73
- *
74
- * If the key would return a collection, a new Cursor is returned.
75
- */
76
- get(key: any, notSetValue?: any): any;
77
-
78
- /**
79
- * Returns the value at the `keyPath` in the cursor, or `notSetValue` if it
80
- * does not exist.
81
- *
82
- * If the keyPath would return a collection, a new Cursor is returned.
83
- */
84
- getIn(keyPath: Array<any>, notSetValue?: any): any;
85
- getIn(keyPath: Immutable.Iterable<any, any>, notSetValue?: any): any;
86
-
87
- /**
88
- * Sets `value` at `key` in the cursor, returning a new cursor to the same
89
- * point in the new data.
90
- *
91
- * If only one parameter is provided, it is set directly as the cursor's value.
92
- */
93
- set(key: any, value: any): Cursor;
94
- set(value: any): Cursor;
95
-
96
- /**
97
- * Deletes `key` from the cursor, returning a new cursor to the same
98
- * point in the new data.
99
- *
100
- * Note: `delete` cannot be safely used in IE8
101
- * @alias remove
102
- */
103
- delete(key: any): Cursor;
104
- remove(key: any): Cursor;
105
-
106
- /**
107
- * Clears the value at this cursor, returning a new cursor to the same
108
- * point in the new data.
109
- */
110
- clear(): Cursor;
111
-
112
- /**
113
- * Updates the value in the data this cursor points to, triggering the
114
- * callback for the root cursor and returning a new cursor pointing to the
115
- * new data.
116
- */
117
- update(updater: (value: any) => any): Cursor;
118
- update(key: any, updater: (value: any) => any): Cursor;
119
- update(key: any, notSetValue: any, updater: (value: any) => any): Cursor;
120
-
121
- /**
122
- * @see `Map#merge`
123
- */
124
- merge(...iterables: Immutable.Iterable<any, any>[]): Cursor;
125
- merge(...iterables: {[key: string]: any}[]): Cursor;
126
-
127
- /**
128
- * @see `Map#mergeWith`
129
- */
130
- mergeWith(
131
- merger: (previous?: any, next?: any) => any,
132
- ...iterables: Immutable.Iterable<any, any>[]
133
- ): Cursor;
134
- mergeWith(
135
- merger: (previous?: any, next?: any) => any,
136
- ...iterables: {[key: string]: any}[]
137
- ): Cursor;
138
-
139
- /**
140
- * @see `Map#mergeDeep`
141
- */
142
- mergeDeep(...iterables: Immutable.Iterable<any, any>[]): Cursor;
143
- mergeDeep(...iterables: {[key: string]: any}[]): Cursor;
144
-
145
- /**
146
- * @see `Map#mergeDeepWith`
147
- */
148
- mergeDeepWith(
149
- merger: (previous?: any, next?: any) => any,
150
- ...iterables: Immutable.Iterable<any, any>[]
151
- ): Cursor;
152
- mergeDeepWith(
153
- merger: (previous?: any, next?: any) => any,
154
- ...iterables: {[key: string]: any}[]
155
- ): Cursor;
156
-
157
- // Deep persistent changes
158
-
159
- /**
160
- * Returns a new Cursor having set `value` at this `keyPath`. If any keys in
161
- * `keyPath` do not exist, a new immutable Map will be created at that key.
162
- */
163
- setIn(keyPath: Array<any>, value: any): Cursor;
164
- setIn(keyPath: Immutable.Iterable<any, any>, value: any): Cursor;
165
-
166
- /**
167
- * Returns a new Cursor with provided `values` appended
168
- */
169
- push(...values: Array<any>): Cursor;
170
-
171
- /**
172
- * Returns a new Cursor with a size ones less than this Cursor,
173
- * excluding the last index in this Cursor.
174
- */
175
- pop(): Cursor;
176
-
177
- /**
178
- * Returns a new Cursor with the provided `values` prepended,
179
- * shifting other values ahead to higher indices.
180
- */
181
- unshift(...values: Array<any>): Cursor;
182
-
183
- /**
184
- * Returns a new Cursor with a size ones less than this Cursor, excluding
185
- * the first index in this Cursor, shifting all other values to a lower index.
186
- */
187
- shift(): Cursor;
188
-
189
- /**
190
- * Returns a new Cursor having removed the value at this `keyPath`.
191
- *
192
- * @alias removeIn
193
- */
194
- deleteIn(keyPath: Array<any>): Cursor;
195
- deleteIn(keyPath: Immutable.Iterable<any, any>): Cursor;
196
- removeIn(keyPath: Array<any>): Cursor;
197
- removeIn(keyPath: Immutable.Iterable<any, any>): Cursor;
198
-
199
- /**
200
- * Returns a new Cursor having applied the `updater` to the value found at
201
- * the keyPath.
202
- *
203
- * If any keys in `keyPath` do not exist, new Immutable `Map`s will
204
- * be created at those keys. If the `keyPath` does not already contain a
205
- * value, the `updater` function will be called with `notSetValue`, if
206
- * provided, otherwise `undefined`.
207
- *
208
- * If the `updater` function returns the same value it was called with, then
209
- * no change will occur. This is still true if `notSetValue` is provided.
210
- */
211
- updateIn(
212
- keyPath: Array<any>,
213
- updater: (value: any) => any
214
- ): Cursor;
215
- updateIn(
216
- keyPath: Array<any>,
217
- notSetValue: any,
218
- updater: (value: any) => any
219
- ): Cursor;
220
- updateIn(
221
- keyPath: Immutable.Iterable<any, any>,
222
- updater: (value: any) => any
223
- ): Cursor;
224
- updateIn(
225
- keyPath: Immutable.Iterable<any, any>,
226
- notSetValue: any,
227
- updater: (value: any) => any
228
- ): Cursor;
229
-
230
- /**
231
- * A combination of `updateIn` and `merge`, returning a new Cursor, but
232
- * performing the merge at a point arrived at by following the keyPath.
233
- * In other words, these two lines are equivalent:
234
- *
235
- * x.updateIn(['a', 'b', 'c'], abc => abc.merge(y));
236
- * x.mergeIn(['a', 'b', 'c'], y);
237
- *
238
- */
239
- mergeIn(
240
- keyPath: Immutable.Iterable<any, any>,
241
- ...iterables: Immutable.Iterable<any, any>[]
242
- ): Cursor;
243
- mergeIn(
244
- keyPath: Array<any>,
245
- ...iterables: Immutable.Iterable<any, any>[]
246
- ): Cursor;
247
- mergeIn(
248
- keyPath: Array<any>,
249
- ...iterables: {[key: string]: any}[]
250
- ): Cursor;
251
-
252
- /**
253
- * A combination of `updateIn` and `mergeDeep`, returning a new Cursor, but
254
- * performing the deep merge at a point arrived at by following the keyPath.
255
- * In other words, these two lines are equivalent:
256
- *
257
- * x.updateIn(['a', 'b', 'c'], abc => abc.mergeDeep(y));
258
- * x.mergeDeepIn(['a', 'b', 'c'], y);
259
- *
260
- */
261
- mergeDeepIn(
262
- keyPath: Immutable.Iterable<any, any>,
263
- ...iterables: Immutable.Iterable<any, any>[]
264
- ): Cursor;
265
- mergeDeepIn(
266
- keyPath: Array<any>,
267
- ...iterables: Immutable.Iterable<any, any>[]
268
- ): Cursor;
269
- mergeDeepIn(
270
- keyPath: Array<any>,
271
- ...iterables: {[key: string]: any}[]
272
- ): Cursor;
273
-
274
- // Transient changes
275
-
276
- /**
277
- * Every time you call one of the above functions, a new immutable value is
278
- * created and the callback is triggered. If you need to apply a series of
279
- * mutations to a Cursor without triggering the callback repeatedly,
280
- * `withMutations()` creates a temporary mutable copy of the value which
281
- * can apply mutations in a highly performant manner. Afterwards the
282
- * callback is triggered with the final value.
283
- */
284
- withMutations(mutator: (mutable: any) => any): Cursor;
285
-
286
- /**
287
- * @ignore
288
- */
289
- map(fn: (v: any, k: any, c: this) => any): this;
290
- }
@@ -1,362 +0,0 @@
1
- /**
2
- * Copyright (c) 2014-2015, Facebook, Inc.
3
- * All rights reserved.
4
- *
5
- * This source code is licensed under the BSD-style license found in the
6
- * LICENSE file in the root directory of this source tree. An additional grant
7
- * of patent rights can be found in the PATENTS file in the same directory.
8
- */
9
-
10
- /**
11
- * DEPRECATED
12
- *
13
- * The Cursor API is deprecated and will be removed in a future major release.
14
- *
15
- * It is strongly suggested that you use the excellent `immutable-cursor` module
16
- * which has an extremely similar API but is much higher quality.
17
- *
18
- * https://github.com/redbadger/immutable-cursor
19
- */
20
- typeof console === 'object' && console.warn && console.warn(
21
- 'The Cursor API is deprecated and will be removed in a future major release.\n' +
22
- '\n' +
23
- 'It is strongly suggested that you use the excellent `immutable-cursor` module\n' +
24
- 'which has an extremely similar API but is much higher quality.\n' +
25
- '\n' +
26
- 'https://github.com/redbadger/immutable-cursor\n' +
27
- );
28
-
29
- /**
30
- * Cursor is expected to be required in a node or other CommonJS context:
31
- *
32
- * var Cursor = require('immutable/contrib/cursor');
33
- *
34
- * If you wish to use it in the browser, please check out Browserify or WebPack!
35
- */
36
-
37
- var Immutable = require('../../');
38
- var Iterable = Immutable.Iterable;
39
- var Iterator = Iterable.Iterator;
40
- var Seq = Immutable.Seq;
41
- var Map = Immutable.Map;
42
- var Record = Immutable.Record;
43
-
44
-
45
- function cursorFrom(rootData, keyPath, onChange) {
46
- if (arguments.length === 1) {
47
- keyPath = [];
48
- } else if (typeof keyPath === 'function') {
49
- onChange = keyPath;
50
- keyPath = [];
51
- } else {
52
- keyPath = valToKeyPath(keyPath);
53
- }
54
- return makeCursor(rootData, keyPath, onChange);
55
- }
56
-
57
-
58
- var KeyedCursorPrototype = Object.create(Seq.Keyed.prototype);
59
- var IndexedCursorPrototype = Object.create(Seq.Indexed.prototype);
60
-
61
- function KeyedCursor(rootData, keyPath, onChange, size) {
62
- this.size = size;
63
- this._rootData = rootData;
64
- this._keyPath = keyPath;
65
- this._onChange = onChange;
66
- }
67
- KeyedCursorPrototype.constructor = KeyedCursor;
68
-
69
- function IndexedCursor(rootData, keyPath, onChange, size) {
70
- this.size = size;
71
- this._rootData = rootData;
72
- this._keyPath = keyPath;
73
- this._onChange = onChange;
74
- }
75
- IndexedCursorPrototype.constructor = IndexedCursor;
76
-
77
- KeyedCursorPrototype.toString = function() {
78
- return this.__toString('Cursor {', '}');
79
- }
80
- IndexedCursorPrototype.toString = function() {
81
- return this.__toString('Cursor [', ']');
82
- }
83
-
84
- KeyedCursorPrototype.deref =
85
- KeyedCursorPrototype.valueOf =
86
- IndexedCursorPrototype.deref =
87
- IndexedCursorPrototype.valueOf = function(notSetValue) {
88
- return this._rootData.getIn(this._keyPath, notSetValue);
89
- }
90
-
91
- KeyedCursorPrototype.get =
92
- IndexedCursorPrototype.get = function(key, notSetValue) {
93
- return this.getIn([key], notSetValue);
94
- }
95
-
96
- KeyedCursorPrototype.getIn =
97
- IndexedCursorPrototype.getIn = function(keyPath, notSetValue) {
98
- keyPath = listToKeyPath(keyPath);
99
- if (keyPath.length === 0) {
100
- return this;
101
- }
102
- var value = this._rootData.getIn(newKeyPath(this._keyPath, keyPath), NOT_SET);
103
- return value === NOT_SET ? notSetValue : wrappedValue(this, keyPath, value);
104
- }
105
-
106
- IndexedCursorPrototype.set =
107
- KeyedCursorPrototype.set = function(key, value) {
108
- if(arguments.length === 1) {
109
- return updateCursor(this, function() { return key; }, []);
110
- } else {
111
- return updateCursor(this, function (m) { return m.set(key, value); }, [key]);
112
- }
113
- }
114
-
115
- IndexedCursorPrototype.push = function(/* values */) {
116
- var args = arguments;
117
- return updateCursor(this, function (m) {
118
- return m.push.apply(m, args);
119
- });
120
- }
121
-
122
- IndexedCursorPrototype.pop = function() {
123
- return updateCursor(this, function (m) {
124
- return m.pop();
125
- });
126
- }
127
-
128
- IndexedCursorPrototype.unshift = function(/* values */) {
129
- var args = arguments;
130
- return updateCursor(this, function (m) {
131
- return m.unshift.apply(m, args);
132
- });
133
- }
134
-
135
- IndexedCursorPrototype.shift = function() {
136
- return updateCursor(this, function (m) {
137
- return m.shift();
138
- });
139
- }
140
-
141
- IndexedCursorPrototype.setIn =
142
- KeyedCursorPrototype.setIn = Map.prototype.setIn;
143
-
144
- KeyedCursorPrototype.remove =
145
- KeyedCursorPrototype['delete'] =
146
- IndexedCursorPrototype.remove =
147
- IndexedCursorPrototype['delete'] = function(key) {
148
- return updateCursor(this, function (m) { return m.remove(key); }, [key]);
149
- }
150
-
151
- IndexedCursorPrototype.removeIn =
152
- IndexedCursorPrototype.deleteIn =
153
- KeyedCursorPrototype.removeIn =
154
- KeyedCursorPrototype.deleteIn = Map.prototype.deleteIn;
155
-
156
- KeyedCursorPrototype.clear =
157
- IndexedCursorPrototype.clear = function() {
158
- return updateCursor(this, function (m) { return m.clear(); });
159
- }
160
-
161
- IndexedCursorPrototype.update =
162
- KeyedCursorPrototype.update = function(keyOrFn, notSetValue, updater) {
163
- return arguments.length === 1 ?
164
- updateCursor(this, keyOrFn) :
165
- this.updateIn([keyOrFn], notSetValue, updater);
166
- }
167
-
168
- IndexedCursorPrototype.updateIn =
169
- KeyedCursorPrototype.updateIn = function(keyPath, notSetValue, updater) {
170
- return updateCursor(this, function (m) {
171
- return m.updateIn(keyPath, notSetValue, updater);
172
- }, keyPath);
173
- }
174
-
175
- IndexedCursorPrototype.merge =
176
- KeyedCursorPrototype.merge = function(/*...iters*/) {
177
- var args = arguments;
178
- return updateCursor(this, function (m) {
179
- return m.merge.apply(m, args);
180
- });
181
- }
182
-
183
- IndexedCursorPrototype.mergeWith =
184
- KeyedCursorPrototype.mergeWith = function(merger/*, ...iters*/) {
185
- var args = arguments;
186
- return updateCursor(this, function (m) {
187
- return m.mergeWith.apply(m, args);
188
- });
189
- }
190
-
191
- IndexedCursorPrototype.mergeIn =
192
- KeyedCursorPrototype.mergeIn = Map.prototype.mergeIn;
193
-
194
- IndexedCursorPrototype.mergeDeep =
195
- KeyedCursorPrototype.mergeDeep = function(/*...iters*/) {
196
- var args = arguments;
197
- return updateCursor(this, function (m) {
198
- return m.mergeDeep.apply(m, args);
199
- });
200
- }
201
-
202
- IndexedCursorPrototype.mergeDeepWith =
203
- KeyedCursorPrototype.mergeDeepWith = function(merger/*, ...iters*/) {
204
- var args = arguments;
205
- return updateCursor(this, function (m) {
206
- return m.mergeDeepWith.apply(m, args);
207
- });
208
- }
209
-
210
- IndexedCursorPrototype.mergeDeepIn =
211
- KeyedCursorPrototype.mergeDeepIn = Map.prototype.mergeDeepIn;
212
-
213
- KeyedCursorPrototype.withMutations =
214
- IndexedCursorPrototype.withMutations = function(fn) {
215
- return updateCursor(this, function (m) {
216
- return (m || Map()).withMutations(fn);
217
- });
218
- }
219
-
220
- KeyedCursorPrototype.cursor =
221
- IndexedCursorPrototype.cursor = function(subKeyPath) {
222
- subKeyPath = valToKeyPath(subKeyPath);
223
- return subKeyPath.length === 0 ? this : subCursor(this, subKeyPath);
224
- }
225
-
226
- /**
227
- * All iterables need to implement __iterate
228
- */
229
- KeyedCursorPrototype.__iterate =
230
- IndexedCursorPrototype.__iterate = function(fn, reverse) {
231
- var cursor = this;
232
- var deref = cursor.deref();
233
- return deref && deref.__iterate ? deref.__iterate(
234
- function (v, k) { return fn(wrappedValue(cursor, [k], v), k, cursor); },
235
- reverse
236
- ) : 0;
237
- }
238
-
239
- /**
240
- * All iterables need to implement __iterator
241
- */
242
- KeyedCursorPrototype.__iterator =
243
- IndexedCursorPrototype.__iterator = function(type, reverse) {
244
- var deref = this.deref();
245
- var cursor = this;
246
- var iterator = deref && deref.__iterator &&
247
- deref.__iterator(Iterator.ENTRIES, reverse);
248
- return new Iterator(function () {
249
- if (!iterator) {
250
- return { value: undefined, done: true };
251
- }
252
- var step = iterator.next();
253
- if (step.done) {
254
- return step;
255
- }
256
- var entry = step.value;
257
- var k = entry[0];
258
- var v = wrappedValue(cursor, [k], entry[1]);
259
- return {
260
- value: type === Iterator.KEYS ? k : type === Iterator.VALUES ? v : [k, v],
261
- done: false
262
- };
263
- });
264
- }
265
-
266
- KeyedCursor.prototype = KeyedCursorPrototype;
267
- IndexedCursor.prototype = IndexedCursorPrototype;
268
-
269
-
270
- var NOT_SET = {}; // Sentinel value
271
-
272
- function makeCursor(rootData, keyPath, onChange, value) {
273
- if (arguments.length < 4) {
274
- value = rootData.getIn(keyPath);
275
- }
276
- var size = value && value.size;
277
- var CursorClass = Iterable.isIndexed(value) ? IndexedCursor : KeyedCursor;
278
- var cursor = new CursorClass(rootData, keyPath, onChange, size);
279
-
280
- if (value instanceof Record) {
281
- defineRecordProperties(cursor, value);
282
- }
283
-
284
- return cursor;
285
- }
286
-
287
- function defineRecordProperties(cursor, value) {
288
- try {
289
- value._keys.forEach(setProp.bind(undefined, cursor));
290
- } catch (error) {
291
- // Object.defineProperty failed. Probably IE8.
292
- }
293
- }
294
-
295
- function setProp(prototype, name) {
296
- Object.defineProperty(prototype, name, {
297
- get: function() {
298
- return this.get(name);
299
- },
300
- set: function(value) {
301
- if (!this.__ownerID) {
302
- throw new Error('Cannot set on an immutable record.');
303
- }
304
- }
305
- });
306
- }
307
-
308
- function wrappedValue(cursor, keyPath, value) {
309
- return Iterable.isIterable(value) ? subCursor(cursor, keyPath, value) : value;
310
- }
311
-
312
- function subCursor(cursor, keyPath, value) {
313
- if (arguments.length < 3) {
314
- return makeCursor( // call without value
315
- cursor._rootData,
316
- newKeyPath(cursor._keyPath, keyPath),
317
- cursor._onChange
318
- );
319
- }
320
- return makeCursor(
321
- cursor._rootData,
322
- newKeyPath(cursor._keyPath, keyPath),
323
- cursor._onChange,
324
- value
325
- );
326
- }
327
-
328
- function updateCursor(cursor, changeFn, changeKeyPath) {
329
- var deepChange = arguments.length > 2;
330
- var newRootData = cursor._rootData.updateIn(
331
- cursor._keyPath,
332
- deepChange ? Map() : undefined,
333
- changeFn
334
- );
335
- var keyPath = cursor._keyPath || [];
336
- var result = cursor._onChange && cursor._onChange.call(
337
- undefined,
338
- newRootData,
339
- cursor._rootData,
340
- deepChange ? newKeyPath(keyPath, changeKeyPath) : keyPath
341
- );
342
- if (result !== undefined) {
343
- newRootData = result;
344
- }
345
- return makeCursor(newRootData, cursor._keyPath, cursor._onChange);
346
- }
347
-
348
- function newKeyPath(head, tail) {
349
- return head.concat(listToKeyPath(tail));
350
- }
351
-
352
- function listToKeyPath(list) {
353
- return Array.isArray(list) ? list : Immutable.Iterable(list).toArray();
354
- }
355
-
356
- function valToKeyPath(val) {
357
- return Array.isArray(val) ? val :
358
- Iterable.isIterable(val) ? val.toArray() :
359
- [val];
360
- }
361
-
362
- exports.from = cursorFrom;