@jbrowse/mobx-state-tree 5.11.1 → 5.11.2

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 CHANGED
@@ -16,6 +16,79 @@ documents only the additions and changes made in this fork.
16
16
  exported string-keyed brand interfaces (`$EmptyObjectBrand`, `$__mstStateTreeNodeType__`),
17
17
  fixing tsgo TS4058/TS4023 errors when MST types appear in exported function return types
18
18
 
19
+ ## Error message changes
20
+
21
+ Validation and conversion errors have been reworked to stay readable on large state
22
+ trees. Upstream MST could throw error messages hundreds of kilobytes long because it
23
+ expanded every union member's full structure and stringified entire snapshots unbounded.
24
+ This fork keeps the errors short while making them more diagnosable.
25
+
26
+ ### Bounded conversion errors
27
+
28
+ `typecheck()` / instantiation errors no longer dump unbounded output:
29
+
30
+ - Stringified snapshots are depth-bound (nested objects past 3 levels collapse to `…`)
31
+ - Each printed value is capped in length
32
+ - At most 10 individual errors are reported, with a `(… and N more errors)` suffix
33
+
34
+ ### Scoped discriminated-union errors
35
+
36
+ Take a union of view types discriminated by a literal `type` property:
37
+
38
+ ```ts
39
+ const LinearGenomeView = types.model("LinearGenomeView", {
40
+ type: types.literal("LinearGenomeView"),
41
+ height: types.number,
42
+ assembly: types.string
43
+ })
44
+ const DotplotView = types.model("DotplotView", {
45
+ type: types.literal("DotplotView"),
46
+ height: types.number
47
+ })
48
+ const AnyView = types.union(LinearGenomeView, DotplotView)
49
+ ```
50
+
51
+ Upstream MST listed every member's full structure on any failure. A single mistyped field
52
+ produced output like this — each member's entire schema expanded inline, repeated for every
53
+ member, often hundreds of kilobytes on a real config union:
54
+
55
+ ```
56
+ No matching type for union(LinearGenomeView | DotplotView)
57
+ (snapshot `{"type":"LinearGenomeView","height":"tall","assembly":"hg38"}` is not assignable
58
+ to type: `({ type: ("LinearGenomeView" | snapshot like `"LinearGenomeView"`); height: number;
59
+ assembly: string } | { type: ("DotplotView" | snapshot like `"DotplotView"`); height: number })`,
60
+ expected an instance of `LinearGenomeView` or a snapshot like `{ type: ("LinearGenomeView" |
61
+ snapshot like `"LinearGenomeView"`); height: number; assembly: string }` instead. … )
62
+ ```
63
+
64
+ Now the error is scoped to the single member whose literal `type` matches the snapshot's
65
+ discriminator, and reports only the property-level reasons it failed.
66
+
67
+ `AnyView.create({ type: "LinearGenomeView", height: "tall", assembly: "hg38" })` throws:
68
+
69
+ ```
70
+ [mobx-state-tree] Error while converting `{"type":"LinearGenomeView","height":"tall","assembly":"hg38"}` to `(LinearGenomeView | DotplotView)`:
71
+
72
+ at path "/height" value `"tall"` is not assignable to type: `number` (Value is not a number).
73
+ ```
74
+
75
+ And in production builds (where full type-checking is skipped) a missing required field on a
76
+ recognized member still names the discriminator and the offending path —
77
+ `AnyView.create({ type: "LinearGenomeView", height: 100 })` throws:
78
+
79
+ ```
80
+ [mobx-state-tree] No matching type for union (LinearGenomeView | DotplotView) for snapshot with type "LinearGenomeView":
81
+ at path "/assembly" value `undefined` is not assignable to type: `string` (Value is not a string).
82
+ ```
83
+
84
+ Instead of a wall of text covering every union member, you get the discriminator that was
85
+ seen plus the property-level reasons that one intended member rejected the snapshot (wrong
86
+ field type, missing required field, etc.). The scoping drills through wrapped members
87
+ (`optional`, `refinement`, `snapshotProcessor`, `late`) to find the underlying model, so
88
+ real-world members like an `optional(model)` config schema are still matched correctly.
89
+ When two members declare the same `type` literal (ambiguous), it falls back to the short
90
+ message rather than guessing.
91
+
19
92
  ## Added APIs
20
93
 
21
94
  ### `types.resilient`
