@jbrowse/mobx-state-tree 6.6.1 → 6.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/index.d.ts +7 -0
- package/dist/mobx-state-tree.cjs +55 -12
- package/dist/mobx-state-tree.cjs.map +1 -1
- package/dist/mobx-state-tree.mjs +55 -12
- package/dist/mobx-state-tree.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [6.7.0](https://github.com/GMOD/mobx-state-tree/compare/v6.6.1...v6.7.0) (2026-09-30)
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
|
|
5
|
+
- A dead node's never-read child reads as a dead instance ([a6c430e](https://github.com/GMOD/mobx-state-tree/commit/a6c430e926ec31fe226a10cafff6e2ea0add4012))
|
|
6
|
+
- Exempt only never-created dead nodes; ADR 0008 ([d15fb5b](https://github.com/GMOD/mobx-state-tree/commit/d15fb5b99399d7844af910db689cbb5c403ddbc3))
|
|
7
|
+
- A never-read node dies as if it had been read ([3ffffae](https://github.com/GMOD/mobx-state-tree/commit/3ffffae9f5f44e7c5ea1573364da2ce6224ff288))
|
|
8
|
+
- Fail clearly, before damaging the tree, on impossible attaches ([25e0dff](https://github.com/GMOD/mobx-state-tree/commit/25e0dffd31b02c57ec31195685e3551de7167bb0))
|
|
9
|
+
- Destroy children that hooks add while a node is built at death ([743f887](https://github.com/GMOD/mobx-state-tree/commit/743f887f0a749f5dff727c86429c5ffb7ce4b726))
|
|
10
|
+
|
|
11
|
+
### Styling
|
|
12
|
+
|
|
13
|
+
- Format ADR 0008 ([4290662](https://github.com/GMOD/mobx-state-tree/commit/42906620c1c6fc58526251310468d0012f446159))
|
|
14
|
+
|
|
1
15
|
## [6.6.1](https://github.com/GMOD/mobx-state-tree/compare/v6.6.0...v6.6.1) (2026-09-25)
|
|
2
16
|
|
|
3
17
|
### Performance Improvements
|
package/dist/index.d.ts
CHANGED
|
@@ -624,6 +624,13 @@ declare class ObjectNode<C, S, T> extends BaseNode<C, S, T> {
|
|
|
624
624
|
clearParent(): void;
|
|
625
625
|
notifyDetachOf(subject: AnyObjectNode): void;
|
|
626
626
|
private notifyChildrenOfDetach;
|
|
627
|
+
/**
|
|
628
|
+
* @internal
|
|
629
|
+
* @hidden
|
|
630
|
+
* A node that died inside a tree is its own root and has no identifier
|
|
631
|
+
* cache, so attaching it, or attaching anything to it, cannot work.
|
|
632
|
+
*/
|
|
633
|
+
assertAttachable(): IdentifierCache;
|
|
627
634
|
setParent(newParent: AnyObjectNode, subpath: string): void;
|
|
628
635
|
protected fireHook(name: Hook): void;
|
|
629
636
|
private _snapshotUponDeath?;
|
package/dist/mobx-state-tree.cjs
CHANGED
|
@@ -468,7 +468,7 @@ function resolveIdentifier(type, target, identifier) {
|
|
|
468
468
|
assertIsType(type, 1);
|
|
469
469
|
assertIsStateTreeNode(target, 2);
|
|
470
470
|
assertIsValidIdentifier(identifier, 3);
|
|
471
|
-
const node = getStateTreeNode(target).root.identifierCache
|
|
471
|
+
const node = getStateTreeNode(target).root.identifierCache?.resolve(type, normalizeIdentifier(identifier));
|
|
472
472
|
return node?.value;
|
|
473
473
|
}
|
|
474
474
|
/**
|
|
@@ -1211,7 +1211,7 @@ class ObjectNode extends BaseNode {
|
|
|
1211
1211
|
// addNodeToCache no-ops without an identifier attribute, and reaching the
|
|
1212
1212
|
// root to ask it is a walk up the whole parent chain
|
|
1213
1213
|
if (this.identifierAttribute) {
|
|
1214
|
-
const cache = parent ? parent.
|
|
1214
|
+
const cache = parent ? parent.assertAttachable() : this.identifierCache;
|
|
1215
1215
|
cache.addNodeToCache(this);
|
|
1216
1216
|
}
|
|
1217
1217
|
}
|
|
@@ -1222,8 +1222,11 @@ class ObjectNode extends BaseNode {
|
|
|
1222
1222
|
}
|
|
1223
1223
|
}
|
|
1224
1224
|
createObservableInstance(fireHooks = true) {
|
|
1225
|
+
const diedUncreated = this.state === NodeLifeCycle.DEAD &&
|
|
1226
|
+
this._observableInstanceState ===
|
|
1227
|
+
ObservableInstanceLifecycle.UNINITIALIZED;
|
|
1225
1228
|
if (devMode()) {
|
|
1226
|
-
if (this.state !== NodeLifeCycle.INITIALIZING) {
|
|
1229
|
+
if (!diedUncreated && this.state !== NodeLifeCycle.INITIALIZING) {
|
|
1227
1230
|
// istanbul ignore next
|
|
1228
1231
|
throw fail("assertion failed: the creation of the observable instance must be done on the initializing phase");
|
|
1229
1232
|
}
|
|
@@ -1276,6 +1279,9 @@ class ObjectNode extends BaseNode {
|
|
|
1276
1279
|
// subscribes to never pays for a full-tree snapshot at creation. keepAlive
|
|
1277
1280
|
// on _snapshotComputed preserves snapshot referential stability without it.
|
|
1278
1281
|
this._childNodes = EMPTY_OBJECT;
|
|
1282
|
+
if (diedUncreated) {
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1279
1285
|
this.state = NodeLifeCycle.CREATED;
|
|
1280
1286
|
if (fireHooks) {
|
|
1281
1287
|
this.fireHook(Hook.afterCreate);
|
|
@@ -1330,6 +1336,19 @@ class ObjectNode extends BaseNode {
|
|
|
1330
1336
|
child.notifyDetachOf(subject);
|
|
1331
1337
|
}
|
|
1332
1338
|
}
|
|
1339
|
+
/**
|
|
1340
|
+
* @internal
|
|
1341
|
+
* @hidden
|
|
1342
|
+
* A node that died inside a tree is its own root and has no identifier
|
|
1343
|
+
* cache, so attaching it, or attaching anything to it, cannot work.
|
|
1344
|
+
*/
|
|
1345
|
+
assertAttachable() {
|
|
1346
|
+
const cache = this.root.identifierCache;
|
|
1347
|
+
if (!cache) {
|
|
1348
|
+
throw fail(`'${this}' is no longer part of a state tree, so it cannot be attached to one or have nodes attached to it.`);
|
|
1349
|
+
}
|
|
1350
|
+
return cache;
|
|
1351
|
+
}
|
|
1333
1352
|
setParent(newParent, subpath) {
|
|
1334
1353
|
const parentChanged = newParent !== this.parent;
|
|
1335
1354
|
const subpathChanged = subpath !== this.subpath;
|
|
@@ -1358,9 +1377,9 @@ class ObjectNode extends BaseNode {
|
|
|
1358
1377
|
}
|
|
1359
1378
|
}
|
|
1360
1379
|
if (parentChanged) {
|
|
1361
|
-
|
|
1380
|
+
this.assertAttachable();
|
|
1362
1381
|
this.environment = undefined; // will use root's
|
|
1363
|
-
newParent.
|
|
1382
|
+
newParent.assertAttachable().mergeCache(this);
|
|
1364
1383
|
this.baseSetParent(newParent, subpath);
|
|
1365
1384
|
this.fireHook(Hook.afterAttach);
|
|
1366
1385
|
}
|
|
@@ -1556,13 +1575,33 @@ class ObjectNode extends BaseNode {
|
|
|
1556
1575
|
addHiddenFinalProp(this.storedValue, "toJSON", toJSON);
|
|
1557
1576
|
}
|
|
1558
1577
|
aboutToDie() {
|
|
1578
|
+
const wasUninitialized = this._observableInstanceState ===
|
|
1579
|
+
ObservableInstanceLifecycle.UNINITIALIZED;
|
|
1580
|
+
const children = this.getChildren();
|
|
1581
|
+
if (wasUninitialized &&
|
|
1582
|
+
(this.hasSnapshotPostProcessor ||
|
|
1583
|
+
children.some(child => child instanceof ObjectNode &&
|
|
1584
|
+
child._observableInstanceState !==
|
|
1585
|
+
ObservableInstanceLifecycle.UNINITIALIZED))) {
|
|
1586
|
+
this.createObservableInstanceIfNeeded();
|
|
1587
|
+
}
|
|
1588
|
+
for (const node of children) {
|
|
1589
|
+
if (node.isAlive) {
|
|
1590
|
+
node.aboutToDie();
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1559
1593
|
if (this._observableInstanceState ===
|
|
1560
1594
|
ObservableInstanceLifecycle.UNINITIALIZED) {
|
|
1561
1595
|
return;
|
|
1562
1596
|
}
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1597
|
+
if (wasUninitialized) {
|
|
1598
|
+
const walked = new Set(children);
|
|
1599
|
+
for (const node of this.getChildren()) {
|
|
1600
|
+
if (node.isAlive && !walked.has(node)) {
|
|
1601
|
+
node.aboutToDie();
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1566
1605
|
// beforeDestroy should run before the disposers since else we could end up in a situation where
|
|
1567
1606
|
// a disposer added with addDisposer at this stage (beforeDestroy) is actually never released
|
|
1568
1607
|
this.baseAboutToDie();
|
|
@@ -1859,12 +1898,16 @@ class ComplexType extends BaseType {
|
|
|
1859
1898
|
current.setParent(parent, subpath);
|
|
1860
1899
|
return current;
|
|
1861
1900
|
}
|
|
1901
|
+
const newNode = getStateTreeNodeSafe(newValue);
|
|
1902
|
+
if (newNode) {
|
|
1903
|
+
newNode.assertAttachable();
|
|
1904
|
+
if (!current.isDetaching && newNode.isWithin(current)) {
|
|
1905
|
+
throw fail(`Cannot assign ${newNode} to '${parent.path}/${subpath}': it is part of ${current}, which it would replace.`);
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1862
1908
|
// current node cannot be recycled in any way
|
|
1863
1909
|
current.die(); // noop if detaching
|
|
1864
|
-
|
|
1865
|
-
if (isStateTreeNode(newValue) && this.isAssignableFrom(getType(newValue))) {
|
|
1866
|
-
// newValue is a Node as well, move it here..
|
|
1867
|
-
const newNode = getStateTreeNode(newValue);
|
|
1910
|
+
if (newNode && this.isAssignableFrom(newNode.type)) {
|
|
1868
1911
|
newNode.setParent(parent, subpath);
|
|
1869
1912
|
return newNode;
|
|
1870
1913
|
}
|