1 | (function() {
|
2 | "use strict";
|
3 |
|
4 |
|
5 | var REACT_ELEMENT_TYPE = typeof Symbol === 'function' && Symbol.for && Symbol.for('react.element');
|
6 | var REACT_ELEMENT_TYPE_FALLBACK = 0xeac7;
|
7 |
|
8 | function addPropertyTo(target, methodName, value) {
|
9 | Object.defineProperty(target, methodName, {
|
10 | enumerable: false,
|
11 | configurable: false,
|
12 | writable: false,
|
13 | value: value
|
14 | });
|
15 | }
|
16 |
|
17 | function banProperty(target, methodName) {
|
18 | addPropertyTo(target, methodName, function() {
|
19 | throw new ImmutableError("The " + methodName +
|
20 | " method cannot be invoked on an Immutable data structure.");
|
21 | });
|
22 | }
|
23 |
|
24 | var immutabilityTag = "__immutable_invariants_hold";
|
25 |
|
26 | function addImmutabilityTag(target) {
|
27 | addPropertyTo(target, immutabilityTag, true);
|
28 | }
|
29 |
|
30 | function isImmutable(target) {
|
31 | if (typeof target === "object") {
|
32 | return target === null || Boolean(
|
33 | Object.getOwnPropertyDescriptor(target, immutabilityTag)
|
34 | );
|
35 | } else {
|
36 |
|
37 |
|
38 | return true;
|
39 | }
|
40 | }
|
41 |
|
42 | function isEqual(a, b) {
|
43 |
|
44 | return (a === b || (a !== a && b !== b));
|
45 | }
|
46 |
|
47 | function isMergableObject(target) {
|
48 | return target !== null && typeof target === "object" && !(Array.isArray(target)) && !(target instanceof Date);
|
49 | }
|
50 |
|
51 | var mutatingObjectMethods = [
|
52 | "setPrototypeOf"
|
53 | ];
|
54 |
|
55 | var nonMutatingObjectMethods = [
|
56 | "keys"
|
57 | ];
|
58 |
|
59 | var mutatingArrayMethods = mutatingObjectMethods.concat([
|
60 | "push", "pop", "sort", "splice", "shift", "unshift", "reverse"
|
61 | ]);
|
62 |
|
63 | var nonMutatingArrayMethods = nonMutatingObjectMethods.concat([
|
64 | "map", "filter", "slice", "concat", "reduce", "reduceRight"
|
65 | ]);
|
66 |
|
67 | var mutatingDateMethods = mutatingObjectMethods.concat([
|
68 | "setDate", "setFullYear", "setHours", "setMilliseconds", "setMinutes", "setMonth", "setSeconds",
|
69 | "setTime", "setUTCDate", "setUTCFullYear", "setUTCHours", "setUTCMilliseconds", "setUTCMinutes",
|
70 | "setUTCMonth", "setUTCSeconds", "setYear"
|
71 | ]);
|
72 |
|
73 | function ImmutableError(message) {
|
74 | var err = new Error(message);
|
75 |
|
76 | err.__proto__ = ImmutableError;
|
77 |
|
78 | return err;
|
79 | }
|
80 | ImmutableError.prototype = Error.prototype;
|
81 |
|
82 | function makeImmutable(obj, bannedMethods) {
|
83 |
|
84 | addImmutabilityTag(obj);
|
85 |
|
86 | if ("development" !== "production") {
|
87 |
|
88 | for (var index in bannedMethods) {
|
89 | if (bannedMethods.hasOwnProperty(index)) {
|
90 | banProperty(obj, bannedMethods[index]);
|
91 | }
|
92 | }
|
93 |
|
94 |
|
95 | Object.freeze(obj);
|
96 | }
|
97 |
|
98 | return obj;
|
99 | }
|
100 |
|
101 | function makeMethodReturnImmutable(obj, methodName) {
|
102 | var currentMethod = obj[methodName];
|
103 |
|
104 | addPropertyTo(obj, methodName, function() {
|
105 | return Immutable(currentMethod.apply(obj, arguments));
|
106 | });
|
107 | }
|
108 |
|
109 | function arraySet(idx, value, config) {
|
110 | var deep = config && config.deep;
|
111 |
|
112 | if (idx in this) {
|
113 | if (deep && this[idx] !== value && isMergableObject(value) && isMergableObject(this[idx])) {
|
114 | value = this[idx].merge(value, {deep: true, mode: 'replace'});
|
115 | }
|
116 | if (isEqual(this[idx], value)) {
|
117 | return this;
|
118 | }
|
119 | }
|
120 |
|
121 | var mutable = asMutableArray.call(this);
|
122 | mutable[idx] = Immutable(value);
|
123 | return makeImmutableArray(mutable);
|
124 | }
|
125 |
|
126 | var immutableEmptyArray = Immutable([]);
|
127 |
|
128 | function arraySetIn(pth, value, config) {
|
129 | var head = pth[0];
|
130 |
|
131 | if (pth.length === 1) {
|
132 | return arraySet.call(this, head, value, config);
|
133 | } else {
|
134 | var tail = pth.slice(1);
|
135 | var thisHead = this[head];
|
136 | var newValue;
|
137 |
|
138 | if (typeof(thisHead) === "object" && thisHead !== null && typeof(thisHead.setIn) === "function") {
|
139 |
|
140 | newValue = thisHead.setIn(tail, value);
|
141 | } else {
|
142 | var nextHead = tail[0];
|
143 |
|
144 | if (nextHead !== '' && isFinite(nextHead)) {
|
145 | newValue = arraySetIn.call(immutableEmptyArray, tail, value);
|
146 | } else {
|
147 | newValue = objectSetIn.call(immutableEmptyObject, tail, value);
|
148 | }
|
149 | }
|
150 |
|
151 | if (head in this && thisHead === newValue) {
|
152 | return this;
|
153 | }
|
154 |
|
155 | var mutable = asMutableArray.call(this);
|
156 | mutable[head] = newValue;
|
157 | return makeImmutableArray(mutable);
|
158 | }
|
159 | }
|
160 |
|
161 | function makeImmutableArray(array) {
|
162 |
|
163 |
|
164 | for (var index in nonMutatingArrayMethods) {
|
165 | if (nonMutatingArrayMethods.hasOwnProperty(index)) {
|
166 | var methodName = nonMutatingArrayMethods[index];
|
167 | makeMethodReturnImmutable(array, methodName);
|
168 | }
|
169 | }
|
170 |
|
171 | addPropertyTo(array, "flatMap", flatMap);
|
172 | addPropertyTo(array, "asObject", asObject);
|
173 | addPropertyTo(array, "asMutable", asMutableArray);
|
174 | addPropertyTo(array, "set", arraySet);
|
175 | addPropertyTo(array, "setIn", arraySetIn);
|
176 | addPropertyTo(array, "update", update);
|
177 | addPropertyTo(array, "updateIn", updateIn);
|
178 |
|
179 | for(var i = 0, length = array.length; i < length; i++) {
|
180 | array[i] = Immutable(array[i]);
|
181 | }
|
182 |
|
183 | return makeImmutable(array, mutatingArrayMethods);
|
184 | }
|
185 |
|
186 | function makeImmutableDate(date) {
|
187 | addPropertyTo(date, "asMutable", asMutableDate);
|
188 |
|
189 | return makeImmutable(date, mutatingDateMethods);
|
190 | }
|
191 |
|
192 | function asMutableDate() {
|
193 | return new Date(this.getTime());
|
194 | }
|
195 |
|
196 | |
197 |
|
198 |
|
199 |
|
200 |
|
201 |
|
202 |
|
203 | function flatMap(iterator) {
|
204 |
|
205 | if (arguments.length === 0) {
|
206 | return this;
|
207 | }
|
208 |
|
209 | var result = [],
|
210 | length = this.length,
|
211 | index;
|
212 |
|
213 | for (index = 0; index < length; index++) {
|
214 | var iteratorResult = iterator(this[index], index, this);
|
215 |
|
216 | if (Array.isArray(iteratorResult)) {
|
217 |
|
218 | result.push.apply(result, iteratorResult);
|
219 | } else {
|
220 |
|
221 | result.push(iteratorResult);
|
222 | }
|
223 | }
|
224 |
|
225 | return makeImmutableArray(result);
|
226 | }
|
227 |
|
228 | |
229 |
|
230 |
|
231 |
|
232 |
|
233 | function without(remove) {
|
234 |
|
235 | if (typeof remove === "undefined" && arguments.length === 0) {
|
236 | return this;
|
237 | }
|
238 |
|
239 | if (typeof remove !== "function") {
|
240 |
|
241 | var keysToRemoveArray = (Array.isArray(remove)) ?
|
242 | remove.slice() : Array.prototype.slice.call(arguments);
|
243 |
|
244 |
|
245 |
|
246 | keysToRemoveArray.forEach(function(el, idx, arr) {
|
247 | if(typeof(el) === "number") {
|
248 | arr[idx] = el.toString();
|
249 | }
|
250 | });
|
251 |
|
252 | remove = function(val, key) {
|
253 | return keysToRemoveArray.indexOf(key) !== -1;
|
254 | };
|
255 | }
|
256 |
|
257 | var result = this.instantiateEmptyObject();
|
258 |
|
259 | for (var key in this) {
|
260 | if (this.hasOwnProperty(key) && remove(this[key], key) === false) {
|
261 | result[key] = this[key];
|
262 | }
|
263 | }
|
264 |
|
265 | return makeImmutableObject(result,
|
266 | {instantiateEmptyObject: this.instantiateEmptyObject});
|
267 | }
|
268 |
|
269 | function asMutableArray(opts) {
|
270 | var result = [], i, length;
|
271 |
|
272 | if(opts && opts.deep) {
|
273 | for(i = 0, length = this.length; i < length; i++) {
|
274 | result.push(asDeepMutable(this[i]));
|
275 | }
|
276 | } else {
|
277 | for(i = 0, length = this.length; i < length; i++) {
|
278 | result.push(this[i]);
|
279 | }
|
280 | }
|
281 |
|
282 | return result;
|
283 | }
|
284 |
|
285 | |
286 |
|
287 |
|
288 |
|
289 |
|
290 |
|
291 |
|
292 | function asObject(iterator) {
|
293 |
|
294 |
|
295 | if (typeof iterator !== "function") {
|
296 | iterator = function(value) { return value; };
|
297 | }
|
298 |
|
299 | var result = {},
|
300 | length = this.length,
|
301 | index;
|
302 |
|
303 | for (index = 0; index < length; index++) {
|
304 | var pair = iterator(this[index], index, this),
|
305 | key = pair[0],
|
306 | value = pair[1];
|
307 |
|
308 | result[key] = value;
|
309 | }
|
310 |
|
311 | return makeImmutableObject(result);
|
312 | }
|
313 |
|
314 | function asDeepMutable(obj) {
|
315 | if (
|
316 | (!obj) ||
|
317 | (typeof obj !== 'object') ||
|
318 | (!Object.getOwnPropertyDescriptor(obj, immutabilityTag)) ||
|
319 | (obj instanceof Date)
|
320 | ) { return obj; }
|
321 | return obj.asMutable({deep: true});
|
322 | }
|
323 |
|
324 | function quickCopy(src, dest) {
|
325 | for (var key in src) {
|
326 | if (Object.getOwnPropertyDescriptor(src, key)) {
|
327 | dest[key] = src[key];
|
328 | }
|
329 | }
|
330 |
|
331 | return dest;
|
332 | }
|
333 |
|
334 | |
335 |
|
336 |
|
337 |
|
338 |
|
339 |
|
340 |
|
341 |
|
342 |
|
343 | function merge(other, config) {
|
344 |
|
345 | if (arguments.length === 0) {
|
346 | return this;
|
347 | }
|
348 |
|
349 | if (other === null || (typeof other !== "object")) {
|
350 | throw new TypeError("Immutable#merge can only be invoked with objects or arrays, not " + JSON.stringify(other));
|
351 | }
|
352 |
|
353 | var receivedArray = (Array.isArray(other)),
|
354 | deep = config && config.deep,
|
355 | mode = config && config.mode || 'merge',
|
356 | merger = config && config.merger,
|
357 | result;
|
358 |
|
359 |
|
360 |
|
361 |
|
362 | function addToResult(currentObj, otherObj, key) {
|
363 | var immutableValue = Immutable(otherObj[key]);
|
364 | var mergerResult = merger && merger(currentObj[key], immutableValue, config);
|
365 | var currentValue = currentObj[key];
|
366 |
|
367 | if ((result !== undefined) ||
|
368 | (mergerResult !== undefined) ||
|
369 | (!currentObj.hasOwnProperty(key)) ||
|
370 | !isEqual(immutableValue, currentValue)) {
|
371 |
|
372 | var newValue;
|
373 |
|
374 | if (mergerResult) {
|
375 | newValue = mergerResult;
|
376 | } else if (deep && isMergableObject(currentValue) && isMergableObject(immutableValue)) {
|
377 | newValue = currentValue.merge(immutableValue, config);
|
378 | } else {
|
379 | newValue = immutableValue;
|
380 | }
|
381 |
|
382 | if (!isEqual(currentValue, newValue) || !currentObj.hasOwnProperty(key)) {
|
383 | if (result === undefined) {
|
384 |
|
385 | result = quickCopy(currentObj, currentObj.instantiateEmptyObject());
|
386 | }
|
387 |
|
388 | result[key] = newValue;
|
389 | }
|
390 | }
|
391 | }
|
392 |
|
393 | function clearDroppedKeys(currentObj, otherObj) {
|
394 | for (var key in currentObj) {
|
395 | if (!otherObj.hasOwnProperty(key)) {
|
396 | if (result === undefined) {
|
397 |
|
398 | result = quickCopy(currentObj, currentObj.instantiateEmptyObject());
|
399 | }
|
400 | delete result[key];
|
401 | }
|
402 | }
|
403 | }
|
404 |
|
405 | var key;
|
406 |
|
407 |
|
408 | if (!receivedArray) {
|
409 |
|
410 | for (key in other) {
|
411 | if (Object.getOwnPropertyDescriptor(other, key)) {
|
412 | addToResult(this, other, key);
|
413 | }
|
414 | }
|
415 | if (mode === 'replace') {
|
416 | clearDroppedKeys(this, other);
|
417 | }
|
418 | } else {
|
419 |
|
420 | for (var index = 0, length = other.length; index < length; index++) {
|
421 | var otherFromArray = other[index];
|
422 |
|
423 | for (key in otherFromArray) {
|
424 | if (otherFromArray.hasOwnProperty(key)) {
|
425 | addToResult(result !== undefined ? result : this, otherFromArray, key);
|
426 | }
|
427 | }
|
428 | }
|
429 | }
|
430 |
|
431 | if (result === undefined) {
|
432 | return this;
|
433 | } else {
|
434 | return makeImmutableObject(result,
|
435 | {instantiateEmptyObject: this.instantiateEmptyObject});
|
436 | }
|
437 | }
|
438 |
|
439 | function objectReplace(value, config) {
|
440 | var deep = config && config.deep;
|
441 |
|
442 |
|
443 | if (arguments.length === 0) {
|
444 | return this;
|
445 | }
|
446 |
|
447 | if (value === null || typeof value !== "object") {
|
448 | throw new TypeError("Immutable#replace can only be invoked with objects or arrays, not " + JSON.stringify(value));
|
449 | }
|
450 |
|
451 | return this.merge(value, {deep: deep, mode: 'replace'});
|
452 | }
|
453 |
|
454 | var immutableEmptyObject = Immutable({});
|
455 |
|
456 | function objectSetIn(path, value, config) {
|
457 | var head = path[0];
|
458 | if (path.length === 1) {
|
459 | return objectSet.call(this, head, value, config);
|
460 | }
|
461 |
|
462 | var tail = path.slice(1);
|
463 | var newValue;
|
464 | var thisHead = this[head];
|
465 |
|
466 | if (this.hasOwnProperty(head) && typeof(thisHead) === "object" && thisHead !== null && typeof(thisHead.setIn) === "function") {
|
467 |
|
468 | newValue = thisHead.setIn(tail, value);
|
469 | } else {
|
470 | newValue = objectSetIn.call(immutableEmptyObject, tail, value);
|
471 | }
|
472 |
|
473 | if (this.hasOwnProperty(head) && thisHead === newValue) {
|
474 | return this;
|
475 | }
|
476 |
|
477 | var mutable = quickCopy(this, this.instantiateEmptyObject());
|
478 | mutable[head] = newValue;
|
479 | return makeImmutableObject(mutable, this);
|
480 | }
|
481 |
|
482 | function objectSet(property, value, config) {
|
483 | var deep = config && config.deep;
|
484 |
|
485 | if (this.hasOwnProperty(property)) {
|
486 | if (deep && this[property] !== value && isMergableObject(value) && isMergableObject(this[property])) {
|
487 | value = this[property].merge(value, {deep: true, mode: 'replace'});
|
488 | }
|
489 | if (isEqual(this[property], value)) {
|
490 | return this;
|
491 | }
|
492 | }
|
493 |
|
494 | var mutable = quickCopy(this, this.instantiateEmptyObject());
|
495 | mutable[property] = Immutable(value);
|
496 | return makeImmutableObject(mutable, this);
|
497 | }
|
498 |
|
499 | function update(property, updater) {
|
500 | var restArgs = Array.prototype.slice.call(arguments, 2);
|
501 | var initialVal = this[property];
|
502 | return this.set(property, updater.apply(initialVal, [initialVal].concat(restArgs)));
|
503 | }
|
504 |
|
505 | function getInPath(obj, path) {
|
506 |
|
507 | for (var i = 0, l = path.length; obj != null && i < l; i++) {
|
508 | obj = obj[path[i]];
|
509 | }
|
510 |
|
511 | return (i && i == l) ? obj : undefined;
|
512 | }
|
513 |
|
514 | function updateIn(path, updater) {
|
515 | var restArgs = Array.prototype.slice.call(arguments, 2);
|
516 | var initialVal = getInPath(this, path);
|
517 |
|
518 | return this.setIn(path, updater.apply(initialVal, [initialVal].concat(restArgs)));
|
519 | }
|
520 |
|
521 | function asMutableObject(opts) {
|
522 | var result = this.instantiateEmptyObject(), key;
|
523 |
|
524 | if(opts && opts.deep) {
|
525 | for (key in this) {
|
526 | if (this.hasOwnProperty(key)) {
|
527 | result[key] = asDeepMutable(this[key]);
|
528 | }
|
529 | }
|
530 | } else {
|
531 | for (key in this) {
|
532 | if (this.hasOwnProperty(key)) {
|
533 | result[key] = this[key];
|
534 | }
|
535 | }
|
536 | }
|
537 |
|
538 | return result;
|
539 | }
|
540 |
|
541 |
|
542 | function instantiatePlainObject() {
|
543 | return {};
|
544 | }
|
545 |
|
546 |
|
547 | function makeImmutableObject(obj, options) {
|
548 | var instantiateEmptyObject =
|
549 | (options && options.instantiateEmptyObject) ?
|
550 | options.instantiateEmptyObject : instantiatePlainObject;
|
551 |
|
552 | addPropertyTo(obj, "merge", merge);
|
553 | addPropertyTo(obj, "replace", objectReplace);
|
554 | addPropertyTo(obj, "without", without);
|
555 | addPropertyTo(obj, "asMutable", asMutableObject);
|
556 | addPropertyTo(obj, "instantiateEmptyObject", instantiateEmptyObject);
|
557 | addPropertyTo(obj, "set", objectSet);
|
558 | addPropertyTo(obj, "setIn", objectSetIn);
|
559 | addPropertyTo(obj, "update", update);
|
560 | addPropertyTo(obj, "updateIn", updateIn);
|
561 |
|
562 | return makeImmutable(obj, mutatingObjectMethods);
|
563 | }
|
564 |
|
565 |
|
566 |
|
567 | function isReactElement(obj) {
|
568 | return typeof obj === 'object' &&
|
569 | obj !== null &&
|
570 | (obj.$$typeof === REACT_ELEMENT_TYPE_FALLBACK || obj.$$typeof === REACT_ELEMENT_TYPE);
|
571 | }
|
572 |
|
573 | function Immutable(obj, options, stackRemaining) {
|
574 | if (isImmutable(obj) || isReactElement(obj)) {
|
575 | return obj;
|
576 | } else if (Array.isArray(obj)) {
|
577 | return makeImmutableArray(obj.slice());
|
578 | } else if (obj instanceof Date) {
|
579 | return makeImmutableDate(new Date(obj.getTime()));
|
580 | } else {
|
581 |
|
582 | var prototype = options && options.prototype;
|
583 | var instantiateEmptyObject =
|
584 | (!prototype || prototype === Object.prototype) ?
|
585 | instantiatePlainObject : (function() { return Object.create(prototype); });
|
586 | var clone = instantiateEmptyObject();
|
587 |
|
588 | if ("development" !== "production") {
|
589 |
|
590 | if (stackRemaining == null) {
|
591 | stackRemaining = 64;
|
592 | }
|
593 | if (stackRemaining <= 0) {
|
594 | throw new ImmutableError("Attempt to construct Immutable from a deeply nested object was detected." +
|
595 | " Have you tried to wrap an object with circular references (e.g. React element)?" +
|
596 | " See https://github.com/rtfeldman/seamless-immutable/wiki/Deeply-nested-object-was-detected for details.");
|
597 | }
|
598 | stackRemaining -= 1;
|
599 | }
|
600 |
|
601 | for (var key in obj) {
|
602 | if (Object.getOwnPropertyDescriptor(obj, key)) {
|
603 | clone[key] = Immutable(obj[key], undefined, stackRemaining);
|
604 | }
|
605 | }
|
606 |
|
607 | return makeImmutableObject(clone,
|
608 | {instantiateEmptyObject: instantiateEmptyObject});
|
609 | }
|
610 | }
|
611 |
|
612 |
|
613 | function toStatic(fn) {
|
614 | function staticWrapper() {
|
615 | var args = [].slice.call(arguments);
|
616 | var self = args.shift();
|
617 | return fn.apply(self, args);
|
618 | }
|
619 |
|
620 | return staticWrapper;
|
621 | }
|
622 |
|
623 |
|
624 |
|
625 |
|
626 | function toStaticObjectOrArray(fnObject, fnArray) {
|
627 | function staticWrapper() {
|
628 | var args = [].slice.call(arguments);
|
629 | var self = args.shift();
|
630 | if (Array.isArray(self)) {
|
631 | return fnArray.apply(self, args);
|
632 | } else {
|
633 | return fnObject.apply(self, args);
|
634 | }
|
635 | }
|
636 |
|
637 | return staticWrapper;
|
638 | }
|
639 |
|
640 |
|
641 | Immutable.from = Immutable;
|
642 | Immutable.isImmutable = isImmutable;
|
643 | Immutable.ImmutableError = ImmutableError;
|
644 | Immutable.merge = toStatic(merge);
|
645 | Immutable.replace = toStatic(objectReplace);
|
646 | Immutable.without = toStatic(without);
|
647 | Immutable.asMutable = toStaticObjectOrArray(asMutableObject, asMutableArray);
|
648 | Immutable.set = toStaticObjectOrArray(objectSet, arraySet);
|
649 | Immutable.setIn = toStaticObjectOrArray(objectSetIn, arraySetIn);
|
650 | Immutable.update = toStatic(update);
|
651 | Immutable.updateIn = toStatic(updateIn);
|
652 | Immutable.flatMap = toStatic(flatMap);
|
653 | Immutable.asObject = toStatic(asObject);
|
654 |
|
655 | Object.freeze(Immutable);
|
656 |
|
657 |
|
658 | if (typeof module === "object") {
|
659 | module.exports = Immutable;
|
660 | } else if (typeof exports === "object") {
|
661 | exports.Immutable = Immutable;
|
662 | } else if (typeof window === "object") {
|
663 | window.Immutable = Immutable;
|
664 | } else if (typeof global === "object") {
|
665 | global.Immutable = Immutable;
|
666 | }
|
667 | })();
|