@@ -28,12 +101,12 @@ crashing the entire state tree.
28
101
  const PluginWidget = types.resilient(
29
102
  KnownWidget,
30
103
  UnknownWidget,
31
- (error, originalSnapshot) => ({ kind: "unknown", raw: originalSnapshot }),
104
+ (error, originalSnapshot) => ({ kind: "unknown", raw: originalSnapshot })
32
105
  )
33
106
 
34
107
  // Arrays of plugins stay alive even if one entry is unrecognized
35
108
  const Store = types.model({
36
- widgets: types.array(PluginWidget),
109
+ widgets: types.array(PluginWidget)
37
110
  })
38
111
  ```
39
112
 
@@ -66,11 +139,11 @@ creating a model:
66
139
 
67
140
  ```ts
68
141
  const Settings = types.model({
69
- theme: types.optional(types.string, "light"),
142
+ theme: types.optional(types.string, "light")
70
143
  })
71
144
 
72
- const s = Settings.create() // theme is "light"
73
- getSnapshot(s) // { theme: "light" }
145
+ const s = Settings.create() // theme is "light"
146
+ getSnapshot(s) // { theme: "light" }
74
147
  ```
75
148
 
76
149
  Even though `"light"` is just the default, it always appears in the snapshot. If you store
@@ -84,17 +157,17 @@ equals the default:
84
157
 
85
158
  ```ts
86
159
  const Settings = types.model({
87
- theme: types.stripDefault(types.string, "light"),
160
+ theme: types.stripDefault(types.string, "light")
88
161
  })
89
162
 
90
163
  const s = Settings.create()
91
- getSnapshot(s) // {} ← key omitted because value equals default
164
+ getSnapshot(s) // {} ← key omitted because value equals default
92
165
 
93
166
  s.theme = "dark"
94
- getSnapshot(s) // { theme: "dark" }
167
+ getSnapshot(s) // { theme: "dark" }
95
168
 
96
169
  s.theme = "light"
97
- getSnapshot(s) // {} ← omitted again
170
+ getSnapshot(s) // {} ← omitted again
98
171
  ```
99
172
 
100
173
  #### Why this matters
@@ -132,7 +205,7 @@ ignored (all children share one element type).
132
205
  const Box = types.model({ x: types.number, y: types.number })
133
206
  const box = Box.create({ x: 1, y: 2 })
134
207
 
135
- getChildType(box, "x").name // "number"
208
+ getChildType(box, "x").name // "number"
136
209
  ```
137
210
 
138
211
  **`getUnionSubtypes(type)`** — given a `types.union` type, returns the array of its member
@@ -141,7 +214,7 @@ types. Useful when you need to enumerate what a union can hold.
141
214
  ```ts
142
215
  const Shape = types.union(Circle, Square, Triangle)
143
216
 
144
- getUnionSubtypes(Shape) // [Circle, Square, Triangle]
217
+ getUnionSubtypes(Shape) // [Circle, Square, Triangle]
145
218
  ```
146
219
 
147
220
  **`getDefaultInstanceOrSnapshot(optionalType)`** — returns the default value (or snapshot)
@@ -151,5 +224,5 @@ default without having to create a model instance.
151
224
  ```ts
152
225
  const t = types.optional(types.string, "hello")
153
226
 
154
- t.getDefaultInstanceOrSnapshot() // "hello"
227
+ t.getDefaultInstanceOrSnapshot() // "hello"
155
228
  ```
