@jbrowse/mobx-state-tree 6.3.0 → 6.5.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 +69 -114
- package/dist/mobx-state-tree.cjs +310 -211
- package/dist/mobx-state-tree.cjs.map +1 -1
- package/dist/mobx-state-tree.mjs +310 -212
- package/dist/mobx-state-tree.mjs.map +1 -1
- package/package.json +3 -1
package/dist/mobx-state-tree.mjs
CHANGED
|
@@ -270,6 +270,8 @@ function unprotect(target) {
|
|
|
270
270
|
* Returns true if the object is in protected mode, @see protect
|
|
271
271
|
*/
|
|
272
272
|
function isProtected(target) {
|
|
273
|
+
// check all arguments
|
|
274
|
+
assertIsStateTreeNode(target, 1);
|
|
273
275
|
return getStateTreeNode(target).isProtected;
|
|
274
276
|
}
|
|
275
277
|
/**
|
|
@@ -301,6 +303,27 @@ function getSnapshot(target, applyPostProcess = true) {
|
|
|
301
303
|
}
|
|
302
304
|
return freeze(node.type.getSnapshot(node, false));
|
|
303
305
|
}
|
|
306
|
+
function findParentAtDepth(node, depth) {
|
|
307
|
+
let remaining = depth;
|
|
308
|
+
let parent = node.parent;
|
|
309
|
+
while (parent) {
|
|
310
|
+
if (--remaining === 0) {
|
|
311
|
+
return parent;
|
|
312
|
+
}
|
|
313
|
+
parent = parent.parent;
|
|
314
|
+
}
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
function findParentOfType(node, type) {
|
|
318
|
+
let parent = node.parent;
|
|
319
|
+
while (parent) {
|
|
320
|
+
if (type.is(parent.storedValue)) {
|
|
321
|
+
return parent;
|
|
322
|
+
}
|
|
323
|
+
parent = parent.parent;
|
|
324
|
+
}
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
304
327
|
/**
|
|
305
328
|
* Given a model instance, returns `true` if the object has a parent, that is, is part of another object, map or array.
|
|
306
329
|
*
|
|
@@ -312,14 +335,7 @@ function hasParent(target, depth = 1) {
|
|
|
312
335
|
// check all arguments
|
|
313
336
|
assertIsStateTreeNode(target, 1);
|
|
314
337
|
assertIsNumber(depth, 2, 0);
|
|
315
|
-
|
|
316
|
-
while (parent) {
|
|
317
|
-
if (--depth === 0) {
|
|
318
|
-
return true;
|
|
319
|
-
}
|
|
320
|
-
parent = parent.parent;
|
|
321
|
-
}
|
|
322
|
-
return false;
|
|
338
|
+
return findParentAtDepth(getStateTreeNode(target), depth) !== null;
|
|
323
339
|
}
|
|
324
340
|
/**
|
|
325
341
|
* Returns the immediate parent of this object, or throws.
|
|
@@ -338,15 +354,11 @@ function getParent(target, depth = 1) {
|
|
|
338
354
|
// check all arguments
|
|
339
355
|
assertIsStateTreeNode(target, 1);
|
|
340
356
|
assertIsNumber(depth, 2, 0);
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
if (--d === 0) {
|
|
345
|
-
return parent.storedValue;
|
|
346
|
-
}
|
|
347
|
-
parent = parent.parent;
|
|
357
|
+
const parent = findParentAtDepth(getStateTreeNode(target), depth);
|
|
358
|
+
if (!parent) {
|
|
359
|
+
throw fail(`Failed to find the parent of ${getStateTreeNode(target)} at depth ${depth}`);
|
|
348
360
|
}
|
|
349
|
-
|
|
361
|
+
return parent.storedValue;
|
|
350
362
|
}
|
|
351
363
|
/**
|
|
352
364
|
* Given a model instance, returns `true` if the object has a parent of given type, that is, is part of another object, map or array
|
|
@@ -359,14 +371,7 @@ function hasParentOfType(target, type) {
|
|
|
359
371
|
// check all arguments
|
|
360
372
|
assertIsStateTreeNode(target, 1);
|
|
361
373
|
assertIsType(type, 2);
|
|
362
|
-
|
|
363
|
-
while (parent) {
|
|
364
|
-
if (type.is(parent.storedValue)) {
|
|
365
|
-
return true;
|
|
366
|
-
}
|
|
367
|
-
parent = parent.parent;
|
|
368
|
-
}
|
|
369
|
-
return false;
|
|
374
|
+
return findParentOfType(getStateTreeNode(target), type) !== null;
|
|
370
375
|
}
|
|
371
376
|
/**
|
|
372
377
|
* Returns the target's parent of a given type, or throws.
|
|
@@ -379,14 +384,11 @@ function getParentOfType(target, type) {
|
|
|
379
384
|
// check all arguments
|
|
380
385
|
assertIsStateTreeNode(target, 1);
|
|
381
386
|
assertIsType(type, 2);
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
return parent.storedValue;
|
|
386
|
-
}
|
|
387
|
-
parent = parent.parent;
|
|
387
|
+
const parent = findParentOfType(getStateTreeNode(target), type);
|
|
388
|
+
if (!parent) {
|
|
389
|
+
throw fail(`Failed to find the parent of ${getStateTreeNode(target)} of a given type`);
|
|
388
390
|
}
|
|
389
|
-
|
|
391
|
+
return parent.storedValue;
|
|
390
392
|
}
|
|
391
393
|
/**
|
|
392
394
|
* Given an object in a model tree, returns the root object of that tree.
|
|
@@ -1195,11 +1197,11 @@ class ObjectNode extends BaseNode {
|
|
|
1195
1197
|
this.identifier = normalizeIdentifier(id);
|
|
1196
1198
|
this.unnormalizedIdentifier = id;
|
|
1197
1199
|
}
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1200
|
+
// addNodeToCache no-ops without an identifier attribute, and reaching the
|
|
1201
|
+
// root to ask it is a walk up the whole parent chain
|
|
1202
|
+
if (this.identifierAttribute) {
|
|
1203
|
+
const cache = parent ? parent.root.identifierCache : this.identifierCache;
|
|
1204
|
+
cache.addNodeToCache(this);
|
|
1203
1205
|
}
|
|
1204
1206
|
}
|
|
1205
1207
|
createObservableInstanceIfNeeded(fireHooks = true) {
|
|
@@ -1347,15 +1349,9 @@ class ObjectNode extends BaseNode {
|
|
|
1347
1349
|
typeof this.storedValue === "object" &&
|
|
1348
1350
|
this.storedValue[name];
|
|
1349
1351
|
if (typeof fn === "function") {
|
|
1350
|
-
|
|
1351
|
-
if (_allowStateChangesInsideComputed) {
|
|
1352
|
-
_allowStateChangesInsideComputed(() => {
|
|
1353
|
-
fn.apply(this.storedValue);
|
|
1354
|
-
});
|
|
1355
|
-
}
|
|
1356
|
-
else {
|
|
1352
|
+
_allowStateChangesInsideComputed(() => {
|
|
1357
1353
|
fn.apply(this.storedValue);
|
|
1358
|
-
}
|
|
1354
|
+
});
|
|
1359
1355
|
}
|
|
1360
1356
|
}
|
|
1361
1357
|
_snapshotUponDeath;
|
|
@@ -1735,8 +1731,8 @@ var TypeFlags;
|
|
|
1735
1731
|
TypeFlags[TypeFlags["Float"] = 4194304] = "Float";
|
|
1736
1732
|
})(TypeFlags || (TypeFlags = {}));
|
|
1737
1733
|
/**
|
|
1738
|
-
*
|
|
1739
|
-
*
|
|
1734
|
+
* The value `getSubTypes()` returns when a type cannot report its subtype,
|
|
1735
|
+
* which is distinct from reporting that it has none (`null`).
|
|
1740
1736
|
*/
|
|
1741
1737
|
const cannotDetermineSubtype = "cannotDetermine";
|
|
1742
1738
|
/**
|
|
@@ -1788,6 +1784,9 @@ class BaseType {
|
|
|
1788
1784
|
// istanbul ignore next
|
|
1789
1785
|
throw fail("unimplemented method");
|
|
1790
1786
|
}
|
|
1787
|
+
describe() {
|
|
1788
|
+
return this.name;
|
|
1789
|
+
}
|
|
1791
1790
|
isAssignableFrom(type) {
|
|
1792
1791
|
return type === this;
|
|
1793
1792
|
}
|
|
@@ -1933,7 +1932,7 @@ class SimpleType extends BaseType {
|
|
|
1933
1932
|
* @returns `true` if the value is a type.
|
|
1934
1933
|
*/
|
|
1935
1934
|
function isType(value) {
|
|
1936
|
-
return typeof value === "object" && value?.isType === true;
|
|
1935
|
+
return (typeof value === "object" && value?.isType === true);
|
|
1937
1936
|
}
|
|
1938
1937
|
/**
|
|
1939
1938
|
* @internal
|
|
@@ -2668,10 +2667,6 @@ function safeStringify(value) {
|
|
|
2668
2667
|
return `<Unserializable: ${e}>`;
|
|
2669
2668
|
}
|
|
2670
2669
|
}
|
|
2671
|
-
/**
|
|
2672
|
-
* @internal
|
|
2673
|
-
* @hidden
|
|
2674
|
-
*/
|
|
2675
2670
|
function prettyPrintValue(value) {
|
|
2676
2671
|
return typeof value === "function"
|
|
2677
2672
|
? `<function${value.name ? ` ${value.name}` : ""}>`
|
|
@@ -2704,12 +2699,8 @@ function toErrorString(error) {
|
|
|
2704
2699
|
expectation = ".";
|
|
2705
2700
|
}
|
|
2706
2701
|
else {
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
// annotation restores the type it actually has here.
|
|
2710
|
-
const complexType = type;
|
|
2711
|
-
const isSnapshotCompatible = isStateTreeNode(value) && complexType.is(getStateTreeNode(value).snapshot);
|
|
2712
|
-
expectation = `, expected an instance of \`${complexType.name}\` or a snapshot like \`${shortenPrintValue(complexType.describe())}\` instead.${isSnapshotCompatible
|
|
2702
|
+
const isSnapshotCompatible = isStateTreeNode(value) && type.is(getStateTreeNode(value).snapshot);
|
|
2703
|
+
expectation = `, expected an instance of \`${type.name}\` or a snapshot like \`${shortenPrintValue(type.describe())}\` instead.${isSnapshotCompatible
|
|
2713
2704
|
? " (Note that a snapshot of the provided value is compatible with the targeted type)"
|
|
2714
2705
|
: ""}`;
|
|
2715
2706
|
}
|
|
@@ -2990,7 +2981,7 @@ function getStateTreeNode(value) {
|
|
|
2990
2981
|
* @hidden
|
|
2991
2982
|
*/
|
|
2992
2983
|
function getStateTreeNodeSafe(value) {
|
|
2993
|
-
return value
|
|
2984
|
+
return value?.["$treenode"] || null;
|
|
2994
2985
|
}
|
|
2995
2986
|
/**
|
|
2996
2987
|
* @internal
|
|
@@ -3302,9 +3293,6 @@ class EventHandler {
|
|
|
3302
3293
|
this.handlers.splice(index, 1);
|
|
3303
3294
|
}
|
|
3304
3295
|
}
|
|
3305
|
-
clear() {
|
|
3306
|
-
this.handlers.length = 0;
|
|
3307
|
-
}
|
|
3308
3296
|
emit(...args) {
|
|
3309
3297
|
const handlers = this.handlers;
|
|
3310
3298
|
// 0 and 1 handlers are by far the common cases (a patch/snapshot listener, a
|
|
@@ -3449,21 +3437,6 @@ function assertIsString(value, argNumber, canBeEmpty = true) {
|
|
|
3449
3437
|
assertArg(value, s => s !== "", "not empty string", argNumber);
|
|
3450
3438
|
}
|
|
3451
3439
|
}
|
|
3452
|
-
/**
|
|
3453
|
-
* @internal
|
|
3454
|
-
* @hidden
|
|
3455
|
-
*/
|
|
3456
|
-
function setImmediateWithFallback(fn) {
|
|
3457
|
-
if (typeof queueMicrotask === "function") {
|
|
3458
|
-
queueMicrotask(fn);
|
|
3459
|
-
}
|
|
3460
|
-
else if (typeof setImmediate === "function") {
|
|
3461
|
-
setImmediate(fn);
|
|
3462
|
-
}
|
|
3463
|
-
else {
|
|
3464
|
-
setTimeout(fn, 1);
|
|
3465
|
-
}
|
|
3466
|
-
}
|
|
3467
3440
|
|
|
3468
3441
|
/**
|
|
3469
3442
|
* See [asynchronous actions](concepts/async-actions.md).
|
|
@@ -3534,10 +3507,6 @@ function toGeneratorFunction(p) {
|
|
|
3534
3507
|
function* toGenerator(p) {
|
|
3535
3508
|
return (yield p);
|
|
3536
3509
|
}
|
|
3537
|
-
/**
|
|
3538
|
-
* @internal
|
|
3539
|
-
* @hidden
|
|
3540
|
-
*/
|
|
3541
3510
|
function createFlowSpawner(name, generator) {
|
|
3542
3511
|
const spawner = function flowSpawner(...flowArgs) {
|
|
3543
3512
|
// Implementation based on https://github.com/tj/co/blob/master/index.js
|
|
@@ -3595,7 +3564,7 @@ function createFlowSpawner(name, generator) {
|
|
|
3595
3564
|
}
|
|
3596
3565
|
catch (e) {
|
|
3597
3566
|
// prettier-ignore
|
|
3598
|
-
|
|
3567
|
+
queueMicrotask(() => {
|
|
3599
3568
|
wrap((_r) => { reject(e); }, "flow_throw", e);
|
|
3600
3569
|
});
|
|
3601
3570
|
return;
|
|
@@ -3611,7 +3580,7 @@ function createFlowSpawner(name, generator) {
|
|
|
3611
3580
|
}
|
|
3612
3581
|
catch (e) {
|
|
3613
3582
|
// prettier-ignore
|
|
3614
|
-
|
|
3583
|
+
queueMicrotask(() => {
|
|
3615
3584
|
wrap((_r) => { reject(e); }, "flow_throw", e);
|
|
3616
3585
|
});
|
|
3617
3586
|
return;
|
|
@@ -3621,7 +3590,7 @@ function createFlowSpawner(name, generator) {
|
|
|
3621
3590
|
function next(ret) {
|
|
3622
3591
|
if (ret.done) {
|
|
3623
3592
|
// prettier-ignore
|
|
3624
|
-
|
|
3593
|
+
queueMicrotask(() => {
|
|
3625
3594
|
wrap((r) => { resolve(r); }, "flow_return", ret.value);
|
|
3626
3595
|
});
|
|
3627
3596
|
return;
|
|
@@ -3649,10 +3618,6 @@ function splitPatch(patch) {
|
|
|
3649
3618
|
}
|
|
3650
3619
|
return [stripPatch(patch), invertPatch(patch)];
|
|
3651
3620
|
}
|
|
3652
|
-
/**
|
|
3653
|
-
* @internal
|
|
3654
|
-
* @hidden
|
|
3655
|
-
*/
|
|
3656
3621
|
function stripPatch(patch) {
|
|
3657
3622
|
// strips `oldvalue` information from the patch, so that it becomes a patch conform the json-patch spec
|
|
3658
3623
|
// this removes the ability to undo the patch
|
|
@@ -3999,13 +3964,6 @@ var MapIdentifierMode;
|
|
|
3999
3964
|
MapIdentifierMode[MapIdentifierMode["NO"] = 2] = "NO";
|
|
4000
3965
|
})(MapIdentifierMode || (MapIdentifierMode = {}));
|
|
4001
3966
|
class MSTMap extends ObservableMap {
|
|
4002
|
-
constructor(initialData, name) {
|
|
4003
|
-
// mobx's default (deep) enhancer. The old `observable.ref.enhancer` arg
|
|
4004
|
-
// read undefined ever since mobx 6 renamed the field to `options_.enhancer`,
|
|
4005
|
-
// so deep has been the effective behavior all along; mobx 7 dropped
|
|
4006
|
-
// `observable.ref` entirely.
|
|
4007
|
-
super(initialData, undefined, name);
|
|
4008
|
-
}
|
|
4009
3967
|
get(key) {
|
|
4010
3968
|
// maybe this is over-enthousiastic? normalize numeric keys to strings
|
|
4011
3969
|
return super.get(`${key}`);
|
|
@@ -4118,7 +4076,8 @@ class MapType extends ComplexType {
|
|
|
4118
4076
|
return result;
|
|
4119
4077
|
}
|
|
4120
4078
|
createNewInstance(childNodes) {
|
|
4121
|
-
|
|
4079
|
+
// undefined is mobx's enhancer argument, left at its deep default
|
|
4080
|
+
return new MSTMap(childNodes, undefined, this.name);
|
|
4122
4081
|
}
|
|
4123
4082
|
finalizeNewInstance(node, instance) {
|
|
4124
4083
|
_interceptReads(instance, node.unbox);
|
|
@@ -4126,9 +4085,6 @@ class MapType extends ComplexType {
|
|
|
4126
4085
|
intercept(instance, this.willChange);
|
|
4127
4086
|
observe(instance, this.didChange);
|
|
4128
4087
|
}
|
|
4129
|
-
describe() {
|
|
4130
|
-
return this.name;
|
|
4131
|
-
}
|
|
4132
4088
|
getChildren(node) {
|
|
4133
4089
|
// return (node.storedValue as ObservableMap<any>).values()
|
|
4134
4090
|
return values(node.storedValue);
|
|
@@ -4305,6 +4261,7 @@ MapType.prototype.applySnapshot = action(MapType.prototype.applySnapshot);
|
|
|
4305
4261
|
* @returns
|
|
4306
4262
|
*/
|
|
4307
4263
|
function map(subtype) {
|
|
4264
|
+
assertIsType(subtype, 1);
|
|
4308
4265
|
return new MapType(subtype);
|
|
4309
4266
|
}
|
|
4310
4267
|
/**
|
|
@@ -4358,9 +4315,6 @@ class ArrayType extends ComplexType {
|
|
|
4358
4315
|
intercept(instance, this.willChange);
|
|
4359
4316
|
observe(instance, this.didChange);
|
|
4360
4317
|
}
|
|
4361
|
-
describe() {
|
|
4362
|
-
return this.name;
|
|
4363
|
-
}
|
|
4364
4318
|
getChildren(node) {
|
|
4365
4319
|
return node.storedValue.slice();
|
|
4366
4320
|
}
|
|
@@ -4732,8 +4686,8 @@ function objectTypeToString() {
|
|
|
4732
4686
|
}
|
|
4733
4687
|
const ANONYMOUS_MODEL_NAME = "AnonymousModel";
|
|
4734
4688
|
/**
|
|
4735
|
-
* A plain loop rather than
|
|
4736
|
-
* indirect call
|
|
4689
|
+
* A plain loop rather than a callback per property, which allocated a closure
|
|
4690
|
+
* and made an indirect call. This runs once per `types.model()` over every
|
|
4737
4691
|
* declared property, and jbrowse builds a ~40-slot schema per track.
|
|
4738
4692
|
*/
|
|
4739
4693
|
function findIdentifierAttribute(properties, propertyNames) {
|
|
@@ -4931,12 +4885,6 @@ class ModelType extends ComplexType {
|
|
|
4931
4885
|
(!devMode() ? addHiddenFinalProp : addHiddenWritableProp)(self, name, actionInvoker);
|
|
4932
4886
|
});
|
|
4933
4887
|
}
|
|
4934
|
-
named = name => {
|
|
4935
|
-
return this.cloneAndEnhance({ name });
|
|
4936
|
-
};
|
|
4937
|
-
props = properties => {
|
|
4938
|
-
return this.cloneAndEnhance({ properties });
|
|
4939
|
-
};
|
|
4940
4888
|
volatile(fn) {
|
|
4941
4889
|
if (typeof fn !== "function") {
|
|
4942
4890
|
throw fail(`You passed an ${typeof fn} to volatile state as an argument, when function is expected`);
|
|
@@ -5019,28 +4967,6 @@ class ModelType extends ComplexType {
|
|
|
5019
4967
|
}
|
|
5020
4968
|
});
|
|
5021
4969
|
}
|
|
5022
|
-
preProcessSnapshot = preProcessor => {
|
|
5023
|
-
const currentPreprocessor = this.preProcessor;
|
|
5024
|
-
if (!currentPreprocessor) {
|
|
5025
|
-
return this.cloneAndEnhance({ preProcessor });
|
|
5026
|
-
}
|
|
5027
|
-
else {
|
|
5028
|
-
return this.cloneAndEnhance({
|
|
5029
|
-
preProcessor: snapshot => currentPreprocessor(preProcessor(snapshot))
|
|
5030
|
-
});
|
|
5031
|
-
}
|
|
5032
|
-
};
|
|
5033
|
-
postProcessSnapshot = postProcessor => {
|
|
5034
|
-
const currentPostprocessor = this.postProcessor;
|
|
5035
|
-
if (!currentPostprocessor) {
|
|
5036
|
-
return this.cloneAndEnhance({ postProcessor });
|
|
5037
|
-
}
|
|
5038
|
-
else {
|
|
5039
|
-
return this.cloneAndEnhance({
|
|
5040
|
-
postProcessor: snapshot => postProcessor(currentPostprocessor(snapshot))
|
|
5041
|
-
});
|
|
5042
|
-
}
|
|
5043
|
-
};
|
|
5044
4970
|
instantiate(parent, subpath, environment, initialValue) {
|
|
5045
4971
|
const value = isStateTreeNode(initialValue)
|
|
5046
4972
|
? initialValue
|
|
@@ -5051,10 +4977,11 @@ class ModelType extends ComplexType {
|
|
|
5051
4977
|
}
|
|
5052
4978
|
initializeChildNodes(objNode, initialSnapshot = {}) {
|
|
5053
4979
|
const type = objNode.type;
|
|
4980
|
+
const properties = type.properties;
|
|
5054
4981
|
const result = {};
|
|
5055
|
-
|
|
5056
|
-
result[name] =
|
|
5057
|
-
}
|
|
4982
|
+
for (const name of type.propertyNames) {
|
|
4983
|
+
result[name] = properties[name].instantiate(objNode, name, undefined, initialSnapshot[name]);
|
|
4984
|
+
}
|
|
5058
4985
|
return result;
|
|
5059
4986
|
}
|
|
5060
4987
|
createNewInstance(childNodes) {
|
|
@@ -5073,9 +5000,9 @@ class ModelType extends ComplexType {
|
|
|
5073
5000
|
}
|
|
5074
5001
|
}
|
|
5075
5002
|
else {
|
|
5076
|
-
|
|
5003
|
+
for (const name of this.propertyNames) {
|
|
5077
5004
|
_interceptReads(instance, name, node.unbox);
|
|
5078
|
-
}
|
|
5005
|
+
}
|
|
5079
5006
|
}
|
|
5080
5007
|
this.initializers.reduce((self, fn) => fn(self), instance);
|
|
5081
5008
|
// views, actions and volatile share the instance namespace with properties,
|
|
@@ -5086,12 +5013,12 @@ class ModelType extends ComplexType {
|
|
|
5086
5013
|
// function/value stops being observable at all. The flag is only set on
|
|
5087
5014
|
// success so a broken type keeps throwing on every create.
|
|
5088
5015
|
if (!this.duplicateKeysChecked) {
|
|
5089
|
-
|
|
5016
|
+
for (const name of this.propertyNames) {
|
|
5090
5017
|
if (isComputedProp(instance, name) ||
|
|
5091
5018
|
!isObservableProp(instance, name)) {
|
|
5092
5019
|
throw fail(`${name} property is declared twice`);
|
|
5093
5020
|
}
|
|
5094
|
-
}
|
|
5021
|
+
}
|
|
5095
5022
|
this.duplicateKeysChecked = true;
|
|
5096
5023
|
}
|
|
5097
5024
|
intercept(instance, this.willChange);
|
|
@@ -5144,24 +5071,16 @@ class ModelType extends ComplexType {
|
|
|
5144
5071
|
}
|
|
5145
5072
|
return res;
|
|
5146
5073
|
}
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
*/
|
|
5152
|
-
getPropertyNode(node, key) {
|
|
5074
|
+
getChildNode(node, key) {
|
|
5075
|
+
if (!(key in this.properties)) {
|
|
5076
|
+
throw fail(`Not a value property: ${key}`);
|
|
5077
|
+
}
|
|
5153
5078
|
const childNode = getPropObservable(node.storedValue, key).raw();
|
|
5154
5079
|
if (!childNode) {
|
|
5155
5080
|
throw fail(`Node not available for property ${key}`);
|
|
5156
5081
|
}
|
|
5157
5082
|
return childNode;
|
|
5158
5083
|
}
|
|
5159
|
-
getChildNode(node, key) {
|
|
5160
|
-
if (!(key in this.properties)) {
|
|
5161
|
-
throw fail(`Not a value property: ${key}`);
|
|
5162
|
-
}
|
|
5163
|
-
return this.getPropertyNode(node, key);
|
|
5164
|
-
}
|
|
5165
5084
|
getSnapshot(node, applyPostProcess = true) {
|
|
5166
5085
|
const res = {};
|
|
5167
5086
|
const storedValue = node.storedValue;
|
|
@@ -5213,9 +5132,9 @@ class ModelType extends ComplexType {
|
|
|
5213
5132
|
applySnapshot(node, snapshot) {
|
|
5214
5133
|
typecheckInternal(this, snapshot);
|
|
5215
5134
|
const preProcessedSnapshot = this.applySnapshotPreProcessor(snapshot);
|
|
5216
|
-
|
|
5135
|
+
for (const name of this.propertyNames) {
|
|
5217
5136
|
node.storedValue[name] = preProcessedSnapshot[name];
|
|
5218
|
-
}
|
|
5137
|
+
}
|
|
5219
5138
|
}
|
|
5220
5139
|
applySnapshotPreProcessor(snapshot) {
|
|
5221
5140
|
const processor = this.preProcessor;
|
|
@@ -5248,12 +5167,6 @@ class ModelType extends ComplexType {
|
|
|
5248
5167
|
}
|
|
5249
5168
|
return typeCheckSuccess();
|
|
5250
5169
|
}
|
|
5251
|
-
forAllProps(fn) {
|
|
5252
|
-
const properties = this.properties;
|
|
5253
|
-
for (const key of this.propertyNames) {
|
|
5254
|
-
fn(key, properties[key]);
|
|
5255
|
-
}
|
|
5256
|
-
}
|
|
5257
5170
|
describe() {
|
|
5258
5171
|
// optimization: cache
|
|
5259
5172
|
return `{ ${this.propertyNames
|
|
@@ -5268,6 +5181,38 @@ class ModelType extends ComplexType {
|
|
|
5268
5181
|
}
|
|
5269
5182
|
}
|
|
5270
5183
|
ModelType.prototype.applySnapshot = action(ModelType.prototype.applySnapshot);
|
|
5184
|
+
// Chain steps shared by every model type; see the field declarations in the
|
|
5185
|
+
// class for why they are not own slots.
|
|
5186
|
+
Object.assign(ModelType.prototype, {
|
|
5187
|
+
named(name) {
|
|
5188
|
+
return this.cloneAndEnhance({ name });
|
|
5189
|
+
},
|
|
5190
|
+
props(properties) {
|
|
5191
|
+
return this.cloneAndEnhance({ properties });
|
|
5192
|
+
},
|
|
5193
|
+
preProcessSnapshot(preProcessor) {
|
|
5194
|
+
const currentPreprocessor = this.preProcessor;
|
|
5195
|
+
if (!currentPreprocessor) {
|
|
5196
|
+
return this.cloneAndEnhance({ preProcessor });
|
|
5197
|
+
}
|
|
5198
|
+
else {
|
|
5199
|
+
return this.cloneAndEnhance({
|
|
5200
|
+
preProcessor: snapshot => currentPreprocessor(preProcessor(snapshot))
|
|
5201
|
+
});
|
|
5202
|
+
}
|
|
5203
|
+
},
|
|
5204
|
+
postProcessSnapshot(postProcessor) {
|
|
5205
|
+
const currentPostprocessor = this.postProcessor;
|
|
5206
|
+
if (!currentPostprocessor) {
|
|
5207
|
+
return this.cloneAndEnhance({ postProcessor });
|
|
5208
|
+
}
|
|
5209
|
+
else {
|
|
5210
|
+
return this.cloneAndEnhance({
|
|
5211
|
+
postProcessor: snapshot => postProcessor(currentPostprocessor(snapshot))
|
|
5212
|
+
});
|
|
5213
|
+
}
|
|
5214
|
+
}
|
|
5215
|
+
});
|
|
5271
5216
|
/**
|
|
5272
5217
|
* `types.model` - Creates a new model type by providing a name, properties, volatile state and actions.
|
|
5273
5218
|
*
|
|
@@ -5378,9 +5323,6 @@ class CoreType extends SimpleType {
|
|
|
5378
5323
|
this.checker = checker;
|
|
5379
5324
|
this.initializer = initializer;
|
|
5380
5325
|
}
|
|
5381
|
-
describe() {
|
|
5382
|
-
return this.name;
|
|
5383
|
-
}
|
|
5384
5326
|
instantiate(parent, subpath, environment, initialValue) {
|
|
5385
5327
|
return createScalarNode(this, parent, subpath, environment, initialValue);
|
|
5386
5328
|
}
|
|
@@ -5547,15 +5489,15 @@ class Literal extends SimpleType {
|
|
|
5547
5489
|
value;
|
|
5548
5490
|
flags = TypeFlags.Literal;
|
|
5549
5491
|
constructor(value) {
|
|
5550
|
-
super(
|
|
5492
|
+
super();
|
|
5551
5493
|
this.value = value;
|
|
5552
5494
|
}
|
|
5495
|
+
computeName() {
|
|
5496
|
+
return JSON.stringify(this.value);
|
|
5497
|
+
}
|
|
5553
5498
|
instantiate(parent, subpath, environment, initialValue) {
|
|
5554
5499
|
return createScalarNode(this, parent, subpath, environment, initialValue);
|
|
5555
5500
|
}
|
|
5556
|
-
describe() {
|
|
5557
|
-
return JSON.stringify(this.value);
|
|
5558
|
-
}
|
|
5559
5501
|
isValidSnapshot(value, context) {
|
|
5560
5502
|
if (isPrimitive(value) && value === this.value) {
|
|
5561
5503
|
return typeCheckSuccess();
|
|
@@ -5613,9 +5555,6 @@ class Refinement extends BaseType {
|
|
|
5613
5555
|
this._predicate = _predicate;
|
|
5614
5556
|
this._message = _message;
|
|
5615
5557
|
}
|
|
5616
|
-
describe() {
|
|
5617
|
-
return this.name;
|
|
5618
|
-
}
|
|
5619
5558
|
instantiate(parent, subpath, environment, initialValue) {
|
|
5620
5559
|
// create the child type
|
|
5621
5560
|
return this._subtype.instantiate(parent, subpath, environment, initialValue);
|
|
@@ -5747,6 +5686,16 @@ function resolveModelType(type) {
|
|
|
5747
5686
|
}
|
|
5748
5687
|
return undefined;
|
|
5749
5688
|
}
|
|
5689
|
+
// The quick-match paths below already know a type carries TypeFlags.Literal,
|
|
5690
|
+
// but `is()` still routes through BaseType.validate — a context array, an entry
|
|
5691
|
+
// object and a `$treenode` probe per property, per candidate member. A real
|
|
5692
|
+
// `Literal` stores its primitive, and its isValidSnapshot is exactly value
|
|
5693
|
+
// equality against it, so compare directly. The `instanceof` gate is load
|
|
5694
|
+
// bearing: wrappers (optional, refinement, snapshotProcessor, late, union)
|
|
5695
|
+
// inherit the Literal flag from what they wrap and must keep the full check.
|
|
5696
|
+
function matchesLiteral(type, value) {
|
|
5697
|
+
return type instanceof Literal ? type.value === value : type.is(value);
|
|
5698
|
+
}
|
|
5750
5699
|
/**
|
|
5751
5700
|
* @internal
|
|
5752
5701
|
* @hidden
|
|
@@ -5774,7 +5723,7 @@ class Union extends BaseType {
|
|
|
5774
5723
|
return cached;
|
|
5775
5724
|
}
|
|
5776
5725
|
let result = TypeFlags.Union;
|
|
5777
|
-
for (const type of this.
|
|
5726
|
+
for (const type of this.members()) {
|
|
5778
5727
|
result |= type.flags;
|
|
5779
5728
|
}
|
|
5780
5729
|
if (!(result & TypeFlags.Late)) {
|
|
@@ -5783,12 +5732,14 @@ class Union extends BaseType {
|
|
|
5783
5732
|
return result;
|
|
5784
5733
|
}
|
|
5785
5734
|
computeName() {
|
|
5786
|
-
return `(${this.
|
|
5735
|
+
return `(${this.members()
|
|
5736
|
+
.map(type => type.name)
|
|
5737
|
+
.join(" | ")})`;
|
|
5787
5738
|
}
|
|
5788
5739
|
constructor(_types, options) {
|
|
5789
5740
|
super();
|
|
5790
5741
|
this._types = _types;
|
|
5791
|
-
// read the
|
|
5742
|
+
// read the options directly rather than spreading defaults into a fresh
|
|
5792
5743
|
// object: this constructor runs once per config slot in jbrowse, and the
|
|
5793
5744
|
// merged object was allocated only to be read twice and dropped
|
|
5794
5745
|
if (options !== undefined) {
|
|
@@ -5798,13 +5749,23 @@ class Union extends BaseType {
|
|
|
5798
5749
|
if (options.eager === false) {
|
|
5799
5750
|
this._eager = false;
|
|
5800
5751
|
}
|
|
5752
|
+
if (options.name !== undefined) {
|
|
5753
|
+
this.name = options.name;
|
|
5754
|
+
}
|
|
5801
5755
|
}
|
|
5802
5756
|
}
|
|
5757
|
+
// The one point membership is read through, so DynamicUnion can substitute
|
|
5758
|
+
// its thunk without duplicating any of the scanning logic below.
|
|
5759
|
+
members() {
|
|
5760
|
+
return this._types;
|
|
5761
|
+
}
|
|
5803
5762
|
isAssignableFrom(type) {
|
|
5804
|
-
return this.
|
|
5763
|
+
return this.members().some(subType => subType.isAssignableFrom(type));
|
|
5805
5764
|
}
|
|
5806
5765
|
describe() {
|
|
5807
|
-
return `(${this.
|
|
5766
|
+
return `(${this.members()
|
|
5767
|
+
.map(factory => factory.describe())
|
|
5768
|
+
.join(" | ")})`;
|
|
5808
5769
|
}
|
|
5809
5770
|
instantiate(parent, subpath, environment, initialValue) {
|
|
5810
5771
|
const type = this.determineType(initialValue, undefined);
|
|
@@ -5859,15 +5820,15 @@ class Union extends BaseType {
|
|
|
5859
5820
|
}
|
|
5860
5821
|
_scanForTypeDiscriminator(discriminator) {
|
|
5861
5822
|
let found;
|
|
5862
|
-
for (const t of this.
|
|
5823
|
+
for (const t of this.members()) {
|
|
5863
5824
|
const model = resolveModelType(t);
|
|
5864
5825
|
if (!model) {
|
|
5865
5826
|
continue;
|
|
5866
5827
|
}
|
|
5867
|
-
const typeProp = model.properties
|
|
5828
|
+
const typeProp = model.properties["type"];
|
|
5868
5829
|
if (!typeProp ||
|
|
5869
5830
|
!(typeProp.flags & TypeFlags.Literal) ||
|
|
5870
|
-
!typeProp
|
|
5831
|
+
!matchesLiteral(typeProp, discriminator)) {
|
|
5871
5832
|
continue;
|
|
5872
5833
|
}
|
|
5873
5834
|
if (found) {
|
|
@@ -5884,15 +5845,18 @@ class Union extends BaseType {
|
|
|
5884
5845
|
}
|
|
5885
5846
|
allMembersDiscriminated() {
|
|
5886
5847
|
if (this._allMembersDiscriminated === undefined) {
|
|
5887
|
-
this._allMembersDiscriminated = this.
|
|
5888
|
-
const model = resolveModelType(t);
|
|
5889
|
-
const typeProp = model &&
|
|
5890
|
-
model.properties.type;
|
|
5891
|
-
return !!typeProp && (typeProp.flags & TypeFlags.Literal) !== 0;
|
|
5892
|
-
});
|
|
5848
|
+
this._allMembersDiscriminated = this.computeAllMembersDiscriminated();
|
|
5893
5849
|
}
|
|
5894
5850
|
return this._allMembersDiscriminated;
|
|
5895
5851
|
}
|
|
5852
|
+
computeAllMembersDiscriminated() {
|
|
5853
|
+
return this.members().every(t => {
|
|
5854
|
+
const model = resolveModelType(t);
|
|
5855
|
+
const typeProp = model &&
|
|
5856
|
+
model.properties["type"];
|
|
5857
|
+
return !!typeProp && (typeProp.flags & TypeFlags.Literal) !== 0;
|
|
5858
|
+
});
|
|
5859
|
+
}
|
|
5896
5860
|
determineType(value, reconcileCurrentType) {
|
|
5897
5861
|
// try the dispatcher, if defined
|
|
5898
5862
|
if (this._dispatcher) {
|
|
@@ -5913,9 +5877,9 @@ class Union extends BaseType {
|
|
|
5913
5877
|
if (reconcileCurrentType.is(value)) {
|
|
5914
5878
|
return reconcileCurrentType;
|
|
5915
5879
|
}
|
|
5916
|
-
return this.
|
|
5880
|
+
return this.members().find(type => type !== reconcileCurrentType && type.is(value));
|
|
5917
5881
|
}
|
|
5918
|
-
return this.
|
|
5882
|
+
return this.members().find(type => type.is(value));
|
|
5919
5883
|
}
|
|
5920
5884
|
tryQuickMatch(value, reconcileCurrentType) {
|
|
5921
5885
|
// state tree nodes need full type compatibility checking
|
|
@@ -5935,7 +5899,7 @@ class Union extends BaseType {
|
|
|
5935
5899
|
this.snapshotLooksLikeType(value, reconcileCurrentType)) {
|
|
5936
5900
|
return reconcileCurrentType;
|
|
5937
5901
|
}
|
|
5938
|
-
for (const type of this.
|
|
5902
|
+
for (const type of this.members()) {
|
|
5939
5903
|
if (type !== reconcileCurrentType &&
|
|
5940
5904
|
this.snapshotLooksLikeType(value, type)) {
|
|
5941
5905
|
return type;
|
|
@@ -5945,7 +5909,7 @@ class Union extends BaseType {
|
|
|
5945
5909
|
}
|
|
5946
5910
|
tryMatchPrimitive(value) {
|
|
5947
5911
|
const valueType = typeof value;
|
|
5948
|
-
for (const type of this.
|
|
5912
|
+
for (const type of this.members()) {
|
|
5949
5913
|
const flags = type.flags;
|
|
5950
5914
|
if ((valueType === "string" && flags & TypeFlags.String) ||
|
|
5951
5915
|
(valueType === "number" &&
|
|
@@ -5961,7 +5925,7 @@ class Union extends BaseType {
|
|
|
5961
5925
|
}
|
|
5962
5926
|
// for literals, check exact value match
|
|
5963
5927
|
if (flags & TypeFlags.Literal) {
|
|
5964
|
-
if (type
|
|
5928
|
+
if (matchesLiteral(type, value)) {
|
|
5965
5929
|
return type;
|
|
5966
5930
|
}
|
|
5967
5931
|
}
|
|
@@ -5993,7 +5957,7 @@ class Union extends BaseType {
|
|
|
5993
5957
|
// for literal types, verify the value matches exactly
|
|
5994
5958
|
// this is critical for discriminated unions
|
|
5995
5959
|
if (flags & TypeFlags.Literal) {
|
|
5996
|
-
if (!propType
|
|
5960
|
+
if (!matchesLiteral(propType, propValue)) {
|
|
5997
5961
|
return false;
|
|
5998
5962
|
}
|
|
5999
5963
|
}
|
|
@@ -6032,10 +5996,11 @@ class Union extends BaseType {
|
|
|
6032
5996
|
// for plain-object snapshots, prefer union members whose literal-typed
|
|
6033
5997
|
// discriminator properties match the value (e.g. {type: "MsaView"})
|
|
6034
5998
|
// so error output is scoped to the intended branch instead of every member
|
|
5999
|
+
const members = this.members();
|
|
6035
6000
|
const candidates = isSnapshotObject
|
|
6036
|
-
?
|
|
6001
|
+
? members.filter(t => this.snapshotLooksLikeType(value, t))
|
|
6037
6002
|
: [];
|
|
6038
|
-
const typesToValidate = candidates.length > 0 ? candidates :
|
|
6003
|
+
const typesToValidate = candidates.length > 0 ? candidates : members;
|
|
6039
6004
|
const allErrors = [];
|
|
6040
6005
|
let applicableTypes = 0;
|
|
6041
6006
|
for (const type of typesToValidate) {
|
|
@@ -6058,7 +6023,7 @@ class Union extends BaseType {
|
|
|
6058
6023
|
return typeCheckFailure(context, value, "No type is applicable for the union").concat(allErrors.flat());
|
|
6059
6024
|
}
|
|
6060
6025
|
getSubTypes() {
|
|
6061
|
-
return this.
|
|
6026
|
+
return this.members();
|
|
6062
6027
|
}
|
|
6063
6028
|
}
|
|
6064
6029
|
// Defaults shared by every union; see the field declarations at the top of the
|
|
@@ -6069,9 +6034,82 @@ Object.assign(Union.prototype, {
|
|
|
6069
6034
|
_discriminatorCache: undefined,
|
|
6070
6035
|
_allMembersDiscriminated: undefined
|
|
6071
6036
|
});
|
|
6037
|
+
/**
|
|
6038
|
+
* @internal
|
|
6039
|
+
* @hidden
|
|
6040
|
+
*
|
|
6041
|
+
* A union whose membership is read fresh from a thunk on every operation, so
|
|
6042
|
+
* members that come into existence after the union was built — a registry of
|
|
6043
|
+
* pluggable types whose modules load on demand — still dispatch, validate, and
|
|
6044
|
+
* satisfy references. That last one is the reason this exists: reference
|
|
6045
|
+
* resolution asks the target type `isAssignableFrom(node.type)` through the
|
|
6046
|
+
* identifier cache, and a membership list frozen at construction would reject
|
|
6047
|
+
* every late-loaded member's instances.
|
|
6048
|
+
*
|
|
6049
|
+
* Every membership-derived cache the base class keeps is bypassed here: flags
|
|
6050
|
+
* and the folded name are recomputed per read, and the discriminator scan is
|
|
6051
|
+
* uncached so a miss stays retryable once the missing member registers. A hit
|
|
6052
|
+
* for a given discriminator is assumed stable — registering two members with
|
|
6053
|
+
* the same `type` literal at different times can leave a stale unambiguous
|
|
6054
|
+
* answer where the base class would have reported ambiguity.
|
|
6055
|
+
*/
|
|
6056
|
+
class DynamicUnion extends Union {
|
|
6057
|
+
_members;
|
|
6058
|
+
constructor(members, options) {
|
|
6059
|
+
super([], options);
|
|
6060
|
+
this._members = members;
|
|
6061
|
+
}
|
|
6062
|
+
members() {
|
|
6063
|
+
return this._members();
|
|
6064
|
+
}
|
|
6065
|
+
get flags() {
|
|
6066
|
+
let result = TypeFlags.Union;
|
|
6067
|
+
for (const type of this.members()) {
|
|
6068
|
+
result |= type.flags;
|
|
6069
|
+
}
|
|
6070
|
+
return result;
|
|
6071
|
+
}
|
|
6072
|
+
get name() {
|
|
6073
|
+
return this._explicitName !== undefined
|
|
6074
|
+
? this._explicitName
|
|
6075
|
+
: this.computeName();
|
|
6076
|
+
}
|
|
6077
|
+
set name(value) {
|
|
6078
|
+
this._explicitName = value;
|
|
6079
|
+
}
|
|
6080
|
+
_findCandidateByTypeDiscriminator(discriminator) {
|
|
6081
|
+
return this._scanForTypeDiscriminator(discriminator);
|
|
6082
|
+
}
|
|
6083
|
+
allMembersDiscriminated() {
|
|
6084
|
+
return this.computeAllMembersDiscriminated();
|
|
6085
|
+
}
|
|
6086
|
+
}
|
|
6087
|
+
const unionInternRoot = {};
|
|
6088
|
+
function internUnion(types) {
|
|
6089
|
+
let node = unionInternRoot;
|
|
6090
|
+
for (const type of types) {
|
|
6091
|
+
const level = (node.next ??= new WeakMap());
|
|
6092
|
+
const existing = level.get(type);
|
|
6093
|
+
if (existing) {
|
|
6094
|
+
node = existing;
|
|
6095
|
+
}
|
|
6096
|
+
else {
|
|
6097
|
+
node = {};
|
|
6098
|
+
level.set(type, node);
|
|
6099
|
+
}
|
|
6100
|
+
}
|
|
6101
|
+
return (node.union ??= new Union(types));
|
|
6102
|
+
}
|
|
6072
6103
|
/**
|
|
6073
6104
|
* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`.
|
|
6074
6105
|
*
|
|
6106
|
+
* Passing `members: () => Type[]` in the options (with no positional member
|
|
6107
|
+
* types) creates a union whose membership is re-read from the thunk on every
|
|
6108
|
+
* operation, so types registered after construction — e.g. from a lazily
|
|
6109
|
+
* loaded module — participate in dispatch, validation and reference
|
|
6110
|
+
* resolution. Pair it with a `dispatcher` for snapshot dispatch and a `name`
|
|
6111
|
+
* for stable error messages.
|
|
6112
|
+
*
|
|
6075
6113
|
* @param optionsOrType
|
|
6076
6114
|
* @param otherTypes
|
|
6077
6115
|
* @returns
|
|
@@ -6091,13 +6129,19 @@ function union(...args) {
|
|
|
6091
6129
|
// check all options
|
|
6092
6130
|
if (devMode()) {
|
|
6093
6131
|
if (options) {
|
|
6094
|
-
assertArg(options, o => isPlainObject(o), "object { eager?: boolean, dispatcher?: Function }", 1);
|
|
6132
|
+
assertArg(options, o => isPlainObject(o), "object { eager?: boolean, dispatcher?: Function, members?: Function, name?: string }", 1);
|
|
6095
6133
|
}
|
|
6096
6134
|
types.forEach((type, i) => {
|
|
6097
6135
|
assertIsType(type, options ? i + 2 : i + 1);
|
|
6098
6136
|
});
|
|
6099
6137
|
}
|
|
6100
|
-
|
|
6138
|
+
if (options?.members !== undefined) {
|
|
6139
|
+
if (types.length > 0) {
|
|
6140
|
+
throw fail("union(): the members option cannot be combined with positional member types");
|
|
6141
|
+
}
|
|
6142
|
+
return new DynamicUnion(options.members, options);
|
|
6143
|
+
}
|
|
6144
|
+
return options === undefined ? internUnion(types) : new Union(types, options);
|
|
6101
6145
|
}
|
|
6102
6146
|
/**
|
|
6103
6147
|
* Returns if a given value represents a union type.
|
|
@@ -6292,13 +6336,35 @@ const undefinedAsOptionalValues = [undefined];
|
|
|
6292
6336
|
* to compile. Guards with a distinct narrowing target (`isArrayType`,
|
|
6293
6337
|
* `isMapType`, `isModelType`) keep their predicate.
|
|
6294
6338
|
*
|
|
6295
|
-
* @template IT
|
|
6296
6339
|
* @param type
|
|
6297
6340
|
* @returns
|
|
6298
6341
|
*/
|
|
6299
6342
|
function isOptionalType(type) {
|
|
6300
6343
|
return isType(type) && (type.flags & TypeFlags.Optional) > 0;
|
|
6301
6344
|
}
|
|
6345
|
+
function isRecord(value) {
|
|
6346
|
+
return typeof value === "object" && value !== null;
|
|
6347
|
+
}
|
|
6348
|
+
/**
|
|
6349
|
+
* The identifier attribute of the model a stripDefault ultimately wraps, or
|
|
6350
|
+
* `null` when there is none. Drills through the single-subtype wrappers the way
|
|
6351
|
+
* `resolveModelType` in union.ts does — that one is module-private there, and
|
|
6352
|
+
* this file may not reach into it.
|
|
6353
|
+
*
|
|
6354
|
+
* `null` is also the answer for an unresolved `types.late`, which only costs the
|
|
6355
|
+
* short-circuit, never correctness: the full structural walk still runs.
|
|
6356
|
+
*/
|
|
6357
|
+
function resolveIdentifierAttribute(type) {
|
|
6358
|
+
let current = type;
|
|
6359
|
+
for (let depth = 0; current && depth < 20; depth++) {
|
|
6360
|
+
if (current instanceof ModelType) {
|
|
6361
|
+
return current.identifierAttribute ? current.identifierAttribute : null;
|
|
6362
|
+
}
|
|
6363
|
+
const wrapper = current;
|
|
6364
|
+
current = wrapper._subtype ?? wrapper.getSubType?.(false);
|
|
6365
|
+
}
|
|
6366
|
+
return null;
|
|
6367
|
+
}
|
|
6302
6368
|
/**
|
|
6303
6369
|
* Compare a child snapshot to a stripped-default's reference snapshot: identity
|
|
6304
6370
|
* for primitives, structural for objects/arrays.
|
|
@@ -6377,6 +6443,22 @@ function defaultSnapshotEquals(a, b) {
|
|
|
6377
6443
|
* @internal
|
|
6378
6444
|
*/
|
|
6379
6445
|
class StripDefaultValue extends OptionalValue {
|
|
6446
|
+
equalsDefault(snapshot, defaultSnapshot) {
|
|
6447
|
+
let identifierAttribute = this._identifierAttribute;
|
|
6448
|
+
if (identifierAttribute === undefined) {
|
|
6449
|
+
identifierAttribute = resolveIdentifierAttribute(this.getSubTypes());
|
|
6450
|
+
this._identifierAttribute = identifierAttribute;
|
|
6451
|
+
}
|
|
6452
|
+
// an identified model's snapshot normally has the same shape as the default
|
|
6453
|
+
// and differs only here, so answering from one key beats walking every key
|
|
6454
|
+
// (including nested objects) until the walk reaches it
|
|
6455
|
+
return identifierAttribute !== null &&
|
|
6456
|
+
isRecord(snapshot) &&
|
|
6457
|
+
isRecord(defaultSnapshot) &&
|
|
6458
|
+
snapshot[identifierAttribute] !== defaultSnapshot[identifierAttribute]
|
|
6459
|
+
? false
|
|
6460
|
+
: defaultSnapshotEquals(snapshot, defaultSnapshot);
|
|
6461
|
+
}
|
|
6380
6462
|
shouldStripFromSnapshot(snapshot) {
|
|
6381
6463
|
if (!this._defaultSnapshot) {
|
|
6382
6464
|
// instantiate the subtype detached with the default and read the node's
|
|
@@ -6385,11 +6467,35 @@ class StripDefaultValue extends OptionalValue {
|
|
|
6385
6467
|
const node = this.getSubTypes().instantiate(null, "", undefined, this.getDefaultInstanceOrSnapshot());
|
|
6386
6468
|
this._defaultSnapshot = { value: node.snapshot };
|
|
6387
6469
|
}
|
|
6388
|
-
|
|
6470
|
+
const defaultSnapshot = this._defaultSnapshot.value;
|
|
6471
|
+
let result;
|
|
6472
|
+
if (isRecord(snapshot)) {
|
|
6473
|
+
// a child node's snapshot is a keepAlive computed, so a stable reference
|
|
6474
|
+
// means unchanged content: the same object always gets the same answer
|
|
6475
|
+
let cache = this._equalsDefaultCache;
|
|
6476
|
+
if (!cache) {
|
|
6477
|
+
cache = new WeakMap();
|
|
6478
|
+
this._equalsDefaultCache = cache;
|
|
6479
|
+
}
|
|
6480
|
+
const cached = cache.get(snapshot);
|
|
6481
|
+
if (cached === undefined) {
|
|
6482
|
+
result = this.equalsDefault(snapshot, defaultSnapshot);
|
|
6483
|
+
cache.set(snapshot, result);
|
|
6484
|
+
}
|
|
6485
|
+
else {
|
|
6486
|
+
result = cached;
|
|
6487
|
+
}
|
|
6488
|
+
}
|
|
6489
|
+
else {
|
|
6490
|
+
result = defaultSnapshotEquals(snapshot, defaultSnapshot);
|
|
6491
|
+
}
|
|
6492
|
+
return result;
|
|
6389
6493
|
}
|
|
6390
6494
|
}
|
|
6391
6495
|
Object.assign(StripDefaultValue.prototype, {
|
|
6392
|
-
_defaultSnapshot: undefined
|
|
6496
|
+
_defaultSnapshot: undefined,
|
|
6497
|
+
_identifierAttribute: undefined,
|
|
6498
|
+
_equalsDefaultCache: undefined
|
|
6393
6499
|
});
|
|
6394
6500
|
/**
|
|
6395
6501
|
* Whether `type` is a strip-default optional whose current child `snapshot`
|
|
@@ -6619,6 +6725,13 @@ class Lazy extends SimpleType {
|
|
|
6619
6725
|
}
|
|
6620
6726
|
reconcile(current, value, parent, subpath) {
|
|
6621
6727
|
if (this.loadedType) {
|
|
6728
|
+
// a node created after load carries the loaded type: let it reconcile so
|
|
6729
|
+
// the instance survives applySnapshot instead of dying on every write
|
|
6730
|
+
const loaded = this.loadedType;
|
|
6731
|
+
const currentType = current.type;
|
|
6732
|
+
if (currentType === loaded) {
|
|
6733
|
+
return this.loadedType.reconcile(current, value, parent, subpath);
|
|
6734
|
+
}
|
|
6622
6735
|
current.die();
|
|
6623
6736
|
return this.loadedType.instantiate(parent, subpath, parent.environment, value);
|
|
6624
6737
|
}
|
|
@@ -6808,9 +6921,6 @@ class BaseReferenceType extends SimpleType {
|
|
|
6808
6921
|
computeName() {
|
|
6809
6922
|
return `reference(${this.targetType.name})`;
|
|
6810
6923
|
}
|
|
6811
|
-
describe() {
|
|
6812
|
-
return this.name;
|
|
6813
|
-
}
|
|
6814
6924
|
isAssignableFrom(type) {
|
|
6815
6925
|
return this.targetType.isAssignableFrom(type);
|
|
6816
6926
|
}
|
|
@@ -7147,9 +7257,6 @@ class IdentifierType extends BaseIdentifierType {
|
|
|
7147
7257
|
constructor() {
|
|
7148
7258
|
super(`identifier`, "string");
|
|
7149
7259
|
}
|
|
7150
|
-
describe() {
|
|
7151
|
-
return `identifier`;
|
|
7152
|
-
}
|
|
7153
7260
|
}
|
|
7154
7261
|
/**
|
|
7155
7262
|
* @internal
|
|
@@ -7159,12 +7266,6 @@ class IdentifierNumberType extends BaseIdentifierType {
|
|
|
7159
7266
|
constructor() {
|
|
7160
7267
|
super("identifierNumber", "number");
|
|
7161
7268
|
}
|
|
7162
|
-
getSnapshot(node) {
|
|
7163
|
-
return node.storedValue;
|
|
7164
|
-
}
|
|
7165
|
-
describe() {
|
|
7166
|
-
return `identifierNumber`;
|
|
7167
|
-
}
|
|
7168
7269
|
}
|
|
7169
7270
|
/**
|
|
7170
7271
|
* `types.identifier` - Identifiers are used to make references, lifecycle events and reconciling works.
|
|
@@ -7295,9 +7396,6 @@ class CustomType extends SimpleType {
|
|
|
7295
7396
|
super(options.name);
|
|
7296
7397
|
this.options = options;
|
|
7297
7398
|
}
|
|
7298
|
-
describe() {
|
|
7299
|
-
return this.name;
|
|
7300
|
-
}
|
|
7301
7399
|
isValidSnapshot(value, context) {
|
|
7302
7400
|
if (this.options.isTargetType(value)) {
|
|
7303
7401
|
return typeCheckSuccess();
|
|
@@ -7501,5 +7599,5 @@ const types = {
|
|
|
7501
7599
|
resilient
|
|
7502
7600
|
};
|
|
7503
7601
|
|
|
7504
|
-
export { addDisposer, addMiddleware, applyAction, applyPatch, applySnapshot, cast, castFlowReturn, castToReferenceSnapshot, castToSnapshot, clone, createActionTrackingMiddleware, createActionTrackingMiddleware2, decorate, destroy, detach, escapeJsonPath, extendInstance, flow, getChildType, getEnv, getIdentifier, getLivelinessChecking, getMembers, getNodeId, getParent, getParentOfType, getPath, getPathParts, getPropertyMembers, getRelativePath, getRoot, getRunningActionContext, getSnapshot, getType, getUnionSubtypes, hasParent, hasParentOfType, isActionContextChildOf, isActionContextThisOrChildOf, isAlive, isArrayType, isFrozenType, isIdentifierType, isLateType, isLiteralType, isMapType, isModelType, isOptionalType, isPrimitiveType, isProtected, isReferenceType, isRefinementType, isRoot, isStateTreeNode, isType, isUnionType, isValidReference, joinJsonPath, onAction, onPatch, onSnapshot, protect, recordActions, recordPatches, resolveIdentifier, resolvePath, setDevMode, setLivelinessChecking, setLivelynessChecking, setTypeChecking, splitJsonPath, types as t, toGenerator, toGeneratorFunction, tryReference, tryResolve, typecheck, types, unescapeJsonPath, unprotect, walk };
|
|
7602
|
+
export { addDisposer, addMiddleware, applyAction, applyPatch, applySnapshot, cannotDetermineSubtype, cast, castFlowReturn, castToReferenceSnapshot, castToSnapshot, clone, createActionTrackingMiddleware, createActionTrackingMiddleware2, decorate, destroy, detach, escapeJsonPath, extendInstance, flow, getChildType, getEnv, getIdentifier, getLivelinessChecking, getMembers, getNodeId, getParent, getParentOfType, getPath, getPathParts, getPropertyMembers, getRelativePath, getRoot, getRunningActionContext, getSnapshot, getType, getUnionSubtypes, hasParent, hasParentOfType, isActionContextChildOf, isActionContextThisOrChildOf, isAlive, isArrayType, isFrozenType, isIdentifierType, isLateType, isLiteralType, isMapType, isModelType, isOptionalType, isPrimitiveType, isProtected, isReferenceType, isRefinementType, isRoot, isStateTreeNode, isType, isUnionType, isValidReference, joinJsonPath, onAction, onPatch, onSnapshot, protect, recordActions, recordPatches, resolveIdentifier, resolvePath, setDevMode, setLivelinessChecking, setLivelynessChecking, setTypeChecking, splitJsonPath, types as t, toGenerator, toGeneratorFunction, tryReference, tryResolve, typecheck, types, unescapeJsonPath, unprotect, walk };
|
|
7505
7603
|
//# sourceMappingURL=mobx-state-tree.mjs.map
|