@jbrowse/mobx-state-tree 6.5.2 → 6.6.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/CHANGELOG.md +33 -0
- package/dist/index.d.ts +151 -116
- package/dist/mobx-state-tree.cjs +416 -386
- package/dist/mobx-state-tree.cjs.map +1 -1
- package/dist/mobx-state-tree.mjs +413 -388
- package/dist/mobx-state-tree.mjs.map +1 -1
- package/package.json +1 -1
package/dist/mobx-state-tree.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isComputedProp, isObservableProp,
|
|
1
|
+
import { isComputedProp, isObservableProp, action, createAtom, computed, _allowStateChangesInsideComputed, reaction, runInAction, observable, values, entries, isObservableArray, isObservableObject, defineProperty as defineProperty$1, _interceptReads, intercept, observe, ObservableMap, _getAdministration, set, makeObservable, getAtom, when } from 'mobx';
|
|
2
2
|
|
|
3
3
|
let livelinessChecking = "warn";
|
|
4
4
|
/**
|
|
@@ -565,7 +565,9 @@ function getRelativePath(base, target) {
|
|
|
565
565
|
}
|
|
566
566
|
/**
|
|
567
567
|
* Returns a deep copy of the given state tree node as new tree.
|
|
568
|
-
*
|
|
568
|
+
* Like `getType(x).create(getSnapshot(x))`, except that a node wrapped in a
|
|
569
|
+
* `types.snapshotProcessor` is recreated through the processor, which
|
|
570
|
+
* `getType(x)` (the wrapped type) would skip.
|
|
569
571
|
*
|
|
570
572
|
* _Tip: clone will create a literal copy, including the same identifiers. To modify identifiers etc. during cloning, don't use clone but take a snapshot of the tree, modify it, and create new instance_
|
|
571
573
|
*
|
|
@@ -577,11 +579,11 @@ function clone(source, keepEnvironment = true) {
|
|
|
577
579
|
// check all arguments
|
|
578
580
|
assertIsStateTreeNode(source, 1);
|
|
579
581
|
const node = getStateTreeNode(source);
|
|
580
|
-
return node.type.create(node.snapshot, keepEnvironment === true
|
|
582
|
+
return (node.snapshotProcessorType ?? node.type).create(node.snapshot, keepEnvironment === true
|
|
581
583
|
? node.root.environment
|
|
582
584
|
: keepEnvironment === false
|
|
583
585
|
? undefined
|
|
584
|
-
: keepEnvironment);
|
|
586
|
+
: keepEnvironment);
|
|
585
587
|
}
|
|
586
588
|
/**
|
|
587
589
|
* Removes a model element from the state tree, and let it live on as a new state tree
|
|
@@ -700,17 +702,15 @@ function walk(target, processor) {
|
|
|
700
702
|
* @returns
|
|
701
703
|
*/
|
|
702
704
|
function getPropertyMembers(typeOrNode) {
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
}
|
|
710
|
-
assertArg(type, t => isModelType(t), "model type or model instance", 1);
|
|
705
|
+
const type = isStateTreeNode(typeOrNode)
|
|
706
|
+
? getType(typeOrNode)
|
|
707
|
+
: typeOrNode;
|
|
708
|
+
assertArg(type, isModelType, "model type or model instance", 1);
|
|
709
|
+
// a wrapped model reports the model's properties; a union of models has no
|
|
710
|
+
// single set and reports none
|
|
711
711
|
return {
|
|
712
712
|
name: type.name,
|
|
713
|
-
properties: { ...type
|
|
713
|
+
properties: { ...asModelType(type)?.properties }
|
|
714
714
|
};
|
|
715
715
|
}
|
|
716
716
|
/**
|
|
@@ -912,16 +912,28 @@ class BaseNode {
|
|
|
912
912
|
}
|
|
913
913
|
}
|
|
914
914
|
_hookSubscribers;
|
|
915
|
-
fireInternalHook(name) {
|
|
916
|
-
|
|
917
|
-
|
|
915
|
+
fireInternalHook(name, subject = this) {
|
|
916
|
+
this._hookSubscribers?.emit(name, subject, name);
|
|
917
|
+
}
|
|
918
|
+
/**
|
|
919
|
+
* Detaching a node takes its whole subtree out of the tree, but only the
|
|
920
|
+
* detached node's parent changes, so only it fires `beforeDetach` for real.
|
|
921
|
+
* Internal subscribers below it (reference watchers on a target) still need
|
|
922
|
+
* to know their node is leaving.
|
|
923
|
+
*/
|
|
924
|
+
notifyDetachOf(subject) {
|
|
925
|
+
this.fireInternalHook(Hook.beforeDetach, subject);
|
|
926
|
+
}
|
|
927
|
+
isWithin(ancestor) {
|
|
928
|
+
for (let node = this.parent; node; node = node.parent) {
|
|
929
|
+
if (node === ancestor) {
|
|
930
|
+
return true;
|
|
931
|
+
}
|
|
918
932
|
}
|
|
933
|
+
return false;
|
|
919
934
|
}
|
|
920
935
|
registerHook(hook, hookHandler) {
|
|
921
|
-
|
|
922
|
-
this._hookSubscribers = new EventHandlers();
|
|
923
|
-
}
|
|
924
|
-
return this._hookSubscribers.register(hook, hookHandler);
|
|
936
|
+
return (this._hookSubscribers ??= new EventHandlers()).register(hook, hookHandler);
|
|
925
937
|
}
|
|
926
938
|
_parent;
|
|
927
939
|
get parent() {
|
|
@@ -982,6 +994,13 @@ class BaseNode {
|
|
|
982
994
|
this.aliveAtom.reportObserved();
|
|
983
995
|
return this.isAlive;
|
|
984
996
|
}
|
|
997
|
+
die() {
|
|
998
|
+
if (!this.isAlive || this.isDetaching) {
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
this.aboutToDie();
|
|
1002
|
+
this.finalizeDeath();
|
|
1003
|
+
}
|
|
985
1004
|
baseFinalizeCreation(whenFinalized) {
|
|
986
1005
|
if (devMode()) {
|
|
987
1006
|
if (!this.isAlive) {
|
|
@@ -1017,6 +1036,7 @@ class BaseNode {
|
|
|
1017
1036
|
this.fireHook(Hook.beforeDestroy);
|
|
1018
1037
|
}
|
|
1019
1038
|
}
|
|
1039
|
+
BaseNode.prototype.die = action(BaseNode.prototype.die);
|
|
1020
1040
|
|
|
1021
1041
|
/**
|
|
1022
1042
|
* @internal
|
|
@@ -1034,9 +1054,6 @@ class ScalarNode extends BaseNode {
|
|
|
1034
1054
|
throw e;
|
|
1035
1055
|
}
|
|
1036
1056
|
this.state = NodeLifeCycle.CREATED;
|
|
1037
|
-
// for scalar nodes there's no point in firing this event since it would fire on the constructor, before
|
|
1038
|
-
// anybody can actually register for/listen to it
|
|
1039
|
-
// this.fireHook(Hook.AfterCreate)
|
|
1040
1057
|
this.finalizeCreation();
|
|
1041
1058
|
}
|
|
1042
1059
|
get root() {
|
|
@@ -1079,13 +1096,6 @@ class ScalarNode extends BaseNode {
|
|
|
1079
1096
|
const path = (this.isAlive ? this.path : this.pathUponDeath) || "<root>";
|
|
1080
1097
|
return `${this.type.name}@${path}${this.isAlive ? "" : " [dead]"}`;
|
|
1081
1098
|
}
|
|
1082
|
-
die() {
|
|
1083
|
-
if (!this.isAlive || this.state === NodeLifeCycle.DETACHING) {
|
|
1084
|
-
return;
|
|
1085
|
-
}
|
|
1086
|
-
this.aboutToDie();
|
|
1087
|
-
this.finalizeDeath();
|
|
1088
|
-
}
|
|
1089
1099
|
finalizeCreation() {
|
|
1090
1100
|
this.baseFinalizeCreation();
|
|
1091
1101
|
}
|
|
@@ -1099,7 +1109,6 @@ class ScalarNode extends BaseNode {
|
|
|
1099
1109
|
this.fireInternalHook(name);
|
|
1100
1110
|
}
|
|
1101
1111
|
}
|
|
1102
|
-
ScalarNode.prototype.die = action(ScalarNode.prototype.die);
|
|
1103
1112
|
|
|
1104
1113
|
let nextNodeId = 1;
|
|
1105
1114
|
var ObservableInstanceLifecycle;
|
|
@@ -1287,8 +1296,8 @@ class ObjectNode extends BaseNode {
|
|
|
1287
1296
|
if (!this.parent) {
|
|
1288
1297
|
return;
|
|
1289
1298
|
}
|
|
1290
|
-
// detach if attached
|
|
1291
1299
|
this.fireHook(Hook.beforeDetach);
|
|
1300
|
+
this.notifyChildrenOfDetach(this);
|
|
1292
1301
|
const previousState = this.state;
|
|
1293
1302
|
this.state = NodeLifeCycle.DETACHING;
|
|
1294
1303
|
const root = this.root;
|
|
@@ -1304,6 +1313,21 @@ class ObjectNode extends BaseNode {
|
|
|
1304
1313
|
this.state = previousState;
|
|
1305
1314
|
}
|
|
1306
1315
|
}
|
|
1316
|
+
notifyDetachOf(subject) {
|
|
1317
|
+
super.notifyDetachOf(subject);
|
|
1318
|
+
this.notifyChildrenOfDetach(subject);
|
|
1319
|
+
}
|
|
1320
|
+
notifyChildrenOfDetach(subject) {
|
|
1321
|
+
// a handler notified earlier in the walk may have destroyed this node.
|
|
1322
|
+
// A node never read still has to be walked: an instance created elsewhere
|
|
1323
|
+
// can have been moved under it, subscribers and all.
|
|
1324
|
+
if (!this.isAlive) {
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
for (const child of this.getChildren()) {
|
|
1328
|
+
child.notifyDetachOf(subject);
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1307
1331
|
setParent(newParent, subpath) {
|
|
1308
1332
|
const parentChanged = newParent !== this.parent;
|
|
1309
1333
|
const subpathChanged = subpath !== this.subpath;
|
|
@@ -1508,37 +1532,27 @@ class ObjectNode extends BaseNode {
|
|
|
1508
1532
|
this.clearParent();
|
|
1509
1533
|
}
|
|
1510
1534
|
preboot() {
|
|
1511
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
1512
|
-
const self = this;
|
|
1513
1535
|
this._applyPatches = createActionInvoker(this.storedValue, "@APPLY_PATCHES", (patches) => {
|
|
1514
1536
|
patches.forEach(patch => {
|
|
1515
1537
|
if (!patch.path) {
|
|
1516
|
-
|
|
1538
|
+
this.type.applySnapshot(this, patch.value);
|
|
1517
1539
|
return;
|
|
1518
1540
|
}
|
|
1519
1541
|
const parts = splitJsonPath(patch.path);
|
|
1520
|
-
const node = resolveNodeByPathParts(
|
|
1542
|
+
const node = resolveNodeByPathParts(this, parts.slice(0, -1));
|
|
1521
1543
|
node.applyPatchLocally(parts[parts.length - 1], patch);
|
|
1522
1544
|
});
|
|
1523
1545
|
});
|
|
1524
1546
|
this._applySnapshot = createActionInvoker(this.storedValue, "@APPLY_SNAPSHOT", (snapshot) => {
|
|
1525
|
-
//
|
|
1526
|
-
if (snapshot ===
|
|
1547
|
+
// the current snapshot needs no reconcile
|
|
1548
|
+
if (snapshot === this.snapshot) {
|
|
1527
1549
|
return;
|
|
1528
1550
|
}
|
|
1529
|
-
|
|
1530
|
-
return self.type.applySnapshot(self, snapshot);
|
|
1551
|
+
this.type.applySnapshot(this, snapshot);
|
|
1531
1552
|
});
|
|
1532
1553
|
addHiddenFinalProp(this.storedValue, "$treenode", this);
|
|
1533
1554
|
addHiddenFinalProp(this.storedValue, "toJSON", toJSON);
|
|
1534
1555
|
}
|
|
1535
|
-
die() {
|
|
1536
|
-
if (!this.isAlive || this.state === NodeLifeCycle.DETACHING) {
|
|
1537
|
-
return;
|
|
1538
|
-
}
|
|
1539
|
-
this.aboutToDie();
|
|
1540
|
-
this.finalizeDeath();
|
|
1541
|
-
}
|
|
1542
1556
|
aboutToDie() {
|
|
1543
1557
|
if (this._observableInstanceState ===
|
|
1544
1558
|
ObservableInstanceLifecycle.UNINITIALIZED) {
|
|
@@ -1550,8 +1564,8 @@ class ObjectNode extends BaseNode {
|
|
|
1550
1564
|
// beforeDestroy should run before the disposers since else we could end up in a situation where
|
|
1551
1565
|
// a disposer added with addDisposer at this stage (beforeDestroy) is actually never released
|
|
1552
1566
|
this.baseAboutToDie();
|
|
1553
|
-
this.
|
|
1554
|
-
this.
|
|
1567
|
+
this._internalEvents?.emit(InternalEvents.Dispose);
|
|
1568
|
+
this._internalEvents?.clear(InternalEvents.Dispose);
|
|
1555
1569
|
}
|
|
1556
1570
|
finalizeDeath() {
|
|
1557
1571
|
// invariant: not called directly but from "die"
|
|
@@ -1562,57 +1576,57 @@ class ObjectNode extends BaseNode {
|
|
|
1562
1576
|
// "kill" the computed prop and just store the last snapshot
|
|
1563
1577
|
const snapshot = this.snapshot;
|
|
1564
1578
|
this._snapshotUponDeath = snapshot;
|
|
1565
|
-
this.
|
|
1579
|
+
this._internalEvents?.clearAll();
|
|
1566
1580
|
this.baseFinalizeDeath();
|
|
1567
1581
|
}
|
|
1568
1582
|
onSnapshot(onChange) {
|
|
1569
1583
|
this._addSnapshotReaction();
|
|
1570
|
-
const unregister = this.
|
|
1584
|
+
const unregister = this.internalEvents().register(InternalEvents.Snapshot, onChange);
|
|
1571
1585
|
return () => {
|
|
1572
1586
|
unregister();
|
|
1573
1587
|
// The reaction re-serializes the whole subtree on every change, so leaving
|
|
1574
1588
|
// it running once the last listener is gone would keep charging the node
|
|
1575
1589
|
// for a snapshot nobody receives. Referential stability of getSnapshot()
|
|
1576
1590
|
// does not depend on it — that comes from keepAlive on _snapshotComputed.
|
|
1577
|
-
if (!this.
|
|
1591
|
+
if (!this._internalEvents?.hasSubscribers(InternalEvents.Snapshot)) {
|
|
1578
1592
|
this._removeSnapshotReaction();
|
|
1579
1593
|
}
|
|
1580
1594
|
};
|
|
1581
1595
|
}
|
|
1582
1596
|
emitSnapshot(snapshot) {
|
|
1583
|
-
this.
|
|
1597
|
+
this._internalEvents?.emit(InternalEvents.Snapshot, snapshot);
|
|
1584
1598
|
}
|
|
1585
1599
|
onPatch(handler) {
|
|
1586
|
-
return this.
|
|
1600
|
+
return this.internalEvents().register(InternalEvents.Patch, handler);
|
|
1587
1601
|
}
|
|
1588
1602
|
emitPatch(basePatch, source) {
|
|
1589
|
-
if (this.
|
|
1603
|
+
if (this._internalEvents?.hasSubscribers(InternalEvents.Patch)) {
|
|
1590
1604
|
const localizedPatch = {
|
|
1591
1605
|
...basePatch,
|
|
1592
1606
|
path: `${source.path.slice(this.path.length)}/${basePatch.path}` // calculate the relative path of the patch
|
|
1593
1607
|
};
|
|
1594
1608
|
const [patch, reversePatch] = splitPatch(localizedPatch);
|
|
1595
|
-
this.
|
|
1609
|
+
this._internalEvents?.emit(InternalEvents.Patch, patch, reversePatch);
|
|
1596
1610
|
}
|
|
1597
1611
|
if (this.parent) {
|
|
1598
1612
|
this.parent.emitPatch(basePatch, source);
|
|
1599
1613
|
}
|
|
1600
1614
|
}
|
|
1601
1615
|
hasDisposer(disposer) {
|
|
1602
|
-
return this.
|
|
1616
|
+
return !!this._internalEvents?.has(InternalEvents.Dispose, disposer);
|
|
1603
1617
|
}
|
|
1604
1618
|
addDisposer(disposer) {
|
|
1605
1619
|
if (!this.hasDisposer(disposer)) {
|
|
1606
|
-
this.
|
|
1620
|
+
this.internalEvents().register(InternalEvents.Dispose, disposer, true);
|
|
1607
1621
|
return;
|
|
1608
1622
|
}
|
|
1609
1623
|
throw fail("cannot add a disposer when it is already registered for execution");
|
|
1610
1624
|
}
|
|
1611
1625
|
removeDisposer(disposer) {
|
|
1612
|
-
if (!this.
|
|
1626
|
+
if (!this._internalEvents?.has(InternalEvents.Dispose, disposer)) {
|
|
1613
1627
|
throw fail("cannot remove a disposer which was never registered for execution");
|
|
1614
1628
|
}
|
|
1615
|
-
this.
|
|
1629
|
+
this._internalEvents?.unregister(InternalEvents.Dispose, disposer);
|
|
1616
1630
|
}
|
|
1617
1631
|
removeMiddleware(middleware) {
|
|
1618
1632
|
if (this.middlewares) {
|
|
@@ -1657,48 +1671,17 @@ class ObjectNode extends BaseNode {
|
|
|
1657
1671
|
// not removeDisposer(), which throws when the registration is already gone —
|
|
1658
1672
|
// the last listener can be disposed from within a disposer, i.e. after
|
|
1659
1673
|
// aboutToDie has cleared them
|
|
1660
|
-
this.
|
|
1674
|
+
this._internalEvents?.unregister(InternalEvents.Dispose, disposer);
|
|
1661
1675
|
disposer();
|
|
1662
1676
|
}
|
|
1663
|
-
//
|
|
1677
|
+
// created on first registration: most nodes never get a listener
|
|
1664
1678
|
_internalEvents;
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
return !!this._internalEvents && this._internalEvents.hasSubscribers(event);
|
|
1668
|
-
}
|
|
1669
|
-
_internalEventsRegister(event, eventHandler, atTheBeginning = false) {
|
|
1670
|
-
if (!this._internalEvents) {
|
|
1671
|
-
this._internalEvents = new EventHandlers();
|
|
1672
|
-
}
|
|
1673
|
-
return this._internalEvents.register(event, eventHandler, atTheBeginning);
|
|
1674
|
-
}
|
|
1675
|
-
_internalEventsHas(event, eventHandler) {
|
|
1676
|
-
return (!!this._internalEvents && this._internalEvents.has(event, eventHandler));
|
|
1677
|
-
}
|
|
1678
|
-
_internalEventsUnregister(event, eventHandler) {
|
|
1679
|
-
if (this._internalEvents) {
|
|
1680
|
-
this._internalEvents.unregister(event, eventHandler);
|
|
1681
|
-
}
|
|
1682
|
-
}
|
|
1683
|
-
_internalEventsEmit(event, ...args) {
|
|
1684
|
-
if (this._internalEvents) {
|
|
1685
|
-
this._internalEvents.emit(event, ...args);
|
|
1686
|
-
}
|
|
1687
|
-
}
|
|
1688
|
-
_internalEventsClear(event) {
|
|
1689
|
-
if (this._internalEvents) {
|
|
1690
|
-
this._internalEvents.clear(event);
|
|
1691
|
-
}
|
|
1692
|
-
}
|
|
1693
|
-
_internalEventsClearAll() {
|
|
1694
|
-
if (this._internalEvents) {
|
|
1695
|
-
this._internalEvents.clearAll();
|
|
1696
|
-
}
|
|
1679
|
+
internalEvents() {
|
|
1680
|
+
return (this._internalEvents ??= new EventHandlers());
|
|
1697
1681
|
}
|
|
1698
1682
|
}
|
|
1699
1683
|
ObjectNode.prototype.createObservableInstance = action(ObjectNode.prototype.createObservableInstance);
|
|
1700
1684
|
ObjectNode.prototype.detach = action(ObjectNode.prototype.detach);
|
|
1701
|
-
ObjectNode.prototype.die = action(ObjectNode.prototype.die);
|
|
1702
1685
|
|
|
1703
1686
|
/**
|
|
1704
1687
|
* @internal
|
|
@@ -1890,7 +1873,6 @@ class ComplexType extends BaseType {
|
|
|
1890
1873
|
return null;
|
|
1891
1874
|
}
|
|
1892
1875
|
}
|
|
1893
|
-
ComplexType.prototype.create = action(ComplexType.prototype.create);
|
|
1894
1876
|
/**
|
|
1895
1877
|
* @internal
|
|
1896
1878
|
* @hidden
|
|
@@ -1900,11 +1882,6 @@ class SimpleType extends BaseType {
|
|
|
1900
1882
|
return snapshot;
|
|
1901
1883
|
}
|
|
1902
1884
|
getValue(node) {
|
|
1903
|
-
// if we ever find a case where scalar nodes can be accessed without iterating through its parent
|
|
1904
|
-
// uncomment this to make sure the parent chain is created when this is accessed
|
|
1905
|
-
// if (node.parent) {
|
|
1906
|
-
// node.parent.createObservableInstanceIfNeeded()
|
|
1907
|
-
// }
|
|
1908
1885
|
return node.storedValue;
|
|
1909
1886
|
}
|
|
1910
1887
|
getSnapshot(node) {
|
|
@@ -1934,6 +1911,30 @@ class SimpleType extends BaseType {
|
|
|
1934
1911
|
function isType(value) {
|
|
1935
1912
|
return (typeof value === "object" && value?.isType === true);
|
|
1936
1913
|
}
|
|
1914
|
+
/**
|
|
1915
|
+
* The one type a wrapper hands everything to: what an `optional`,
|
|
1916
|
+
* `stripDefault`, `refinement`, `snapshotProcessor` or (resolved) `late`
|
|
1917
|
+
* wraps. `undefined` for any other type, including a union or a `resilient`,
|
|
1918
|
+
* which pick a type per value.
|
|
1919
|
+
*
|
|
1920
|
+
* Resolves a `late` type's definition if it has not been read yet.
|
|
1921
|
+
*/
|
|
1922
|
+
function getWrappedType(type) {
|
|
1923
|
+
const subtype = type.getSubTypes();
|
|
1924
|
+
return isType(subtype) ? subtype : undefined;
|
|
1925
|
+
}
|
|
1926
|
+
/**
|
|
1927
|
+
* Strips every wrapper {@link getWrappedType} sees through, down to the type
|
|
1928
|
+
* that actually builds the value: for a complex type `T`,
|
|
1929
|
+
* `getType(T.create(snapshot)) === unwrapType(T)`.
|
|
1930
|
+
*
|
|
1931
|
+
* `types.model({ xs: types.array(X) }).properties.xs`, for instance, is an
|
|
1932
|
+
* `optional` whose unwrapped type is the array type.
|
|
1933
|
+
*/
|
|
1934
|
+
function unwrapType(type) {
|
|
1935
|
+
const wrapped = getWrappedType(type);
|
|
1936
|
+
return wrapped ? unwrapType(wrapped) : type;
|
|
1937
|
+
}
|
|
1937
1938
|
/**
|
|
1938
1939
|
* @internal
|
|
1939
1940
|
* @hidden
|
|
@@ -2932,7 +2933,7 @@ function createScalarNode(type, parent, subpath, environment, initialValue) {
|
|
|
2932
2933
|
* @hidden
|
|
2933
2934
|
*/
|
|
2934
2935
|
function isNode(value) {
|
|
2935
|
-
return value instanceof
|
|
2936
|
+
return value instanceof BaseNode;
|
|
2936
2937
|
}
|
|
2937
2938
|
|
|
2938
2939
|
/**
|
|
@@ -3111,25 +3112,6 @@ function fail(message = "Illegal state") {
|
|
|
3111
3112
|
function identity(_) {
|
|
3112
3113
|
return _;
|
|
3113
3114
|
}
|
|
3114
|
-
/**
|
|
3115
|
-
* @internal
|
|
3116
|
-
* @hidden
|
|
3117
|
-
*/
|
|
3118
|
-
const isInteger = Number.isInteger;
|
|
3119
|
-
/**
|
|
3120
|
-
* @internal
|
|
3121
|
-
* @hidden
|
|
3122
|
-
*/
|
|
3123
|
-
function isFloat(val) {
|
|
3124
|
-
return Number(val) === val && val % 1 !== 0;
|
|
3125
|
-
}
|
|
3126
|
-
/**
|
|
3127
|
-
* @internal
|
|
3128
|
-
* @hidden
|
|
3129
|
-
*/
|
|
3130
|
-
function isFinite(val) {
|
|
3131
|
-
return Number.isFinite(val);
|
|
3132
|
-
}
|
|
3133
3115
|
/**
|
|
3134
3116
|
* @internal
|
|
3135
3117
|
* @hidden
|
|
@@ -3777,11 +3759,8 @@ class SnapshotProcessor extends BaseType {
|
|
|
3777
3759
|
return sn;
|
|
3778
3760
|
}
|
|
3779
3761
|
_fixNode(node) {
|
|
3780
|
-
// the node's type is the *inner* type, so `getType(instance).create(...)`
|
|
3781
|
-
// would bypass the processors — point it at ours instead
|
|
3782
|
-
const nodeType = node.type;
|
|
3783
|
-
nodeType.create = this.create.bind(this);
|
|
3784
3762
|
if (node instanceof ObjectNode) {
|
|
3763
|
+
node.snapshotProcessorType = this;
|
|
3785
3764
|
node.hasSnapshotPostProcessor = !!this._processors.postProcessor;
|
|
3786
3765
|
}
|
|
3787
3766
|
const oldGetSnapshot = node.getSnapshot;
|
|
@@ -4265,14 +4244,20 @@ function map(subtype) {
|
|
|
4265
4244
|
return new MapType(subtype);
|
|
4266
4245
|
}
|
|
4267
4246
|
/**
|
|
4268
|
-
* Returns if a
|
|
4269
|
-
*
|
|
4270
|
-
* @param type
|
|
4271
|
-
* @returns `true` if it is a map type.
|
|
4247
|
+
* Returns if a type is a map type, or wraps or unions one. For the map type
|
|
4248
|
+
* itself, use {@link asMapType}.
|
|
4272
4249
|
*/
|
|
4273
4250
|
function isMapType(type) {
|
|
4274
4251
|
return isType(type) && (type.flags & TypeFlags.Map) > 0;
|
|
4275
4252
|
}
|
|
4253
|
+
/**
|
|
4254
|
+
* The map type `type` builds its values with, seeing through the wrappers
|
|
4255
|
+
* {@link unwrapType} does, or `undefined` if that is not a map type.
|
|
4256
|
+
*/
|
|
4257
|
+
function asMapType(type) {
|
|
4258
|
+
const unwrapped = unwrapType(type);
|
|
4259
|
+
return unwrapped instanceof MapType ? unwrapped : undefined;
|
|
4260
|
+
}
|
|
4276
4261
|
|
|
4277
4262
|
/**
|
|
4278
4263
|
* @internal
|
|
@@ -4482,98 +4467,174 @@ function array(subtype) {
|
|
|
4482
4467
|
*/
|
|
4483
4468
|
function reconcileArrayChildren(parent, childType, oldNodes, newValues, firstNewPath) {
|
|
4484
4469
|
let nothingChanged = true;
|
|
4485
|
-
|
|
4486
|
-
//
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
childType instanceof ModelType &&
|
|
4497
|
-
childType.identifierAttribute) {
|
|
4498
|
-
const byId = new Map();
|
|
4499
|
-
for (const n of oldNodes) {
|
|
4500
|
-
if (n instanceof ObjectNode && n.identifier !== null) {
|
|
4501
|
-
byId.set(n.identifier, n);
|
|
4502
|
-
}
|
|
4503
|
-
}
|
|
4504
|
-
idIndex = { attr: childType.identifierAttribute, byId };
|
|
4505
|
-
}
|
|
4506
|
-
for (let i = 0;; i++) {
|
|
4507
|
-
const hasNewNode = i <= newValues.length - 1;
|
|
4508
|
-
const oldNode = oldNodes[i];
|
|
4509
|
-
let newValue = hasNewNode ? newValues[i] : undefined;
|
|
4470
|
+
const result = [];
|
|
4471
|
+
// every old node before `next` is claimed
|
|
4472
|
+
const claimed = new Uint8Array(oldNodes.length);
|
|
4473
|
+
let next = 0;
|
|
4474
|
+
let finder;
|
|
4475
|
+
for (let i = 0; i < newValues.length; i++) {
|
|
4476
|
+
while (claimed[next]) {
|
|
4477
|
+
next++;
|
|
4478
|
+
}
|
|
4479
|
+
const oldNode = oldNodes[next];
|
|
4480
|
+
let newValue = newValues[i];
|
|
4510
4481
|
const newPath = `${firstNewPath + i}`;
|
|
4511
4482
|
// for some reason, instead of newValue we got a node, fallback to the storedValue
|
|
4512
4483
|
// TODO: https://github.com/mobxjs/mobx-state-tree/issues/340#issuecomment-325581681
|
|
4513
4484
|
if (isNode(newValue)) {
|
|
4514
4485
|
newValue = newValue.storedValue;
|
|
4515
4486
|
}
|
|
4516
|
-
if (!oldNode
|
|
4517
|
-
|
|
4518
|
-
|
|
4487
|
+
if (!oldNode) {
|
|
4488
|
+
if (isStateTreeNode(newValue) &&
|
|
4489
|
+
getStateTreeNode(newValue).parent === parent) {
|
|
4490
|
+
// this node is owned by this parent, but not in the reconcilable set, so it must be double
|
|
4491
|
+
throw fail(`Cannot add an object to a state tree if it is already part of the same or another state tree. Tried to assign an object to '${parent.path}/${newPath}', but it lives already at '${getStateTreeNode(newValue).path}'`);
|
|
4492
|
+
}
|
|
4493
|
+
nothingChanged = false;
|
|
4494
|
+
result.push(valueAsNode(childType, parent, newPath, newValue));
|
|
4495
|
+
}
|
|
4496
|
+
else if (areSame(oldNode, newValue)) {
|
|
4497
|
+
claimed[next] = 1;
|
|
4498
|
+
result.push(valueAsNode(childType, parent, newPath, newValue, oldNode));
|
|
4519
4499
|
}
|
|
4520
|
-
else
|
|
4521
|
-
// new one does not exists
|
|
4500
|
+
else {
|
|
4522
4501
|
nothingChanged = false;
|
|
4523
|
-
|
|
4502
|
+
// a single-element write scans one node, cheaper than building an index
|
|
4503
|
+
const j = oldNodes.length > 1
|
|
4504
|
+
? (finder ??= new ReuseFinder(childType, oldNodes, claimed)).find(newValue, next)
|
|
4505
|
+
: scanForSame(oldNodes, claimed, next, newValue);
|
|
4506
|
+
let oldMatch;
|
|
4507
|
+
if (j >= 0) {
|
|
4508
|
+
claimed[j] = 1;
|
|
4509
|
+
oldMatch = oldNodes[j];
|
|
4510
|
+
}
|
|
4511
|
+
result.push(valueAsNode(childType, parent, newPath, newValue, oldMatch));
|
|
4512
|
+
}
|
|
4513
|
+
}
|
|
4514
|
+
for (let j = next; j < oldNodes.length; j++) {
|
|
4515
|
+
if (!claimed[j]) {
|
|
4516
|
+
nothingChanged = false;
|
|
4517
|
+
const oldNode = oldNodes[j];
|
|
4524
4518
|
if (oldNode instanceof ObjectNode) {
|
|
4525
4519
|
// since it is going to be returned by pop/splice/shift better create it before killing it
|
|
4526
4520
|
// so it doesn't end up in an undead state
|
|
4527
4521
|
oldNode.createObservableInstanceIfNeeded();
|
|
4528
4522
|
}
|
|
4529
4523
|
oldNode.die();
|
|
4530
|
-
i--;
|
|
4531
4524
|
}
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
}
|
|
4540
|
-
nothingChanged = false;
|
|
4541
|
-
const newNode = valueAsNode(childType, parent, newPath, newValue);
|
|
4542
|
-
oldNodes.splice(i, 0, newNode);
|
|
4525
|
+
}
|
|
4526
|
+
return nothingChanged ? null : result;
|
|
4527
|
+
}
|
|
4528
|
+
function scanForSame(oldNodes, claimed, from, value) {
|
|
4529
|
+
for (let j = from; j < oldNodes.length; j++) {
|
|
4530
|
+
if (!claimed[j] && areSame(oldNodes[j], value)) {
|
|
4531
|
+
return j;
|
|
4543
4532
|
}
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4533
|
+
}
|
|
4534
|
+
return -1;
|
|
4535
|
+
}
|
|
4536
|
+
/**
|
|
4537
|
+
* Picks the old node the reorder branch reuses: the first unclaimed one
|
|
4538
|
+
* `areSame` holds for. `areSame` reduces to an equality — node identity for a
|
|
4539
|
+
* live node, the old node's snapshot for anything else — except where the
|
|
4540
|
+
* value is a plain object and the old node carries an identifier, where it
|
|
4541
|
+
* runs `is()` before matching ids. So only that case scans, and an identified
|
|
4542
|
+
* plain model looks its id up instead, as ADR 0001 records.
|
|
4543
|
+
*/
|
|
4544
|
+
class ReuseFinder {
|
|
4545
|
+
oldNodes;
|
|
4546
|
+
claimed;
|
|
4547
|
+
idAttribute;
|
|
4548
|
+
byId;
|
|
4549
|
+
byNode;
|
|
4550
|
+
bySnapshot;
|
|
4551
|
+
anyIdentified;
|
|
4552
|
+
constructor(childType, oldNodes, claimed) {
|
|
4553
|
+
this.oldNodes = oldNodes;
|
|
4554
|
+
this.claimed = claimed;
|
|
4555
|
+
this.idAttribute =
|
|
4556
|
+
childType instanceof ModelType ? childType.identifierAttribute : undefined;
|
|
4557
|
+
}
|
|
4558
|
+
find(value, next) {
|
|
4559
|
+
let j;
|
|
4560
|
+
if (this.idAttribute && isPlainObject(value)) {
|
|
4561
|
+
j =
|
|
4562
|
+
this.idIndex(next).get(normalizeIdentifier(value[this.idAttribute])) ??
|
|
4563
|
+
-1;
|
|
4564
|
+
}
|
|
4565
|
+
else if (isStateTreeNode(value)) {
|
|
4566
|
+
j = this.nodeIndex(next).get(getStateTreeNode(value)) ?? -1;
|
|
4567
|
+
}
|
|
4568
|
+
else if (!isPlainObject(value) || !this.hasIdentifiedNode(next)) {
|
|
4569
|
+
j = this.firstWithSnapshot(value, next);
|
|
4547
4570
|
}
|
|
4548
4571
|
else {
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4572
|
+
return scanForSame(this.oldNodes, this.claimed, next, value);
|
|
4573
|
+
}
|
|
4574
|
+
return j >= 0 && !this.claimed[j] && areSame(this.oldNodes[j], value)
|
|
4575
|
+
? j
|
|
4576
|
+
: -1;
|
|
4577
|
+
}
|
|
4578
|
+
// last one wins on a duplicate id, even when it is already claimed
|
|
4579
|
+
idIndex(next) {
|
|
4580
|
+
if (!this.byId) {
|
|
4581
|
+
this.byId = new Map();
|
|
4582
|
+
for (let j = next; j < this.oldNodes.length; j++) {
|
|
4583
|
+
const node = this.oldNodes[j];
|
|
4584
|
+
if (node instanceof ObjectNode && node.identifier !== null) {
|
|
4585
|
+
this.byId.set(node.identifier, j);
|
|
4560
4586
|
}
|
|
4561
4587
|
}
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4588
|
+
}
|
|
4589
|
+
return this.byId;
|
|
4590
|
+
}
|
|
4591
|
+
nodeIndex(next) {
|
|
4592
|
+
if (!this.byNode) {
|
|
4593
|
+
this.byNode = new Map();
|
|
4594
|
+
for (let j = next; j < this.oldNodes.length; j++) {
|
|
4595
|
+
this.byNode.set(this.oldNodes[j], j);
|
|
4596
|
+
}
|
|
4597
|
+
}
|
|
4598
|
+
return this.byNode;
|
|
4599
|
+
}
|
|
4600
|
+
hasIdentifiedNode(next) {
|
|
4601
|
+
if (this.anyIdentified === undefined) {
|
|
4602
|
+
this.anyIdentified = this.oldNodes
|
|
4603
|
+
.slice(next)
|
|
4604
|
+
.some(node => node instanceof ObjectNode &&
|
|
4605
|
+
node.identifier !== null &&
|
|
4606
|
+
!!node.identifierAttribute);
|
|
4607
|
+
}
|
|
4608
|
+
return this.anyIdentified;
|
|
4609
|
+
}
|
|
4610
|
+
firstWithSnapshot(value, next) {
|
|
4611
|
+
if (!this.bySnapshot) {
|
|
4612
|
+
const first = new Map();
|
|
4613
|
+
const nextSame = new Int32Array(this.oldNodes.length);
|
|
4614
|
+
for (let j = this.oldNodes.length - 1; j >= next; j--) {
|
|
4615
|
+
const node = this.oldNodes[j];
|
|
4616
|
+
if (!this.claimed[j] && node.isAlive) {
|
|
4617
|
+
const snapshot = node.snapshot;
|
|
4618
|
+
nextSame[j] = first.get(snapshot) ?? -1;
|
|
4619
|
+
first.set(snapshot, j);
|
|
4569
4620
|
}
|
|
4570
4621
|
}
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4622
|
+
this.bySnapshot = { first, nextSame };
|
|
4623
|
+
}
|
|
4624
|
+
const { first, nextSame } = this.bySnapshot;
|
|
4625
|
+
const head = first.get(value);
|
|
4626
|
+
if (head === undefined) {
|
|
4627
|
+
return -1;
|
|
4628
|
+
}
|
|
4629
|
+
let j = head;
|
|
4630
|
+
while (j >= 0 && (this.claimed[j] || !this.oldNodes[j].isAlive)) {
|
|
4631
|
+
j = nextSame[j];
|
|
4574
4632
|
}
|
|
4633
|
+
if (j !== head) {
|
|
4634
|
+
first.set(value, j);
|
|
4635
|
+
}
|
|
4636
|
+
return j;
|
|
4575
4637
|
}
|
|
4576
|
-
return nothingChanged ? null : oldNodes;
|
|
4577
4638
|
}
|
|
4578
4639
|
/**
|
|
4579
4640
|
* Convert a value to a node at given parent and subpath. Attempts to reuse old node if possible and given.
|
|
@@ -4642,14 +4703,20 @@ function areSame(oldNode, newValue) {
|
|
|
4642
4703
|
oldNodeType.isMatchingSnapshotId(oldNode, newValue));
|
|
4643
4704
|
}
|
|
4644
4705
|
/**
|
|
4645
|
-
* Returns if a
|
|
4646
|
-
*
|
|
4647
|
-
* @param type
|
|
4648
|
-
* @returns `true` if the type is an array type.
|
|
4706
|
+
* Returns if a type is an array type, or wraps or unions one. For the array
|
|
4707
|
+
* type itself, use {@link asArrayType}.
|
|
4649
4708
|
*/
|
|
4650
4709
|
function isArrayType(type) {
|
|
4651
4710
|
return isType(type) && (type.flags & TypeFlags.Array) > 0;
|
|
4652
4711
|
}
|
|
4712
|
+
/**
|
|
4713
|
+
* The array type `type` builds its values with, seeing through the wrappers
|
|
4714
|
+
* {@link unwrapType} does, or `undefined` if that is not an array type.
|
|
4715
|
+
*/
|
|
4716
|
+
function asArrayType(type) {
|
|
4717
|
+
const unwrapped = unwrapType(type);
|
|
4718
|
+
return unwrapped instanceof ArrayType ? unwrapped : undefined;
|
|
4719
|
+
}
|
|
4653
4720
|
|
|
4654
4721
|
const PRE_PROCESS_SNAPSHOT = "preProcessSnapshot";
|
|
4655
4722
|
const POST_PROCESS_SNAPSHOT = "postProcessSnapshot";
|
|
@@ -4684,6 +4751,12 @@ function getPropObservables(storedValue) {
|
|
|
4684
4751
|
function objectTypeToString() {
|
|
4685
4752
|
return getStateTreeNode(this).toString();
|
|
4686
4753
|
}
|
|
4754
|
+
/** `second` applied to `first`'s result, allocating only when both exist */
|
|
4755
|
+
function chainProcessors(first, second) {
|
|
4756
|
+
return first && second
|
|
4757
|
+
? snapshot => second(first(snapshot))
|
|
4758
|
+
: (first ?? second);
|
|
4759
|
+
}
|
|
4687
4760
|
const ANONYMOUS_MODEL_NAME = "AnonymousModel";
|
|
4688
4761
|
/**
|
|
4689
4762
|
* A plain loop rather than a callback per property, which allocated a closure
|
|
@@ -4972,8 +5045,6 @@ class ModelType extends ComplexType {
|
|
|
4972
5045
|
? initialValue
|
|
4973
5046
|
: this.applySnapshotPreProcessor(initialValue);
|
|
4974
5047
|
return createObjectNode(this, parent, subpath, environment, value);
|
|
4975
|
-
// Optimization: record all prop- view- and action names after first construction, and generate an optimal base class
|
|
4976
|
-
// that pre-reserves all these fields for fast object-member lookups
|
|
4977
5048
|
}
|
|
4978
5049
|
initializeChildNodes(objNode, initialSnapshot = {}) {
|
|
4979
5050
|
const type = objNode.type;
|
|
@@ -5137,15 +5208,12 @@ class ModelType extends ComplexType {
|
|
|
5137
5208
|
}
|
|
5138
5209
|
}
|
|
5139
5210
|
applySnapshotPreProcessor(snapshot) {
|
|
5140
|
-
const
|
|
5141
|
-
return
|
|
5211
|
+
const preProcessor = this.preProcessor;
|
|
5212
|
+
return preProcessor ? preProcessor(snapshot) : snapshot;
|
|
5142
5213
|
}
|
|
5143
5214
|
applySnapshotPostProcessor(snapshot) {
|
|
5144
5215
|
const postProcessor = this.postProcessor;
|
|
5145
|
-
|
|
5146
|
-
return postProcessor.call(null, snapshot);
|
|
5147
|
-
}
|
|
5148
|
-
return snapshot;
|
|
5216
|
+
return postProcessor ? postProcessor(snapshot) : snapshot;
|
|
5149
5217
|
}
|
|
5150
5218
|
getChildType(propertyName) {
|
|
5151
5219
|
assertIsString(propertyName, 1);
|
|
@@ -5168,7 +5236,6 @@ class ModelType extends ComplexType {
|
|
|
5168
5236
|
return typeCheckSuccess();
|
|
5169
5237
|
}
|
|
5170
5238
|
describe() {
|
|
5171
|
-
// optimization: cache
|
|
5172
5239
|
return `{ ${this.propertyNames
|
|
5173
5240
|
.map(key => `${key}: ${this.properties[key].describe()}`)
|
|
5174
5241
|
.join("; ")} }`;
|
|
@@ -5190,27 +5257,17 @@ Object.assign(ModelType.prototype, {
|
|
|
5190
5257
|
props(properties) {
|
|
5191
5258
|
return this.cloneAndEnhance({ properties });
|
|
5192
5259
|
},
|
|
5260
|
+
// a newly added pre-processor sees the raw snapshot first; a newly added
|
|
5261
|
+
// post-processor sees what the existing one produced
|
|
5193
5262
|
preProcessSnapshot(preProcessor) {
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
}
|
|
5198
|
-
else {
|
|
5199
|
-
return this.cloneAndEnhance({
|
|
5200
|
-
preProcessor: snapshot => currentPreprocessor(preProcessor(snapshot))
|
|
5201
|
-
});
|
|
5202
|
-
}
|
|
5263
|
+
return this.cloneAndEnhance({
|
|
5264
|
+
preProcessor: chainProcessors(preProcessor, this.preProcessor)
|
|
5265
|
+
});
|
|
5203
5266
|
},
|
|
5204
5267
|
postProcessSnapshot(postProcessor) {
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
}
|
|
5209
|
-
else {
|
|
5210
|
-
return this.cloneAndEnhance({
|
|
5211
|
-
postProcessor: snapshot => postProcessor(currentPostprocessor(snapshot))
|
|
5212
|
-
});
|
|
5213
|
-
}
|
|
5268
|
+
return this.cloneAndEnhance({
|
|
5269
|
+
postProcessor: chainProcessors(this.postProcessor, postProcessor)
|
|
5270
|
+
});
|
|
5214
5271
|
}
|
|
5215
5272
|
});
|
|
5216
5273
|
/**
|
|
@@ -5234,39 +5291,44 @@ function model(...args) {
|
|
|
5234
5291
|
* the types are composed into a new Type with the given name
|
|
5235
5292
|
*/
|
|
5236
5293
|
function compose(...args) {
|
|
5237
|
-
// TODO: just join the base type names if no name is provided
|
|
5238
5294
|
const hasTypename = typeof args[0] === "string";
|
|
5239
5295
|
const typeName = hasTypename ? args[0] : ANONYMOUS_MODEL_NAME;
|
|
5240
5296
|
if (hasTypename) {
|
|
5241
5297
|
args.shift();
|
|
5242
5298
|
}
|
|
5243
|
-
//
|
|
5299
|
+
// exactly a model type: each part's own properties and initializers are
|
|
5300
|
+
// read below, and a wrapper around a model has neither
|
|
5244
5301
|
if (devMode()) {
|
|
5245
5302
|
args.forEach((type, i) => {
|
|
5246
|
-
assertArg(type,
|
|
5303
|
+
assertArg(type, t => t instanceof ModelType, "mobx-state-tree model type", hasTypename ? i + 2 : i + 1);
|
|
5247
5304
|
});
|
|
5248
5305
|
}
|
|
5249
5306
|
return args
|
|
5250
5307
|
.reduce((prev, cur) => prev.cloneAndEnhance({
|
|
5251
|
-
name: `${prev.name}_${cur.name}`,
|
|
5252
5308
|
properties: cur.properties,
|
|
5253
5309
|
// cur.properties is another ModelType's already-converted+frozen bag
|
|
5254
5310
|
propertiesAreConverted: true,
|
|
5255
5311
|
initializers: cur.initializers,
|
|
5256
|
-
preProcessor: (
|
|
5257
|
-
postProcessor: (
|
|
5312
|
+
preProcessor: chainProcessors(prev.preProcessor, cur.preProcessor),
|
|
5313
|
+
postProcessor: chainProcessors(prev.postProcessor, cur.postProcessor)
|
|
5258
5314
|
}))
|
|
5259
5315
|
.named(typeName);
|
|
5260
5316
|
}
|
|
5261
5317
|
/**
|
|
5262
|
-
* Returns if a
|
|
5263
|
-
*
|
|
5264
|
-
* @param type
|
|
5265
|
-
* @returns
|
|
5318
|
+
* Returns if a type is a model type, or wraps or unions one. For the model
|
|
5319
|
+
* type itself, use {@link asModelType}.
|
|
5266
5320
|
*/
|
|
5267
5321
|
function isModelType(type) {
|
|
5268
5322
|
return isType(type) && (type.flags & TypeFlags.Object) > 0;
|
|
5269
5323
|
}
|
|
5324
|
+
/**
|
|
5325
|
+
* The model type `type` builds its values with, seeing through the wrappers
|
|
5326
|
+
* {@link unwrapType} does, or `undefined` if that is not a model type.
|
|
5327
|
+
*/
|
|
5328
|
+
function asModelType(type) {
|
|
5329
|
+
const unwrapped = unwrapType(type);
|
|
5330
|
+
return unwrapped instanceof ModelType ? unwrapped : undefined;
|
|
5331
|
+
}
|
|
5270
5332
|
/**
|
|
5271
5333
|
* `extendInstance` - attaches additional actions, views and volatile state to an
|
|
5272
5334
|
* already-created model instance, using the same instantiation machinery as
|
|
@@ -5292,7 +5354,7 @@ function extendInstance(instance, fn) {
|
|
|
5292
5354
|
throw fail("extendInstance expects a mobx-state-tree node");
|
|
5293
5355
|
}
|
|
5294
5356
|
const type = getStateTreeNode(instance).type;
|
|
5295
|
-
if (!
|
|
5357
|
+
if (!(type instanceof ModelType)) {
|
|
5296
5358
|
throw fail("extendInstance can only be used on model instances");
|
|
5297
5359
|
}
|
|
5298
5360
|
// Views/actions/volatile are installed via defineProperty + makeObservable — the
|
|
@@ -5300,9 +5362,8 @@ function extendInstance(instance, fn) {
|
|
|
5300
5362
|
// write-protection interceptor is attached (see finalizeNewInstance). On a live
|
|
5301
5363
|
// instance that interceptor is already active, so run the attach inside an action
|
|
5302
5364
|
// context: isRunningAction() then short-circuits assertWritable.
|
|
5303
|
-
const modelType = type;
|
|
5304
5365
|
const attach = createActionInvoker(instance, "@@extendInstance", (() => {
|
|
5305
|
-
|
|
5366
|
+
type.applyExtensionToInstance(instance, fn(instance));
|
|
5306
5367
|
}));
|
|
5307
5368
|
attach();
|
|
5308
5369
|
return instance;
|
|
@@ -5374,7 +5435,7 @@ const number = new CoreType("number", TypeFlags.Number, v => typeof v === "numbe
|
|
|
5374
5435
|
* })
|
|
5375
5436
|
* ```
|
|
5376
5437
|
*/
|
|
5377
|
-
const integer = new CoreType("integer", TypeFlags.Integer,
|
|
5438
|
+
const integer = new CoreType("integer", TypeFlags.Integer, Number.isInteger);
|
|
5378
5439
|
/**
|
|
5379
5440
|
* `types.float` - Creates a type that can only contain an float value.
|
|
5380
5441
|
*
|
|
@@ -5386,7 +5447,7 @@ const integer = new CoreType("integer", TypeFlags.Integer, v => isInteger(v));
|
|
|
5386
5447
|
* })
|
|
5387
5448
|
* ```
|
|
5388
5449
|
*/
|
|
5389
|
-
const float = new CoreType("float", TypeFlags.Float, v =>
|
|
5450
|
+
const float = new CoreType("float", TypeFlags.Float, v => Number(v) === v && v % 1 !== 0);
|
|
5390
5451
|
/**
|
|
5391
5452
|
* `types.finite` - Creates a type that can only contain an finite value.
|
|
5392
5453
|
*
|
|
@@ -5398,7 +5459,7 @@ const float = new CoreType("float", TypeFlags.Float, v => isFloat(v));
|
|
|
5398
5459
|
* })
|
|
5399
5460
|
* ```
|
|
5400
5461
|
*/
|
|
5401
|
-
const finite = new CoreType("finite", TypeFlags.Finite,
|
|
5462
|
+
const finite = new CoreType("finite", TypeFlags.Finite, Number.isFinite);
|
|
5402
5463
|
/**
|
|
5403
5464
|
* `types.boolean` - Creates a type that can only contain a boolean value.
|
|
5404
5465
|
* This type is used for boolean values by default
|
|
@@ -5459,11 +5520,9 @@ function getPrimitiveFactoryFromValue(value) {
|
|
|
5459
5520
|
/**
|
|
5460
5521
|
* Returns if a given value represents a primitive type.
|
|
5461
5522
|
*
|
|
5462
|
-
*
|
|
5463
|
-
*
|
|
5464
|
-
*
|
|
5465
|
-
* to compile. Guards with a distinct narrowing target (`isArrayType`,
|
|
5466
|
-
* `isMapType`, `isModelType`) keep their predicate.
|
|
5523
|
+
* Like every `isXType` guard it reads the type's flags, which wrappers and
|
|
5524
|
+
* unions inherit from what they hold, so it is also true for a type that wraps
|
|
5525
|
+
* or unions one. Use {@link unwrapType} to get at the type itself.
|
|
5467
5526
|
*
|
|
5468
5527
|
* @param type
|
|
5469
5528
|
* @returns
|
|
@@ -5529,11 +5588,9 @@ function literal(value) {
|
|
|
5529
5588
|
/**
|
|
5530
5589
|
* Returns if a given value represents a literal type.
|
|
5531
5590
|
*
|
|
5532
|
-
*
|
|
5533
|
-
*
|
|
5534
|
-
*
|
|
5535
|
-
* to compile. Guards with a distinct narrowing target (`isArrayType`,
|
|
5536
|
-
* `isMapType`, `isModelType`) keep their predicate.
|
|
5591
|
+
* Like every `isXType` guard it reads the type's flags, which wrappers and
|
|
5592
|
+
* unions inherit from what they hold, so it is also true for a type that wraps
|
|
5593
|
+
* or unions one. Use {@link unwrapType} to get at the type itself.
|
|
5537
5594
|
*
|
|
5538
5595
|
* @param type
|
|
5539
5596
|
* @returns
|
|
@@ -5611,11 +5668,9 @@ function refinement(...args) {
|
|
|
5611
5668
|
/**
|
|
5612
5669
|
* Returns if a given value is a refinement type.
|
|
5613
5670
|
*
|
|
5614
|
-
*
|
|
5615
|
-
*
|
|
5616
|
-
*
|
|
5617
|
-
* to compile. Guards with a distinct narrowing target (`isArrayType`,
|
|
5618
|
-
* `isMapType`, `isModelType`) keep their predicate.
|
|
5671
|
+
* Like every `isXType` guard it reads the type's flags, which wrappers and
|
|
5672
|
+
* unions inherit from what they hold, so it is also true for a type that wraps
|
|
5673
|
+
* or unions one. Use {@link unwrapType} to get at the type itself.
|
|
5619
5674
|
*
|
|
5620
5675
|
* @param type
|
|
5621
5676
|
* @returns
|
|
@@ -5628,6 +5683,10 @@ function isRefinementType(type) {
|
|
|
5628
5683
|
* `types.enumeration` - Can be used to create an string based enumeration.
|
|
5629
5684
|
* (note: this methods is just sugar for a union of string literals)
|
|
5630
5685
|
*
|
|
5686
|
+
* The member type is inferred from the options, so a literal array, an
|
|
5687
|
+
* `as const` array and `Object.values(SomeStringEnum)` all produce the exact
|
|
5688
|
+
* union; only an array already typed `string[]` falls back to `string`.
|
|
5689
|
+
*
|
|
5631
5690
|
* Example:
|
|
5632
5691
|
* ```ts
|
|
5633
5692
|
* const TrafficLight = types.model({
|
|
@@ -5639,52 +5698,47 @@ function isRefinementType(type) {
|
|
|
5639
5698
|
* @param options possible values this enumeration can have
|
|
5640
5699
|
* @returns
|
|
5641
5700
|
*/
|
|
5642
|
-
function enumeration(
|
|
5643
|
-
const
|
|
5644
|
-
|
|
5701
|
+
function enumeration(nameOrOptions, maybeOptions) {
|
|
5702
|
+
const name = typeof nameOrOptions === "string" ? nameOrOptions : undefined;
|
|
5703
|
+
const options = typeof nameOrOptions === "string" ? maybeOptions : nameOrOptions;
|
|
5645
5704
|
if (devMode()) {
|
|
5646
|
-
|
|
5705
|
+
options.forEach((option, i) => {
|
|
5647
5706
|
assertIsString(option, i + 1);
|
|
5648
5707
|
});
|
|
5649
5708
|
}
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
}
|
|
5654
|
-
return type;
|
|
5709
|
+
// built directly rather than through union(): its members are fresh
|
|
5710
|
+
// literals, so interning could never share it, and the name belongs to this
|
|
5711
|
+
// union alone
|
|
5712
|
+
return new Union(options.map(option => literal(`${option}`)), name === undefined ? undefined : { name });
|
|
5655
5713
|
}
|
|
5656
5714
|
|
|
5657
|
-
//
|
|
5658
|
-
//
|
|
5659
|
-
//
|
|
5660
|
-
// members are rarely bare models (jbrowse config schemas
|
|
5661
|
-
// always optional(model) or optional(snapshotProcessor(model))).
|
|
5662
|
-
//
|
|
5663
|
-
//
|
|
5664
|
-
|
|
5665
|
-
// Only *successful* resolutions are cached. A wrapper chain's shape is fixed at
|
|
5666
|
-
// construction, so once a member resolves to a ModelType it always will; but a
|
|
5667
|
-
// `late` member reports no subtype until its definition evaluates, and that
|
|
5668
|
-
// miss must stay retryable.
|
|
5669
|
-
const resolvedModelTypes = new WeakMap();
|
|
5715
|
+
// The model a member is meant for: the one under its wrappers, and for a
|
|
5716
|
+
// `resilient` member the one it tries first. Matching a snapshot to a member
|
|
5717
|
+
// (quick-match dispatch, discriminator scoping) keys on that model's props,
|
|
5718
|
+
// and real-world members are rarely bare models (jbrowse config schemas are
|
|
5719
|
+
// always optional(model) or optional(snapshotProcessor(model))).
|
|
5720
|
+
// Misses are cached too, unless the member holds a `late` type: that has no
|
|
5721
|
+
// subtype until its definition evaluates, so its miss must stay retryable.
|
|
5722
|
+
const intendedModelTypes = new WeakMap();
|
|
5670
5723
|
function resolveModelType(type) {
|
|
5671
|
-
|
|
5672
|
-
|
|
5724
|
+
const cached = intendedModelTypes.get(type);
|
|
5725
|
+
if (cached !== undefined) {
|
|
5726
|
+
return cached ?? undefined;
|
|
5673
5727
|
}
|
|
5674
|
-
const
|
|
5675
|
-
if (
|
|
5676
|
-
|
|
5728
|
+
const model = findIntendedModelType(type);
|
|
5729
|
+
if (model || !(type.flags & TypeFlags.Late)) {
|
|
5730
|
+
intendedModelTypes.set(type, model ?? null);
|
|
5677
5731
|
}
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
const wrapper = current;
|
|
5685
|
-
current = wrapper._subtype ?? wrapper.getSubType?.(false);
|
|
5732
|
+
return model;
|
|
5733
|
+
}
|
|
5734
|
+
function findIntendedModelType(type) {
|
|
5735
|
+
const unwrapped = unwrapType(type);
|
|
5736
|
+
if (unwrapped instanceof ModelType) {
|
|
5737
|
+
return unwrapped;
|
|
5686
5738
|
}
|
|
5687
|
-
return
|
|
5739
|
+
return unwrapped instanceof Resilient
|
|
5740
|
+
? findIntendedModelType(unwrapped.primaryType)
|
|
5741
|
+
: undefined;
|
|
5688
5742
|
}
|
|
5689
5743
|
// The quick-match paths below already know a type carries TypeFlags.Literal,
|
|
5690
5744
|
// but `is()` still routes through BaseType.validate — a context array, an entry
|
|
@@ -5722,13 +5776,17 @@ class Union extends BaseType {
|
|
|
5722
5776
|
if (cached !== undefined) {
|
|
5723
5777
|
return cached;
|
|
5724
5778
|
}
|
|
5779
|
+
const result = this.foldFlags();
|
|
5780
|
+
if (!(result & TypeFlags.Late)) {
|
|
5781
|
+
this._flags = result;
|
|
5782
|
+
}
|
|
5783
|
+
return result;
|
|
5784
|
+
}
|
|
5785
|
+
foldFlags() {
|
|
5725
5786
|
let result = TypeFlags.Union;
|
|
5726
5787
|
for (const type of this.members()) {
|
|
5727
5788
|
result |= type.flags;
|
|
5728
5789
|
}
|
|
5729
|
-
if (!(result & TypeFlags.Late)) {
|
|
5730
|
-
this._flags = result;
|
|
5731
|
-
}
|
|
5732
5790
|
return result;
|
|
5733
5791
|
}
|
|
5734
5792
|
computeName() {
|
|
@@ -6063,11 +6121,7 @@ class DynamicUnion extends Union {
|
|
|
6063
6121
|
return this._members();
|
|
6064
6122
|
}
|
|
6065
6123
|
get flags() {
|
|
6066
|
-
|
|
6067
|
-
for (const type of this.members()) {
|
|
6068
|
-
result |= type.flags;
|
|
6069
|
-
}
|
|
6070
|
-
return result;
|
|
6124
|
+
return this.foldFlags();
|
|
6071
6125
|
}
|
|
6072
6126
|
get name() {
|
|
6073
6127
|
return this._explicitName !== undefined
|
|
@@ -6146,11 +6200,9 @@ function union(...args) {
|
|
|
6146
6200
|
/**
|
|
6147
6201
|
* Returns if a given value represents a union type.
|
|
6148
6202
|
*
|
|
6149
|
-
*
|
|
6150
|
-
*
|
|
6151
|
-
*
|
|
6152
|
-
* to compile. Guards with a distinct narrowing target (`isArrayType`,
|
|
6153
|
-
* `isMapType`, `isModelType`) keep their predicate.
|
|
6203
|
+
* Like every `isXType` guard it reads the type's flags, which wrappers and
|
|
6204
|
+
* unions inherit from what they hold, so it is also true for a type that wraps
|
|
6205
|
+
* or unions one. Use {@link unwrapType} to get at the type itself.
|
|
6154
6206
|
*
|
|
6155
6207
|
* @param type
|
|
6156
6208
|
* @returns
|
|
@@ -6159,13 +6211,9 @@ function isUnionType(type) {
|
|
|
6159
6211
|
return isType(type) && (type.flags & TypeFlags.Union) > 0;
|
|
6160
6212
|
}
|
|
6161
6213
|
/**
|
|
6162
|
-
* Returns the member types of a union
|
|
6163
|
-
*
|
|
6164
|
-
*
|
|
6165
|
-
* the type they wrap, so `isUnionType` is true for e.g. an optional-of-union,
|
|
6166
|
-
* but their `getSubTypes()` reports the single wrapped type rather than the
|
|
6167
|
-
* union's members. This drills through those wrappers until the union's member
|
|
6168
|
-
* array surfaces.
|
|
6214
|
+
* Returns the member types of a union, seeing through the wrappers
|
|
6215
|
+
* {@link unwrapType} does: `isUnionType` is also true for e.g. an
|
|
6216
|
+
* optional-of-union.
|
|
6169
6217
|
*
|
|
6170
6218
|
* @param type a type for which `isUnionType` is true
|
|
6171
6219
|
* @returns the array of member types of the underlying union
|
|
@@ -6174,16 +6222,11 @@ function getUnionSubtypes(type) {
|
|
|
6174
6222
|
if (!isUnionType(type)) {
|
|
6175
6223
|
throw fail("expected a union type");
|
|
6176
6224
|
}
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
subtypes !== null &&
|
|
6180
|
-
!Array.isArray(subtypes)) {
|
|
6181
|
-
subtypes = subtypes.getSubTypes();
|
|
6182
|
-
}
|
|
6183
|
-
if (!Array.isArray(subtypes)) {
|
|
6225
|
+
const union = unwrapType(type);
|
|
6226
|
+
if (!(union instanceof Union)) {
|
|
6184
6227
|
throw fail("could not extract subtypes from union type");
|
|
6185
6228
|
}
|
|
6186
|
-
return
|
|
6229
|
+
return union.getSubTypes();
|
|
6187
6230
|
}
|
|
6188
6231
|
|
|
6189
6232
|
/**
|
|
@@ -6330,11 +6373,9 @@ const undefinedAsOptionalValues = [undefined];
|
|
|
6330
6373
|
/**
|
|
6331
6374
|
* Returns if a value represents an optional type.
|
|
6332
6375
|
*
|
|
6333
|
-
*
|
|
6334
|
-
*
|
|
6335
|
-
*
|
|
6336
|
-
* to compile. Guards with a distinct narrowing target (`isArrayType`,
|
|
6337
|
-
* `isMapType`, `isModelType`) keep their predicate.
|
|
6376
|
+
* Like every `isXType` guard it reads the type's flags, which wrappers and
|
|
6377
|
+
* unions inherit from what they hold, so it is also true for a type that wraps
|
|
6378
|
+
* or unions one. Use {@link unwrapType} to get at the type itself.
|
|
6338
6379
|
*
|
|
6339
6380
|
* @param type
|
|
6340
6381
|
* @returns
|
|
@@ -6345,26 +6386,6 @@ function isOptionalType(type) {
|
|
|
6345
6386
|
function isRecord(value) {
|
|
6346
6387
|
return typeof value === "object" && value !== null;
|
|
6347
6388
|
}
|
|
6348
|
-
/**
|
|
6349
|
-
* The identifier attribute of the model a stripDefault ultimately wraps, or
|
|
6350
|
-
* `null` when there is none. Drills through the single-subtype wrappers the way
|
|
6351
|
-
* `resolveModelType` in union.ts does — that one is module-private there, and
|
|
6352
|
-
* this file may not reach into it.
|
|
6353
|
-
*
|
|
6354
|
-
* `null` is also the answer for an unresolved `types.late`, which only costs the
|
|
6355
|
-
* short-circuit, never correctness: the full structural walk still runs.
|
|
6356
|
-
*/
|
|
6357
|
-
function resolveIdentifierAttribute(type) {
|
|
6358
|
-
let current = type;
|
|
6359
|
-
for (let depth = 0; current && depth < 20; depth++) {
|
|
6360
|
-
if (current instanceof ModelType) {
|
|
6361
|
-
return current.identifierAttribute ? current.identifierAttribute : null;
|
|
6362
|
-
}
|
|
6363
|
-
const wrapper = current;
|
|
6364
|
-
current = wrapper._subtype ?? wrapper.getSubType?.(false);
|
|
6365
|
-
}
|
|
6366
|
-
return null;
|
|
6367
|
-
}
|
|
6368
6389
|
/**
|
|
6369
6390
|
* Compare a child snapshot to a stripped-default's reference snapshot: identity
|
|
6370
6391
|
* for primitives, structural for objects/arrays.
|
|
@@ -6446,7 +6467,10 @@ class StripDefaultValue extends OptionalValue {
|
|
|
6446
6467
|
equalsDefault(snapshot, defaultSnapshot) {
|
|
6447
6468
|
let identifierAttribute = this._identifierAttribute;
|
|
6448
6469
|
if (identifierAttribute === undefined) {
|
|
6449
|
-
|
|
6470
|
+
// null when not wrapping an identified model; an unresolved late member
|
|
6471
|
+
// also lands here, which only costs the short-circuit below
|
|
6472
|
+
identifierAttribute =
|
|
6473
|
+
asModelType(this.getSubTypes())?.identifierAttribute ?? null;
|
|
6450
6474
|
this._identifierAttribute = identifierAttribute;
|
|
6451
6475
|
}
|
|
6452
6476
|
// an identified model's snapshot normally has the same shape as the default
|
|
@@ -6556,16 +6580,14 @@ class Late extends BaseType {
|
|
|
6556
6580
|
}
|
|
6557
6581
|
getSubType(mustSucceed) {
|
|
6558
6582
|
if (!this._subType) {
|
|
6559
|
-
let t
|
|
6583
|
+
let t;
|
|
6560
6584
|
try {
|
|
6561
6585
|
t = this._definition();
|
|
6562
6586
|
}
|
|
6563
6587
|
catch (e) {
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
}
|
|
6568
|
-
else {
|
|
6588
|
+
// a self-referencing definition can read its binding before it is
|
|
6589
|
+
// initialized; that is "not defined yet", like returning undefined
|
|
6590
|
+
if (!(e instanceof ReferenceError)) {
|
|
6569
6591
|
throw e;
|
|
6570
6592
|
}
|
|
6571
6593
|
}
|
|
@@ -6581,10 +6603,15 @@ class Late extends BaseType {
|
|
|
6581
6603
|
}
|
|
6582
6604
|
return this._subType;
|
|
6583
6605
|
}
|
|
6584
|
-
constructor(
|
|
6606
|
+
constructor(_definition, name) {
|
|
6585
6607
|
super(name);
|
|
6586
6608
|
this._definition = _definition;
|
|
6587
6609
|
}
|
|
6610
|
+
// the unnamed form is named after the definition's source text, which is
|
|
6611
|
+
// only worth building if something reads it
|
|
6612
|
+
computeName() {
|
|
6613
|
+
return `late(${this._definition.toString()})`;
|
|
6614
|
+
}
|
|
6588
6615
|
instantiate(parent, subpath, environment, initialValue) {
|
|
6589
6616
|
return this.getSubType(true).instantiate(parent, subpath, environment, initialValue);
|
|
6590
6617
|
}
|
|
@@ -6593,7 +6620,7 @@ class Late extends BaseType {
|
|
|
6593
6620
|
}
|
|
6594
6621
|
describe() {
|
|
6595
6622
|
const t = this.getSubType(false);
|
|
6596
|
-
return t ? t.name : "<
|
|
6623
|
+
return t ? t.name : "<unknown late type>";
|
|
6597
6624
|
}
|
|
6598
6625
|
isValidSnapshot(value, context) {
|
|
6599
6626
|
const t = this.getSubType(false);
|
|
@@ -6608,8 +6635,7 @@ class Late extends BaseType {
|
|
|
6608
6635
|
return t ? t.isAssignableFrom(type) : false;
|
|
6609
6636
|
}
|
|
6610
6637
|
getSubTypes() {
|
|
6611
|
-
|
|
6612
|
-
return subtype ? subtype : cannotDetermineSubtype;
|
|
6638
|
+
return this.getSubType(false) ?? cannotDetermineSubtype;
|
|
6613
6639
|
}
|
|
6614
6640
|
}
|
|
6615
6641
|
/**
|
|
@@ -6629,26 +6655,21 @@ class Late extends BaseType {
|
|
|
6629
6655
|
* @returns
|
|
6630
6656
|
*/
|
|
6631
6657
|
function late(nameOrType, maybeType) {
|
|
6632
|
-
const name = typeof nameOrType === "string"
|
|
6633
|
-
? nameOrType
|
|
6634
|
-
: `late(${nameOrType.toString()})`;
|
|
6658
|
+
const name = typeof nameOrType === "string" ? nameOrType : undefined;
|
|
6635
6659
|
const type = typeof nameOrType === "string" ? maybeType : nameOrType;
|
|
6636
|
-
// checks that the type is actually a late type
|
|
6637
6660
|
if (devMode()) {
|
|
6638
6661
|
if (!(typeof type === "function" && type.length === 0)) {
|
|
6639
6662
|
throw fail(`Invalid late type, expected a function with zero arguments that returns a type, got: ${type}`);
|
|
6640
6663
|
}
|
|
6641
6664
|
}
|
|
6642
|
-
return new Late(
|
|
6665
|
+
return new Late(type, name);
|
|
6643
6666
|
}
|
|
6644
6667
|
/**
|
|
6645
6668
|
* Returns if a given value represents a late type.
|
|
6646
6669
|
*
|
|
6647
|
-
*
|
|
6648
|
-
*
|
|
6649
|
-
*
|
|
6650
|
-
* to compile. Guards with a distinct narrowing target (`isArrayType`,
|
|
6651
|
-
* `isMapType`, `isModelType`) keep their predicate.
|
|
6670
|
+
* Like every `isXType` guard it reads the type's flags, which wrappers and
|
|
6671
|
+
* unions inherit from what they hold, so it is also true for a type that wraps
|
|
6672
|
+
* or unions one. Use {@link unwrapType} to get at the type itself.
|
|
6652
6673
|
*
|
|
6653
6674
|
* @param type
|
|
6654
6675
|
* @returns
|
|
@@ -6658,7 +6679,8 @@ function isLateType(type) {
|
|
|
6658
6679
|
}
|
|
6659
6680
|
|
|
6660
6681
|
function lazy(name, options) {
|
|
6661
|
-
//
|
|
6682
|
+
// a lazy type stands in for the type it loads, down to that type's own
|
|
6683
|
+
// methods (a model's `.props`, say), which the placeholder does not have
|
|
6662
6684
|
return new Lazy(name, options);
|
|
6663
6685
|
}
|
|
6664
6686
|
/**
|
|
@@ -6825,11 +6847,9 @@ function frozen(arg) {
|
|
|
6825
6847
|
/**
|
|
6826
6848
|
* Returns if a given value represents a frozen type.
|
|
6827
6849
|
*
|
|
6828
|
-
*
|
|
6829
|
-
*
|
|
6830
|
-
*
|
|
6831
|
-
* to compile. Guards with a distinct narrowing target (`isArrayType`,
|
|
6832
|
-
* `isMapType`, `isModelType`) keep their predicate.
|
|
6850
|
+
* Like every `isXType` guard it reads the type's flags, which wrappers and
|
|
6851
|
+
* unions inherit from what they hold, so it is also true for a type that wraps
|
|
6852
|
+
* or unions one. Use {@link unwrapType} to get at the type itself.
|
|
6833
6853
|
*
|
|
6834
6854
|
* @param type
|
|
6835
6855
|
* @returns
|
|
@@ -6973,9 +6993,10 @@ class BaseReferenceType extends SimpleType {
|
|
|
6973
6993
|
return undefined;
|
|
6974
6994
|
}
|
|
6975
6995
|
const refTargetNode = getStateTreeNode(refTargetValue);
|
|
6976
|
-
const hookHandler = (
|
|
6996
|
+
const hookHandler = (subject, refTargetNodeHook) => {
|
|
6977
6997
|
const cause = getInvalidationCause(refTargetNodeHook);
|
|
6978
|
-
|
|
6998
|
+
// a reference detached along with its target still resolves it
|
|
6999
|
+
if (!cause || (cause === "detach" && storedRefNode.isWithin(subject))) {
|
|
6979
7000
|
return;
|
|
6980
7001
|
}
|
|
6981
7002
|
this.fireInvalidated(cause, storedRefNode, referenceId, refTargetNode);
|
|
@@ -7173,11 +7194,9 @@ function reference(subType, options) {
|
|
|
7173
7194
|
/**
|
|
7174
7195
|
* Returns if a given value represents a reference type.
|
|
7175
7196
|
*
|
|
7176
|
-
*
|
|
7177
|
-
*
|
|
7178
|
-
*
|
|
7179
|
-
* to compile. Guards with a distinct narrowing target (`isArrayType`,
|
|
7180
|
-
* `isMapType`, `isModelType`) keep their predicate.
|
|
7197
|
+
* Like every `isXType` guard it reads the type's flags, which wrappers and
|
|
7198
|
+
* unions inherit from what they hold, so it is also true for a type that wraps
|
|
7199
|
+
* or unions one. Use {@link unwrapType} to get at the type itself.
|
|
7181
7200
|
*
|
|
7182
7201
|
* @param type
|
|
7183
7202
|
* @returns
|
|
@@ -7302,11 +7321,9 @@ const identifierNumber = new IdentifierNumberType();
|
|
|
7302
7321
|
/**
|
|
7303
7322
|
* Returns if a given value represents an identifier type.
|
|
7304
7323
|
*
|
|
7305
|
-
*
|
|
7306
|
-
*
|
|
7307
|
-
*
|
|
7308
|
-
* to compile. Guards with a distinct narrowing target (`isArrayType`,
|
|
7309
|
-
* `isMapType`, `isModelType`) keep their predicate.
|
|
7324
|
+
* Like every `isXType` guard it reads the type's flags, which wrappers and
|
|
7325
|
+
* unions inherit from what they hold, so it is also true for a type that wraps
|
|
7326
|
+
* or unions one. Use {@link unwrapType} to get at the type itself.
|
|
7310
7327
|
*
|
|
7311
7328
|
* @param type
|
|
7312
7329
|
* @returns
|
|
@@ -7437,6 +7454,10 @@ class CustomType extends SimpleType {
|
|
|
7437
7454
|
}
|
|
7438
7455
|
}
|
|
7439
7456
|
|
|
7457
|
+
/**
|
|
7458
|
+
* @internal
|
|
7459
|
+
* @hidden
|
|
7460
|
+
*/
|
|
7440
7461
|
class Resilient extends BaseType {
|
|
7441
7462
|
_subtype;
|
|
7442
7463
|
_fallbackType;
|
|
@@ -7444,6 +7465,10 @@ class Resilient extends BaseType {
|
|
|
7444
7465
|
get flags() {
|
|
7445
7466
|
return this._subtype.flags;
|
|
7446
7467
|
}
|
|
7468
|
+
/** the type tried first; the fallback takes over only when it fails */
|
|
7469
|
+
get primaryType() {
|
|
7470
|
+
return this._subtype;
|
|
7471
|
+
}
|
|
7447
7472
|
constructor(_subtype, _fallbackType, _createFallbackSnapshot) {
|
|
7448
7473
|
super();
|
|
7449
7474
|
this._subtype = _subtype;
|
|
@@ -7599,5 +7624,5 @@ const types = {
|
|
|
7599
7624
|
resilient
|
|
7600
7625
|
};
|
|
7601
7626
|
|
|
7602
|
-
export { addDisposer, addMiddleware, applyAction, applyPatch, applySnapshot, cannotDetermineSubtype, cast, castFlowReturn, castToReferenceSnapshot, castToSnapshot, clone, createActionTrackingMiddleware, createActionTrackingMiddleware2, decorate, destroy, detach, escapeJsonPath, extendInstance, flow, getChildType, getEnv, getIdentifier, getLivelinessChecking, getMembers, getNodeId, getParent, getParentOfType, getPath, getPathParts, getPropertyMembers, getRelativePath, getRoot, getRunningActionContext, getSnapshot, getType, getUnionSubtypes, hasParent, hasParentOfType, isActionContextChildOf, isActionContextThisOrChildOf, isAlive, isArrayType, isFrozenType, isIdentifierType, isLateType, isLiteralType, isMapType, isModelType, isOptionalType, isPrimitiveType, isProtected, isReferenceType, isRefinementType, isRoot, isStateTreeNode, isType, isUnionType, isValidReference, joinJsonPath, onAction, onPatch, onSnapshot, protect, recordActions, recordPatches, resolveIdentifier, resolvePath, setDevMode, setLivelinessChecking, setLivelynessChecking, setTypeChecking, splitJsonPath, types as t, toGenerator, toGeneratorFunction, tryReference, tryResolve, typecheck, types, unescapeJsonPath, unprotect, walk };
|
|
7627
|
+
export { addDisposer, addMiddleware, applyAction, applyPatch, applySnapshot, asArrayType, asMapType, asModelType, cannotDetermineSubtype, cast, castFlowReturn, castToReferenceSnapshot, castToSnapshot, clone, createActionTrackingMiddleware, createActionTrackingMiddleware2, decorate, destroy, detach, escapeJsonPath, extendInstance, flow, getChildType, getEnv, getIdentifier, getLivelinessChecking, getMembers, getNodeId, getParent, getParentOfType, getPath, getPathParts, getPropertyMembers, getRelativePath, getRoot, getRunningActionContext, getSnapshot, getType, getUnionSubtypes, getWrappedType, hasParent, hasParentOfType, isActionContextChildOf, isActionContextThisOrChildOf, isAlive, isArrayType, isFrozenType, isIdentifierType, isLateType, isLiteralType, isMapType, isModelType, isOptionalType, isPrimitiveType, isProtected, isReferenceType, isRefinementType, isRoot, isStateTreeNode, isType, isUnionType, isValidReference, joinJsonPath, onAction, onPatch, onSnapshot, protect, recordActions, recordPatches, resolveIdentifier, resolvePath, setDevMode, setLivelinessChecking, setLivelynessChecking, setTypeChecking, splitJsonPath, types as t, toGenerator, toGeneratorFunction, tryReference, tryResolve, typecheck, types, unescapeJsonPath, unprotect, unwrapType, walk };
|
|
7603
7628
|
//# sourceMappingURL=mobx-state-tree.mjs.map
|