mobx-state-tree 7.0.2 → 7.1.0

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.
@@ -340,7 +340,7 @@ export declare function isAlive(target: IAnyStateTreeNode): boolean;
340
340
  export declare function addDisposer(target: IAnyStateTreeNode, disposer: IDisposer): IDisposer;
341
341
  /**
342
342
  * Returns the environment of the current state tree, or throws. For more info on environments,
343
- * see [Dependency injection](https://github.com/mobxjs/mobx-state-tree#dependency-injection)
343
+ * see [Dependency injection](/concepts/dependency-injection)
344
344
  *
345
345
  * Please note that in child nodes access to the root is only possible
346
346
  * once the `afterAttach` hook has fired
@@ -1,4 +1,4 @@
1
- import { IValidationContext, IValidationResult, IStateTreeNode, ModelPrimitive } from "../../internal";
1
+ import { IValidationContext, IValidationResult, IStateTreeNode, ObjectNode, ModelPrimitive, AnyNode } from "../../internal";
2
2
  import type { WritableKeys } from "ts-essentials";
3
3
  /**
4
4
  * A state tree node value.
@@ -154,6 +154,8 @@ export type SnapshotOut<T> = T extends {
154
154
  * ```
155
155
  */
156
156
  export type SnapshotOrInstance<T> = SnapshotIn<T> | Instance<T>;
157
+ export declare function canApplyDirectSnapshot(childType: IAnyType, childNode: AnyNode, newValue: any): childNode is ObjectNode<any, any, any>;
158
+ export declare function resolveDirectApplyType(type: IAnyType): IAnyType;
157
159
  /**
158
160
  * Returns if a given value represents a type.
159
161
  *
@@ -795,7 +795,7 @@ function addDisposer(target, disposer) {
795
795
  }
796
796
  /**
797
797
  * Returns the environment of the current state tree, or throws. For more info on environments,
798
- * see [Dependency injection](https://github.com/mobxjs/mobx-state-tree#dependency-injection)
798
+ * see [Dependency injection](/concepts/dependency-injection)
799
799
  *
800
800
  * Please note that in child nodes access to the root is only possible
801
801
  * once the `afterAttach` hook has fired
@@ -2169,6 +2169,17 @@ var ObjectNode = /** @class */ (function (_super) {
2169
2169
  return this._internalEventsRegister(InternalEvents.Patch, handler);
2170
2170
  }
2171
2171
  });
2172
+ Object.defineProperty(ObjectNode.prototype, "hasPatchSubscribers", {
2173
+ enumerable: false,
2174
+ configurable: true,
2175
+ writable: true,
2176
+ value: function () {
2177
+ if (this._internalEventsHasSubscribers(InternalEvents.Patch)) {
2178
+ return true;
2179
+ }
2180
+ return this.parent ? this.parent.hasPatchSubscribers() : false;
2181
+ }
2182
+ });
2172
2183
  Object.defineProperty(ObjectNode.prototype, "emitPatch", {
2173
2184
  enumerable: false,
2174
2185
  configurable: true,
@@ -2381,6 +2392,7 @@ var TypeFlags;
2381
2392
  TypeFlags[TypeFlags["Lazy"] = 1048576] = "Lazy";
2382
2393
  TypeFlags[TypeFlags["Finite"] = 2097152] = "Finite";
2383
2394
  TypeFlags[TypeFlags["Float"] = 4194304] = "Float";
2395
+ TypeFlags[TypeFlags["BigInt"] = 8388608] = "BigInt";
2384
2396
  })(TypeFlags || (TypeFlags = {}));
2385
2397
  /**
2386
2398
  * @internal
@@ -2697,6 +2709,38 @@ var SimpleType = /** @class */ (function (_super) {
2697
2709
  });
2698
2710
  return SimpleType;
2699
2711
  }(BaseType));
