@jbrowse/mobx-state-tree 5.11.2 → 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/dist/index.d.ts +1 -1
- package/dist/mobx-state-tree.cjs +65 -80
- package/dist/mobx-state-tree.cjs.map +1 -1
- package/dist/mobx-state-tree.mjs +65 -80
- package/dist/mobx-state-tree.mjs.map +1 -1
- package/package.json +1 -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)) {
|
|
@@ -1666,9 +1667,6 @@ ObjectNode.prototype.createObservableInstance = action(ObjectNode.prototype.crea
|
|
|
1666
1667
|
ObjectNode.prototype.detach = action(ObjectNode.prototype.detach);
|
|
1667
1668
|
ObjectNode.prototype.die = action(ObjectNode.prototype.die);
|
|
1668
1669
|
|
|
1669
|
-
// Cache for validation results to avoid re-validating the same object against the same type
|
|
1670
|
-
// Uses WeakMap so cached objects can be garbage collected
|
|
1671
|
-
const validationCache = new WeakMap();
|
|
1672
1670
|
/**
|
|
1673
1671
|
* @internal
|
|
1674
1672
|
* @hidden
|
|
@@ -1744,27 +1742,7 @@ class BaseType {
|
|
|
1744
1742
|
: typeCheckFailure(context, value);
|
|
1745
1743
|
// it is tempting to compare snapshots, but in that case we should always clone on assignments...
|
|
1746
1744
|
}
|
|
1747
|
-
|
|
1748
|
-
if (typeof value === "object" && value !== null && context.length === 1) {
|
|
1749
|
-
const typeCache = validationCache.get(value);
|
|
1750
|
-
if (typeCache) {
|
|
1751
|
-
const cached = typeCache.get(this);
|
|
1752
|
-
if (cached !== undefined) {
|
|
1753
|
-
return cached;
|
|
1754
|
-
}
|
|
1755
|
-
}
|
|
1756
|
-
}
|
|
1757
|
-
const result = this.isValidSnapshot(value, context);
|
|
1758
|
-
// cache result for object values (only at root level)
|
|
1759
|
-
if (typeof value === "object" && value !== null && context.length === 1) {
|
|
1760
|
-
let typeCache = validationCache.get(value);
|
|
1761
|
-
if (!typeCache) {
|
|
1762
|
-
typeCache = new WeakMap();
|
|
1763
|
-
validationCache.set(value, typeCache);
|
|
1764
|
-
}
|
|
1765
|
-
typeCache.set(this, result);
|
|
1766
|
-
}
|
|
1767
|
-
return result;
|
|
1745
|
+
return this.isValidSnapshot(value, context);
|
|
1768
1746
|
}
|
|
1769
1747
|
is(thing) {
|
|
1770
1748
|
return this.validate(thing, [{ path: "", type: this }]).length === 0;
|
|
@@ -3239,8 +3217,6 @@ function addHiddenWritableProp(object, propName, value) {
|
|
|
3239
3217
|
*/
|
|
3240
3218
|
class EventHandler {
|
|
3241
3219
|
handlers = [];
|
|
3242
|
-
emitting = false;
|
|
3243
|
-
pendingUnregisters = null;
|
|
3244
3220
|
get hasSubscribers() {
|
|
3245
3221
|
return this.handlers.length > 0;
|
|
3246
3222
|
}
|
|
@@ -3259,14 +3235,6 @@ class EventHandler {
|
|
|
3259
3235
|
return this.handlers.includes(fn);
|
|
3260
3236
|
}
|
|
3261
3237
|
unregister(fn) {
|
|
3262
|
-
if (this.emitting) {
|
|
3263
|
-
// defer unregistration until emit is done
|
|
3264
|
-
if (!this.pendingUnregisters) {
|
|
3265
|
-
this.pendingUnregisters = [];
|
|
3266
|
-
}
|
|
3267
|
-
this.pendingUnregisters.push(fn);
|
|
3268
|
-
return;
|
|
3269
|
-
}
|
|
3270
3238
|
const index = this.handlers.indexOf(fn);
|
|
3271
3239
|
if (index >= 0) {
|
|
3272
3240
|
this.handlers.splice(index, 1);
|
|
@@ -3276,26 +3244,10 @@ class EventHandler {
|
|
|
3276
3244
|
this.handlers.length = 0;
|
|
3277
3245
|
}
|
|
3278
3246
|
emit(...args) {
|
|
3279
|
-
//
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
f(...args);
|
|
3284
|
-
}
|
|
3285
|
-
}
|
|
3286
|
-
finally {
|
|
3287
|
-
this.emitting = false;
|
|
3288
|
-
// process any deferred unregistrations
|
|
3289
|
-
if (this.pendingUnregisters) {
|
|
3290
|
-
for (const fn of this.pendingUnregisters) {
|
|
3291
|
-
const index = this.handlers.indexOf(fn);
|
|
3292
|
-
if (index >= 0) {
|
|
3293
|
-
this.handlers.splice(index, 1);
|
|
3294
|
-
}
|
|
3295
|
-
}
|
|
3296
|
-
this.pendingUnregisters = null;
|
|
3297
|
-
}
|
|
3298
|
-
}
|
|
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));
|
|
3299
3251
|
}
|
|
3300
3252
|
}
|
|
3301
3253
|
/**
|
|
@@ -4448,6 +4400,23 @@ function array(subtype) {
|
|
|
4448
4400
|
}
|
|
4449
4401
|
function reconcileArrayChildren(parent, childType, oldNodes, newValues, newPaths) {
|
|
4450
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
|
+
}
|
|
4451
4420
|
for (let i = 0;; i++) {
|
|
4452
4421
|
const hasNewNode = i <= newValues.length - 1;
|
|
4453
4422
|
const oldNode = oldNodes[i];
|
|
@@ -4491,13 +4460,26 @@ function reconcileArrayChildren(parent, childType, oldNodes, newValues, newPaths
|
|
|
4491
4460
|
oldNodes[i] = valueAsNode(childType, parent, newPath, newValue, oldNode);
|
|
4492
4461
|
}
|
|
4493
4462
|
else {
|
|
4494
|
-
// nothing to do, try to reorder
|
|
4463
|
+
// nothing to do, try to reorder: find a candidate old node to reuse
|
|
4495
4464
|
let oldMatch = undefined;
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
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)) {
|
|
4499
4473
|
oldMatch = oldNodes.splice(j, 1)[0];
|
|
4500
|
-
|
|
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
|
+
}
|
|
4501
4483
|
}
|
|
4502
4484
|
}
|
|
4503
4485
|
nothingChanged = false;
|
|
@@ -4657,6 +4639,9 @@ class ModelType extends ComplexType {
|
|
|
4657
4639
|
preProcessor;
|
|
4658
4640
|
postProcessor;
|
|
4659
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;
|
|
4660
4645
|
constructor(opts) {
|
|
4661
4646
|
super(opts.name || defaultObjectOptions.name);
|
|
4662
4647
|
Object.assign(this, defaultObjectOptions, opts);
|
|
@@ -4846,6 +4831,21 @@ class ModelType extends ComplexType {
|
|
|
4846
4831
|
_interceptReads(instance, name, node.unbox);
|
|
4847
4832
|
});
|
|
4848
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
|
+
}
|
|
4849
4849
|
intercept(instance, this.willChange);
|
|
4850
4850
|
observe(instance, this.didChange);
|
|
4851
4851
|
}
|
|
@@ -4900,14 +4900,7 @@ class ModelType extends ComplexType {
|
|
|
4900
4900
|
getSnapshot(node, applyPostProcess = true) {
|
|
4901
4901
|
const res = {};
|
|
4902
4902
|
this.forAllProps((name, type) => {
|
|
4903
|
-
|
|
4904
|
-
// TODO: FIXME, make sure the observable ref is used!
|
|
4905
|
-
const atom = getAtom(node.storedValue, name);
|
|
4906
|
-
atom.reportObserved();
|
|
4907
|
-
}
|
|
4908
|
-
catch (_e) {
|
|
4909
|
-
throw fail(`${name} property is declared twice`);
|
|
4910
|
-
}
|
|
4903
|
+
getAtom(node.storedValue, name).reportObserved();
|
|
4911
4904
|
const snapshot = this.getChildNode(node, name).snapshot;
|
|
4912
4905
|
// strip-default optionals omit their key when equal to the default
|
|
4913
4906
|
if (!shouldStripChildFromSnapshot(type, snapshot)) {
|
|
@@ -5519,22 +5512,14 @@ class Union extends BaseType {
|
|
|
5519
5512
|
if (this._dispatcher) {
|
|
5520
5513
|
return this._dispatcher(value);
|
|
5521
5514
|
}
|
|
5522
|
-
// 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).
|
|
5523
5518
|
if (!isTypeCheckingEnabled()) {
|
|
5524
5519
|
const quickMatch = this.tryQuickMatch(value, reconcileCurrentType);
|
|
5525
5520
|
if (quickMatch) {
|
|
5526
5521
|
return quickMatch;
|
|
5527
5522
|
}
|
|
5528
|
-
// for plain object snapshots that didn't match via quick path, try all types
|
|
5529
|
-
// with quick matching before falling back to full validation
|
|
5530
|
-
// (state tree nodes must go through full validation for type identity checks)
|
|
5531
|
-
if (isPlainObject(value) && !isStateTreeNode(value)) {
|
|
5532
|
-
for (const type of this._types) {
|
|
5533
|
-
if (this.snapshotLooksLikeType(value, type)) {
|
|
5534
|
-
return type;
|
|
5535
|
-
}
|
|
5536
|
-
}
|
|
5537
|
-
}
|
|
5538
5523
|
}
|
|
5539
5524
|
// find the most accomodating type
|
|
5540
5525
|
// if we are using reconciliation try the current node type first (fix for #1045)
|