@jbrowse/mobx-state-tree 5.11.1 → 5.12.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/README.md +85 -12
- package/dist/index.d.ts +2 -48
- package/dist/mobx-state-tree.cjs +144 -164
- package/dist/mobx-state-tree.cjs.map +1 -1
- package/dist/mobx-state-tree.mjs +145 -164
- package/dist/mobx-state-tree.mjs.map +1 -1
- package/package.json +6 -1
package/dist/mobx-state-tree.mjs
CHANGED
|
@@ -764,10 +764,11 @@ function getMembers(target) {
|
|
|
764
764
|
}
|
|
765
765
|
return;
|
|
766
766
|
}
|
|
767
|
-
|
|
767
|
+
const value = descriptor.value;
|
|
768
|
+
if (value?._isFlowAction === true) {
|
|
768
769
|
reflected.flowActions.push(key);
|
|
769
770
|
}
|
|
770
|
-
if (
|
|
771
|
+
if (value?._isMSTAction === true) {
|
|
771
772
|
reflected.actions.push(key);
|
|
772
773
|
}
|
|
773
774
|
else if (isObservableProp(target, key)) {
|
|
@@ -1116,6 +1117,21 @@ class ScalarNode extends BaseNode {
|
|
|
1116
1117
|
ScalarNode.prototype.die = action(ScalarNode.prototype.die);
|
|
1117
1118
|
|
|
1118
1119
|
let nextNodeId = 1;
|
|
1120
|
+
var ObservableInstanceLifecycle;
|
|
1121
|
+
(function (ObservableInstanceLifecycle) {
|
|
1122
|
+
// the actual observable instance has not been created yet
|
|
1123
|
+
ObservableInstanceLifecycle[ObservableInstanceLifecycle["UNINITIALIZED"] = 0] = "UNINITIALIZED";
|
|
1124
|
+
// the actual observable instance is being created
|
|
1125
|
+
ObservableInstanceLifecycle[ObservableInstanceLifecycle["CREATING"] = 1] = "CREATING";
|
|
1126
|
+
// the actual observable instance has been created
|
|
1127
|
+
ObservableInstanceLifecycle[ObservableInstanceLifecycle["CREATED"] = 2] = "CREATED";
|
|
1128
|
+
})(ObservableInstanceLifecycle || (ObservableInstanceLifecycle = {}));
|
|
1129
|
+
var InternalEvents;
|
|
1130
|
+
(function (InternalEvents) {
|
|
1131
|
+
InternalEvents["Dispose"] = "dispose";
|
|
1132
|
+
InternalEvents["Patch"] = "patch";
|
|
1133
|
+
InternalEvents["Snapshot"] = "snapshot";
|
|
1134
|
+
})(InternalEvents || (InternalEvents = {}));
|
|
1119
1135
|
const snapshotReactionOptions = {
|
|
1120
1136
|
onError(e) {
|
|
1121
1137
|
throw e;
|
|
@@ -1147,7 +1163,7 @@ class ObjectNode extends BaseNode {
|
|
|
1147
1163
|
_autoUnbox = true; // unboxing is disabled when reading child nodes
|
|
1148
1164
|
_isRunningAction = false; // only relevant for root
|
|
1149
1165
|
_hasSnapshotReaction = false;
|
|
1150
|
-
_observableInstanceState =
|
|
1166
|
+
_observableInstanceState = ObservableInstanceLifecycle.UNINITIALIZED;
|
|
1151
1167
|
_childNodes;
|
|
1152
1168
|
_initialSnapshot;
|
|
1153
1169
|
_cachedInitialSnapshot;
|
|
@@ -1192,7 +1208,7 @@ class ObjectNode extends BaseNode {
|
|
|
1192
1208
|
}
|
|
1193
1209
|
createObservableInstanceIfNeeded(fireHooks = true) {
|
|
1194
1210
|
if (this._observableInstanceState ===
|
|
1195
|
-
|
|
1211
|
+
ObservableInstanceLifecycle.UNINITIALIZED) {
|
|
1196
1212
|
this.createObservableInstance(fireHooks);
|
|
1197
1213
|
}
|
|
1198
1214
|
}
|
|
@@ -1203,7 +1219,7 @@ class ObjectNode extends BaseNode {
|
|
|
1203
1219
|
throw fail("assertion failed: the creation of the observable instance must be done on the initializing phase");
|
|
1204
1220
|
}
|
|
1205
1221
|
}
|
|
1206
|
-
this._observableInstanceState =
|
|
1222
|
+
this._observableInstanceState = ObservableInstanceLifecycle.CREATING;
|
|
1207
1223
|
// make sure the parent chain is created as well
|
|
1208
1224
|
// array with parent chain from parent to child
|
|
1209
1225
|
const parentChain = [];
|
|
@@ -1213,7 +1229,7 @@ class ObjectNode extends BaseNode {
|
|
|
1213
1229
|
// this is done to avoid traversing the whole tree to the root when using
|
|
1214
1230
|
// the same reference again
|
|
1215
1231
|
while (parent?._observableInstanceState ===
|
|
1216
|
-
|
|
1232
|
+
ObservableInstanceLifecycle.UNINITIALIZED) {
|
|
1217
1233
|
parentChain.unshift(parent);
|
|
1218
1234
|
parent = parent.parent;
|
|
1219
1235
|
}
|
|
@@ -1238,7 +1254,7 @@ class ObjectNode extends BaseNode {
|
|
|
1238
1254
|
finally {
|
|
1239
1255
|
this._isRunningAction = false;
|
|
1240
1256
|
}
|
|
1241
|
-
this._observableInstanceState =
|
|
1257
|
+
this._observableInstanceState = ObservableInstanceLifecycle.CREATED;
|
|
1242
1258
|
this._snapshotComputed.trackAndCompute();
|
|
1243
1259
|
if (this.isRoot) {
|
|
1244
1260
|
this._addSnapshotReaction();
|
|
@@ -1352,7 +1368,7 @@ class ObjectNode extends BaseNode {
|
|
|
1352
1368
|
if (!this.isAlive) {
|
|
1353
1369
|
return this._snapshotUponDeath;
|
|
1354
1370
|
}
|
|
1355
|
-
return this._observableInstanceState ===
|
|
1371
|
+
return this._observableInstanceState === ObservableInstanceLifecycle.CREATED
|
|
1356
1372
|
? this._getActualSnapshot()
|
|
1357
1373
|
: this._getCachedInitialSnapshot();
|
|
1358
1374
|
}
|
|
@@ -1415,7 +1431,7 @@ class ObjectNode extends BaseNode {
|
|
|
1415
1431
|
this._autoUnbox = false;
|
|
1416
1432
|
try {
|
|
1417
1433
|
return this._observableInstanceState ===
|
|
1418
|
-
|
|
1434
|
+
ObservableInstanceLifecycle.CREATED
|
|
1419
1435
|
? this.type.getChildNode(this, subpath)
|
|
1420
1436
|
: this._childNodes[subpath];
|
|
1421
1437
|
}
|
|
@@ -1428,7 +1444,7 @@ class ObjectNode extends BaseNode {
|
|
|
1428
1444
|
this._autoUnbox = false;
|
|
1429
1445
|
try {
|
|
1430
1446
|
return this._observableInstanceState ===
|
|
1431
|
-
|
|
1447
|
+
ObservableInstanceLifecycle.CREATED
|
|
1432
1448
|
? this.type.getChildren(this)
|
|
1433
1449
|
: convertChildNodesToArray(this._childNodes);
|
|
1434
1450
|
}
|
|
@@ -1514,7 +1530,7 @@ class ObjectNode extends BaseNode {
|
|
|
1514
1530
|
}
|
|
1515
1531
|
aboutToDie() {
|
|
1516
1532
|
if (this._observableInstanceState ===
|
|
1517
|
-
|
|
1533
|
+
ObservableInstanceLifecycle.UNINITIALIZED) {
|
|
1518
1534
|
return;
|
|
1519
1535
|
}
|
|
1520
1536
|
this.getChildren().forEach(node => {
|
|
@@ -1523,8 +1539,8 @@ class ObjectNode extends BaseNode {
|
|
|
1523
1539
|
// beforeDestroy should run before the disposers since else we could end up in a situation where
|
|
1524
1540
|
// a disposer added with addDisposer at this stage (beforeDestroy) is actually never released
|
|
1525
1541
|
this.baseAboutToDie();
|
|
1526
|
-
this._internalEventsEmit(
|
|
1527
|
-
this._internalEventsClear(
|
|
1542
|
+
this._internalEventsEmit(InternalEvents.Dispose);
|
|
1543
|
+
this._internalEventsClear(InternalEvents.Dispose);
|
|
1528
1544
|
}
|
|
1529
1545
|
finalizeDeath() {
|
|
1530
1546
|
// invariant: not called directly but from "die"
|
|
@@ -1540,42 +1556,42 @@ class ObjectNode extends BaseNode {
|
|
|
1540
1556
|
}
|
|
1541
1557
|
onSnapshot(onChange) {
|
|
1542
1558
|
this._addSnapshotReaction();
|
|
1543
|
-
return this._internalEventsRegister(
|
|
1559
|
+
return this._internalEventsRegister(InternalEvents.Snapshot, onChange);
|
|
1544
1560
|
}
|
|
1545
1561
|
emitSnapshot(snapshot) {
|
|
1546
|
-
this._internalEventsEmit(
|
|
1562
|
+
this._internalEventsEmit(InternalEvents.Snapshot, snapshot);
|
|
1547
1563
|
}
|
|
1548
1564
|
onPatch(handler) {
|
|
1549
|
-
return this._internalEventsRegister(
|
|
1565
|
+
return this._internalEventsRegister(InternalEvents.Patch, handler);
|
|
1550
1566
|
}
|
|
1551
1567
|
emitPatch(basePatch, source) {
|
|
1552
|
-
if (this._internalEventsHasSubscribers(
|
|
1568
|
+
if (this._internalEventsHasSubscribers(InternalEvents.Patch)) {
|
|
1553
1569
|
const localizedPatch = {
|
|
1554
1570
|
...basePatch,
|
|
1555
|
-
path: `${source.path.
|
|
1571
|
+
path: `${source.path.slice(this.path.length)}/${basePatch.path}` // calculate the relative path of the patch
|
|
1556
1572
|
};
|
|
1557
1573
|
const [patch, reversePatch] = splitPatch(localizedPatch);
|
|
1558
|
-
this._internalEventsEmit(
|
|
1574
|
+
this._internalEventsEmit(InternalEvents.Patch, patch, reversePatch);
|
|
1559
1575
|
}
|
|
1560
1576
|
if (this.parent) {
|
|
1561
1577
|
this.parent.emitPatch(basePatch, source);
|
|
1562
1578
|
}
|
|
1563
1579
|
}
|
|
1564
1580
|
hasDisposer(disposer) {
|
|
1565
|
-
return this._internalEventsHas(
|
|
1581
|
+
return this._internalEventsHas(InternalEvents.Dispose, disposer);
|
|
1566
1582
|
}
|
|
1567
1583
|
addDisposer(disposer) {
|
|
1568
1584
|
if (!this.hasDisposer(disposer)) {
|
|
1569
|
-
this._internalEventsRegister(
|
|
1585
|
+
this._internalEventsRegister(InternalEvents.Dispose, disposer, true);
|
|
1570
1586
|
return;
|
|
1571
1587
|
}
|
|
1572
1588
|
throw fail("cannot add a disposer when it is already registered for execution");
|
|
1573
1589
|
}
|
|
1574
1590
|
removeDisposer(disposer) {
|
|
1575
|
-
if (!this._internalEventsHas(
|
|
1591
|
+
if (!this._internalEventsHas(InternalEvents.Dispose, disposer)) {
|
|
1576
1592
|
throw fail("cannot remove a disposer which was never registered for execution");
|
|
1577
1593
|
}
|
|
1578
|
-
this._internalEventsUnregister(
|
|
1594
|
+
this._internalEventsUnregister(InternalEvents.Dispose, disposer);
|
|
1579
1595
|
}
|
|
1580
1596
|
removeMiddleware(middleware) {
|
|
1581
1597
|
if (this.middlewares) {
|
|
@@ -1651,9 +1667,6 @@ ObjectNode.prototype.createObservableInstance = action(ObjectNode.prototype.crea
|
|
|
1651
1667
|
ObjectNode.prototype.detach = action(ObjectNode.prototype.detach);
|
|
1652
1668
|
ObjectNode.prototype.die = action(ObjectNode.prototype.die);
|
|
1653
1669
|
|
|
1654
|
-
// Cache for validation results to avoid re-validating the same object against the same type
|
|
1655
|
-
// Uses WeakMap so cached objects can be garbage collected
|
|
1656
|
-
const validationCache = new WeakMap();
|
|
1657
1670
|
/**
|
|
1658
1671
|
* @internal
|
|
1659
1672
|
* @hidden
|
|
@@ -1729,27 +1742,7 @@ class BaseType {
|
|
|
1729
1742
|
: typeCheckFailure(context, value);
|
|
1730
1743
|
// it is tempting to compare snapshots, but in that case we should always clone on assignments...
|
|
1731
1744
|
}
|
|
1732
|
-
|
|
1733
|
-
if (typeof value === "object" && value !== null && context.length === 1) {
|
|
1734
|
-
const typeCache = validationCache.get(value);
|
|
1735
|
-
if (typeCache) {
|
|
1736
|
-
const cached = typeCache.get(this);
|
|
1737
|
-
if (cached !== undefined) {
|
|
1738
|
-
return cached;
|
|
1739
|
-
}
|
|
1740
|
-
}
|
|
1741
|
-
}
|
|
1742
|
-
const result = this.isValidSnapshot(value, context);
|
|
1743
|
-
// cache result for object values (only at root level)
|
|
1744
|
-
if (typeof value === "object" && value !== null && context.length === 1) {
|
|
1745
|
-
let typeCache = validationCache.get(value);
|
|
1746
|
-
if (!typeCache) {
|
|
1747
|
-
typeCache = new WeakMap();
|
|
1748
|
-
validationCache.set(value, typeCache);
|
|
1749
|
-
}
|
|
1750
|
-
typeCache.set(this, result);
|
|
1751
|
-
}
|
|
1752
|
-
return result;
|
|
1745
|
+
return this.isValidSnapshot(value, context);
|
|
1753
1746
|
}
|
|
1754
1747
|
is(thing) {
|
|
1755
1748
|
return this.validate(thing, [{ path: "", type: this }]).length === 0;
|
|
@@ -2565,22 +2558,47 @@ function isActionContextThisOrChildOf(actionContext, parentOrThis) {
|
|
|
2565
2558
|
}
|
|
2566
2559
|
|
|
2567
2560
|
const MAX_STRINGIFY_DEPTH = 3;
|
|
2561
|
+
const MAX_STRINGIFY_ARRAY_ITEMS = 10;
|
|
2562
|
+
const MAX_STRINGIFY_OBJECT_KEYS = 20;
|
|
2563
|
+
const MAX_STRINGIFY_STRING_LENGTH = 100;
|
|
2564
|
+
// Recursively cap depth, array length, object key count, and string length so a
|
|
2565
|
+
// huge offending snapshot degrades into readable, bounded context instead of a
|
|
2566
|
+
// wall of text that then gets sliced mid-structure. The depth cap also bounds
|
|
2567
|
+
// recursion on circular structures.
|
|
2568
|
+
function truncateForStringify(value, depth) {
|
|
2569
|
+
if (typeof value === "string") {
|
|
2570
|
+
return value.length > MAX_STRINGIFY_STRING_LENGTH
|
|
2571
|
+
? `${value.substring(0, MAX_STRINGIFY_STRING_LENGTH)}… (${value.length - MAX_STRINGIFY_STRING_LENGTH} more characters)`
|
|
2572
|
+
: value;
|
|
2573
|
+
}
|
|
2574
|
+
if (value === null || typeof value !== "object") {
|
|
2575
|
+
return value;
|
|
2576
|
+
}
|
|
2577
|
+
if (depth >= MAX_STRINGIFY_DEPTH) {
|
|
2578
|
+
return Array.isArray(value) ? "[…]" : "{…}";
|
|
2579
|
+
}
|
|
2580
|
+
if (Array.isArray(value)) {
|
|
2581
|
+
const items = value
|
|
2582
|
+
.slice(0, MAX_STRINGIFY_ARRAY_ITEMS)
|
|
2583
|
+
.map(item => truncateForStringify(item, depth + 1));
|
|
2584
|
+
if (value.length > MAX_STRINGIFY_ARRAY_ITEMS) {
|
|
2585
|
+
items.push(`… ${value.length - MAX_STRINGIFY_ARRAY_ITEMS} more items`);
|
|
2586
|
+
}
|
|
2587
|
+
return items;
|
|
2588
|
+
}
|
|
2589
|
+
const keys = Object.keys(value);
|
|
2590
|
+
const result = {};
|
|
2591
|
+
for (const key of keys.slice(0, MAX_STRINGIFY_OBJECT_KEYS)) {
|
|
2592
|
+
result[key] = truncateForStringify(value[key], depth + 1);
|
|
2593
|
+
}
|
|
2594
|
+
if (keys.length > MAX_STRINGIFY_OBJECT_KEYS) {
|
|
2595
|
+
result["…"] = `${keys.length - MAX_STRINGIFY_OBJECT_KEYS} more keys`;
|
|
2596
|
+
}
|
|
2597
|
+
return result;
|
|
2598
|
+
}
|
|
2568
2599
|
function safeStringify(value) {
|
|
2569
2600
|
try {
|
|
2570
|
-
|
|
2571
|
-
return JSON.stringify(value, function (_key, val) {
|
|
2572
|
-
if (val !== null && typeof val === "object") {
|
|
2573
|
-
while (ancestors.length > 0 &&
|
|
2574
|
-
ancestors[ancestors.length - 1] !== this) {
|
|
2575
|
-
ancestors.pop();
|
|
2576
|
-
}
|
|
2577
|
-
if (ancestors.length >= MAX_STRINGIFY_DEPTH) {
|
|
2578
|
-
return Array.isArray(val) ? "[…]" : "{…}";
|
|
2579
|
-
}
|
|
2580
|
-
ancestors.push(val);
|
|
2581
|
-
}
|
|
2582
|
-
return val;
|
|
2583
|
-
});
|
|
2601
|
+
return JSON.stringify(truncateForStringify(value, 0));
|
|
2584
2602
|
}
|
|
2585
2603
|
catch (e) {
|
|
2586
2604
|
// istanbul ignore next
|
|
@@ -3011,31 +3029,6 @@ function convertChildNodesToArray(childNodes) {
|
|
|
3011
3029
|
return result;
|
|
3012
3030
|
}
|
|
3013
3031
|
|
|
3014
|
-
// based on: https://github.com/mobxjs/mobx-utils/blob/master/src/async-action.ts
|
|
3015
|
-
/*
|
|
3016
|
-
All contents of this file are deprecated.
|
|
3017
|
-
|
|
3018
|
-
The term `process` has been replaced with `flow` to avoid conflicts with the
|
|
3019
|
-
global `process` object.
|
|
3020
|
-
|
|
3021
|
-
Refer to `flow.ts` for any further changes to this implementation.
|
|
3022
|
-
*/
|
|
3023
|
-
const DEPRECATION_MESSAGE = "See https://github.com/mobxjs/mobx-state-tree/issues/399 for more information. " +
|
|
3024
|
-
"Note that the middleware event types starting with `process` now start with `flow`.";
|
|
3025
|
-
/**
|
|
3026
|
-
* @hidden
|
|
3027
|
-
*
|
|
3028
|
-
* @deprecated has been renamed to `flow()`.
|
|
3029
|
-
* See https://github.com/mobxjs/mobx-state-tree/issues/399 for more information.
|
|
3030
|
-
* Note that the middleware event types starting with `process` now start with `flow`.
|
|
3031
|
-
*
|
|
3032
|
-
* @returns {Promise}
|
|
3033
|
-
*/
|
|
3034
|
-
function process$1(asyncAction) {
|
|
3035
|
-
deprecated("process", `\`process()\` has been renamed to \`flow()\`. ${DEPRECATION_MESSAGE}`);
|
|
3036
|
-
return flow(asyncAction);
|
|
3037
|
-
}
|
|
3038
|
-
|
|
3039
3032
|
const plainObjectString = Object.toString();
|
|
3040
3033
|
/**
|
|
3041
3034
|
* @internal
|
|
@@ -3224,8 +3217,6 @@ function addHiddenWritableProp(object, propName, value) {
|
|
|
3224
3217
|
*/
|
|
3225
3218
|
class EventHandler {
|
|
3226
3219
|
handlers = [];
|
|
3227
|
-
emitting = false;
|
|
3228
|
-
pendingUnregisters = null;
|
|
3229
3220
|
get hasSubscribers() {
|
|
3230
3221
|
return this.handlers.length > 0;
|
|
3231
3222
|
}
|
|
@@ -3244,14 +3235,6 @@ class EventHandler {
|
|
|
3244
3235
|
return this.handlers.includes(fn);
|
|
3245
3236
|
}
|
|
3246
3237
|
unregister(fn) {
|
|
3247
|
-
if (this.emitting) {
|
|
3248
|
-
// defer unregistration until emit is done
|
|
3249
|
-
if (!this.pendingUnregisters) {
|
|
3250
|
-
this.pendingUnregisters = [];
|
|
3251
|
-
}
|
|
3252
|
-
this.pendingUnregisters.push(fn);
|
|
3253
|
-
return;
|
|
3254
|
-
}
|
|
3255
3238
|
const index = this.handlers.indexOf(fn);
|
|
3256
3239
|
if (index >= 0) {
|
|
3257
3240
|
this.handlers.splice(index, 1);
|
|
@@ -3261,26 +3244,10 @@ class EventHandler {
|
|
|
3261
3244
|
this.handlers.length = 0;
|
|
3262
3245
|
}
|
|
3263
3246
|
emit(...args) {
|
|
3264
|
-
//
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
f(...args);
|
|
3269
|
-
}
|
|
3270
|
-
}
|
|
3271
|
-
finally {
|
|
3272
|
-
this.emitting = false;
|
|
3273
|
-
// process any deferred unregistrations
|
|
3274
|
-
if (this.pendingUnregisters) {
|
|
3275
|
-
for (const fn of this.pendingUnregisters) {
|
|
3276
|
-
const index = this.handlers.indexOf(fn);
|
|
3277
|
-
if (index >= 0) {
|
|
3278
|
-
this.handlers.splice(index, 1);
|
|
3279
|
-
}
|
|
3280
|
-
}
|
|
3281
|
-
this.pendingUnregisters = null;
|
|
3282
|
-
}
|
|
3283
|
-
}
|
|
3247
|
+
// iterate a copy so (un)registrations during emit don't disturb this pass
|
|
3248
|
+
// and reentrant emits stay correct
|
|
3249
|
+
const handlers = this.handlers.slice();
|
|
3250
|
+
handlers.forEach(f => f(...args));
|
|
3284
3251
|
}
|
|
3285
3252
|
}
|
|
3286
3253
|
/**
|
|
@@ -3326,25 +3293,6 @@ class EventHandlers {
|
|
|
3326
3293
|
}
|
|
3327
3294
|
}
|
|
3328
3295
|
}
|
|
3329
|
-
/**
|
|
3330
|
-
* @internal
|
|
3331
|
-
* @hidden
|
|
3332
|
-
*/
|
|
3333
|
-
const deprecated = function (id, message) {
|
|
3334
|
-
// skip if running production
|
|
3335
|
-
if (!devMode()) {
|
|
3336
|
-
return;
|
|
3337
|
-
}
|
|
3338
|
-
// warn if hasn't been warned before
|
|
3339
|
-
if (deprecated.ids && !deprecated.ids.hasOwnProperty(id)) {
|
|
3340
|
-
warnError(`Deprecation warning: ${message}`);
|
|
3341
|
-
}
|
|
3342
|
-
// mark as warned to avoid duplicate warn message
|
|
3343
|
-
if (deprecated.ids) {
|
|
3344
|
-
deprecated.ids[id] = true;
|
|
3345
|
-
}
|
|
3346
|
-
};
|
|
3347
|
-
deprecated.ids = {};
|
|
3348
3296
|
/**
|
|
3349
3297
|
* @internal
|
|
3350
3298
|
* @hidden
|
|
@@ -4297,9 +4245,9 @@ class ArrayType extends ComplexType {
|
|
|
4297
4245
|
return node.storedValue.slice();
|
|
4298
4246
|
}
|
|
4299
4247
|
getChildNode(node, key) {
|
|
4300
|
-
const
|
|
4301
|
-
if (
|
|
4302
|
-
return
|
|
4248
|
+
const child = node.storedValue[Number(key)];
|
|
4249
|
+
if (child) {
|
|
4250
|
+
return child;
|
|
4303
4251
|
}
|
|
4304
4252
|
throw fail(`Not a child: ${key}`);
|
|
4305
4253
|
}
|
|
@@ -4452,6 +4400,23 @@ function array(subtype) {
|
|
|
4452
4400
|
}
|
|
4453
4401
|
function reconcileArrayChildren(parent, childType, oldNodes, newValues, newPaths) {
|
|
4454
4402
|
let nothingChanged = true;
|
|
4403
|
+
// When the element type is a plain model with an identifier, index the old
|
|
4404
|
+
// nodes by id so a moved / replaced child is matched in O(1) instead of the
|
|
4405
|
+
// linear scan in the reorder branch below. This turns a full array
|
|
4406
|
+
// replacement (the common "load new data" case) from O(n^2) into O(n). Types
|
|
4407
|
+
// whose id extraction needs type-specific preprocessing (union,
|
|
4408
|
+
// snapshotProcessor, late, ...) are intentionally excluded: areSame must run
|
|
4409
|
+
// `is()` before their id check, so they stay on the scan path.
|
|
4410
|
+
let idIndex;
|
|
4411
|
+
if (childType instanceof ModelType && childType.identifierAttribute) {
|
|
4412
|
+
const byId = new Map();
|
|
4413
|
+
for (const n of oldNodes) {
|
|
4414
|
+
if (n instanceof ObjectNode && n.identifier !== null) {
|
|
4415
|
+
byId.set(n.identifier, n);
|
|
4416
|
+
}
|
|
4417
|
+
}
|
|
4418
|
+
idIndex = { attr: childType.identifierAttribute, byId };
|
|
4419
|
+
}
|
|
4455
4420
|
for (let i = 0;; i++) {
|
|
4456
4421
|
const hasNewNode = i <= newValues.length - 1;
|
|
4457
4422
|
const oldNode = oldNodes[i];
|
|
@@ -4466,7 +4431,7 @@ function reconcileArrayChildren(parent, childType, oldNodes, newValues, newPaths
|
|
|
4466
4431
|
// both are empty, end
|
|
4467
4432
|
break;
|
|
4468
4433
|
}
|
|
4469
|
-
else if (!hasNewNode) {
|
|
4434
|
+
else if (oldNode && !hasNewNode) {
|
|
4470
4435
|
// new one does not exists
|
|
4471
4436
|
nothingChanged = false;
|
|
4472
4437
|
oldNodes.splice(i, 1);
|
|
@@ -4495,13 +4460,26 @@ function reconcileArrayChildren(parent, childType, oldNodes, newValues, newPaths
|
|
|
4495
4460
|
oldNodes[i] = valueAsNode(childType, parent, newPath, newValue, oldNode);
|
|
4496
4461
|
}
|
|
4497
4462
|
else {
|
|
4498
|
-
// nothing to do, try to reorder
|
|
4463
|
+
// nothing to do, try to reorder: find a candidate old node to reuse
|
|
4499
4464
|
let oldMatch = undefined;
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4465
|
+
if (idIndex && isPlainObject(newValue)) {
|
|
4466
|
+
// for an identified element type a plain-object snapshot can only match
|
|
4467
|
+
// by id (it is never a live node, and snapshot-reference equality still
|
|
4468
|
+
// implies the same id), so a miss means "nothing to reuse" without
|
|
4469
|
+
// scanning. areSame still verifies the single candidate.
|
|
4470
|
+
const candidate = idIndex.byId.get(normalizeIdentifier(newValue[idIndex.attr]));
|
|
4471
|
+
const j = candidate ? oldNodes.indexOf(candidate, i) : -1;
|
|
4472
|
+
if (j >= i && areSame(oldNodes[j], newValue)) {
|
|
4503
4473
|
oldMatch = oldNodes.splice(j, 1)[0];
|
|
4504
|
-
|
|
4474
|
+
}
|
|
4475
|
+
}
|
|
4476
|
+
else {
|
|
4477
|
+
// find a possible candidate to reuse
|
|
4478
|
+
for (let j = i; j < oldNodes.length; j++) {
|
|
4479
|
+
if (areSame(oldNodes[j], newValue)) {
|
|
4480
|
+
oldMatch = oldNodes.splice(j, 1)[0];
|
|
4481
|
+
break;
|
|
4482
|
+
}
|
|
4505
4483
|
}
|
|
4506
4484
|
}
|
|
4507
4485
|
nothingChanged = false;
|
|
@@ -4661,6 +4639,9 @@ class ModelType extends ComplexType {
|
|
|
4661
4639
|
preProcessor;
|
|
4662
4640
|
postProcessor;
|
|
4663
4641
|
propertyNames;
|
|
4642
|
+
// member/property name collisions are a property of the type, so we only need
|
|
4643
|
+
// to check the first instance we finalize (see finalizeNewInstance)
|
|
4644
|
+
duplicateKeysChecked = false;
|
|
4664
4645
|
constructor(opts) {
|
|
4665
4646
|
super(opts.name || defaultObjectOptions.name);
|
|
4666
4647
|
Object.assign(this, defaultObjectOptions, opts);
|
|
@@ -4850,6 +4831,21 @@ class ModelType extends ComplexType {
|
|
|
4850
4831
|
_interceptReads(instance, name, node.unbox);
|
|
4851
4832
|
});
|
|
4852
4833
|
this.initializers.reduce((self, fn) => fn(self), instance);
|
|
4834
|
+
// views, actions and volatile share the instance namespace with properties,
|
|
4835
|
+
// so a view/action reusing a property name silently clobbers that property's
|
|
4836
|
+
// observable value. It's a type-level mistake (identical for every instance),
|
|
4837
|
+
// so we check just the first one we finalize: a healthy property stays a
|
|
4838
|
+
// plain observable, a shadowing getter becomes a computed, and a shadowing
|
|
4839
|
+
// function/value stops being observable at all. The flag is only set on
|
|
4840
|
+
// success so a broken type keeps throwing on every create.
|
|
4841
|
+
if (!this.duplicateKeysChecked) {
|
|
4842
|
+
this.forAllProps(name => {
|
|
4843
|
+
if (isComputedProp(instance, name) || !isObservableProp(instance, name)) {
|
|
4844
|
+
throw fail(`${name} property is declared twice`);
|
|
4845
|
+
}
|
|
4846
|
+
});
|
|
4847
|
+
this.duplicateKeysChecked = true;
|
|
4848
|
+
}
|
|
4853
4849
|
intercept(instance, this.willChange);
|
|
4854
4850
|
observe(instance, this.didChange);
|
|
4855
4851
|
}
|
|
@@ -4904,14 +4900,7 @@ class ModelType extends ComplexType {
|
|
|
4904
4900
|
getSnapshot(node, applyPostProcess = true) {
|
|
4905
4901
|
const res = {};
|
|
4906
4902
|
this.forAllProps((name, type) => {
|
|
4907
|
-
|
|
4908
|
-
// TODO: FIXME, make sure the observable ref is used!
|
|
4909
|
-
const atom = getAtom(node.storedValue, name);
|
|
4910
|
-
atom.reportObserved();
|
|
4911
|
-
}
|
|
4912
|
-
catch (_e) {
|
|
4913
|
-
throw fail(`${name} property is declared twice`);
|
|
4914
|
-
}
|
|
4903
|
+
getAtom(node.storedValue, name).reportObserved();
|
|
4915
4904
|
const snapshot = this.getChildNode(node, name).snapshot;
|
|
4916
4905
|
// strip-default optionals omit their key when equal to the default
|
|
4917
4906
|
if (!shouldStripChildFromSnapshot(type, snapshot)) {
|
|
@@ -5523,22 +5512,14 @@ class Union extends BaseType {
|
|
|
5523
5512
|
if (this._dispatcher) {
|
|
5524
5513
|
return this._dispatcher(value);
|
|
5525
5514
|
}
|
|
5526
|
-
// fast path: when type checking is disabled, try quick structural matching
|
|
5515
|
+
// fast path: when type checking is disabled, try quick structural matching
|
|
5516
|
+
// first. This skips full recursive validation of every property value, a
|
|
5517
|
+
// meaningful win for wide model members (e.g. jbrowse config schemas).
|
|
5527
5518
|
if (!isTypeCheckingEnabled()) {
|
|
5528
5519
|
const quickMatch = this.tryQuickMatch(value, reconcileCurrentType);
|
|
5529
5520
|
if (quickMatch) {
|
|
5530
5521
|
return quickMatch;
|
|
5531
5522
|
}
|
|
5532
|
-
// for plain object snapshots that didn't match via quick path, try all types
|
|
5533
|
-
// with quick matching before falling back to full validation
|
|
5534
|
-
// (state tree nodes must go through full validation for type identity checks)
|
|
5535
|
-
if (isPlainObject(value) && !isStateTreeNode(value)) {
|
|
5536
|
-
for (const type of this._types) {
|
|
5537
|
-
if (this.snapshotLooksLikeType(value, type)) {
|
|
5538
|
-
return type;
|
|
5539
|
-
}
|
|
5540
|
-
}
|
|
5541
|
-
}
|
|
5542
5523
|
}
|
|
5543
5524
|
// find the most accomodating type
|
|
5544
5525
|
// if we are using reconciliation try the current node type first (fix for #1045)
|
|
@@ -7006,5 +6987,5 @@ const types = {
|
|
|
7006
6987
|
resilient
|
|
7007
6988
|
};
|
|
7008
6989
|
|
|
7009
|
-
export { addDisposer, addMiddleware, applyAction, applyPatch, applySnapshot, cast, castFlowReturn, castToReferenceSnapshot, castToSnapshot, clone, createActionTrackingMiddleware, createActionTrackingMiddleware2, decorate, destroy, detach, escapeJsonPath, 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,
|
|
6990
|
+
export { addDisposer, addMiddleware, applyAction, applyPatch, applySnapshot, cast, castFlowReturn, castToReferenceSnapshot, castToSnapshot, clone, createActionTrackingMiddleware, createActionTrackingMiddleware2, decorate, destroy, detach, escapeJsonPath, 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 };
|
|
7010
6991
|
//# sourceMappingURL=mobx-state-tree.mjs.map
|