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