package/dist/index.d.ts CHANGED
@@ -1284,52 +1284,6 @@ interface IAnyStateTreeNode extends STNValue<any, IAnyType> {
1284
1284
  */
1285
1285
  declare function isStateTreeNode<IT extends IAnyComplexType = IAnyComplexType>(value: any): value is STNValue<Instance<IT>, IT>;
1286
1286
 
1287
- /**
1288
- * @deprecated has been renamed to `flow()`.
1289
- * @hidden
1290
- */
1291
- declare function process<R>(generator: () => IterableIterator<any>): () => Promise<R>;
1292
- /**
1293
- * @deprecated has been renamed to `flow()`.
1294
- * @hidden
1295
- */
1296
- declare function process<A1>(generator: (a1: A1) => IterableIterator<any>): (a1: A1) => Promise<any>;
1297
- /**
1298
- * @deprecated has been renamed to `flow()`.
1299
- * @hidden
1300
- */
1301
- declare function process<A1, A2>(generator: (a1: A1, a2: A2) => IterableIterator<any>): (a1: A1, a2: A2) => Promise<any>;
1302
- /**
1303
- * @deprecated has been renamed to `flow()`.
1304
- * @hidden
1305
- */
1306
- declare function process<A1, A2, A3>(generator: (a1: A1, a2: A2, a3: A3) => IterableIterator<any>): (a1: A1, a2: A2, a3: A3) => Promise<any>;
1307
- /**
1308
- * @deprecated has been renamed to `flow()`.
1309
- * @hidden
1310
- */
1311
- declare function process<A1, A2, A3, A4>(generator: (a1: A1, a2: A2, a3: A3, a4: A4) => IterableIterator<any>): (a1: A1, a2: A2, a3: A3, a4: A4) => Promise<any>;
1312
- /**
1313
- * @deprecated has been renamed to `flow()`.
1314
- * @hidden
1315
- */
1316
- declare function process<A1, A2, A3, A4, A5>(generator: (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5) => IterableIterator<any>): (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5) => Promise<any>;
1317
- /**
1318
- * @deprecated has been renamed to `flow()`.
1319
- * @hidden
1320
- */
1321
- declare function process<A1, A2, A3, A4, A5, A6>(generator: (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6) => IterableIterator<any>): (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6) => Promise<any>;
1322
- /**
1323
- * @deprecated has been renamed to `flow()`.
1324
- * @hidden
1325
- */
1326
- declare function process<A1, A2, A3, A4, A5, A6, A7>(generator: (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7) => IterableIterator<any>): (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7) => Promise<any>;
1327
- /**
1328
- * @deprecated has been renamed to `flow()`.
1329
- * @hidden
1330
- */
1331
- declare function process<A1, A2, A3, A4, A5, A6, A7, A8>(generator: (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8) => IterableIterator<any>): (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8) => Promise<any>;
1332
-
1333
1287
  /**
1334
1288
  * @hidden
1335
1289
  */
@@ -2185,5 +2139,5 @@ declare const types: {
2185
2139
  resilient: typeof resilient;
2186
2140
  };
2187
2141
 
2188
- 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, process, protect, recordActions, recordPatches, resolveIdentifier, resolvePath, setDevMode, setLivelinessChecking, setLivelynessChecking, setTypeChecking, splitJsonPath, types as t, toGenerator, toGeneratorFunction, tryReference, tryResolve, typecheck, types, unescapeJsonPath, unprotect, walk };
2142
+ 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 };
2189
2143
  export type { $EmptyObjectBrand, CustomTypeOptions, IActionContext, IActionRecorder, IActionTrackingMiddleware2Call, IActionTrackingMiddleware2Hooks, IActionTrackingMiddlewareHooks, IAnyComplexType, IAnyModelType, IAnyStateTreeNode, IAnyType, IArrayType, IComplexType, IDisposer, IJsonPatch, IMSTArray, IMSTMap, IMapType, IMaybe, IMaybeIType, IMaybeNull, IMiddlewareEvent, IMiddlewareEventType, IMiddlewareHandler, IModelReflectionData, IModelReflectionPropertiesData, IModelType, IOptionalIType, IPatchRecorder, IReferenceType, IReversibleJsonPatch, ISerializedActionCall, ISimpleType, ISnapshotProcessor, ISnapshotProcessors, IStateTreeNode, IType, ITypeUnion, Instance, LivelinessMode, LivelynessMode, ModelActions, ModelCreationType, ModelCreationType2, ModelInstanceType, ModelInstanceTypeProps, ModelPrimitive, ModelProperties, ModelPropertiesDeclaration, ModelPropertiesDeclarationToProperties, ModelSnapshotType, ModelSnapshotType2, OnReferenceInvalidated, OnReferenceInvalidatedEvent, OptionalDefaultValueOrFunction, ReferenceIdentifier, ReferenceOptions, ReferenceOptionsGetSet, ReferenceOptionsOnInvalidated, SnapshotIn, SnapshotOrInstance, SnapshotOut, TypeOfValue, TypeOrStateTreeNodeToStateTreeNode, UnionOptions, UnionStringArray, ValidOptionalValue, ValidOptionalValues, _CustomCSProcessor, _CustomJoin, _CustomOrOther, _NotCustomized };
