@jbrowse/mobx-state-tree 5.11.0 → 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 +225 -24
- package/dist/index.d.ts +1 -47
- package/dist/mobx-state-tree.cjs +91 -84
- package/dist/mobx-state-tree.cjs.map +1 -1
- package/dist/mobx-state-tree.mjs +92 -84
- package/dist/mobx-state-tree.mjs.map +1 -1
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -1,27 +1,228 @@
|
|
|
1
1
|
# @jbrowse/mobx-state-tree
|
|
2
2
|
|
|
3
|
-
Fork of mobx-state-tree v5.4.2 for use in
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
and a fallback type is used instead of crashing the entire state tree. This is
|
|
17
|
-
useful for arrays or maps that may contain unknown or invalid entries (e.g.
|
|
18
|
-
plugin types that are not installed). It takes a primary type, a fallback type,
|
|
19
|
-
and a `createFallbackSnapshot` callback that receives the error and original
|
|
20
|
-
snapshot. Note: `isValidSnapshot` always returns success for resilient types,
|
|
21
|
-
meaning any value is considered a valid snapshot. Validation is deferred to
|
|
22
|
-
instantiation time, where failures are caught and routed to the fallback
|
|
23
|
-
- removed NonEmptyObject annotation (also at upstream in post v5 versions)
|
|
24
|
-
- replaced `unique symbol` phantom properties (`$emptyObject`, `$stateTreeNodeType`) with
|
|
3
|
+
Fork of [mobx-state-tree](https://mobx-state-tree.js.org) v5.4.2 maintained for use in
|
|
4
|
+
[JBrowse 2](https://jbrowse.org). All upstream types and APIs are available — this page
|
|
5
|
+
documents only the additions and changes made in this fork.
|
|
6
|
+
|
|
7
|
+
## Infrastructure changes
|
|
8
|
+
|
|
9
|
+
- Updated TypeScript and import paths to use explicit file extensions
|
|
10
|
+
- Replaced `process.env.NODE_ENV` with an exported `setDevMode()` function
|
|
11
|
+
- Converted tests from Jest to Vitest
|
|
12
|
+
- Replaced tslint with eslint + typescript-eslint
|
|
13
|
+
- Dual CJS/ESM build (avoids issues when both are imported in the same Vite build)
|
|
14
|
+
- Removed unused dependencies and the `NonEmptyObject` annotation
|
|
15
|
+
- Replaced `unique symbol` phantom properties (`$emptyObject`, `$stateTreeNodeType`) with
|
|
25
16
|
exported string-keyed brand interfaces (`$EmptyObjectBrand`, `$__mstStateTreeNodeType__`),
|
|
26
|
-
fixing tsgo TS4058/TS4023 errors when MST types
|
|
27
|
-
|
|
17
|
+
fixing tsgo TS4058/TS4023 errors when MST types appear in exported function return types
|
|
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
|
+
|
|
92
|
+
## Added APIs
|
|
93
|
+
|
|
94
|
+
### `types.resilient`
|
|
95
|
+
|
|
96
|
+
Wraps a type so that if instantiation fails (e.g. because the snapshot is from an unknown
|
|
97
|
+
plugin that is not installed), the error is caught and a fallback type is used instead of
|
|
98
|
+
crashing the entire state tree.
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
const PluginWidget = types.resilient(
|
|
102
|
+
KnownWidget,
|
|
103
|
+
UnknownWidget,
|
|
104
|
+
(error, originalSnapshot) => ({ kind: "unknown", raw: originalSnapshot })
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
// Arrays of plugins stay alive even if one entry is unrecognized
|
|
108
|
+
const Store = types.model({
|
|
109
|
+
widgets: types.array(PluginWidget)
|
|
110
|
+
})
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`types.resilient` takes three arguments:
|
|
114
|
+
|
|
115
|
+
- `type` — the primary type to try first
|
|
116
|
+
- `fallbackType` — the type to use when the primary fails
|
|
117
|
+
- `createFallbackSnapshot(error, originalSnapshot)` — a callback that receives the caught
|
|
118
|
+
error and the original snapshot, and returns a valid snapshot for the fallback type
|
|
119
|
+
|
|
120
|
+
**Important caveat:** `isValidSnapshot` always returns success for a resilient type. Any
|
|
121
|
+
value is considered a valid snapshot — validation is deferred to instantiation time, where
|
|
122
|
+
failures are caught and routed to the fallback.
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
### `types.stripDefault`
|
|
127
|
+
|
|
128
|
+
Like `types.optional`, but omits the property key from the parent model's snapshot entirely
|
|
129
|
+
when the value equals the default.
|
|
130
|
+
|
|
131
|
+
#### Background: snapshots and `types.optional`
|
|
132
|
+
|
|
133
|
+
In MST, a **snapshot** is the plain JSON representation of your model — what you'd get from
|
|
134
|
+
`getSnapshot(model)` and what you'd pass to `Model.create(...)`. Snapshots are used for
|
|
135
|
+
serialization, persistence, and undo/redo.
|
|
136
|
+
|
|
137
|
+
`types.optional` lets you define a property with a default value so it can be omitted when
|
|
138
|
+
creating a model:
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
const Settings = types.model({
|
|
142
|
+
theme: types.optional(types.string, "light")
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
const s = Settings.create() // theme is "light"
|
|
146
|
+
getSnapshot(s) // { theme: "light" }
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Even though `"light"` is just the default, it always appears in the snapshot. If you store
|
|
150
|
+
or diff these snapshots, every instance carries that redundant data.
|
|
151
|
+
|
|
152
|
+
#### What `types.stripDefault` does
|
|
153
|
+
|
|
154
|
+
`types.stripDefault` works exactly like `types.optional` at runtime — the property gets its
|
|
155
|
+
default when missing — but the key is **left out of the snapshot entirely** when the value
|
|
156
|
+
equals the default:
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
const Settings = types.model({
|
|
160
|
+
theme: types.stripDefault(types.string, "light")
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
const s = Settings.create()
|
|
164
|
+
getSnapshot(s) // {} ← key omitted because value equals default
|
|
165
|
+
|
|
166
|
+
s.theme = "dark"
|
|
167
|
+
getSnapshot(s) // { theme: "dark" }
|
|
168
|
+
|
|
169
|
+
s.theme = "light"
|
|
170
|
+
getSnapshot(s) // {} ← omitted again
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
#### Why this matters
|
|
174
|
+
|
|
175
|
+
Without `stripDefault`, keeping defaults out of snapshots requires a manual
|
|
176
|
+
`postProcessSnapshot` on every model. `stripDefault` handles this automatically per-property.
|
|
177
|
+
|
|
178
|
+
This is especially useful when:
|
|
179
|
+
|
|
180
|
+
- Snapshots are stored or synced and you want to minimize their size
|
|
181
|
+
- You diff snapshots (e.g. for undo/redo or change detection) and want default values to
|
|
182
|
+
appear as "no change" rather than an explicit write
|
|
183
|
+
- You have many optional fields and don't want boilerplate `postProcessSnapshot`
|
|
184
|
+
|
|
185
|
+
#### How the default comparison works
|
|
186
|
+
|
|
187
|
+
The comparison is done against the **normalized** default snapshot, not the raw value you
|
|
188
|
+
passed in. MST instantiates the subtype with the default once, reads back its snapshot
|
|
189
|
+
(which applies any nested model defaults and post-processing), and caches that as the
|
|
190
|
+
reference. This means a complex nested default that gains extra fields at instantiation time
|
|
191
|
+
will still compare correctly.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
### Reflection API additions
|
|
196
|
+
|
|
197
|
+
These utilities expose type metadata that is useful for building generic tooling (e.g.
|
|
198
|
+
editors, inspectors, plugin systems) that need to introspect an MST type at runtime.
|
|
199
|
+
|
|
200
|
+
**`getChildType(node, propertyName?)`** — returns the declared MST type of a child
|
|
201
|
+
property on a model, array, or map instance. For arrays and maps the property name is
|
|
202
|
+
ignored (all children share one element type).
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
const Box = types.model({ x: types.number, y: types.number })
|
|
206
|
+
const box = Box.create({ x: 1, y: 2 })
|
|
207
|
+
|
|
208
|
+
getChildType(box, "x").name // "number"
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**`getUnionSubtypes(type)`** — given a `types.union` type, returns the array of its member
|
|
212
|
+
types. Useful when you need to enumerate what a union can hold.
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
const Shape = types.union(Circle, Square, Triangle)
|
|
216
|
+
|
|
217
|
+
getUnionSubtypes(Shape) // [Circle, Square, Triangle]
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**`getDefaultInstanceOrSnapshot(optionalType)`** — returns the default value (or snapshot)
|
|
221
|
+
declared on a `types.optional` or `types.stripDefault` type. Lets generic tooling read the
|
|
222
|
+
default without having to create a model instance.
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
const t = types.optional(types.string, "hello")
|
|
226
|
+
|
|
227
|
+
t.getDefaultInstanceOrSnapshot() // "hello"
|
|
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,
|
|
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 };
|
package/dist/mobx-state-tree.cjs
CHANGED
|
@@ -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 =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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 ===
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
1529
|
-
this._internalEventsClear(
|
|
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(
|
|
1560
|
+
return this._internalEventsRegister(InternalEvents.Snapshot, onChange);
|
|
1546
1561
|
}
|
|
1547
1562
|
emitSnapshot(snapshot) {
|
|
1548
|
-
this._internalEventsEmit(
|
|
1563
|
+
this._internalEventsEmit(InternalEvents.Snapshot, snapshot);
|
|
1549
1564
|
}
|
|
1550
1565
|
onPatch(handler) {
|
|
1551
|
-
return this._internalEventsRegister(
|
|
1566
|
+
return this._internalEventsRegister(InternalEvents.Patch, handler);
|
|
1552
1567
|
}
|
|
1553
1568
|
emitPatch(basePatch, source) {
|
|
1554
|
-
if (this._internalEventsHasSubscribers(
|
|
1569
|
+
if (this._internalEventsHasSubscribers(InternalEvents.Patch)) {
|
|
1555
1570
|
const localizedPatch = {
|
|
1556
1571
|
...basePatch,
|
|
1557
|
-
path: `${source.path.
|
|
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(
|
|
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(
|
|
1582
|
+
return this._internalEventsHas(InternalEvents.Dispose, disposer);
|
|
1568
1583
|
}
|
|
1569
1584
|
addDisposer(disposer) {
|
|
1570
1585
|
if (!this.hasDisposer(disposer)) {
|
|
1571
|
-
this._internalEventsRegister(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
|
4303
|
-
if (
|
|
4304
|
-
return
|
|
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);
|
|
@@ -5901,6 +5897,18 @@ function defaultSnapshotEquals(a, b) {
|
|
|
5901
5897
|
a !== null &&
|
|
5902
5898
|
typeof b === "object" &&
|
|
5903
5899
|
b !== null) {
|
|
5900
|
+
// Cheap structural short-circuit before the full stringify compare: a
|
|
5901
|
+
// value of a different size can't equal the default, so the common strip
|
|
5902
|
+
// case (non-empty value vs an empty `[]`/`{}` default) avoids stringifying
|
|
5903
|
+
// a potentially large snapshot on every getSnapshot.
|
|
5904
|
+
if (Array.isArray(a) !== Array.isArray(b)) {
|
|
5905
|
+
return false;
|
|
5906
|
+
}
|
|
5907
|
+
const aSize = Array.isArray(a) ? a.length : Object.keys(a).length;
|
|
5908
|
+
const bSize = Array.isArray(b) ? b.length : Object.keys(b).length;
|
|
5909
|
+
if (aSize !== bSize) {
|
|
5910
|
+
return false;
|
|
5911
|
+
}
|
|
5904
5912
|
return JSON.stringify(a) === JSON.stringify(b);
|
|
5905
5913
|
}
|
|
5906
5914
|
return false;
|
|
@@ -7056,7 +7064,6 @@ exports.joinJsonPath = joinJsonPath;
|
|
|
7056
7064
|
exports.onAction = onAction;
|
|
7057
7065
|
exports.onPatch = onPatch;
|
|
7058
7066
|
exports.onSnapshot = onSnapshot;
|
|
7059
|
-
exports.process = process$1;
|
|
7060
7067
|
exports.protect = protect;
|
|
7061
7068
|
exports.recordActions = recordActions;
|
|
7062
7069
|
exports.recordPatches = recordPatches;
|