@jbrowse/mobx-state-tree 5.9.2 → 5.10.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 +4 -2
- package/dist/mobx-state-tree.cjs +132 -13
- package/dist/mobx-state-tree.cjs.map +1 -1
- package/dist/mobx-state-tree.mjs +132 -13
- package/dist/mobx-state-tree.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,12 +7,11 @@ Fork of mobx-state-tree v5.4.2 for use in jbrowse
|
|
|
7
7
|
- updated typescript
|
|
8
8
|
- updated to import actual filepaths instead of node module resolution
|
|
9
9
|
- reduced rollup config
|
|
10
|
-
- tried tsdown but builds were very slow for some reason
|
|
11
10
|
- removed process.env.NODE_ENV from code, instead exporting a setDevMode function
|
|
12
11
|
- converted tests to vitest
|
|
13
12
|
- remove unused dependencies
|
|
14
13
|
- updated tslint to eslint and typescript-eslint
|
|
15
|
-
-
|
|
14
|
+
- dual CJS/ESM build using main and module fields (pure ESM causes trouble when both are imported in vite)
|
|
16
15
|
- added `types.resilient` - wraps a type so that instantiation errors are caught
|
|
17
16
|
and a fallback type is used instead of crashing the entire state tree. This is
|
|
18
17
|
useful for arrays or maps that may contain unknown or invalid entries (e.g.
|
|
@@ -22,3 +21,6 @@ Fork of mobx-state-tree v5.4.2 for use in jbrowse
|
|
|
22
21
|
meaning any value is considered a valid snapshot. Validation is deferred to
|
|
23
22
|
instantiation time, where failures are caught and routed to the fallback
|
|
24
23
|
- removed NonEmptyObject annotation (also at upstream in post v5 versions)
|
|
24
|
+
- replaced `unique symbol` phantom properties (`$emptyObject`, `$stateTreeNodeType`) with
|
|
25
|
+
exported string-keyed brand interfaces (`$EmptyObjectBrand`, `$__mstStateTreeNodeType__`),
|
|
26
|
+
fixing tsgo TS4058/TS4023 errors when MST types propagate into exported function return types
|
package/dist/mobx-state-tree.cjs
CHANGED
|
@@ -2701,16 +2701,27 @@ function typecheck(type, value) {
|
|
|
2701
2701
|
}
|
|
2702
2702
|
}
|
|
2703
2703
|
const MAX_ERRORS_REPORTED = 10;
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2704
|
+
/**
|
|
2705
|
+
* @internal
|
|
2706
|
+
* @hidden
|
|
2707
|
+
* Format a list of validation errors as bullet-style lines, capped at
|
|
2708
|
+
* MAX_ERRORS_REPORTED entries with an overflow suffix. Shared by typecheck()
|
|
2709
|
+
* and union's `noMatchMessage` so prod-build union failures can include
|
|
2710
|
+
* candidate validation errors using the same formatting.
|
|
2711
|
+
*/
|
|
2712
|
+
function formatValidationErrorLines(errors) {
|
|
2708
2713
|
const shown = errors.slice(0, MAX_ERRORS_REPORTED).map(toErrorString);
|
|
2709
2714
|
const overflow = errors.length - shown.length;
|
|
2710
2715
|
if (overflow > 0) {
|
|
2711
2716
|
shown.push(`(… and ${overflow} more error${overflow === 1 ? "" : "s"})`);
|
|
2712
2717
|
}
|
|
2713
|
-
return
|
|
2718
|
+
return shown;
|
|
2719
|
+
}
|
|
2720
|
+
function validationErrorsToString(type, value, errors) {
|
|
2721
|
+
if (errors.length === 0) {
|
|
2722
|
+
return undefined;
|
|
2723
|
+
}
|
|
2724
|
+
return (`Error while converting ${shortenPrintValue(prettyPrintValue(value))} to \`${type.name}\`:\n\n ` + formatValidationErrorLines(errors).join("\n "));
|
|
2714
2725
|
}
|
|
2715
2726
|
|
|
2716
2727
|
let identifierCacheId = 0;
|
|
@@ -5391,6 +5402,25 @@ function enumeration(name, options) {
|
|
|
5391
5402
|
return type;
|
|
5392
5403
|
}
|
|
5393
5404
|
|
|
5405
|
+
// Drill through single-subtype wrappers — optional(), refinement(),
|
|
5406
|
+
// snapshotProcessor(), late() — to the underlying ModelType. Discriminated-
|
|
5407
|
+
// union scoping keys on a member's literal `type` property, but real-world
|
|
5408
|
+
// members are rarely bare models (jbrowse config schemas, for instance, are
|
|
5409
|
+
// always optional(model) or optional(snapshotProcessor(model))). Without this
|
|
5410
|
+
// the scoping never engages and every failure prints every member's full
|
|
5411
|
+
// structure. Wrappers expose their child as `_subtype` (optional/refinement/
|
|
5412
|
+
// snapshotProcessor) or via `getSubType()` (late); bounded to avoid cycles.
|
|
5413
|
+
function resolveModelType(type) {
|
|
5414
|
+
let current = type;
|
|
5415
|
+
for (let depth = 0; current && depth < 20; depth++) {
|
|
5416
|
+
if (current instanceof ModelType) {
|
|
5417
|
+
return current;
|
|
5418
|
+
}
|
|
5419
|
+
const wrapper = current;
|
|
5420
|
+
current = wrapper._subtype ?? wrapper.getSubType?.(false);
|
|
5421
|
+
}
|
|
5422
|
+
return undefined;
|
|
5423
|
+
}
|
|
5394
5424
|
/**
|
|
5395
5425
|
* @internal
|
|
5396
5426
|
* @hidden
|
|
@@ -5440,10 +5470,74 @@ class Union extends BaseType {
|
|
|
5440
5470
|
return type.reconcile(current, newValue, parent, subpath);
|
|
5441
5471
|
}
|
|
5442
5472
|
noMatchMessage(value) {
|
|
5443
|
-
const
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5473
|
+
const base = `No matching type for union ${this.name}`;
|
|
5474
|
+
if (!isPlainObject(value)) {
|
|
5475
|
+
return base;
|
|
5476
|
+
}
|
|
5477
|
+
const discriminator = value.type;
|
|
5478
|
+
if (typeof discriminator !== "string") {
|
|
5479
|
+
return base;
|
|
5480
|
+
}
|
|
5481
|
+
const baseWithDiscriminator = `${base} for snapshot with type "${discriminator}"`;
|
|
5482
|
+
// If exactly one union member has a literal `type` property matching the
|
|
5483
|
+
// snapshot's discriminator, run its validate() so we can append the
|
|
5484
|
+
// property-level reasons it didn't match. This converts the bare prod-build
|
|
5485
|
+
// "no matching type" into something diagnosable (e.g. which field was the
|
|
5486
|
+
// wrong type, which required field was missing) without re-bloating the
|
|
5487
|
+
// message back to every-member's full describe() output.
|
|
5488
|
+
const candidate = this._findCandidateByTypeDiscriminator(discriminator);
|
|
5489
|
+
if (!candidate) {
|
|
5490
|
+
return baseWithDiscriminator;
|
|
5491
|
+
}
|
|
5492
|
+
const errors = candidate.validate(value, [
|
|
5493
|
+
{ path: "", type: candidate }
|
|
5494
|
+
]);
|
|
5495
|
+
if (errors.length === 0) {
|
|
5496
|
+
return baseWithDiscriminator;
|
|
5497
|
+
}
|
|
5498
|
+
return (`${baseWithDiscriminator}:\n ` +
|
|
5499
|
+
formatValidationErrorLines(errors).join("\n "));
|
|
5500
|
+
}
|
|
5501
|
+
_findCandidateByTypeDiscriminator(discriminator) {
|
|
5502
|
+
let found;
|
|
5503
|
+
for (const t of this._types) {
|
|
5504
|
+
const model = resolveModelType(t);
|
|
5505
|
+
if (!model) {
|
|
5506
|
+
continue;
|
|
5507
|
+
}
|
|
5508
|
+
const typeProp = model.properties.type;
|
|
5509
|
+
if (!typeProp ||
|
|
5510
|
+
!(typeProp.flags & TypeFlags.Literal) ||
|
|
5511
|
+
!typeProp.is(discriminator)) {
|
|
5512
|
+
continue;
|
|
5513
|
+
}
|
|
5514
|
+
if (found) {
|
|
5515
|
+
// Ambiguous (two members declare the same `type` literal). Fall back
|
|
5516
|
+
// to the short message rather than picking arbitrarily.
|
|
5517
|
+
return undefined;
|
|
5518
|
+
}
|
|
5519
|
+
// Return the original (possibly wrapped) member, not the unwrapped
|
|
5520
|
+
// model, so validate()/is() still apply optional defaults and any
|
|
5521
|
+
// snapshotProcessor pre-processing.
|
|
5522
|
+
found = t;
|
|
5523
|
+
}
|
|
5524
|
+
return found;
|
|
5525
|
+
}
|
|
5526
|
+
// True when every member resolves to a model carrying a literal `type`
|
|
5527
|
+
// discriminator — i.e. a fully discriminated union, where a snapshot's `type`
|
|
5528
|
+
// uniquely identifies the intended member and no untagged catch-all member
|
|
5529
|
+
// could also accept it. Cached: membership is fixed at construction.
|
|
5530
|
+
_allMembersDiscriminated;
|
|
5531
|
+
allMembersDiscriminated() {
|
|
5532
|
+
if (this._allMembersDiscriminated === undefined) {
|
|
5533
|
+
this._allMembersDiscriminated = this._types.every(t => {
|
|
5534
|
+
const model = resolveModelType(t);
|
|
5535
|
+
const typeProp = model &&
|
|
5536
|
+
model.properties.type;
|
|
5537
|
+
return !!typeProp && (typeProp.flags & TypeFlags.Literal) !== 0;
|
|
5538
|
+
});
|
|
5539
|
+
}
|
|
5540
|
+
return this._allMembersDiscriminated;
|
|
5447
5541
|
}
|
|
5448
5542
|
determineType(value, reconcileCurrentType) {
|
|
5449
5543
|
// try the dispatcher, if defined
|
|
@@ -5532,11 +5626,14 @@ class Union extends BaseType {
|
|
|
5532
5626
|
}
|
|
5533
5627
|
snapshotLooksLikeType(value, type) {
|
|
5534
5628
|
// for model types, check if snapshot has all the required property keys
|
|
5535
|
-
// and that any literal-typed properties match exactly
|
|
5536
|
-
|
|
5537
|
-
|
|
5629
|
+
// and that any literal-typed properties match exactly. Unwrap optional() /
|
|
5630
|
+
// snapshotProcessor() / refinement() / late() so wrapped members (e.g.
|
|
5631
|
+
// jbrowse config schemas, which are always optional(model)) still match.
|
|
5632
|
+
const model = resolveModelType(type);
|
|
5633
|
+
if (model) {
|
|
5634
|
+
const props = model.properties;
|
|
5538
5635
|
// use cached propertyNames from ModelType instead of Object.keys()
|
|
5539
|
-
for (const key of
|
|
5636
|
+
for (const key of model.propertyNames) {
|
|
5540
5637
|
const propType = props[key];
|
|
5541
5638
|
const isOptional = propType.flags & TypeFlags.Optional;
|
|
5542
5639
|
const propValue = value[key];
|
|
@@ -5563,6 +5660,28 @@ class Union extends BaseType {
|
|
|
5563
5660
|
if (this._dispatcher) {
|
|
5564
5661
|
return this._dispatcher(value).validate(value, context);
|
|
5565
5662
|
}
|
|
5663
|
+
// For plain-object snapshots carrying a `type` discriminator, validate only
|
|
5664
|
+
// the single member whose literal `type` matches.
|
|
5665
|
+
// - Clean validation short-circuits to success only when it is sound to skip
|
|
5666
|
+
// the other members: an eager union (first match wins) or a fully
|
|
5667
|
+
// discriminated one (no untagged catch-all could also match). A non-eager
|
|
5668
|
+
// union with a catch-all must still fall through so ambiguity is counted.
|
|
5669
|
+
// - A failure is the definitive, scoped error only when every member is
|
|
5670
|
+
// discriminated; otherwise a catch-all could still accept the value, so
|
|
5671
|
+
// fall through to full validation.
|
|
5672
|
+
if (isPlainObject(value) && !isStateTreeNode(value)) {
|
|
5673
|
+
const discriminator = value.type;
|
|
5674
|
+
if (typeof discriminator === "string") {
|
|
5675
|
+
const candidate = this._findCandidateByTypeDiscriminator(discriminator);
|
|
5676
|
+
if (candidate) {
|
|
5677
|
+
const errors = candidate.validate(value, context);
|
|
5678
|
+
const cleanAndUnique = errors.length === 0 && this._eager;
|
|
5679
|
+
if (cleanAndUnique || this.allMembersDiscriminated()) {
|
|
5680
|
+
return errors;
|
|
5681
|
+
}
|
|
5682
|
+
}
|
|
5683
|
+
}
|
|
5684
|
+
}
|
|
5566
5685
|
// for plain-object snapshots, prefer union members whose literal-typed
|
|
5567
5686
|
// discriminator properties match the value (e.g. {type: "MsaView"})
|
|
5568
5687
|
// so error output is scoped to the intended branch instead of every member
|