mobx 6.10.0 → 6.10.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # mobx
2
2
 
3
+ ## 6.10.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [`c8d9374d`](https://github.com/mobxjs/mobx/commit/c8d9374d4f3b05cfec0d690e0eb3ada4f619ff0b) [#3748](https://github.com/mobxjs/mobx/pull/3748) Thanks [@mweststrate](https://github.com/mweststrate)! - Fixed: #3747, computed values becoming stale if the underlying observable was created and updated outside a reactive context
8
+
9
+ ## 6.10.1
10
+
11
+ ### Patch Changes
12
+
13
+ - [`3ceeb865`](https://github.com/mobxjs/mobx/commit/3ceeb8651e328c4c7211c875696b3f5269fea834) [#3732](https://github.com/mobxjs/mobx/pull/3732) Thanks [@urugator](https://github.com/urugator)! - - fix: #3728: Observable initialization updates state version.
14
+ - fix: Observable set initialization violates `enforceActions: "always"`.
15
+ - fix: Changing keys of observable object does not respect `enforceActions`.
16
+
3
17
  ## 6.10.0
4
18
 
5
19
  ### Minor Changes
@@ -2,13 +2,14 @@ import { IDerivationState_, IObservable, IDerivation, Lambda } from "../internal
2
2
  export declare const $mobx: unique symbol;
3
3
  export interface IAtom extends IObservable {
4
4
  reportObserved(): boolean;
5
- reportChanged(): any;
5
+ reportChanged(): void;
6
6
  }
7
7
  export declare class Atom implements IAtom {
8
8
  name_: string;
9
9
  isPendingUnobservation_: boolean;
10
10
  isBeingObserved_: boolean;
11
11
  observers_: Set<IDerivation>;
12
+ batchId_: number;
12
13
  diffValue_: number;
13
14
  lastAccessedBy_: number;
14
15
  lowestObserverState_: IDerivationState_;
@@ -37,6 +37,11 @@ export declare class MobXGlobals {
37
37
  * Are we in a batch block? (and how many of them)
38
38
  */
39
39
  inBatch: number;
40
+ /**
41
+ * ID of the latest batch. Used to suppress reportChanged of newly created atoms.
42
+ * Note the value persists even after batch ended.
43
+ */
44
+ batchId: number;
40
45
  /**
41
46
  * Observables that don't have observers anymore, and are about to be
42
47
  * suspended, unless somebody else accesses it in the same batch
@@ -426,12 +426,14 @@ var Atom = /*#__PURE__*/function () {
426
426
  this.isPendingUnobservation_ = false;
427
427
  this.isBeingObserved_ = false;
428
428
  this.observers_ = new Set();
429
+ this.batchId_ = void 0;
429
430
  this.diffValue_ = 0;
430
431
  this.lastAccessedBy_ = 0;
431
432
  this.lowestObserverState_ = IDerivationState_.NOT_TRACKING_;
432
433
  this.onBOL = void 0;
433
434
  this.onBUOL = void 0;
434
435
  this.name_ = name_;
436
+ this.batchId_ = globalState.inBatch ? globalState.batchId : NaN;
435
437
  }
436
438
  // onBecomeObservedListeners
437
439
  var _proto = Atom.prototype;
@@ -460,11 +462,15 @@ var Atom = /*#__PURE__*/function () {
460
462
  * Invoke this method _after_ this method has changed to signal mobx that all its observers should invalidate.
461
463
  */;
462
464
  _proto.reportChanged = function reportChanged() {
465
+ if (!globalState.inBatch || this.batchId_ !== globalState.batchId) {
466
+ // We could update state version only at the end of batch,
467
+ // but we would still have to switch some global flag here to signal a change.
468
+ globalState.stateVersion = globalState.stateVersion < Number.MAX_SAFE_INTEGER ? globalState.stateVersion + 1 : Number.MIN_SAFE_INTEGER;
469
+ // Avoids the possibility of hitting the same globalState.batchId when it cycled through all integers (necessary?)
470
+ this.batchId_ = NaN;
471
+ }
463
472
  startBatch();
464
473
  propagateChanged(this);
465
- // We could update state version only at the end of batch,
466
- // but we would still have to switch some global flag here to signal a change.
467
- globalState.stateVersion = globalState.stateVersion < Number.MAX_SAFE_INTEGER ? globalState.stateVersion + 1 : Number.MIN_SAFE_INTEGER;
468
474
  endBatch();
469
475
  };
470
476
  _proto.toString = function toString() {
@@ -993,7 +999,9 @@ var observableFactories = {
993
999
  return new ObservableSet(initialValues, getEnhancerFromOptions(o), o.name);
994
1000
  },
995
1001
  object: function object(props, decorators, options) {
996
- return extendObservable(globalState.useProxies === false || (options == null ? void 0 : options.proxy) === false ? asObservableObject({}, options) : asDynamicObservableObject({}, options), props, decorators);
1002
+ return initObservable(function () {
1003
+ return extendObservable(globalState.useProxies === false || (options == null ? void 0 : options.proxy) === false ? asObservableObject({}, options) : asDynamicObservableObject({}, options), props, decorators);
1004
+ });
997
1005
  },
998
1006
  ref: /*#__PURE__*/createDecoratorAnnotation(observableRefAnnotation),
999
1007
  shallow: /*#__PURE__*/createDecoratorAnnotation(observableShallowAnnotation),
@@ -1815,6 +1823,7 @@ var MobXGlobals = function MobXGlobals() {
1815
1823
  this.runId = 0;
1816
1824
  this.mobxGuid = 0;
1817
1825
  this.inBatch = 0;
1826
+ this.batchId = Number.MIN_SAFE_INTEGER;
1818
1827
  this.pendingUnobservations = [];
1819
1828
  this.pendingReactions = [];
1820
1829
  this.isRunningReactions = false;
@@ -1954,6 +1963,9 @@ function queueForUnobservation(observable) {
1954
1963
  * Avoids unnecessary recalculations.
1955
1964
  */
1956
1965
  function startBatch() {
1966
+ if (globalState.inBatch === 0) {
1967
+ globalState.batchId = globalState.batchId < Number.MAX_SAFE_INTEGER ? globalState.batchId + 1 : Number.MIN_SAFE_INTEGER;
1968
+ }
1957
1969
  globalState.inBatch++;
1958
1970
  }
1959
1971
  function endBatch() {
@@ -2629,17 +2641,14 @@ function extendObservable(target, properties, annotations, options) {
2629
2641
  }
2630
2642
  // Pull descriptors first, so we don't have to deal with props added by administration ($mobx)
2631
2643
  var descriptors = getOwnPropertyDescriptors(properties);
2632
- var adm = asObservableObject(target, options)[$mobx];
2633
- startBatch();
2634
- try {
2644
+ initObservable(function () {
2645
+ var adm = asObservableObject(target, options)[$mobx];
2635
2646
  ownKeys(descriptors).forEach(function (key) {
2636
2647
  adm.extend_(key, descriptors[key],
2637
2648
  // must pass "undefined" for { key: undefined }
2638
2649
  !annotations ? true : key in annotations ? annotations[key] : true);
2639
2650
  });
2640
- } finally {
2641
- endBatch();
2642
- }
2651
+ });
2643
2652
  return target;
2644
2653
  }
2645
2654
 
@@ -3325,10 +3334,9 @@ function notifyListeners(listenable, change) {
3325
3334
  }
3326
3335
 
3327
3336
  function makeObservable(target, annotations, options) {
3328
- var adm = asObservableObject(target, options)[$mobx];
3329
- startBatch();
3330
- try {
3337
+ initObservable(function () {
3331
3338
  var _annotations;
3339
+ var adm = asObservableObject(target, options)[$mobx];
3332
3340
  if ("development" !== "production" && annotations && target[storedAnnotationsSymbol]) {
3333
3341
  die("makeObservable second arg must be nullish when using decorators. Mixing @decorator syntax with annotations is not supported.");
3334
3342
  }
@@ -3338,9 +3346,7 @@ function makeObservable(target, annotations, options) {
3338
3346
  ownKeys(annotations).forEach(function (key) {
3339
3347
  return adm.make_(key, annotations[key]);
3340
3348
  });
3341
- } finally {
3342
- endBatch();
3343
- }
3349
+ });
3344
3350
  return target;
3345
3351
  }
3346
3352
  // proto[keysSymbol] = new Set<PropertyKey>()
@@ -3359,26 +3365,23 @@ function makeAutoObservable(target, overrides, options) {
3359
3365
  if (isPlainObject(target)) {
3360
3366
  return extendObservable(target, target, overrides, options);
3361
3367
  }
3362
- var adm = asObservableObject(target, options)[$mobx];
3363
- // Optimization: cache keys on proto
3364
- // Assumes makeAutoObservable can be called only once per object and can't be used in subclass
3365
- if (!target[keysSymbol]) {
3366
- var proto = Object.getPrototypeOf(target);
3367
- var keys = new Set([].concat(ownKeys(target), ownKeys(proto)));
3368
- keys["delete"]("constructor");
3369
- keys["delete"]($mobx);
3370
- addHiddenProp(proto, keysSymbol, keys);
3371
- }
3372
- startBatch();
3373
- try {
3368
+ initObservable(function () {
3369
+ var adm = asObservableObject(target, options)[$mobx];
3370
+ // Optimization: cache keys on proto
3371
+ // Assumes makeAutoObservable can be called only once per object and can't be used in subclass
3372
+ if (!target[keysSymbol]) {
3373
+ var proto = Object.getPrototypeOf(target);
3374
+ var keys = new Set([].concat(ownKeys(target), ownKeys(proto)));
3375
+ keys["delete"]("constructor");
3376
+ keys["delete"]($mobx);
3377
+ addHiddenProp(proto, keysSymbol, keys);
3378
+ }
3374
3379
  target[keysSymbol].forEach(function (key) {
3375
3380
  return adm.make_(key,
3376
3381
  // must pass "undefined" for { key: undefined }
3377
3382
  !overrides ? true : key in overrides ? overrides[key] : true);
3378
3383
  });
3379
- } finally {
3380
- endBatch();
3381
- }
3384
+ });
3382
3385
  return target;
3383
3386
  }
3384
3387
 
@@ -3686,16 +3689,16 @@ function createObservableArray(initialValues, enhancer, name, owned) {
3686
3689
  owned = false;
3687
3690
  }
3688
3691
  assertProxies();
3689
- var adm = new ObservableArrayAdministration(name, enhancer, owned, false);
3690
- addHiddenFinalProp(adm.values_, $mobx, adm);
3691
- var proxy = new Proxy(adm.values_, arrayTraps);
3692
- adm.proxy_ = proxy;
3693
- if (initialValues && initialValues.length) {
3694
- var prev = allowStateChangesStart(true);
3695
- adm.spliceWithArray_(0, 0, initialValues);
3696
- allowStateChangesEnd(prev);
3697
- }
3698
- return proxy;
3692
+ return initObservable(function () {
3693
+ var adm = new ObservableArrayAdministration(name, enhancer, owned, false);
3694
+ addHiddenFinalProp(adm.values_, $mobx, adm);
3695
+ var proxy = new Proxy(adm.values_, arrayTraps);
3696
+ adm.proxy_ = proxy;
3697
+ if (initialValues && initialValues.length) {
3698
+ adm.spliceWithArray_(0, 0, initialValues);
3699
+ }
3700
+ return proxy;
3701
+ });
3699
3702
  }
3700
3703
  // eslint-disable-next-line
3701
3704
  var arrayExtensions = {
@@ -3891,11 +3894,13 @@ var ObservableMap = /*#__PURE__*/function () {
3891
3894
  if (!isFunction(Map)) {
3892
3895
  die(18);
3893
3896
  }
3894
- this.keysAtom_ = createAtom( this.name_ + ".keys()" );
3895
- this.data_ = new Map();
3896
- this.hasMap_ = new Map();
3897
- allowStateChanges(true, function () {
3898
- _this.merge(initialData);
3897
+ initObservable(function () {
3898
+ _this.keysAtom_ = createAtom("development" !== "production" ? _this.name_ + ".keys()" : "ObservableMap.keys()");
3899
+ _this.data_ = new Map();
3900
+ _this.hasMap_ = new Map();
3901
+ if (initialData) {
3902
+ _this.merge(initialData);
3903
+ }
3899
3904
  });
3900
3905
  }
3901
3906
  var _proto = ObservableMap.prototype;
@@ -4279,6 +4284,7 @@ _Symbol$iterator$1 = Symbol.iterator;
4279
4284
  _Symbol$toStringTag$1 = Symbol.toStringTag;
4280
4285
  var ObservableSet = /*#__PURE__*/function () {
4281
4286
  function ObservableSet(initialData, enhancer, name_) {
4287
+ var _this = this;
4282
4288
  if (enhancer === void 0) {
4283
4289
  enhancer = deepEnhancer;
4284
4290
  }
@@ -4297,13 +4303,15 @@ var ObservableSet = /*#__PURE__*/function () {
4297
4303
  if (!isFunction(Set)) {
4298
4304
  die(22);
4299
4305
  }
4300
- this.atom_ = createAtom(this.name_);
4301
4306
  this.enhancer_ = function (newV, oldV) {
4302
4307
  return enhancer(newV, oldV, name_);
4303
4308
  };
4304
- if (initialData) {
4305
- this.replace(initialData);
4306
- }
4309
+ initObservable(function () {
4310
+ _this.atom_ = createAtom(_this.name_);
4311
+ if (initialData) {
4312
+ _this.replace(initialData);
4313
+ }
4314
+ });
4307
4315
  }
4308
4316
  var _proto = ObservableSet.prototype;
4309
4317
  _proto.dehanceValue_ = function dehanceValue_(value) {
@@ -4313,12 +4321,12 @@ var ObservableSet = /*#__PURE__*/function () {
4313
4321
  return value;
4314
4322
  };
4315
4323
  _proto.clear = function clear() {
4316
- var _this = this;
4324
+ var _this2 = this;
4317
4325
  transaction(function () {
4318
4326
  untracked(function () {
4319
- for (var _iterator = _createForOfIteratorHelperLoose(_this.data_.values()), _step; !(_step = _iterator()).done;) {
4327
+ for (var _iterator = _createForOfIteratorHelperLoose(_this2.data_.values()), _step; !(_step = _iterator()).done;) {
4320
4328
  var value = _step.value;
4321
- _this["delete"](value);
4329
+ _this2["delete"](value);
4322
4330
  }
4323
4331
  });
4324
4332
  });
@@ -4330,7 +4338,7 @@ var ObservableSet = /*#__PURE__*/function () {
4330
4338
  }
4331
4339
  };
4332
4340
  _proto.add = function add(value) {
4333
- var _this2 = this;
4341
+ var _this3 = this;
4334
4342
  checkIfStateModificationsAreAllowed(this.atom_);
4335
4343
  if (hasInterceptors(this)) {
4336
4344
  var change = interceptChange(this, {
@@ -4347,8 +4355,8 @@ var ObservableSet = /*#__PURE__*/function () {
4347
4355
 
4348
4356
  if (!this.has(value)) {
4349
4357
  transaction(function () {
4350
- _this2.data_.add(_this2.enhancer_(value, undefined));
4351
- _this2.atom_.reportChanged();
4358
+ _this3.data_.add(_this3.enhancer_(value, undefined));
4359
+ _this3.atom_.reportChanged();
4352
4360
  });
4353
4361
  var notifySpy = isSpyEnabled();
4354
4362
  var notify = hasListeners(this);
@@ -4372,7 +4380,7 @@ var ObservableSet = /*#__PURE__*/function () {
4372
4380
  return this;
4373
4381
  };
4374
4382
  _proto["delete"] = function _delete(value) {
4375
- var _this3 = this;
4383
+ var _this4 = this;
4376
4384
  if (hasInterceptors(this)) {
4377
4385
  var change = interceptChange(this, {
4378
4386
  type: DELETE,
@@ -4397,8 +4405,8 @@ var ObservableSet = /*#__PURE__*/function () {
4397
4405
  spyReportStart(_change2);
4398
4406
  }
4399
4407
  transaction(function () {
4400
- _this3.atom_.reportChanged();
4401
- _this3.data_["delete"](value);
4408
+ _this4.atom_.reportChanged();
4409
+ _this4.data_["delete"](value);
4402
4410
  });
4403
4411
  if (notify) {
4404
4412
  notifyListeners(this, _change2);
@@ -4451,20 +4459,20 @@ var ObservableSet = /*#__PURE__*/function () {
4451
4459
  });
4452
4460
  };
4453
4461
  _proto.replace = function replace(other) {
4454
- var _this4 = this;
4462
+ var _this5 = this;
4455
4463
  if (isObservableSet(other)) {
4456
4464
  other = new Set(other);
4457
4465
  }
4458
4466
  transaction(function () {
4459
4467
  if (Array.isArray(other)) {
4460
- _this4.clear();
4468
+ _this5.clear();
4461
4469
  other.forEach(function (value) {
4462
- return _this4.add(value);
4470
+ return _this5.add(value);
4463
4471
  });
4464
4472
  } else if (isES6Set(other)) {
4465
- _this4.clear();
4473
+ _this5.clear();
4466
4474
  other.forEach(function (value) {
4467
- return _this4.add(value);
4475
+ return _this5.add(value);
4468
4476
  });
4469
4477
  } else if (other !== null && other !== undefined) {
4470
4478
  die("Cannot initialize set from " + other);
@@ -4728,6 +4736,7 @@ var ObservableObjectAdministration = /*#__PURE__*/function () {
4728
4736
  if (proxyTrap === void 0) {
4729
4737
  proxyTrap = false;
4730
4738
  }
4739
+ checkIfStateModificationsAreAllowed(this.keysAtom_);
4731
4740
  try {
4732
4741
  startBatch();
4733
4742
  // Delete
@@ -4775,6 +4784,7 @@ var ObservableObjectAdministration = /*#__PURE__*/function () {
4775
4784
  if (proxyTrap === void 0) {
4776
4785
  proxyTrap = false;
4777
4786
  }
4787
+ checkIfStateModificationsAreAllowed(this.keysAtom_);
4778
4788
  try {
4779
4789
  startBatch();
4780
4790
  // Delete
@@ -4826,6 +4836,7 @@ var ObservableObjectAdministration = /*#__PURE__*/function () {
4826
4836
  if (proxyTrap === void 0) {
4827
4837
  proxyTrap = false;
4828
4838
  }
4839
+ checkIfStateModificationsAreAllowed(this.keysAtom_);
4829
4840
  try {
4830
4841
  startBatch();
4831
4842
  // Delete
@@ -4881,6 +4892,7 @@ var ObservableObjectAdministration = /*#__PURE__*/function () {
4881
4892
  if (proxyTrap === void 0) {
4882
4893
  proxyTrap = false;
4883
4894
  }
4895
+ checkIfStateModificationsAreAllowed(this.keysAtom_);
4884
4896
  // No such prop
4885
4897
  if (!hasProp(this.target_, key)) {
4886
4898
  return true;
@@ -5110,6 +5122,17 @@ function assertAnnotable(adm, annotation, key) {
5110
5122
 
5111
5123
  // Bug in safari 9.* (or iOS 9 safari mobile). See #364
5112
5124
  var ENTRY_0 = /*#__PURE__*/createArrayEntryDescriptor(0);
5125
+ var safariPrototypeSetterInheritanceBug = /*#__PURE__*/function () {
5126
+ var v = false;
5127
+ var p = {};
5128
+ Object.defineProperty(p, "0", {
5129
+ set: function set() {
5130
+ v = true;
5131
+ }
5132
+ });
5133
+ /*#__PURE__*/Object.create(p)["0"] = 1;
5134
+ return v === false;
5135
+ }();
5113
5136
  /**
5114
5137
  * This array buffer contains two lists of properties, so that all arrays
5115
5138
  * can recycle their property definitions, which significantly improves performance of creating
@@ -5142,20 +5165,20 @@ var LegacyObservableArray = /*#__PURE__*/function (_StubArray, _Symbol$toStringT
5142
5165
  owned = false;
5143
5166
  }
5144
5167
  _this = _StubArray.call(this) || this;
5145
- var adm = new ObservableArrayAdministration(name, enhancer, owned, true);
5146
- adm.proxy_ = _assertThisInitialized(_this);
5147
- addHiddenFinalProp(_assertThisInitialized(_this), $mobx, adm);
5148
- if (initialValues && initialValues.length) {
5149
- var prev = allowStateChangesStart(true);
5150
- // @ts-ignore
5151
- _this.spliceWithArray(0, 0, initialValues);
5152
- allowStateChangesEnd(prev);
5153
- }
5154
- {
5155
- // Seems that Safari won't use numeric prototype setter untill any * numeric property is
5156
- // defined on the instance. After that it works fine, even if this property is deleted.
5157
- Object.defineProperty(_assertThisInitialized(_this), "0", ENTRY_0);
5158
- }
5168
+ initObservable(function () {
5169
+ var adm = new ObservableArrayAdministration(name, enhancer, owned, true);
5170
+ adm.proxy_ = _assertThisInitialized(_this);
5171
+ addHiddenFinalProp(_assertThisInitialized(_this), $mobx, adm);
5172
+ if (initialValues && initialValues.length) {
5173
+ // @ts-ignore
5174
+ _this.spliceWithArray(0, 0, initialValues);
5175
+ }
5176
+ if (safariPrototypeSetterInheritanceBug) {
5177
+ // Seems that Safari won't use numeric prototype setter untill any * numeric property is
5178
+ // defined on the instance. After that it works fine, even if this property is deleted.
5179
+ Object.defineProperty(_assertThisInitialized(_this), "0", ENTRY_0);
5180
+ }
5181
+ });
5159
5182
  return _this;
5160
5183
  }
5161
5184
  var _proto = LegacyObservableArray.prototype;
@@ -5310,6 +5333,24 @@ function getDebugName(thing, property) {
5310
5333
  }
5311
5334
  return named.name_;
5312
5335
  }
5336
+ /**
5337
+ * Helper function for initializing observable structures, it applies:
5338
+ * 1. allowStateChanges so we don't violate enforceActions.
5339
+ * 2. untracked so we don't accidentaly subscribe to anything observable accessed during init in case the observable is created inside derivation.
5340
+ * 3. batch to avoid state version updates
5341
+ */
5342
+ function initObservable(cb) {
5343
+ var derivation = untrackedStart();
5344
+ var allowStateChanges = allowStateChangesStart(true);
5345
+ startBatch();
5346
+ try {
5347
+ return cb();
5348
+ } finally {
5349
+ endBatch();
5350
+ allowStateChangesEnd(allowStateChanges);
5351
+ untrackedEnd(derivation);
5352
+ }
5353
+ }
5313
5354
 
5314
5355
  var toString = objectPrototype.toString;
5315
5356
  function deepEqual(a, b, depth) {