mobx 4.12.0 → 4.14.1

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/lib/mobx.es6.js CHANGED
@@ -4,8 +4,15 @@ const EMPTY_ARRAY = [];
4
4
  Object.freeze(EMPTY_ARRAY);
5
5
  const EMPTY_OBJECT = {};
6
6
  Object.freeze(EMPTY_OBJECT);
7
+ const mockGlobal = {};
7
8
  function getGlobal() {
8
- return typeof window !== "undefined" ? window : global;
9
+ if (typeof window !== "undefined") {
10
+ return window;
11
+ }
12
+ if (typeof global !== "undefined") {
13
+ return global;
14
+ }
15
+ return mockGlobal;
9
16
  }
10
17
  function getNextId() {
11
18
  return ++globalState.mobxGuid;
@@ -65,6 +72,20 @@ function isPlainObject(value) {
65
72
  const proto = Object.getPrototypeOf(value);
66
73
  return proto === Object.prototype || proto === null;
67
74
  }
75
+ function convertToMap(dataStructure) {
76
+ if (isES6Map(dataStructure) || isObservableMap(dataStructure)) {
77
+ return dataStructure;
78
+ }
79
+ else if (Array.isArray(dataStructure)) {
80
+ return new Map(dataStructure);
81
+ }
82
+ else if (isPlainObject(dataStructure)) {
83
+ return new Map(Object.entries(dataStructure));
84
+ }
85
+ else {
86
+ return fail(`Cannot convert to map from '${dataStructure}'`);
87
+ }
88
+ }
68
89
  function makeNonEnumerable(object, propNames) {
69
90
  for (let i = 0; i < propNames.length; i++) {
70
91
  addHiddenProp(object, propNames[i], object[propNames[i]]);
@@ -118,15 +139,6 @@ function isES6Map(thing) {
118
139
  function isES6Set(thing) {
119
140
  return thing instanceof Set;
120
141
  }
121
- function getMapLikeKeys(map) {
122
- if (isPlainObject(map))
123
- return Object.keys(map);
124
- if (Array.isArray(map))
125
- return map.map(([key]) => key);
126
- if (isES6Map(map) || isObservableMap(map))
127
- return iteratorToArray(map.keys());
128
- return fail(`Cannot get keys from '${map}'`);
129
- }
130
142
  // use Array.from in Mobx 5
131
143
  function iteratorToArray(it) {
132
144
  const res = [];
@@ -153,13 +165,13 @@ function declareIterator(prototType, iteratorFactory) {
153
165
  addHiddenFinalProp(prototType, iteratorSymbol(), iteratorFactory);
154
166
  }
155
167
  function makeIterable(iterator) {
156
- iterator[iteratorSymbol()] = self;
168
+ iterator[iteratorSymbol()] = getSelf;
157
169
  return iterator;
158
170
  }
159
171
  function toStringTagSymbol() {
160
172
  return (typeof Symbol === "function" && Symbol.toStringTag) || "@@toStringTag";
161
173
  }
162
- function self() {
174
+ function getSelf() {
163
175
  return this;
164
176
  }
165
177
 
@@ -223,13 +235,17 @@ function identityComparer(a, b) {
223
235
  function structuralComparer(a, b) {
224
236
  return deepEqual(a, b);
225
237
  }
238
+ function shallowComparer(a, b) {
239
+ return deepEqual(a, b, 1);
240
+ }
226
241
  function defaultComparer(a, b) {
227
242
  return areBothNaN(a, b) || identityComparer(a, b);
228
243
  }
229
244
  const comparer = {
230
245
  identity: identityComparer,
231
246
  structural: structuralComparer,
232
- default: defaultComparer
247
+ default: defaultComparer,
248
+ shallow: shallowComparer
233
249
  };
234
250
 
235
251
  const enumerableDescriptorCache = {};
@@ -549,6 +565,275 @@ const computed = function computed(arg1, arg2, arg3) {
549
565
  };
550
566
  computed.struct = computedStructDecorator;
551
567
 
568
+ var IDerivationState;
569
+ (function (IDerivationState) {
570
+ // before being run or (outside batch and not being observed)
571
+ // at this point derivation is not holding any data about dependency tree
572
+ IDerivationState[IDerivationState["NOT_TRACKING"] = -1] = "NOT_TRACKING";
573
+ // no shallow dependency changed since last computation
574
+ // won't recalculate derivation
575
+ // this is what makes mobx fast
576
+ IDerivationState[IDerivationState["UP_TO_DATE"] = 0] = "UP_TO_DATE";
577
+ // some deep dependency changed, but don't know if shallow dependency changed
578
+ // will require to check first if UP_TO_DATE or POSSIBLY_STALE
579
+ // currently only ComputedValue will propagate POSSIBLY_STALE
580
+ //
581
+ // having this state is second big optimization:
582
+ // don't have to recompute on every dependency change, but only when it's needed
583
+ IDerivationState[IDerivationState["POSSIBLY_STALE"] = 1] = "POSSIBLY_STALE";
584
+ // A shallow dependency has changed since last computation and the derivation
585
+ // will need to recompute when it's needed next.
586
+ IDerivationState[IDerivationState["STALE"] = 2] = "STALE";
587
+ })(IDerivationState || (IDerivationState = {}));
588
+ var TraceMode;
589
+ (function (TraceMode) {
590
+ TraceMode[TraceMode["NONE"] = 0] = "NONE";
591
+ TraceMode[TraceMode["LOG"] = 1] = "LOG";
592
+ TraceMode[TraceMode["BREAK"] = 2] = "BREAK";
593
+ })(TraceMode || (TraceMode = {}));
594
+ class CaughtException {
595
+ constructor(cause) {
596
+ this.cause = cause;
597
+ // Empty
598
+ }
599
+ }
600
+ function isCaughtException(e) {
601
+ return e instanceof CaughtException;
602
+ }
603
+ /**
604
+ * Finds out whether any dependency of the derivation has actually changed.
605
+ * If dependenciesState is 1 then it will recalculate dependencies,
606
+ * if any dependency changed it will propagate it by changing dependenciesState to 2.
607
+ *
608
+ * By iterating over the dependencies in the same order that they were reported and
609
+ * stopping on the first change, all the recalculations are only called for ComputedValues
610
+ * that will be tracked by derivation. That is because we assume that if the first x
611
+ * dependencies of the derivation doesn't change then the derivation should run the same way
612
+ * up until accessing x-th dependency.
613
+ */
614
+ function shouldCompute(derivation) {
615
+ switch (derivation.dependenciesState) {
616
+ case IDerivationState.UP_TO_DATE:
617
+ return false;
618
+ case IDerivationState.NOT_TRACKING:
619
+ case IDerivationState.STALE:
620
+ return true;
621
+ case IDerivationState.POSSIBLY_STALE: {
622
+ const prevUntracked = untrackedStart(); // no need for those computeds to be reported, they will be picked up in trackDerivedFunction.
623
+ const obs = derivation.observing, l = obs.length;
624
+ for (let i = 0; i < l; i++) {
625
+ const obj = obs[i];
626
+ if (isComputedValue(obj)) {
627
+ if (globalState.disableErrorBoundaries) {
628
+ obj.get();
629
+ }
630
+ else {
631
+ try {
632
+ obj.get();
633
+ }
634
+ catch (e) {
635
+ // we are not interested in the value *or* exception at this moment, but if there is one, notify all
636
+ untrackedEnd(prevUntracked);
637
+ return true;
638
+ }
639
+ }
640
+ // if ComputedValue `obj` actually changed it will be computed and propagated to its observers.
641
+ // and `derivation` is an observer of `obj`
642
+ // invariantShouldCompute(derivation)
643
+ if (derivation.dependenciesState === IDerivationState.STALE) {
644
+ untrackedEnd(prevUntracked);
645
+ return true;
646
+ }
647
+ }
648
+ }
649
+ changeDependenciesStateTo0(derivation);
650
+ untrackedEnd(prevUntracked);
651
+ return false;
652
+ }
653
+ }
654
+ }
655
+ // function invariantShouldCompute(derivation: IDerivation) {
656
+ // const newDepState = (derivation as any).dependenciesState
657
+ // if (
658
+ // process.env.NODE_ENV === "production" &&
659
+ // (newDepState === IDerivationState.POSSIBLY_STALE ||
660
+ // newDepState === IDerivationState.NOT_TRACKING)
661
+ // )
662
+ // fail("Illegal dependency state")
663
+ // }
664
+ function isComputingDerivation() {
665
+ return globalState.trackingDerivation !== null; // filter out actions inside computations
666
+ }
667
+ function checkIfStateModificationsAreAllowed(atom) {
668
+ const hasObservers = atom.observers.length > 0;
669
+ // Should never be possible to change an observed observable from inside computed, see #798
670
+ if (globalState.computationDepth > 0 && hasObservers)
671
+ fail(process.env.NODE_ENV !== "production" &&
672
+ `Computed values are not allowed to cause side effects by changing observables that are already being observed. Tried to modify: ${atom.name}`);
673
+ // Should not be possible to change observed state outside strict mode, except during initialization, see #563
674
+ if (!globalState.allowStateChanges && (hasObservers || globalState.enforceActions === "strict"))
675
+ fail(process.env.NODE_ENV !== "production" &&
676
+ (globalState.enforceActions
677
+ ? "Since strict-mode is enabled, changing observed observable values outside actions is not allowed. Please wrap the code in an `action` if this change is intended. Tried to modify: "
678
+ : "Side effects like changing state are not allowed at this point. Are you trying to modify state from, for example, the render function of a React component? Tried to modify: ") +
679
+ atom.name);
680
+ }
681
+ function checkIfStateReadsAreAllowed(observable) {
682
+ if (process.env.NODE_ENV !== "production" &&
683
+ !globalState.allowStateReads &&
684
+ globalState.observableRequiresReaction) {
685
+ console.warn(`[mobx] Observable ${observable.name} being read outside a reactive context`);
686
+ }
687
+ }
688
+ /**
689
+ * Executes the provided function `f` and tracks which observables are being accessed.
690
+ * The tracking information is stored on the `derivation` object and the derivation is registered
691
+ * as observer of any of the accessed observables.
692
+ */
693
+ function trackDerivedFunction(derivation, f, context) {
694
+ const prevAllowStateReads = allowStateReadsStart(true);
695
+ // pre allocate array allocation + room for variation in deps
696
+ // array will be trimmed by bindDependencies
697
+ changeDependenciesStateTo0(derivation);
698
+ derivation.newObserving = new Array(derivation.observing.length + 100);
699
+ derivation.unboundDepsCount = 0;
700
+ derivation.runId = ++globalState.runId;
701
+ const prevTracking = globalState.trackingDerivation;
702
+ globalState.trackingDerivation = derivation;
703
+ let result;
704
+ if (globalState.disableErrorBoundaries === true) {
705
+ result = f.call(context);
706
+ }
707
+ else {
708
+ try {
709
+ result = f.call(context);
710
+ }
711
+ catch (e) {
712
+ result = new CaughtException(e);
713
+ }
714
+ }
715
+ globalState.trackingDerivation = prevTracking;
716
+ bindDependencies(derivation);
717
+ if (derivation.observing.length === 0) {
718
+ warnAboutDerivationWithoutDependencies(derivation);
719
+ }
720
+ allowStateReadsEnd(prevAllowStateReads);
721
+ return result;
722
+ }
723
+ function warnAboutDerivationWithoutDependencies(derivation) {
724
+ if (process.env.NODE_ENV === "production")
725
+ return;
726
+ if (globalState.reactionRequiresObservable || derivation.requiresObservable) {
727
+ console.warn(`[mobx] Derivation ${derivation.name} is created/updated without reading any observable value`);
728
+ }
729
+ }
730
+ /**
731
+ * diffs newObserving with observing.
732
+ * update observing to be newObserving with unique observables
733
+ * notify observers that become observed/unobserved
734
+ */
735
+ function bindDependencies(derivation) {
736
+ // invariant(derivation.dependenciesState !== IDerivationState.NOT_TRACKING, "INTERNAL ERROR bindDependencies expects derivation.dependenciesState !== -1");
737
+ const prevObserving = derivation.observing;
738
+ const observing = (derivation.observing = derivation.newObserving);
739
+ let lowestNewObservingDerivationState = IDerivationState.UP_TO_DATE;
740
+ // Go through all new observables and check diffValue: (this list can contain duplicates):
741
+ // 0: first occurrence, change to 1 and keep it
742
+ // 1: extra occurrence, drop it
743
+ let i0 = 0, l = derivation.unboundDepsCount;
744
+ for (let i = 0; i < l; i++) {
745
+ const dep = observing[i];
746
+ if (dep.diffValue === 0) {
747
+ dep.diffValue = 1;
748
+ if (i0 !== i)
749
+ observing[i0] = dep;
750
+ i0++;
751
+ }
752
+ // Upcast is 'safe' here, because if dep is IObservable, `dependenciesState` will be undefined,
753
+ // not hitting the condition
754
+ if (dep.dependenciesState > lowestNewObservingDerivationState) {
755
+ lowestNewObservingDerivationState = dep.dependenciesState;
756
+ }
757
+ }
758
+ observing.length = i0;
759
+ derivation.newObserving = null; // newObserving shouldn't be needed outside tracking (statement moved down to work around FF bug, see #614)
760
+ // Go through all old observables and check diffValue: (it is unique after last bindDependencies)
761
+ // 0: it's not in new observables, unobserve it
762
+ // 1: it keeps being observed, don't want to notify it. change to 0
763
+ l = prevObserving.length;
764
+ while (l--) {
765
+ const dep = prevObserving[l];
766
+ if (dep.diffValue === 0) {
767
+ removeObserver(dep, derivation);
768
+ }
769
+ dep.diffValue = 0;
770
+ }
771
+ // Go through all new observables and check diffValue: (now it should be unique)
772
+ // 0: it was set to 0 in last loop. don't need to do anything.
773
+ // 1: it wasn't observed, let's observe it. set back to 0
774
+ while (i0--) {
775
+ const dep = observing[i0];
776
+ if (dep.diffValue === 1) {
777
+ dep.diffValue = 0;
778
+ addObserver(dep, derivation);
779
+ }
780
+ }
781
+ // Some new observed derivations may become stale during this derivation computation
782
+ // so they have had no chance to propagate staleness (#916)
783
+ if (lowestNewObservingDerivationState !== IDerivationState.UP_TO_DATE) {
784
+ derivation.dependenciesState = lowestNewObservingDerivationState;
785
+ derivation.onBecomeStale();
786
+ }
787
+ }
788
+ function clearObserving(derivation) {
789
+ // invariant(globalState.inBatch > 0, "INTERNAL ERROR clearObserving should be called only inside batch");
790
+ const obs = derivation.observing;
791
+ derivation.observing = [];
792
+ let i = obs.length;
793
+ while (i--)
794
+ removeObserver(obs[i], derivation);
795
+ derivation.dependenciesState = IDerivationState.NOT_TRACKING;
796
+ }
797
+ function untracked(action) {
798
+ const prev = untrackedStart();
799
+ const res = action();
800
+ untrackedEnd(prev);
801
+ return res;
802
+ }
803
+ function untrackedStart() {
804
+ const prev = globalState.trackingDerivation;
805
+ globalState.trackingDerivation = null;
806
+ return prev;
807
+ }
808
+ function untrackedEnd(prev) {
809
+ globalState.trackingDerivation = prev;
810
+ }
811
+ function allowStateReadsStart(allowStateReads) {
812
+ const prev = globalState.allowStateReads;
813
+ globalState.allowStateReads = allowStateReads;
814
+ return prev;
815
+ }
816
+ function allowStateReadsEnd(prev) {
817
+ globalState.allowStateReads = prev;
818
+ }
819
+ /**
820
+ * needed to keep `lowestObserverState` correct. when changing from (2 or 1) to 0
821
+ *
822
+ */
823
+ function changeDependenciesStateTo0(derivation) {
824
+ if (derivation.dependenciesState === IDerivationState.UP_TO_DATE)
825
+ return;
826
+ derivation.dependenciesState = IDerivationState.UP_TO_DATE;
827
+ const obs = derivation.observing;
828
+ let i = obs.length;
829
+ while (i--)
830
+ obs[i].lowestObserverState = IDerivationState.UP_TO_DATE;
831
+ }
832
+
833
+ // we don't use globalState for these in order to avoid possible issues with multiple
834
+ // mobx versions
835
+ let currentActionId = 0;
836
+ let nextActionId = 1;
552
837
  function createAction(actionName, fn) {
553
838
  if (process.env.NODE_ENV !== "production") {
554
839
  invariant(typeof fn === "function", "`action` can only be invoked on functions");
@@ -562,25 +847,19 @@ function createAction(actionName, fn) {
562
847
  return res;
563
848
  }
564
849
  function executeAction(actionName, fn, scope, args) {
565
- const runInfo = startAction(actionName, fn, scope, args);
566
- let shouldSupressReactionError = true;
850
+ const runInfo = _startAction(actionName, scope, args);
567
851
  try {
568
- const res = fn.apply(scope, args);
569
- shouldSupressReactionError = false;
570
- return res;
852
+ return fn.apply(scope, args);
853
+ }
854
+ catch (err) {
855
+ runInfo.error = err;
856
+ throw err;
571
857
  }
572
858
  finally {
573
- if (shouldSupressReactionError) {
574
- globalState.suppressReactionErrors = shouldSupressReactionError;
575
- endAction(runInfo);
576
- globalState.suppressReactionErrors = false;
577
- }
578
- else {
579
- endAction(runInfo);
580
- }
859
+ _endAction(runInfo);
581
860
  }
582
861
  }
583
- function startAction(actionName, fn, scope, args) {
862
+ function _startAction(actionName, scope, args) {
584
863
  const notifySpy = isSpyEnabled() && !!actionName;
585
864
  let startTime = 0;
586
865
  if (notifySpy) {
@@ -600,19 +879,35 @@ function startAction(actionName, fn, scope, args) {
600
879
  const prevDerivation = untrackedStart();
601
880
  startBatch();
602
881
  const prevAllowStateChanges = allowStateChangesStart(true);
603
- return {
882
+ const prevAllowStateReads = allowStateReadsStart(true);
883
+ const runInfo = {
604
884
  prevDerivation,
605
885
  prevAllowStateChanges,
886
+ prevAllowStateReads,
606
887
  notifySpy,
607
- startTime
888
+ startTime,
889
+ actionId: nextActionId++,
890
+ parentActionId: currentActionId
608
891
  };
892
+ currentActionId = runInfo.actionId;
893
+ return runInfo;
609
894
  }
610
- function endAction(runInfo) {
895
+ function _endAction(runInfo) {
896
+ if (currentActionId !== runInfo.actionId) {
897
+ fail("invalid action stack. did you forget to finish an action?");
898
+ }
899
+ currentActionId = runInfo.parentActionId;
900
+ if (runInfo.error !== undefined) {
901
+ globalState.suppressReactionErrors = true;
902
+ }
611
903
  allowStateChangesEnd(runInfo.prevAllowStateChanges);
904
+ allowStateReadsEnd(runInfo.prevAllowStateReads);
612
905
  endBatch();
613
906
  untrackedEnd(runInfo.prevDerivation);
614
- if (runInfo.notifySpy)
907
+ if (runInfo.notifySpy) {
615
908
  spyReportEnd({ time: Date.now() - runInfo.startTime });
909
+ }
910
+ globalState.suppressReactionErrors = false;
616
911
  }
617
912
  function allowStateChanges(allowStateChanges, func) {
618
913
  const prev = allowStateChangesStart(allowStateChanges);
@@ -847,350 +1142,112 @@ class ComputedValue {
847
1142
  if (this.setter) {
848
1143
  invariant(!this.isRunningSetter, `The setter of computed value '${this.name}' is trying to update itself. Did you intend to update an _observable_ value, instead of the computed property?`);
849
1144
  this.isRunningSetter = true;
850
- try {
851
- this.setter.call(this.scope, value);
852
- }
853
- finally {
854
- this.isRunningSetter = false;
855
- }
856
- }
857
- else
858
- invariant(false, process.env.NODE_ENV !== "production" &&
859
- `[ComputedValue '${this.name}'] It is not possible to assign a new value to a computed value.`);
860
- }
861
- trackAndCompute() {
862
- if (isSpyEnabled()) {
863
- spyReport({
864
- object: this.scope,
865
- type: "compute",
866
- name: this.name
867
- });
868
- }
869
- const oldValue = this.value;
870
- const wasSuspended =
871
- /* see #1208 */ this.dependenciesState === IDerivationState.NOT_TRACKING;
872
- const newValue = this.computeValue(true);
873
- const changed = wasSuspended ||
874
- isCaughtException(oldValue) ||
875
- isCaughtException(newValue) ||
876
- !this.equals(oldValue, newValue);
877
- if (changed) {
878
- this.value = newValue;
879
- }
880
- return changed;
881
- }
882
- computeValue(track) {
883
- this.isComputing = true;
884
- globalState.computationDepth++;
885
- let res;
886
- if (track) {
887
- res = trackDerivedFunction(this, this.derivation, this.scope);
888
- }
889
- else {
890
- if (globalState.disableErrorBoundaries === true) {
891
- res = this.derivation.call(this.scope);
892
- }
893
- else {
894
- try {
895
- res = this.derivation.call(this.scope);
896
- }
897
- catch (e) {
898
- res = new CaughtException(e);
899
- }
900
- }
901
- }
902
- globalState.computationDepth--;
903
- this.isComputing = false;
904
- return res;
905
- }
906
- suspend() {
907
- if (!this.keepAlive) {
908
- clearObserving(this);
909
- this.value = undefined; // don't hold on to computed value!
910
- }
911
- }
912
- observe(listener, fireImmediately) {
913
- let firstTime = true;
914
- let prevValue = undefined;
915
- return autorun(() => {
916
- let newValue = this.get();
917
- if (!firstTime || fireImmediately) {
918
- const prevU = untrackedStart();
919
- listener({
920
- type: "update",
921
- object: this,
922
- newValue,
923
- oldValue: prevValue
924
- });
925
- untrackedEnd(prevU);
926
- }
927
- firstTime = false;
928
- prevValue = newValue;
929
- });
930
- }
931
- warnAboutUntrackedRead() {
932
- if (process.env.NODE_ENV === "production")
933
- return;
934
- if (this.requiresReaction === true) {
935
- fail(`[mobx] Computed value ${this.name} is read outside a reactive context`);
936
- }
937
- if (this.isTracing !== TraceMode.NONE) {
938
- console.log(`[mobx.trace] '${this.name}' is being read outside a reactive context. Doing a full recompute`);
939
- }
940
- if (globalState.computedRequiresReaction) {
941
- console.warn(`[mobx] Computed value ${this.name} is being read outside a reactive context. Doing a full recompute`);
942
- }
943
- }
944
- toJSON() {
945
- return this.get();
946
- }
947
- toString() {
948
- return `${this.name}[${this.derivation.toString()}]`;
949
- }
950
- valueOf() {
951
- return toPrimitive(this.get());
952
- }
953
- }
954
- ComputedValue.prototype[primitiveSymbol()] = ComputedValue.prototype.valueOf;
955
- const isComputedValue = createInstanceofPredicate("ComputedValue", ComputedValue);
956
-
957
- var IDerivationState;
958
- (function (IDerivationState) {
959
- // before being run or (outside batch and not being observed)
960
- // at this point derivation is not holding any data about dependency tree
961
- IDerivationState[IDerivationState["NOT_TRACKING"] = -1] = "NOT_TRACKING";
962
- // no shallow dependency changed since last computation
963
- // won't recalculate derivation
964
- // this is what makes mobx fast
965
- IDerivationState[IDerivationState["UP_TO_DATE"] = 0] = "UP_TO_DATE";
966
- // some deep dependency changed, but don't know if shallow dependency changed
967
- // will require to check first if UP_TO_DATE or POSSIBLY_STALE
968
- // currently only ComputedValue will propagate POSSIBLY_STALE
969
- //
970
- // having this state is second big optimization:
971
- // don't have to recompute on every dependency change, but only when it's needed
972
- IDerivationState[IDerivationState["POSSIBLY_STALE"] = 1] = "POSSIBLY_STALE";
973
- // A shallow dependency has changed since last computation and the derivation
974
- // will need to recompute when it's needed next.
975
- IDerivationState[IDerivationState["STALE"] = 2] = "STALE";
976
- })(IDerivationState || (IDerivationState = {}));
977
- var TraceMode;
978
- (function (TraceMode) {
979
- TraceMode[TraceMode["NONE"] = 0] = "NONE";
980
- TraceMode[TraceMode["LOG"] = 1] = "LOG";
981
- TraceMode[TraceMode["BREAK"] = 2] = "BREAK";
982
- })(TraceMode || (TraceMode = {}));
983
- class CaughtException {
984
- constructor(cause) {
985
- this.cause = cause;
986
- // Empty
987
- }
988
- }
989
- function isCaughtException(e) {
990
- return e instanceof CaughtException;
991
- }
992
- /**
993
- * Finds out whether any dependency of the derivation has actually changed.
994
- * If dependenciesState is 1 then it will recalculate dependencies,
995
- * if any dependency changed it will propagate it by changing dependenciesState to 2.
996
- *
997
- * By iterating over the dependencies in the same order that they were reported and
998
- * stopping on the first change, all the recalculations are only called for ComputedValues
999
- * that will be tracked by derivation. That is because we assume that if the first x
1000
- * dependencies of the derivation doesn't change then the derivation should run the same way
1001
- * up until accessing x-th dependency.
1002
- */
1003
- function shouldCompute(derivation) {
1004
- switch (derivation.dependenciesState) {
1005
- case IDerivationState.UP_TO_DATE:
1006
- return false;
1007
- case IDerivationState.NOT_TRACKING:
1008
- case IDerivationState.STALE:
1009
- return true;
1010
- case IDerivationState.POSSIBLY_STALE: {
1011
- const prevUntracked = untrackedStart(); // no need for those computeds to be reported, they will be picked up in trackDerivedFunction.
1012
- const obs = derivation.observing, l = obs.length;
1013
- for (let i = 0; i < l; i++) {
1014
- const obj = obs[i];
1015
- if (isComputedValue(obj)) {
1016
- if (globalState.disableErrorBoundaries) {
1017
- obj.get();
1018
- }
1019
- else {
1020
- try {
1021
- obj.get();
1022
- }
1023
- catch (e) {
1024
- // we are not interested in the value *or* exception at this moment, but if there is one, notify all
1025
- untrackedEnd(prevUntracked);
1026
- return true;
1027
- }
1028
- }
1029
- // if ComputedValue `obj` actually changed it will be computed and propagated to its observers.
1030
- // and `derivation` is an observer of `obj`
1031
- // invariantShouldCompute(derivation)
1032
- if (derivation.dependenciesState === IDerivationState.STALE) {
1033
- untrackedEnd(prevUntracked);
1034
- return true;
1035
- }
1036
- }
1145
+ try {
1146
+ this.setter.call(this.scope, value);
1147
+ }
1148
+ finally {
1149
+ this.isRunningSetter = false;
1037
1150
  }
1038
- changeDependenciesStateTo0(derivation);
1039
- untrackedEnd(prevUntracked);
1040
- return false;
1041
1151
  }
1152
+ else
1153
+ invariant(false, process.env.NODE_ENV !== "production" &&
1154
+ `[ComputedValue '${this.name}'] It is not possible to assign a new value to a computed value.`);
1042
1155
  }
1043
- }
1044
- // function invariantShouldCompute(derivation: IDerivation) {
1045
- // const newDepState = (derivation as any).dependenciesState
1046
- // if (
1047
- // process.env.NODE_ENV === "production" &&
1048
- // (newDepState === IDerivationState.POSSIBLY_STALE ||
1049
- // newDepState === IDerivationState.NOT_TRACKING)
1050
- // )
1051
- // fail("Illegal dependency state")
1052
- // }
1053
- function isComputingDerivation() {
1054
- return globalState.trackingDerivation !== null; // filter out actions inside computations
1055
- }
1056
- function checkIfStateModificationsAreAllowed(atom) {
1057
- const hasObservers = atom.observers.length > 0;
1058
- // Should never be possible to change an observed observable from inside computed, see #798
1059
- if (globalState.computationDepth > 0 && hasObservers)
1060
- fail(process.env.NODE_ENV !== "production" &&
1061
- `Computed values are not allowed to cause side effects by changing observables that are already being observed. Tried to modify: ${atom.name}`);
1062
- // Should not be possible to change observed state outside strict mode, except during initialization, see #563
1063
- if (!globalState.allowStateChanges && (hasObservers || globalState.enforceActions === "strict"))
1064
- fail(process.env.NODE_ENV !== "production" &&
1065
- (globalState.enforceActions
1066
- ? "Since strict-mode is enabled, changing observed observable values outside actions is not allowed. Please wrap the code in an `action` if this change is intended. Tried to modify: "
1067
- : "Side effects like changing state are not allowed at this point. Are you trying to modify state from, for example, the render function of a React component? Tried to modify: ") +
1068
- atom.name);
1069
- }
1070
- /**
1071
- * Executes the provided function `f` and tracks which observables are being accessed.
1072
- * The tracking information is stored on the `derivation` object and the derivation is registered
1073
- * as observer of any of the accessed observables.
1074
- */
1075
- function trackDerivedFunction(derivation, f, context) {
1076
- // pre allocate array allocation + room for variation in deps
1077
- // array will be trimmed by bindDependencies
1078
- changeDependenciesStateTo0(derivation);
1079
- derivation.newObserving = new Array(derivation.observing.length + 100);
1080
- derivation.unboundDepsCount = 0;
1081
- derivation.runId = ++globalState.runId;
1082
- const prevTracking = globalState.trackingDerivation;
1083
- globalState.trackingDerivation = derivation;
1084
- let result;
1085
- if (globalState.disableErrorBoundaries === true) {
1086
- result = f.call(context);
1087
- }
1088
- else {
1089
- try {
1090
- result = f.call(context);
1156
+ trackAndCompute() {
1157
+ if (isSpyEnabled()) {
1158
+ spyReport({
1159
+ object: this.scope,
1160
+ type: "compute",
1161
+ name: this.name
1162
+ });
1091
1163
  }
1092
- catch (e) {
1093
- result = new CaughtException(e);
1164
+ const oldValue = this.value;
1165
+ const wasSuspended =
1166
+ /* see #1208 */ this.dependenciesState === IDerivationState.NOT_TRACKING;
1167
+ const newValue = this.computeValue(true);
1168
+ const changed = wasSuspended ||
1169
+ isCaughtException(oldValue) ||
1170
+ isCaughtException(newValue) ||
1171
+ !this.equals(oldValue, newValue);
1172
+ if (changed) {
1173
+ this.value = newValue;
1094
1174
  }
1175
+ return changed;
1095
1176
  }
1096
- globalState.trackingDerivation = prevTracking;
1097
- bindDependencies(derivation);
1098
- return result;
1099
- }
1100
- /**
1101
- * diffs newObserving with observing.
1102
- * update observing to be newObserving with unique observables
1103
- * notify observers that become observed/unobserved
1104
- */
1105
- function bindDependencies(derivation) {
1106
- // invariant(derivation.dependenciesState !== IDerivationState.NOT_TRACKING, "INTERNAL ERROR bindDependencies expects derivation.dependenciesState !== -1");
1107
- const prevObserving = derivation.observing;
1108
- const observing = (derivation.observing = derivation.newObserving);
1109
- let lowestNewObservingDerivationState = IDerivationState.UP_TO_DATE;
1110
- // Go through all new observables and check diffValue: (this list can contain duplicates):
1111
- // 0: first occurrence, change to 1 and keep it
1112
- // 1: extra occurrence, drop it
1113
- let i0 = 0, l = derivation.unboundDepsCount;
1114
- for (let i = 0; i < l; i++) {
1115
- const dep = observing[i];
1116
- if (dep.diffValue === 0) {
1117
- dep.diffValue = 1;
1118
- if (i0 !== i)
1119
- observing[i0] = dep;
1120
- i0++;
1177
+ computeValue(track) {
1178
+ this.isComputing = true;
1179
+ globalState.computationDepth++;
1180
+ let res;
1181
+ if (track) {
1182
+ res = trackDerivedFunction(this, this.derivation, this.scope);
1121
1183
  }
1122
- // Upcast is 'safe' here, because if dep is IObservable, `dependenciesState` will be undefined,
1123
- // not hitting the condition
1124
- if (dep.dependenciesState > lowestNewObservingDerivationState) {
1125
- lowestNewObservingDerivationState = dep.dependenciesState;
1184
+ else {
1185
+ if (globalState.disableErrorBoundaries === true) {
1186
+ res = this.derivation.call(this.scope);
1187
+ }
1188
+ else {
1189
+ try {
1190
+ res = this.derivation.call(this.scope);
1191
+ }
1192
+ catch (e) {
1193
+ res = new CaughtException(e);
1194
+ }
1195
+ }
1126
1196
  }
1197
+ globalState.computationDepth--;
1198
+ this.isComputing = false;
1199
+ return res;
1127
1200
  }
1128
- observing.length = i0;
1129
- derivation.newObserving = null; // newObserving shouldn't be needed outside tracking (statement moved down to work around FF bug, see #614)
1130
- // Go through all old observables and check diffValue: (it is unique after last bindDependencies)
1131
- // 0: it's not in new observables, unobserve it
1132
- // 1: it keeps being observed, don't want to notify it. change to 0
1133
- l = prevObserving.length;
1134
- while (l--) {
1135
- const dep = prevObserving[l];
1136
- if (dep.diffValue === 0) {
1137
- removeObserver(dep, derivation);
1201
+ suspend() {
1202
+ if (!this.keepAlive) {
1203
+ clearObserving(this);
1204
+ this.value = undefined; // don't hold on to computed value!
1138
1205
  }
1139
- dep.diffValue = 0;
1140
1206
  }
1141
- // Go through all new observables and check diffValue: (now it should be unique)
1142
- // 0: it was set to 0 in last loop. don't need to do anything.
1143
- // 1: it wasn't observed, let's observe it. set back to 0
1144
- while (i0--) {
1145
- const dep = observing[i0];
1146
- if (dep.diffValue === 1) {
1147
- dep.diffValue = 0;
1148
- addObserver(dep, derivation);
1207
+ observe(listener, fireImmediately) {
1208
+ let firstTime = true;
1209
+ let prevValue = undefined;
1210
+ return autorun(() => {
1211
+ let newValue = this.get();
1212
+ if (!firstTime || fireImmediately) {
1213
+ const prevU = untrackedStart();
1214
+ listener({
1215
+ type: "update",
1216
+ object: this,
1217
+ newValue,
1218
+ oldValue: prevValue
1219
+ });
1220
+ untrackedEnd(prevU);
1221
+ }
1222
+ firstTime = false;
1223
+ prevValue = newValue;
1224
+ });
1225
+ }
1226
+ warnAboutUntrackedRead() {
1227
+ if (process.env.NODE_ENV === "production")
1228
+ return;
1229
+ if (this.requiresReaction === true) {
1230
+ fail(`[mobx] Computed value ${this.name} is read outside a reactive context`);
1231
+ }
1232
+ if (this.isTracing !== TraceMode.NONE) {
1233
+ console.log(`[mobx.trace] '${this.name}' is being read outside a reactive context. Doing a full recompute`);
1234
+ }
1235
+ if (globalState.computedRequiresReaction) {
1236
+ console.warn(`[mobx] Computed value ${this.name} is being read outside a reactive context. Doing a full recompute`);
1149
1237
  }
1150
1238
  }
1151
- // Some new observed derivations may become stale during this derivation computation
1152
- // so they have had no chance to propagate staleness (#916)
1153
- if (lowestNewObservingDerivationState !== IDerivationState.UP_TO_DATE) {
1154
- derivation.dependenciesState = lowestNewObservingDerivationState;
1155
- derivation.onBecomeStale();
1239
+ toJSON() {
1240
+ return this.get();
1241
+ }
1242
+ toString() {
1243
+ return `${this.name}[${this.derivation.toString()}]`;
1244
+ }
1245
+ valueOf() {
1246
+ return toPrimitive(this.get());
1156
1247
  }
1157
1248
  }
1158
- function clearObserving(derivation) {
1159
- // invariant(globalState.inBatch > 0, "INTERNAL ERROR clearObserving should be called only inside batch");
1160
- const obs = derivation.observing;
1161
- derivation.observing = [];
1162
- let i = obs.length;
1163
- while (i--)
1164
- removeObserver(obs[i], derivation);
1165
- derivation.dependenciesState = IDerivationState.NOT_TRACKING;
1166
- }
1167
- function untracked(action) {
1168
- const prev = untrackedStart();
1169
- const res = action();
1170
- untrackedEnd(prev);
1171
- return res;
1172
- }
1173
- function untrackedStart() {
1174
- const prev = globalState.trackingDerivation;
1175
- globalState.trackingDerivation = null;
1176
- return prev;
1177
- }
1178
- function untrackedEnd(prev) {
1179
- globalState.trackingDerivation = prev;
1180
- }
1181
- /**
1182
- * needed to keep `lowestObserverState` correct. when changing from (2 or 1) to 0
1183
- *
1184
- */
1185
- function changeDependenciesStateTo0(derivation) {
1186
- if (derivation.dependenciesState === IDerivationState.UP_TO_DATE)
1187
- return;
1188
- derivation.dependenciesState = IDerivationState.UP_TO_DATE;
1189
- const obs = derivation.observing;
1190
- let i = obs.length;
1191
- while (i--)
1192
- obs[i].lowestObserverState = IDerivationState.UP_TO_DATE;
1193
- }
1249
+ ComputedValue.prototype[primitiveSymbol()] = ComputedValue.prototype.valueOf;
1250
+ const isComputedValue = createInstanceofPredicate("ComputedValue", ComputedValue);
1194
1251
 
1195
1252
  /**
1196
1253
  * These values will persist if global state is reset
@@ -1200,6 +1257,9 @@ const persistentKeys = [
1200
1257
  "spyListeners",
1201
1258
  "enforceActions",
1202
1259
  "computedRequiresReaction",
1260
+ "reactionRequiresObservable",
1261
+ "observableRequiresReaction",
1262
+ "allowStateReads",
1203
1263
  "disableErrorBoundaries",
1204
1264
  "runId",
1205
1265
  "UNCHANGED"
@@ -1260,6 +1320,11 @@ class MobXGlobals {
1260
1320
  * To ensure that those functions stay pure.
1261
1321
  */
1262
1322
  this.allowStateChanges = true;
1323
+ /**
1324
+ * Is it allowed to read observables at this point?
1325
+ * Used to hold the state needed for `observableRequiresReaction`
1326
+ */
1327
+ this.allowStateReads = true;
1263
1328
  /**
1264
1329
  * If strict mode is enabled, state changes are by default not allowed
1265
1330
  */
@@ -1276,6 +1341,16 @@ class MobXGlobals {
1276
1341
  * Warn if computed values are accessed outside a reactive context
1277
1342
  */
1278
1343
  this.computedRequiresReaction = false;
1344
+ /**
1345
+ * (Experimental)
1346
+ * Warn if you try to create to derivation / reactive context without accessing any observable.
1347
+ */
1348
+ this.reactionRequiresObservable = false;
1349
+ /**
1350
+ * (Experimental)
1351
+ * Warn if observables are accessed outside a reactive context
1352
+ */
1353
+ this.observableRequiresReaction = false;
1279
1354
  /**
1280
1355
  * Allows overwriting of computed properties, useful in tests but not prod as it can cause
1281
1356
  * memory leaks. See https://github.com/mobxjs/mobx/issues/1867
@@ -1456,6 +1531,7 @@ function endBatch() {
1456
1531
  }
1457
1532
  }
1458
1533
  function reportObserved(observable) {
1534
+ checkIfStateReadsAreAllowed(observable);
1459
1535
  const derivation = globalState.trackingDerivation;
1460
1536
  if (derivation !== null) {
1461
1537
  /**
@@ -1590,10 +1666,11 @@ function printDepTree(tree, lines, depth) {
1590
1666
  }
1591
1667
 
1592
1668
  class Reaction {
1593
- constructor(name = "Reaction@" + getNextId(), onInvalidate, errorHandler) {
1669
+ constructor(name = "Reaction@" + getNextId(), onInvalidate, errorHandler, requiresObservable = false) {
1594
1670
  this.name = name;
1595
1671
  this.onInvalidate = onInvalidate;
1596
1672
  this.errorHandler = errorHandler;
1673
+ this.requiresObservable = requiresObservable;
1597
1674
  this.observing = []; // nodes we are looking at. Our value depends on these nodes
1598
1675
  this.newObserving = [];
1599
1676
  this.dependenciesState = IDerivationState.NOT_TRACKING;
@@ -1935,7 +2012,7 @@ function autorun(view, opts = EMPTY_OBJECT) {
1935
2012
  // normal autorun
1936
2013
  reaction = new Reaction(name, function () {
1937
2014
  this.track(reactionRunner);
1938
- }, opts.onError);
2015
+ }, opts.onError, opts.requiresObservable);
1939
2016
  }
1940
2017
  else {
1941
2018
  const scheduler = createSchedulerFromOptions(opts);
@@ -1950,7 +2027,7 @@ function autorun(view, opts = EMPTY_OBJECT) {
1950
2027
  reaction.track(reactionRunner);
1951
2028
  });
1952
2029
  }
1953
- }, opts.onError);
2030
+ }, opts.onError, opts.requiresObservable);
1954
2031
  }
1955
2032
  function reactionRunner() {
1956
2033
  view(reaction);
@@ -1993,7 +2070,7 @@ function reaction(expression, effect, opts = EMPTY_OBJECT) {
1993
2070
  isScheduled = true;
1994
2071
  scheduler(reactionRunner);
1995
2072
  }
1996
- }, opts.onError);
2073
+ }, opts.onError, opts.requiresObservable);
1997
2074
  function reactionRunner() {
1998
2075
  isScheduled = false; // Q: move into reaction runner?
1999
2076
  if (r.isDisposed)
@@ -2032,8 +2109,8 @@ function onBecomeUnobserved(thing, arg2, arg3) {
2032
2109
  return interceptHook("onBecomeUnobserved", thing, arg2, arg3);
2033
2110
  }
2034
2111
  function interceptHook(hook, thing, arg2, arg3) {
2035
- const atom = typeof arg2 === "string" ? getAtom(thing, arg2) : getAtom(thing);
2036
- const cb = typeof arg2 === "string" ? arg3 : arg2;
2112
+ const atom = typeof arg3 === "function" ? getAtom(thing, arg2) : getAtom(thing);
2113
+ const cb = typeof arg3 === "function" ? arg3 : arg2;
2037
2114
  const orig = atom[hook];
2038
2115
  if (typeof orig !== "function")
2039
2116
  return fail(process.env.NODE_ENV !== "production" && "Not an atom that can be (un)observed");
@@ -2047,7 +2124,7 @@ function interceptHook(hook, thing, arg2, arg3) {
2047
2124
  }
2048
2125
 
2049
2126
  function configure(options) {
2050
- const { enforceActions, computedRequiresReaction, computedConfigurable, disableErrorBoundaries, arrayBuffer, reactionScheduler } = options;
2127
+ const { enforceActions, computedRequiresReaction, computedConfigurable, disableErrorBoundaries, arrayBuffer, reactionScheduler, reactionRequiresObservable, observableRequiresReaction } = options;
2051
2128
  if (options.isolateGlobalState === true) {
2052
2129
  isolateGlobalState();
2053
2130
  }
@@ -2077,6 +2154,13 @@ function configure(options) {
2077
2154
  if (computedRequiresReaction !== undefined) {
2078
2155
  globalState.computedRequiresReaction = !!computedRequiresReaction;
2079
2156
  }
2157
+ if (reactionRequiresObservable !== undefined) {
2158
+ globalState.reactionRequiresObservable = !!reactionRequiresObservable;
2159
+ }
2160
+ if (observableRequiresReaction !== undefined) {
2161
+ globalState.observableRequiresReaction = !!observableRequiresReaction;
2162
+ globalState.allowStateReads = !globalState.observableRequiresReaction;
2163
+ }
2080
2164
  if (computedConfigurable !== undefined) {
2081
2165
  globalState.computedConfigurable = !!computedConfigurable;
2082
2166
  }
@@ -3297,9 +3381,16 @@ class ObservableMap {
3297
3381
  return this._data.has(key);
3298
3382
  }
3299
3383
  has(key) {
3300
- if (this._hasMap.has(key))
3301
- return this._hasMap.get(key).get();
3302
- return this._updateHasMapEntry(key, false).get();
3384
+ if (!globalState.trackingDerivation)
3385
+ return this._has(key);
3386
+ let entry = this._hasMap.get(key);
3387
+ if (!entry) {
3388
+ // todo: replace with atom (breaking change)
3389
+ const newEntry = (entry = new ObservableValue(this._has(key), referenceEnhancer, `${this.name}.${stringifyKey(key)}?`, false));
3390
+ this._hasMap.set(key, newEntry);
3391
+ onBecomeUnobserved(newEntry, () => this._hasMap.delete(key));
3392
+ }
3393
+ return entry.get();
3303
3394
  }
3304
3395
  set(key, value) {
3305
3396
  const hasKey = this._has(key);
@@ -3361,16 +3452,10 @@ class ObservableMap {
3361
3452
  return false;
3362
3453
  }
3363
3454
  _updateHasMapEntry(key, value) {
3364
- // optimization; don't fill the hasMap if we are not observing, or remove entry if there are no observers anymore
3365
3455
  let entry = this._hasMap.get(key);
3366
3456
  if (entry) {
3367
3457
  entry.setNewValue(value);
3368
3458
  }
3369
- else {
3370
- entry = new ObservableValue(value, referenceEnhancer, `${this.name}.${stringifyKey(key)}?`, false);
3371
- this._hasMap.set(key, entry);
3372
- }
3373
- return entry;
3374
3459
  }
3375
3460
  _updateValue(key, newValue) {
3376
3461
  const observable = this._data.get(key);
@@ -3495,14 +3580,32 @@ class ObservableMap {
3495
3580
  }
3496
3581
  replace(values) {
3497
3582
  transaction(() => {
3498
- // grab all the keys that are present in the new map but not present in the current map
3499
- // and delete them from the map, then merge the new map
3500
- // this will cause reactions only on changed values
3501
- const newKeys = getMapLikeKeys(values);
3583
+ const replacementMap = convertToMap(values);
3502
3584
  const oldKeys = this._keys;
3503
- const missingKeys = oldKeys.filter(k => newKeys.indexOf(k) === -1);
3504
- missingKeys.forEach(k => this.delete(k));
3505
- this.merge(values);
3585
+ const newKeys = Array.from(replacementMap.keys());
3586
+ let keysChanged = false;
3587
+ for (let i = 0; i < oldKeys.length; i++) {
3588
+ const oldKey = oldKeys[i];
3589
+ // key order change
3590
+ if (oldKeys.length === newKeys.length && oldKey !== newKeys[i]) {
3591
+ keysChanged = true;
3592
+ }
3593
+ // deleted key
3594
+ if (!replacementMap.has(oldKey)) {
3595
+ keysChanged = true;
3596
+ this.delete(oldKey);
3597
+ }
3598
+ }
3599
+ replacementMap.forEach((value, key) => {
3600
+ // new key
3601
+ if (!this._data.has(key)) {
3602
+ keysChanged = true;
3603
+ }
3604
+ this.set(key, value);
3605
+ });
3606
+ if (keysChanged) {
3607
+ this._keys.replace(newKeys);
3608
+ }
3506
3609
  });
3507
3610
  return this;
3508
3611
  }
@@ -4082,12 +4185,12 @@ function getDebugName(thing, property) {
4082
4185
  }
4083
4186
 
4084
4187
  const toString = Object.prototype.toString;
4085
- function deepEqual(a, b) {
4086
- return eq(a, b);
4188
+ function deepEqual(a, b, depth = -1) {
4189
+ return eq(a, b, depth);
4087
4190
  }
4088
4191
  // Copied from https://github.com/jashkenas/underscore/blob/5c237a7c682fb68fd5378203f0bf22dce1624854/underscore.js#L1186-L1289
4089
4192
  // Internal recursive comparison function for `isEqual`.
4090
- function eq(a, b, aStack, bStack) {
4193
+ function eq(a, b, depth, aStack, bStack) {
4091
4194
  // Identical objects are equal. `0 === -0`, but they aren't identical.
4092
4195
  // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
4093
4196
  if (a === b)
@@ -4102,10 +4205,6 @@ function eq(a, b, aStack, bStack) {
4102
4205
  const type = typeof a;
4103
4206
  if (type !== "function" && type !== "object" && typeof b != "object")
4104
4207
  return false;
4105
- return deepEq(a, b, aStack, bStack);
4106
- }
4107
- // Internal recursive comparison function for `isEqual`.
4108
- function deepEq(a, b, aStack, bStack) {
4109
4208
  // Unwrap any wrapped objects.
4110
4209
  a = unwrap(a);
4111
4210
  b = unwrap(b);
@@ -4155,6 +4254,12 @@ function deepEq(a, b, aStack, bStack) {
4155
4254
  return false;
4156
4255
  }
4157
4256
  }
4257
+ if (depth === 0) {
4258
+ return false;
4259
+ }
4260
+ else if (depth < 0) {
4261
+ depth = -1;
4262
+ }
4158
4263
  // Assume equality for cyclic structures. The algorithm for detecting cyclic
4159
4264
  // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
4160
4265
  // Initializing stack of traversed objects.
@@ -4179,7 +4284,7 @@ function deepEq(a, b, aStack, bStack) {
4179
4284
  return false;
4180
4285
  // Deep compare the contents, ignoring non-numeric properties.
4181
4286
  while (length--) {
4182
- if (!eq(a[length], b[length], aStack, bStack))
4287
+ if (!eq(a[length], b[length], depth - 1, aStack, bStack))
4183
4288
  return false;
4184
4289
  }
4185
4290
  }
@@ -4194,7 +4299,7 @@ function deepEq(a, b, aStack, bStack) {
4194
4299
  while (length--) {
4195
4300
  // Deep compare each member
4196
4301
  key = keys[length];
4197
- if (!(has$1(b, key) && eq(a[key], b[key], aStack, bStack)))
4302
+ if (!(has$1(b, key) && eq(a[key], b[key], depth - 1, aStack, bStack)))
4198
4303
  return false;
4199
4304
  }
4200
4305
  }
@@ -4249,7 +4354,7 @@ try {
4249
4354
  process.env.NODE_ENV;
4250
4355
  }
4251
4356
  catch (e) {
4252
- const g = typeof window !== "undefined" ? window : global;
4357
+ const g = getGlobal();
4253
4358
  if (typeof process === "undefined")
4254
4359
  g.process = {};
4255
4360
  g.process.env = {};
@@ -4318,4 +4423,4 @@ if (process.env.NODE_ENV !== "production" &&
4318
4423
  });
4319
4424
  }
4320
4425
 
4321
- export { $mobx, IDerivationState, ObservableMap, ObservableSet, Reaction, allowStateChanges as _allowStateChanges, allowStateChangesInsideComputed as _allowStateChangesInsideComputed, getAdministration as _getAdministration, getGlobalState as _getGlobalState, interceptReads as _interceptReads, isComputingDerivation as _isComputingDerivation, resetGlobalState as _resetGlobalState, action, autorun, comparer, computed, configure, createAtom, decorate, entries, extendObservable, extendShallowObservable, flow, get, getAtom, getDebugName, getDependencyTree, getObserverTree, has, intercept, isAction, isArrayLike, isObservableValue as isBoxedObservable, isComputed, isComputedProp, isObservable, isObservableArray, isObservableMap, isObservableObject, isObservableProp, isObservableSet, keys, observable, observe, onBecomeObserved, onBecomeUnobserved, onReactionError, reaction, remove, runInAction, set, spy, toJS, trace, transaction, untracked, values, when };
4426
+ export { $mobx, IDerivationState, ObservableMap, ObservableSet, Reaction, allowStateChanges as _allowStateChanges, allowStateChangesInsideComputed as _allowStateChangesInsideComputed, _endAction, getAdministration as _getAdministration, getGlobalState as _getGlobalState, interceptReads as _interceptReads, isComputingDerivation as _isComputingDerivation, resetGlobalState as _resetGlobalState, _startAction, action, autorun, comparer, computed, configure, createAtom, decorate, entries, extendObservable, extendShallowObservable, flow, get, getAtom, getDebugName, getDependencyTree, getObserverTree, has, intercept, isAction, isArrayLike, isObservableValue as isBoxedObservable, isComputed, isComputedProp, isObservable, isObservableArray, isObservableMap, isObservableObject, isObservableProp, isObservableSet, keys, observable, observe, onBecomeObserved, onBecomeUnobserved, onReactionError, reaction, remove, runInAction, set, spy, toJS, trace, transaction, untracked, values, when };