@@ -1118,6 +1118,21 @@ class ScalarNode extends BaseNode {
1118
1118
  ScalarNode.prototype.die = mobx.action(ScalarNode.prototype.die);
1119
1119
 
1120
1120
  let nextNodeId = 1;
1121
+ var ObservableInstanceLifecycle;
1122
+ (function (ObservableInstanceLifecycle) {
1123
+ // the actual observable instance has not been created yet
1124
+ ObservableInstanceLifecycle[ObservableInstanceLifecycle["UNINITIALIZED"] = 0] = "UNINITIALIZED";
1125
+ // the actual observable instance is being created
1126
+ ObservableInstanceLifecycle[ObservableInstanceLifecycle["CREATING"] = 1] = "CREATING";
1127
+ // the actual observable instance has been created
1128
+ ObservableInstanceLifecycle[ObservableInstanceLifecycle["CREATED"] = 2] = "CREATED";
1129
+ })(ObservableInstanceLifecycle || (ObservableInstanceLifecycle = {}));
1130
+ var InternalEvents;
1131
+ (function (InternalEvents) {
1132
+ InternalEvents["Dispose"] = "dispose";
1133
+ InternalEvents["Patch"] = "patch";
1134
+ InternalEvents["Snapshot"] = "snapshot";
1135
+ })(InternalEvents || (InternalEvents = {}));
1121
1136
  const snapshotReactionOptions = {
1122
1137
  onError(e) {
1123
1138
  throw e;
@@ -1149,7 +1164,7 @@ class ObjectNode extends BaseNode {
1149
1164
  _autoUnbox = true; // unboxing is disabled when reading child nodes
1150
1165
  _isRunningAction = false; // only relevant for root
1151
1166
  _hasSnapshotReaction = false;
1152
- _observableInstanceState = 0 /* ObservableInstanceLifecycle.UNINITIALIZED */;
1167
+ _observableInstanceState = ObservableInstanceLifecycle.UNINITIALIZED;
1153
1168
  _childNodes;
1154
1169
  _initialSnapshot;
1155
1170
  _cachedInitialSnapshot;
@@ -1194,7 +1209,7 @@ class ObjectNode extends BaseNode {
1194
1209
  }
1195
1210
  createObservableInstanceIfNeeded(fireHooks = true) {
1196
1211
  if (this._observableInstanceState ===
1197
- 0 /* ObservableInstanceLifecycle.UNINITIALIZED */) {
1212
+ ObservableInstanceLifecycle.UNINITIALIZED) {
1198
1213
  this.createObservableInstance(fireHooks);
1199
1214
  }
1200
1215
  }
@@ -1205,7 +1220,7 @@ class ObjectNode extends BaseNode {
1205
1220
  throw fail("assertion failed: the creation of the observable instance must be done on the initializing phase");
1206
1221
  }
1207
1222
  }
1208
- this._observableInstanceState = 1 /* ObservableInstanceLifecycle.CREATING */;
1223
+ this._observableInstanceState = ObservableInstanceLifecycle.CREATING;
1209
1224
  // make sure the parent chain is created as well
1210
1225
  // array with parent chain from parent to child
1211
1226
  const parentChain = [];
@@ -1215,7 +1230,7 @@ class ObjectNode extends BaseNode {
1215
1230
  // this is done to avoid traversing the whole tree to the root when using
1216
1231
  // the same reference again
1217
1232
  while (parent?._observableInstanceState ===
1218
- 0 /* ObservableInstanceLifecycle.UNINITIALIZED */) {
1233
+ ObservableInstanceLifecycle.UNINITIALIZED) {
1219
1234
  parentChain.unshift(parent);
1220
1235
  parent = parent.parent;
1221
1236
  }
@@ -1240,7 +1255,7 @@ class ObjectNode extends BaseNode {
1240
1255
  finally {
1241
1256
  this._isRunningAction = false;
1242
1257
  }
1243
- this._observableInstanceState = 2 /* ObservableInstanceLifecycle.CREATED */;
1258
+ this._observableInstanceState = ObservableInstanceLifecycle.CREATED;
1244
1259
  this._snapshotComputed.trackAndCompute();
1245
1260
  if (this.isRoot) {
1246
1261
  this._addSnapshotReaction();
@@ -1354,7 +1369,7 @@ class ObjectNode extends BaseNode {
1354
1369
  if (!this.isAlive) {
1355
1370
  return this._snapshotUponDeath;
1356
1371
  }
1357
- return this._observableInstanceState === 2 /* ObservableInstanceLifecycle.CREATED */
1372
+ return this._observableInstanceState === ObservableInstanceLifecycle.CREATED
1358
1373
  ? this._getActualSnapshot()
1359
1374
  : this._getCachedInitialSnapshot();
1360
1375
  }
@@ -1417,7 +1432,7 @@ class ObjectNode extends BaseNode {
1417
1432
  this._autoUnbox = false;
1418
1433
  try {
1419
1434
  return this._observableInstanceState ===
1420
- 2 /* ObservableInstanceLifecycle.CREATED */
1435
+ ObservableInstanceLifecycle.CREATED
1421
1436
  ? this.type.getChildNode(this, subpath)
1422
1437
  : this._childNodes[subpath];
1423
1438
  }
@@ -1430,7 +1445,7 @@ class ObjectNode extends BaseNode {
1430
1445
  this._autoUnbox = false;
1431
1446
  try {
1432
1447
  return this._observableInstanceState ===
1433
- 2 /* ObservableInstanceLifecycle.CREATED */
1448
+ ObservableInstanceLifecycle.CREATED
1434
1449
  ? this.type.getChildren(this)
1435
1450
  : convertChildNodesToArray(this._childNodes);
1436
1451
  }
@@ -1516,7 +1531,7 @@ class ObjectNode extends BaseNode {
1516
1531
  }
1517
1532
  aboutToDie() {
1518
1533
  if (this._observableInstanceState ===
1519
- 0 /* ObservableInstanceLifecycle.UNINITIALIZED */) {
1534
+ ObservableInstanceLifecycle.UNINITIALIZED) {
1520
1535
  return;
1521
1536
  }
1522
1537
  this.getChildren().forEach(node => {
@@ -1525,8 +1540,8 @@ class ObjectNode extends BaseNode {
1525
1540
  // beforeDestroy should run before the disposers since else we could end up in a situation where
1526
1541
  // a disposer added with addDisposer at this stage (beforeDestroy) is actually never released
1527
1542
  this.baseAboutToDie();
1528
- this._internalEventsEmit("dispose" /* InternalEvents.Dispose */);
1529
- this._internalEventsClear("dispose" /* InternalEvents.Dispose */);
1543
+ this._internalEventsEmit(InternalEvents.Dispose);
1544
+ this._internalEventsClear(InternalEvents.Dispose);
1530
1545
  }
1531
1546
  finalizeDeath() {
1532
1547
  // invariant: not called directly but from "die"
@@ -1542,42 +1557,42 @@ class ObjectNode extends BaseNode {
1542
1557
  }
1543
1558
  onSnapshot(onChange) {
1544
1559
  this._addSnapshotReaction();
1545
- return this._internalEventsRegister("snapshot" /* InternalEvents.Snapshot */, onChange);
1560
+ return this._internalEventsRegister(InternalEvents.Snapshot, onChange);
1546
1561
  }
1547
1562
  emitSnapshot(snapshot) {
1548
- this._internalEventsEmit("snapshot" /* InternalEvents.Snapshot */, snapshot);
1563
+ this._internalEventsEmit(InternalEvents.Snapshot, snapshot);
1549
1564
  }
1550
1565
  onPatch(handler) {
1551
- return this._internalEventsRegister("patch" /* InternalEvents.Patch */, handler);
1566
+ return this._internalEventsRegister(InternalEvents.Patch, handler);
1552
1567
  }
1553
1568
  emitPatch(basePatch, source) {
1554
- if (this._internalEventsHasSubscribers("patch" /* InternalEvents.Patch */)) {
1569
+ if (this._internalEventsHasSubscribers(InternalEvents.Patch)) {
1555
1570
  const localizedPatch = {
1556
1571
  ...basePatch,
1557
- path: `${source.path.substr(this.path.length)}/${basePatch.path}` // calculate the relative path of the patch
1572
+ path: `${source.path.slice(this.path.length)}/${basePatch.path}` // calculate the relative path of the patch
1558
1573
  };
1559
1574
  const [patch, reversePatch] = splitPatch(localizedPatch);
1560
- this._internalEventsEmit("patch" /* InternalEvents.Patch */, patch, reversePatch);
1575
+ this._internalEventsEmit(InternalEvents.Patch, patch, reversePatch);
1561
1576
  }
1562
1577
  if (this.parent) {
1563
1578
  this.parent.emitPatch(basePatch, source);
1564
1579
  }
1565
1580
  }
1566
1581
  hasDisposer(disposer) {
1567
- return this._internalEventsHas("dispose" /* InternalEvents.Dispose */, disposer);
1582
+ return this._internalEventsHas(InternalEvents.Dispose, disposer);
1568
1583
  }
1569
1584
  addDisposer(disposer) {
1570
1585
  if (!this.hasDisposer(disposer)) {
1571
- this._internalEventsRegister("dispose" /* InternalEvents.Dispose */, disposer, true);
1586
+ this._internalEventsRegister(InternalEvents.Dispose, disposer, true);
1572
1587
  return;
1573
1588
  }
1574
1589
  throw fail("cannot add a disposer when it is already registered for execution");
1575
1590
  }
1576
1591
  removeDisposer(disposer) {
1577
- if (!this._internalEventsHas("dispose" /* InternalEvents.Dispose */, disposer)) {
1592
+ if (!this._internalEventsHas(InternalEvents.Dispose, disposer)) {
1578
1593
  throw fail("cannot remove a disposer which was never registered for execution");
1579
1594
  }
1580
- this._internalEventsUnregister("dispose" /* InternalEvents.Dispose */, disposer);
1595
+ this._internalEventsUnregister(InternalEvents.Dispose, disposer);
1581
1596
  }
1582
1597
  removeMiddleware(middleware) {
1583
1598
  if (this.middlewares) {
@@ -2567,22 +2582,47 @@ function isActionContextThisOrChildOf(actionContext, parentOrThis) {
2567
2582
  }
2568
2583
 
2569
2584
  const MAX_STRINGIFY_DEPTH = 3;
2585
+ const MAX_STRINGIFY_ARRAY_ITEMS = 10;
2586
+ const MAX_STRINGIFY_OBJECT_KEYS = 20;
2587
+ const MAX_STRINGIFY_STRING_LENGTH = 100;
2588
+ // Recursively cap depth, array length, object key count, and string length so a
2589
+ // huge offending snapshot degrades into readable, bounded context instead of a
2590
+ // wall of text that then gets sliced mid-structure. The depth cap also bounds
2591
+ // recursion on circular structures.
2592
+ function truncateForStringify(value, depth) {
2593
+ if (typeof value === "string") {
2594
+ return value.length > MAX_STRINGIFY_STRING_LENGTH
2595
+ ? `${value.substring(0, MAX_STRINGIFY_STRING_LENGTH)}… (${value.length - MAX_STRINGIFY_STRING_LENGTH} more characters)`
2596
+ : value;
2597
+ }
2598
+ if (value === null || typeof value !== "object") {
2599
+ return value;
2600
+ }
2601
+ if (depth >= MAX_STRINGIFY_DEPTH) {
2602
+ return Array.isArray(value) ? "[…]" : "{…}";
2603
+ }
2604
+ if (Array.isArray(value)) {
2605
+ const items = value
2606
+ .slice(0, MAX_STRINGIFY_ARRAY_ITEMS)
2607
+ .map(item => truncateForStringify(item, depth + 1));
2608
+ if (value.length > MAX_STRINGIFY_ARRAY_ITEMS) {
2609
+ items.push(`… ${value.length - MAX_STRINGIFY_ARRAY_ITEMS} more items`);
2610
+ }
2611
+ return items;
2612
+ }
2613
+ const keys = Object.keys(value);
2614
+ const result = {};
2615
+ for (const key of keys.slice(0, MAX_STRINGIFY_OBJECT_KEYS)) {
2616
+ result[key] = truncateForStringify(value[key], depth + 1);
2617
+ }
2618
+ if (keys.length > MAX_STRINGIFY_OBJECT_KEYS) {
2619
+ result["…"] = `${keys.length - MAX_STRINGIFY_OBJECT_KEYS} more keys`;
2620
+ }
2621
+ return result;
2622
+ }
2570
2623
  function safeStringify(value) {
2571
2624
  try {
2572
- const ancestors = [];
2573
- return JSON.stringify(value, function (_key, val) {
2574
- if (val !== null && typeof val === "object") {
2575
- while (ancestors.length > 0 &&
2576
- ancestors[ancestors.length - 1] !== this) {
2577
- ancestors.pop();
2578
- }
2579
- if (ancestors.length >= MAX_STRINGIFY_DEPTH) {
2580
- return Array.isArray(val) ? "[…]" : "{…}";
2581
- }
2582
- ancestors.push(val);
2583
- }
2584
- return val;
2585
- });
2625
+ return JSON.stringify(truncateForStringify(value, 0));
2586
2626
  }
2587
2627
  catch (e) {
2588
2628
  // istanbul ignore next
@@ -3013,31 +3053,6 @@ function convertChildNodesToArray(childNodes) {
3013
3053
  return result;
3014
3054
  }
3015
3055
 
3016
- // based on: https://github.com/mobxjs/mobx-utils/blob/master/src/async-action.ts
3017
- /*
3018
- All contents of this file are deprecated.
3019
-
3020
- The term `process` has been replaced with `flow` to avoid conflicts with the
3021
- global `process` object.
3022
-
3023
- Refer to `flow.ts` for any further changes to this implementation.
3024
- */
3025
- const DEPRECATION_MESSAGE = "See https://github.com/mobxjs/mobx-state-tree/issues/399 for more information. " +
3026
- "Note that the middleware event types starting with `process` now start with `flow`.";
3027
- /**
3028
- * @hidden
3029
- *
3030
- * @deprecated has been renamed to `flow()`.
3031
- * See https://github.com/mobxjs/mobx-state-tree/issues/399 for more information.
3032
- * Note that the middleware event types starting with `process` now start with `flow`.
3033
- *
3034
- * @returns {Promise}
3035
- */
3036
- function process$1(asyncAction) {
3037
- deprecated("process", `\`process()\` has been renamed to \`flow()\`. ${DEPRECATION_MESSAGE}`);
3038
- return flow(asyncAction);
3039
- }
3040
-
3041
3056
  const plainObjectString = Object.toString();
3042
3057
  /**
3043
3058
  * @internal
@@ -3328,25 +3343,6 @@ class EventHandlers {
3328
3343
  }
3329
3344
  }
3330
3345
  }
3331
- /**
3332
- * @internal
3333
- * @hidden
3334
- */
3335
- const deprecated = function (id, message) {
3336
- // skip if running production
3337
- if (!devMode()) {
3338
- return;
3339
- }
3340
- // warn if hasn't been warned before
3341
- if (deprecated.ids && !deprecated.ids.hasOwnProperty(id)) {
3342
- warnError(`Deprecation warning: ${message}`);
3343
- }
3344
- // mark as warned to avoid duplicate warn message
3345
- if (deprecated.ids) {
3346
- deprecated.ids[id] = true;
3347
- }
3348
- };
3349
- deprecated.ids = {};
3350
3346
  /**
3351
3347
  * @internal
3352
3348
  * @hidden
@@ -4299,9 +4295,9 @@ class ArrayType extends ComplexType {
4299
4295
  return node.storedValue.slice();
4300
4296
  }
4301
4297
  getChildNode(node, key) {
4302
- const index = Number(key);
4303
- if (index < node.storedValue.length) {
4304
- return node.storedValue[index];
4298
+ const child = node.storedValue[Number(key)];
4299
+ if (child) {
4300
+ return child;
4305
4301
  }
4306
4302
  throw fail(`Not a child: ${key}`);
4307
4303
  }
@@ -4468,7 +4464,7 @@ function reconcileArrayChildren(parent, childType, oldNodes, newValues, newPaths
4468
4464
  // both are empty, end
4469
4465
  break;
4470
4466
  }
4471
- else if (!hasNewNode) {
4467
+ else if (oldNode && !hasNewNode) {
4472
4468
  // new one does not exists
4473
4469
  nothingChanged = false;
4474
4470
  oldNodes.splice(i, 1);
@@ -7068,7 +7064,6 @@ exports.joinJsonPath = joinJsonPath;
7068
7064
  exports.onAction = onAction;
7069
7065
  exports.onPatch = onPatch;
7070
7066
  exports.onSnapshot = onSnapshot;
7071
- exports.process = process$1;
7072
7067
  exports.protect = protect;
7073
7068
  exports.recordActions = recordActions;
7074
7069
  exports.recordPatches = recordPatches;