2712
+ function canApplyDirectSnapshot(childType, childNode, newValue) {
2713
+ var reconciliationType = childNode.getReconciliationType();
2714
+ var expectedReconciliationType = resolveDirectApplyType(childType);
2715
+ // Only types that reconcile as the same transparent-wrapper-adjusted type can safely reuse
2716
+ // the existing child node. Wrappers with their own validation or snapshot semantics
2717
+ // intentionally keep a distinct reconciliation type so they fall back to the validated path.
2718
+ var hasMatchingReconciliationType = reconciliationType === expectedReconciliationType;
2719
+ return (childNode instanceof ObjectNode &&
2720
+ hasMatchingReconciliationType &&
2721
+ reconciliationType instanceof ComplexType &&
2722
+ isMutable(newValue) &&
2723
+ !isStateTreeNode(newValue) &&
2724
+ reconciliationType.isMatchingSnapshotId(childNode, newValue));
2725
+ }
2726
+ function resolveDirectApplyType(type) {
2727
+ var subTypes = type.getSubTypes();
2728
+ if (!subTypes ||
2729
+ Array.isArray(subTypes) ||
2730
+ subTypes === cannotDetermineSubtype ||
2731
+ !canUnwrapDirectApplyType(type)) {
2732
+ return type;
2733
+ }
2734
+ // Only unwrap wrappers that are transparent for direct apply. Wrappers with their own
2735
+ // validation or snapshot processing must keep their wrapper identity here.
2736
+ return resolveDirectApplyType(subTypes);
2737
+ }
2738
+ function canUnwrapDirectApplyType(type) {
2739
+ var transparentWrapperFlags = TypeFlags.Optional | TypeFlags.Late;
2740
+ var nonTransparentWrapperFlags = TypeFlags.Refinement | TypeFlags.SnapshotProcessor | TypeFlags.Union;
2741
+ return ((type.flags & transparentWrapperFlags) > 0 &&
2742
+ (type.flags & nonTransparentWrapperFlags) === 0);
2743
+ }
2700
2744
  /**
2701
2745
  * Returns if a given value represents a type.
2702
2746
  *
@@ -4046,6 +4090,7 @@ function isPrimitive(value, includeDate) {
4046
4090
  typeof value === "string" ||
4047
4091
  typeof value === "number" ||
4048
4092
  typeof value === "boolean" ||
4093
+ typeof value === "bigint" ||
4049
4094
  (includeDate && value instanceof Date));
4050
4095
  }
4051
4096
  /**
@@ -4930,6 +4975,8 @@ function proxyNodeTypeMethods(nodeType, snapshotProcessorType) {
4930
4975
  /**
4931
4976
  * `types.snapshotProcessor` - Runs a pre/post snapshot processor before/after serializing a given type.
4932
4977
  *
4978
+ * [See known issue with `applySnapshot` and `preProcessSnapshot`](https://github.com/mobxjs/mobx-state-tree/issues/1317)
4979
+ *
4933
4980
  * Example:
4934
4981
  * ```ts
4935
4982
  * const Todo1 = types.model({ text: types.string })
@@ -5380,23 +5427,33 @@ var MapType = /** @class */ (function (_super) {
5380
5427
  configurable: true,
5381
5428
  writable: true,
5382
5429
  value: function (node, snapshot) {
5383
- typecheckInternal(this, snapshot);
5430
+ if (!isPlainObject(snapshot)) {
5431
+ typecheckInternal(this, snapshot);
5432
+ return;
5433
+ }
5384
5434
  var target = node.storedValue;
5385
- var currentKeys = {};
5435
+ var childType = this.getChildType();
5386
5436
  Array.from(target.keys()).forEach(function (key) {
5387
- currentKeys[key] = false;
5388
- });
5389
- if (snapshot) {
5390
- // Don't use target.replace, as it will throw away all existing items first
5391
- for (var key in snapshot) {
5392
- target.set(key, snapshot[key]);
5393
- currentKeys["" + key] = true;
5394
- }
5395
- }
5396
- Object.keys(currentKeys).forEach(function (key) {
5397
- if (currentKeys[key] === false)
5437
+ if (!Object.prototype.hasOwnProperty.call(snapshot, key)) {
5398
5438
  target.delete(key);
5439
+ return;
5440
+ }
5441
+ var childNode = node.getChildNode(key);
5442
+ var newValue = snapshot[key];
5443
+ if (childNode.snapshot === newValue)
5444
+ return;
5445
+ if (canApplyDirectSnapshot(childType, childNode, newValue)) {
5446
+ childNode.applySnapshot(newValue);
5447
+ }
5448
+ else {
5449
+ target.set(key, newValue);
5450
+ }
5399
5451
  });
5452
+ for (var key in snapshot) {
5453
+ if (!Object.prototype.hasOwnProperty.call(snapshot, key) || target.has(key))
5454
+ continue;
5455
+ target.set(key, snapshot[key]);
5456
+ }
5400
5457
  }
5401
5458
  });
5402
5459
  Object.defineProperty(MapType.prototype, "getChildType", {
@@ -5722,9 +5779,52 @@ var ArrayType = /** @class */ (function (_super) {
5722
5779
  configurable: true,
5723
5780
  writable: true,
5724
5781
  value: function (node, snapshot) {
5725
- typecheckInternal(this, snapshot);
5782
+ if (!isArray(snapshot)) {
5783
+ typecheckInternal(this, snapshot);
5784
+ return;
5785
+ }
5726
5786
  var target = node.storedValue;
5727
- target.replace(snapshot);
5787
+ var childNodes = node.getChildren();
5788
+ var oldLength = childNodes.length;
5789
+ var newLength = snapshot.length;
5790
+ var childType = this.getChildType();
5791
+ var minLength = Math.min(oldLength, newLength);
5792
+ var firstChangedIndex = findFirstChangedIndex(childNodes, snapshot, minLength);
5793
+ // If all array items are the same and the length did not change, there is nothing to do.
5794
+ if (firstChangedIndex === oldLength && firstChangedIndex === newLength) {
5795
+ return;
5796
+ }
5797
+ // Preserve the old "always replace" behavior for length changes and when patches are being
5798
+ // observed, since those cases are more sensitive to patch shape (for example, splice
5799
+ // would otherwise emit add/remove patch sequences) and benchmark variance.
5800
+ if (oldLength !== newLength || node.hasPatchSubscribers()) {
5801
+ target.replace(snapshot);
5802
+ return;
5803
+ }
5804
+ // When every changed entry can reuse its existing child node, update them in place
5805
+ // instead of going through array replacement/splice.
5806
+ if (canApplyDirectSnapshotsInRange(childType, childNodes, snapshot, firstChangedIndex)) {
5807
+ applyDirectSnapshotsInRange(childNodes, snapshot, firstChangedIndex);
5808
+ return;
5809
+ }
5810
+ var oldEnd = oldLength - 1;
5811
+ var newEnd = newLength - 1;
5812
+ while (oldEnd >= firstChangedIndex &&
5813
+ newEnd >= firstChangedIndex &&
5814
+ childNodes[oldEnd].snapshot === snapshot[newEnd]) {
5815
+ oldEnd--;
5816
+ newEnd--;
5817
+ }
5818
+ // Trim the unchanged suffix too, so we only replace the minimal changed window.
5819
+ var replacedCount = oldEnd >= firstChangedIndex ? oldEnd - firstChangedIndex + 1 : 0;
5820
+ var replacementSnapshots = newEnd >= firstChangedIndex
5821
+ ? snapshot.slice(firstChangedIndex, newEnd + 1)
5822
+ : EMPTY_ARRAY;
5823
+ if (replacedCount === 1 && replacementSnapshots.length === 1) {
5824
+ target[firstChangedIndex] = replacementSnapshots[0];
5825
+ return;
5826
+ }
5827
+ target.splice.apply(target, __spreadArray([firstChangedIndex, replacedCount], __read(replacementSnapshots), false));
5728
5828
  }
5729
5829
  });
5730
5830
  Object.defineProperty(ArrayType.prototype, "getChildType", {
@@ -5796,6 +5896,31 @@ function array(subtype) {
5796
5896
  assertIsType(subtype, 1);
5797
5897
  return new ArrayType("".concat(subtype.name, "[]"), subtype);
5798
5898
  }
5899
+ function findFirstChangedIndex(childNodes, snapshot, length) {
5900
+ var index = 0;
5901
+ while (index < length && childNodes[index].snapshot === snapshot[index]) {
5902
+ index++;
5903
+ }
5904
+ return index;
5905
+ }
5906
+ function canApplyDirectSnapshotsInRange(childType, childNodes, snapshot, startIndex) {
5907
+ for (var i = startIndex; i < childNodes.length; i++) {
5908
+ if (childNodes[i].snapshot === snapshot[i])
5909
+ continue;
5910
+ if (!canApplyDirectSnapshot(childType, childNodes[i], snapshot[i])) {
5911
+ return false;
5912
+ }
5913
+ }
5914
+ return true;
5915
+ }
5916
+ function applyDirectSnapshotsInRange(childNodes, snapshot, startIndex) {
5917
+ for (var i = startIndex; i < childNodes.length; i++) {
5918
+ var childNode = childNodes[i];
5919
+ if (childNode.snapshot === snapshot[i])
5920
+ continue;
5921
+ childNode.applySnapshot(snapshot[i]);
5922
+ }
5923
+ }
5799
5924
  function reconcileArrayChildren(parent, childType, oldNodes, newValues, newPaths) {
5800
5925
  var nothingChanged = true;
5801
5926
  for (var i = 0;; i++) {
@@ -6441,10 +6566,25 @@ var ModelType = /** @class */ (function (_super) {
6441
6566
  configurable: true,
6442
6567
  writable: true,
6443
6568
  value: function (node, snapshot) {
6444
- typecheckInternal(this, snapshot);
6445
6569
  var preProcessedSnapshot = this.applySnapshotPreProcessor(snapshot);
6446
- this.forAllProps(function (name) {
6447
- node.storedValue[name] = preProcessedSnapshot[name];
6570
+ var isPreProcessedSnapshotNonPlain = !isPlainObject(preProcessedSnapshot);
6571
+ // Fast-path plain-object snapshots, but still validate when preprocessing is required
6572
+ // or when preprocessing produces an invalid model snapshot.
6573
+ if (!isPlainObject(snapshot) || isPreProcessedSnapshotNonPlain) {
6574
+ typecheckInternal(this, snapshot);
6575
+ if (isPreProcessedSnapshotNonPlain)
6576
+ return;
6577
+ }
6578
+ this.forAllProps(function (name, childType) {
6579
+ var childNode = node.getChildNode(name);
6580
+ var newValue = preProcessedSnapshot[name];
6581
+ if (childNode.snapshot === newValue)
6582
+ return;
6583
+ if (canApplyDirectSnapshot(childType, childNode, newValue)) {
6584
+ childNode.applySnapshot(newValue);
6585
+ return;
6586
+ }
6587
+ node.storedValue[name] = newValue;
6448
6588
  });
6449
6589
  }
6450
6590
  });
@@ -6735,6 +6875,37 @@ var float = new CoreType("float", TypeFlags.Float, function (v) { return isFloat
6735
6875
  */
6736
6876
  // tslint:disable-next-line:variable-name
6737
6877
  var finite = new CoreType("finite", TypeFlags.Finite, function (v) { return isFinite(v); });
6878
+ var _BigIntPrimitive = new CoreType("bigint", TypeFlags.BigInt, function (v) {
6879
+ if (typeof v === "bigint") {
6880
+ return true;
6881
+ }
6882
+ if (typeof v === "string" || typeof v === "number") {
6883
+ try {
6884
+ // BigInt primitive constructor verifies whether the value is a valid integer
6885
+ BigInt(v);
6886
+ return true;
6887
+ }
6888
+ catch (_a) { }
6889
+ }
6890
+ return false;
6891
+ }, function (v) { return (typeof v === "bigint" ? v : BigInt(v)); });
6892
+ _BigIntPrimitive.getSnapshot = function (node) {
6893
+ return String(node.storedValue);
6894
+ };
6895
+ /**
6896
+ * `types.bigint` - Creates a type that can only contain a bigint value.
6897
+ * Snapshots serialize to string (JSON-safe) and deserialize from string, number or bigint.
6898
+ *
6899
+ * Example:
6900
+ * ```ts
6901
+ * const BigId = types.model({
6902
+ * id: types.identifier,
6903
+ * value: types.bigint
6904
+ * })
6905
+ * getSnapshot(store).value // "0" (string, JSON-safe)
6906
+ * ```
6907
+ */
6908
+ var bigint = _BigIntPrimitive;
6738
6909
  /**
6739
6910
  * `types.boolean` - Creates a type that can only contain a boolean value.
6740
6911
  * This type is used for boolean values by default
@@ -6786,6 +6957,8 @@ function getPrimitiveFactoryFromValue(value) {
6786
6957
  return number; // In the future, isInteger(value) ? integer : number would be interesting, but would be too breaking for now
6787
6958
  case "boolean":
6788
6959
  return boolean;
6960
+ case "bigint":
6961
+ return bigint;
6789
6962
  case "object":
6790
6963
  if (value instanceof Date)
6791
6964
  return DatePrimitive;
@@ -6805,7 +6978,8 @@ function isPrimitiveType(type) {
6805
6978
  TypeFlags.Number |
6806
6979
  TypeFlags.Integer |
6807
6980
  TypeFlags.Boolean |
6808
- TypeFlags.Date)) >
6981
+ TypeFlags.Date |
6982
+ TypeFlags.BigInt)) >
6809
6983
  0);
6810
6984
  }
6811
6985
 
@@ -8636,6 +8810,7 @@ var types = {
8636
8810
  integer: integer,
8637
8811
  float: float,
8638
8812
  finite: finite,
8813
+ bigint: bigint,
8639
8814
  Date: DatePrimitive,
8640
8815
  map: map,
8641
8816
  array: array,