mobx-keystone 1.25.0 → 2.0.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/CHANGELOG.md +123 -0
- package/dist/mobx-keystone.esm.js +1478 -952
- package/dist/mobx-keystone.esm.mjs +1478 -952
- package/dist/mobx-keystone.umd.js +1483 -952
- package/dist/types/actionMiddlewares/actionSerialization/dateSerializer.d.ts +1 -1
- package/dist/types/dataModel/dataModelInstanceCache.d.ts +1 -0
- package/dist/types/deepChange/onDeepChange.d.ts +9 -0
- package/dist/types/parent/detach.d.ts +1 -1
- package/dist/types/parent/findChildren.d.ts +1 -1
- package/dist/types/patch/applyPatches.d.ts +2 -0
- package/dist/types/redux/connectReduxDevTools.d.ts +2 -1
- package/dist/types/snapshot/SnapshotOf.d.ts +2 -2
- package/dist/types/standardActions/arrayActions.d.ts +1 -1
- package/dist/types/treeUtils/sandbox.d.ts +0 -4
- package/dist/types/types/TypeCheckError.d.ts +1 -0
- package/dist/types/types/utility/typesRefinement.d.ts +2 -2
- package/dist/types/utils/forEachWithDelayedThrow.d.ts +1 -0
- package/dist/types/utils/index.d.ts +13 -0
- package/dist/types/utils/mapUtils.d.ts +2 -2
- package/dist/types/utils/setLike.d.ts +1 -0
- package/package.json +1 -1
- package/src/action/applyAction.ts +1 -1
- package/src/action/middleware.ts +17 -36
- package/src/action/modelFlow.ts +4 -5
- package/src/action/mutationBatch.ts +10 -10
- package/src/action/pendingActions.ts +3 -4
- package/src/actionMiddlewares/actionSerialization/actionSerialization.ts +19 -14
- package/src/actionMiddlewares/actionSerialization/applySerializedAction.ts +29 -20
- package/src/actionMiddlewares/actionSerialization/arraySerializer.ts +1 -1
- package/src/actionMiddlewares/actionSerialization/dateSerializer.ts +4 -3
- package/src/actionMiddlewares/actionSerialization/mapSerializer.ts +4 -12
- package/src/actionMiddlewares/actionSerialization/setSerializer.ts +4 -13
- package/src/actionMiddlewares/actionTrackingMiddleware.ts +11 -13
- package/src/actionMiddlewares/transactionMiddleware.ts +42 -11
- package/src/actionMiddlewares/undoMiddleware.ts +65 -46
- package/src/actionMiddlewares/utils.ts +2 -1
- package/src/computedTree/computedTree.ts +14 -3
- package/src/context/context.ts +17 -45
- package/src/dataModel/BaseDataModel.ts +20 -16
- package/src/dataModel/dataModelInstanceCache.ts +8 -0
- package/src/deepChange/onDeepChange.ts +179 -24
- package/src/frozen/Frozen.ts +50 -33
- package/src/model/BaseModel.ts +4 -9
- package/src/model/newModel.ts +21 -24
- package/src/model/utils.ts +2 -2
- package/src/modelShared/modelClassInitializer.ts +3 -2
- package/src/modelShared/modelDecorator.ts +34 -14
- package/src/modelShared/modelInfo.ts +1 -1
- package/src/modelShared/prop.ts +6 -9
- package/src/modelShared/sharedInternalModel.ts +16 -3
- package/src/parent/detach.ts +1 -1
- package/src/parent/findChildren.ts +4 -7
- package/src/parent/onChildAttachedTo.ts +44 -28
- package/src/parent/path.ts +5 -3
- package/src/parent/setParent.ts +7 -0
- package/src/parent/walkTree.ts +21 -37
- package/src/patch/applyPatches.ts +69 -34
- package/src/patch/emitPatch.ts +142 -26
- package/src/patch/jsonPatch.ts +5 -0
- package/src/patch/patchRecorder.ts +18 -14
- package/src/redux/connectReduxDevTools.ts +24 -18
- package/src/redux/redux.ts +5 -21
- package/src/ref/core.ts +18 -2
- package/src/rootStore/attachDetach.ts +27 -16
- package/src/rootStore/rootStore.ts +10 -6
- package/src/snapshot/SnapshotOf.ts +2 -2
- package/src/snapshot/applySnapshot.ts +1 -1
- package/src/snapshot/clone.ts +1 -2
- package/src/snapshot/cloneTreeValue.ts +1 -2
- package/src/snapshot/fromModelSnapshot.ts +6 -2
- package/src/snapshot/internal.ts +22 -9
- package/src/snapshot/onSnapshot.ts +12 -1
- package/src/snapshot/reconcileModelSnapshot.ts +6 -6
- package/src/snapshot/reconcilePlainObjectSnapshot.ts +5 -4
- package/src/standardActions/arrayActions.ts +12 -2
- package/src/standardActions/objectActions.ts +3 -2
- package/src/transforms/ImmutableDate.ts +4 -0
- package/src/transforms/asMap.ts +3 -1
- package/src/treeUtils/deepEquals.ts +15 -13
- package/src/treeUtils/draft.ts +8 -0
- package/src/treeUtils/sandbox.ts +31 -27
- package/src/tweaker/core.ts +2 -4
- package/src/tweaker/tweak.ts +2 -1
- package/src/tweaker/tweakArray.ts +83 -20
- package/src/tweaker/tweakPlainObject.ts +76 -23
- package/src/tweaker/typeChecking.ts +124 -15
- package/src/types/TypeCheckError.ts +17 -19
- package/src/types/createCachedTypeCheck.ts +27 -2
- package/src/types/objectBased/typesDataModelData.ts +4 -2
- package/src/types/objectBased/typesModel.ts +4 -2
- package/src/types/objectBased/typesObject.ts +20 -16
- package/src/types/objectBased/typesRecord.ts +6 -13
- package/src/types/objectBased/typesRef.ts +2 -2
- package/src/types/primitiveBased/typesEnum.ts +4 -2
- package/src/types/primitiveBased/typesPrimitive.ts +9 -4
- package/src/types/typeCheckErrorUtils.ts +1 -0
- package/src/types/utility/typesCodecSupport.ts +97 -56
- package/src/types/utility/typesMap.ts +24 -41
- package/src/types/utility/typesRefinement.ts +3 -2
- package/src/types/utility/typesSet.ts +24 -0
- package/src/utils/ModelPool.ts +3 -3
- package/src/utils/chainFns.ts +4 -0
- package/src/utils/decorators.ts +1 -1
- package/src/utils/errorDiagnostics.ts +6 -2
- package/src/utils/forEachWithDelayedThrow.ts +83 -0
- package/src/utils/index.ts +34 -2
- package/src/utils/mapUtils.ts +3 -7
- package/src/utils/setIfDifferent.ts +3 -2
- package/src/utils/setLike.ts +134 -0
- package/src/wrappers/ArraySet.ts +5 -9
- package/src/wrappers/ObjectMap.ts +15 -11
- package/src/wrappers/asMap.ts +30 -18
- package/src/wrappers/asSet.ts +36 -12
- package/dist/types/action/modelFlowPromiseGenerator.d.ts +0 -1
- package/src/action/modelFlowPromiseGenerator.ts +0 -127
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { assertIsPrimitive } from "../../utils"
|
|
1
|
+
import { assertIsPrimitive, isEqualOrBothNaN } from "../../utils"
|
|
2
2
|
import type { PrimitiveValue } from "../../utils/types"
|
|
3
3
|
import { registerStandardTypeResolver, type StandardTypeResolverFn } from "../resolveTypeChecker"
|
|
4
4
|
import type { AnyStandardType, IdentityType } from "../schemas"
|
|
@@ -31,7 +31,12 @@ export function typesLiteral<T extends PrimitiveValue>(literal: T): IdentityType
|
|
|
31
31
|
typeName = "null"
|
|
32
32
|
break
|
|
33
33
|
default:
|
|
34
|
-
typeName =
|
|
34
|
+
typeName =
|
|
35
|
+
typeof literal === "bigint"
|
|
36
|
+
? `${literal}n`
|
|
37
|
+
: typeof literal === "number" && !Number.isFinite(literal)
|
|
38
|
+
? String(literal)
|
|
39
|
+
: JSON.stringify(literal)
|
|
35
40
|
break
|
|
36
41
|
}
|
|
37
42
|
|
|
@@ -41,7 +46,7 @@ export function typesLiteral<T extends PrimitiveValue>(literal: T): IdentityType
|
|
|
41
46
|
TypeCheckerBaseType.Primitive,
|
|
42
47
|
|
|
43
48
|
(value, path, typeCheckedValue) =>
|
|
44
|
-
value
|
|
49
|
+
isEqualOrBothNaN(value, literal)
|
|
45
50
|
? null
|
|
46
51
|
: new TypeCheckError({
|
|
47
52
|
path,
|
|
@@ -53,7 +58,7 @@ export function typesLiteral<T extends PrimitiveValue>(literal: T): IdentityType
|
|
|
53
58
|
() => typeName,
|
|
54
59
|
typeInfoGen,
|
|
55
60
|
|
|
56
|
-
(value) => (value
|
|
61
|
+
(value) => (isEqualOrBothNaN(value, literal) ? thisTc : null),
|
|
57
62
|
undefined,
|
|
58
63
|
undefined
|
|
59
64
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isObservableArray, isObservableObject, remove } from "mobx"
|
|
2
2
|
import type { ModelPropTransform } from "../../modelShared/prop"
|
|
3
|
-
import { isArray, isObject, lazy } from "../../utils"
|
|
3
|
+
import { copyOwnEnumerableProps, isArray, isObject, lazy } from "../../utils"
|
|
4
4
|
import { setIfDifferent } from "../../utils/setIfDifferent"
|
|
5
5
|
import { ArrayTypeInfo, typesArray } from "../arrayBased/typesArray"
|
|
6
6
|
import { TupleTypeInfo, typesTuple } from "../arrayBased/typesTuple"
|
|
@@ -19,23 +19,26 @@ import {
|
|
|
19
19
|
type RuntimeAdapter,
|
|
20
20
|
} from "./typesCodecCore"
|
|
21
21
|
import { OrTypeInfo, typesOr } from "./typesOr"
|
|
22
|
-
import { RefinementTypeInfo } from "./typesRefinement"
|
|
22
|
+
import { RefinementTypeInfo, typesRefinement } from "./typesRefinement"
|
|
23
23
|
import { SkipCheckTypeInfo, typesSkipCheck } from "./typesSkipCheck"
|
|
24
24
|
import { TagTypeInfo, typesTag } from "./typesTag"
|
|
25
25
|
|
|
26
26
|
const codecSupportCache = new WeakMap<AnyStandardType, ResolvedCodecSupport>()
|
|
27
27
|
|
|
28
28
|
function getArrayIndex(prop: PropertyKey): number | undefined {
|
|
29
|
-
// Proxy
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return
|
|
29
|
+
// Proxy traps receive string or symbol keys, including strings for numeric indices.
|
|
30
|
+
if (typeof prop !== "string") return undefined
|
|
31
|
+
const first = prop.charCodeAt(0)
|
|
32
|
+
if (first < 48 || first > 57) return undefined
|
|
33
|
+
|
|
34
|
+
const index = Number(prop)
|
|
35
|
+
return Number.isInteger(index) && index >= 0 && index < 0xffffffff && String(index) === prop
|
|
36
|
+
? index
|
|
37
|
+
: undefined
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
function normalizeArrayIndex(index: number, length: number): number {
|
|
41
|
+
index = Math.trunc(index) || 0
|
|
39
42
|
if (index < 0) {
|
|
40
43
|
return Math.max(length + index, 0)
|
|
41
44
|
}
|
|
@@ -44,6 +47,7 @@ function normalizeArrayIndex(index: number, length: number): number {
|
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
function resolveArrayAtIndex(index: number, length: number): number | undefined {
|
|
50
|
+
index = Math.trunc(index) || 0
|
|
47
51
|
const resolvedIndex = index < 0 ? length + index : index
|
|
48
52
|
|
|
49
53
|
if (resolvedIndex < 0 || resolvedIndex >= length) {
|
|
@@ -90,11 +94,7 @@ function objectLikeToStored(
|
|
|
90
94
|
return runtime as never
|
|
91
95
|
}
|
|
92
96
|
|
|
93
|
-
|
|
94
|
-
for (const key of Object.keys(runtime)) {
|
|
95
|
-
stored[key] = convertValue(key, runtime[key])
|
|
96
|
-
}
|
|
97
|
-
return stored
|
|
97
|
+
return copyOwnEnumerableProps({}, runtime, (value, key) => convertValue(key, value))
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
/**
|
|
@@ -155,8 +155,7 @@ function createObjectRuntimeAdapter(
|
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
Reflect.set(target, prop, value)
|
|
159
|
-
return true
|
|
158
|
+
return Reflect.set(target, prop, value)
|
|
160
159
|
},
|
|
161
160
|
|
|
162
161
|
...objectRecordProxyTraps,
|
|
@@ -217,8 +216,7 @@ function createRecordRuntimeAdapter(
|
|
|
217
216
|
return true
|
|
218
217
|
}
|
|
219
218
|
|
|
220
|
-
Reflect.set(target, prop, value)
|
|
221
|
-
return true
|
|
219
|
+
return Reflect.set(target, prop, value)
|
|
222
220
|
},
|
|
223
221
|
|
|
224
222
|
...objectRecordProxyTraps,
|
|
@@ -250,7 +248,9 @@ function createArrayLikeRuntimeAdapter(
|
|
|
250
248
|
const storedByRuntime = new WeakMap<unknown[], unknown[]>()
|
|
251
249
|
|
|
252
250
|
const decodeIndex = (target: unknown[], index: number) =>
|
|
253
|
-
index < 0 ||
|
|
251
|
+
index < 0 ||
|
|
252
|
+
index >= target.length ||
|
|
253
|
+
(!isObservableArray(target) && !Reflect.has(target, index))
|
|
254
254
|
? undefined
|
|
255
255
|
: getItemAdapter(index).toRuntime(target[index], (newStoredValue) => {
|
|
256
256
|
target[index] = newStoredValue
|
|
@@ -265,13 +265,18 @@ function createArrayLikeRuntimeAdapter(
|
|
|
265
265
|
return Reflect.apply(method, receiver, args)
|
|
266
266
|
}
|
|
267
267
|
const materializeRuntimeValues = (target: unknown[]) =>
|
|
268
|
-
|
|
268
|
+
target.map((_value, index) => decodeIndex(target, index))
|
|
269
269
|
const replaceStoredValues = (target: unknown[], runtimeValues: unknown[]) => {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
target.
|
|
273
|
-
|
|
274
|
-
|
|
270
|
+
const storedValues = runtimeValues.map((value, index) => getItemAdapter(index).toStored(value))
|
|
271
|
+
if (isObservableArray(target)) {
|
|
272
|
+
target.replace(storedValues)
|
|
273
|
+
} else {
|
|
274
|
+
target.length = storedValues.length
|
|
275
|
+
for (let i = 0; i < storedValues.length; i++) {
|
|
276
|
+
if (i in storedValues) target[i] = storedValues[i]
|
|
277
|
+
else delete target[i]
|
|
278
|
+
}
|
|
279
|
+
}
|
|
275
280
|
}
|
|
276
281
|
const mutateViaRuntime = (
|
|
277
282
|
target: unknown[],
|
|
@@ -296,6 +301,11 @@ function createArrayLikeRuntimeAdapter(
|
|
|
296
301
|
}
|
|
297
302
|
|
|
298
303
|
const proxy: unknown[] = new Proxy(stored, {
|
|
304
|
+
has(target, prop) {
|
|
305
|
+
const index = getArrayIndex(prop)
|
|
306
|
+
if (index !== undefined && isObservableArray(target)) return index < target.length
|
|
307
|
+
return Reflect.has(target, prop)
|
|
308
|
+
},
|
|
299
309
|
get(target, prop, receiver) {
|
|
300
310
|
const index = getArrayIndex(prop)
|
|
301
311
|
if (index !== undefined) {
|
|
@@ -332,8 +342,9 @@ function createArrayLikeRuntimeAdapter(
|
|
|
332
342
|
}
|
|
333
343
|
|
|
334
344
|
const indexValue = target.length - 1
|
|
345
|
+
const present = isObservableArray(target) || indexValue in target
|
|
335
346
|
const value = target.pop()
|
|
336
|
-
return getItemAdapter(indexValue).toRuntime(value)
|
|
347
|
+
return present ? getItemAdapter(indexValue).toRuntime(value) : undefined
|
|
337
348
|
}
|
|
338
349
|
case "shift":
|
|
339
350
|
return () => {
|
|
@@ -341,8 +352,9 @@ function createArrayLikeRuntimeAdapter(
|
|
|
341
352
|
return undefined
|
|
342
353
|
}
|
|
343
354
|
|
|
355
|
+
const present = isObservableArray(target) || 0 in target
|
|
344
356
|
const value = target.shift()
|
|
345
|
-
return getItemAdapter(0).toRuntime(value)
|
|
357
|
+
return present ? getItemAdapter(0).toRuntime(value) : undefined
|
|
346
358
|
}
|
|
347
359
|
case "unshift":
|
|
348
360
|
return (...items: unknown[]) =>
|
|
@@ -350,12 +362,21 @@ function createArrayLikeRuntimeAdapter(
|
|
|
350
362
|
...items.map((item, indexValue) => getItemAdapter(indexValue).toStored(item))
|
|
351
363
|
)
|
|
352
364
|
case "splice":
|
|
353
|
-
return (
|
|
365
|
+
return (...args: [start?: number, deleteCount?: number, ...items: unknown[]]) => {
|
|
366
|
+
const [start = 0, deleteCount, ...items] = args
|
|
354
367
|
const normalizedStart = normalizeArrayIndex(start, target.length)
|
|
355
368
|
const actualDeleteCount =
|
|
356
|
-
|
|
357
|
-
?
|
|
358
|
-
:
|
|
369
|
+
args.length === 0
|
|
370
|
+
? 0
|
|
371
|
+
: args.length === 1
|
|
372
|
+
? target.length - normalizedStart
|
|
373
|
+
: Math.max(
|
|
374
|
+
0,
|
|
375
|
+
Math.min(
|
|
376
|
+
Math.trunc(deleteCount ?? 0) || 0,
|
|
377
|
+
target.length - normalizedStart
|
|
378
|
+
)
|
|
379
|
+
)
|
|
359
380
|
|
|
360
381
|
const removedValues = target
|
|
361
382
|
.slice(normalizedStart, normalizedStart + actualDeleteCount)
|
|
@@ -443,8 +464,7 @@ function createArrayLikeRuntimeAdapter(
|
|
|
443
464
|
return true
|
|
444
465
|
}
|
|
445
466
|
|
|
446
|
-
Reflect.set(target, prop, value)
|
|
447
|
-
return true
|
|
467
|
+
return Reflect.set(target, prop, value)
|
|
448
468
|
},
|
|
449
469
|
})
|
|
450
470
|
|
|
@@ -461,7 +481,7 @@ function createArrayLikeRuntimeAdapter(
|
|
|
461
481
|
return cachedStored
|
|
462
482
|
}
|
|
463
483
|
|
|
464
|
-
return
|
|
484
|
+
return runtime.map((value, index) => getItemAdapter(index).toStored(value))
|
|
465
485
|
}
|
|
466
486
|
|
|
467
487
|
return runtime as never
|
|
@@ -490,44 +510,55 @@ function createCodecLeafRuntimeAdapter(
|
|
|
490
510
|
toRuntime(stored, setStored) {
|
|
491
511
|
const cachedRuntime = isObject(stored) ? runtimeByStored.get(stored) : undefined
|
|
492
512
|
|
|
493
|
-
|
|
513
|
+
// Declared up front (rather than initialized from the call) so that a setter invoked
|
|
514
|
+
// while decoding can read it without hitting the temporal dead zone.
|
|
515
|
+
let runtime: unknown
|
|
516
|
+
let storedChanged = false
|
|
517
|
+
runtime = transform.transform({
|
|
494
518
|
originalValue: stored,
|
|
495
519
|
cachedTransformedValue: cachedRuntime,
|
|
496
520
|
setOriginalValue(newStoredValue) {
|
|
497
521
|
if (setStored) {
|
|
498
|
-
|
|
522
|
+
try {
|
|
523
|
+
setStored(newStoredValue)
|
|
524
|
+
} finally {
|
|
525
|
+
// A retained codec setter can replace the value after decoding. Neither
|
|
526
|
+
// direction of the cache may keep associating it with the old stored value.
|
|
527
|
+
storedChanged = true
|
|
528
|
+
if (isObject(runtime)) storedByRuntime.delete(runtime)
|
|
529
|
+
if (isObject(stored)) runtimeByStored.delete(stored)
|
|
530
|
+
}
|
|
499
531
|
}
|
|
500
532
|
},
|
|
501
533
|
})
|
|
502
534
|
|
|
503
|
-
if (
|
|
504
|
-
storedByRuntime.set(runtime, stored)
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
if (isObject(stored)) {
|
|
508
|
-
runtimeByStored.set(stored, runtime)
|
|
535
|
+
if (!storedChanged) {
|
|
536
|
+
if (isObject(runtime)) storedByRuntime.set(runtime, stored)
|
|
537
|
+
if (isObject(stored)) runtimeByStored.set(stored, runtime)
|
|
509
538
|
}
|
|
510
539
|
|
|
511
540
|
return runtime
|
|
512
541
|
},
|
|
513
542
|
|
|
514
543
|
toStored(runtime) {
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
544
|
+
if (isObject(runtime)) {
|
|
545
|
+
const cachedStored = storedByRuntime.get(runtime)
|
|
546
|
+
if (cachedStored !== undefined || storedByRuntime.has(runtime)) {
|
|
547
|
+
return cachedStored
|
|
548
|
+
}
|
|
518
549
|
}
|
|
519
550
|
|
|
551
|
+
let cacheResult = false
|
|
520
552
|
const stored = transform.untransform({
|
|
521
553
|
transformedValue: runtime,
|
|
522
|
-
cacheTransformedValue: () => {
|
|
554
|
+
cacheTransformedValue: () => {
|
|
555
|
+
cacheResult = true
|
|
556
|
+
},
|
|
523
557
|
})
|
|
524
558
|
|
|
525
|
-
if (
|
|
526
|
-
storedByRuntime.set(runtime, stored)
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
if (isObject(stored)) {
|
|
530
|
-
runtimeByStored.set(stored, runtime)
|
|
559
|
+
if (cacheResult) {
|
|
560
|
+
if (isObject(runtime)) storedByRuntime.set(runtime, stored)
|
|
561
|
+
if (isObject(stored)) runtimeByStored.set(stored, runtime)
|
|
531
562
|
}
|
|
532
563
|
|
|
533
564
|
return stored
|
|
@@ -536,7 +567,7 @@ function createCodecLeafRuntimeAdapter(
|
|
|
536
567
|
toStoredIfCached(runtime) {
|
|
537
568
|
if (isObject(runtime)) {
|
|
538
569
|
const cachedStored = storedByRuntime.get(runtime)
|
|
539
|
-
if (cachedStored !== undefined) {
|
|
570
|
+
if (cachedStored !== undefined || storedByRuntime.has(runtime)) {
|
|
540
571
|
return { found: true, value: cachedStored }
|
|
541
572
|
}
|
|
542
573
|
}
|
|
@@ -675,7 +706,7 @@ function resolveCodecSupportForStandardType(type: AnyStandardType): ResolvedCode
|
|
|
675
706
|
}
|
|
676
707
|
} else if (typeInfo instanceof ObjectTypeInfo) {
|
|
677
708
|
const childSupports = lazy(() => {
|
|
678
|
-
const supports: Record<string, ResolvedCodecSupport> =
|
|
709
|
+
const supports: Record<string, ResolvedCodecSupport> = Object.create(null)
|
|
679
710
|
const props = typeInfo.props
|
|
680
711
|
for (const propName of Object.keys(props)) {
|
|
681
712
|
supports[propName] = resolveCodecSupportForStandardType(props[propName].type)
|
|
@@ -690,7 +721,7 @@ function resolveCodecSupportForStandardType(type: AnyStandardType): ResolvedCode
|
|
|
690
721
|
: {
|
|
691
722
|
hasCodec: true,
|
|
692
723
|
storedType: typesObject(() => {
|
|
693
|
-
const storedProps: Record<string, AnyStandardType> =
|
|
724
|
+
const storedProps: Record<string, AnyStandardType> = Object.create(null)
|
|
694
725
|
const props = typeInfo.props
|
|
695
726
|
for (const propName of Object.keys(props)) {
|
|
696
727
|
storedProps[propName] = childSupports()[propName].storedType
|
|
@@ -722,7 +753,17 @@ function resolveCodecSupportForStandardType(type: AnyStandardType): ResolvedCode
|
|
|
722
753
|
} else if (typeInfo instanceof RefinementTypeInfo) {
|
|
723
754
|
const baseSupport = resolveCodecSupportForStandardType(typeInfo.baseType)
|
|
724
755
|
|
|
725
|
-
resolvedSupport = baseSupport.hasCodec
|
|
756
|
+
resolvedSupport = !baseSupport.hasCodec
|
|
757
|
+
? noCodecSupport(type)
|
|
758
|
+
: {
|
|
759
|
+
hasCodec: true,
|
|
760
|
+
storedType: typesRefinement(
|
|
761
|
+
baseSupport.storedType,
|
|
762
|
+
(stored) => typeInfo.checkFunction(baseSupport.adapter.toRuntime(stored)),
|
|
763
|
+
typeInfo.typeName
|
|
764
|
+
),
|
|
765
|
+
adapter: baseSupport.adapter,
|
|
766
|
+
}
|
|
726
767
|
} else if (typeInfo instanceof SkipCheckTypeInfo) {
|
|
727
768
|
const baseSupport = resolveCodecSupportForStandardType(typeInfo.baseType)
|
|
728
769
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ModelPropTransform } from "../../modelShared/prop"
|
|
2
|
-
import { isMap } from "../../utils"
|
|
2
|
+
import { isMap, setProtoProp } from "../../utils"
|
|
3
3
|
import { asMap } from "../../wrappers/asMap"
|
|
4
4
|
import { typesArray } from "../arrayBased/typesArray"
|
|
5
5
|
import { typesTuple } from "../arrayBased/typesTuple"
|
|
@@ -19,6 +19,15 @@ function makeMapProxy<TKeyStored, TKeyRuntime, TValueStored, TValueRuntime>(
|
|
|
19
19
|
keyAdapter: RuntimeAdapter<TKeyStored, TKeyRuntime>,
|
|
20
20
|
valueAdapter: RuntimeAdapter<TValueStored, TValueRuntime>
|
|
21
21
|
): Map<TKeyRuntime, TValueRuntime> {
|
|
22
|
+
// Writes through the decoded value must land back on the entry it came from.
|
|
23
|
+
const toRuntimeValue = (storedKey: TKeyStored, storedValue: TValueStored): TValueRuntime =>
|
|
24
|
+
valueAdapter.toRuntime(storedValue, (newStoredValue) => {
|
|
25
|
+
storedMap.set(storedKey, newStoredValue)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const getValue = (storedKey: TKeyStored): TValueRuntime =>
|
|
29
|
+
toRuntimeValue(storedKey, storedMap.get(storedKey) as TValueStored)
|
|
30
|
+
|
|
22
31
|
return new Proxy(storedMap, {
|
|
23
32
|
get(target, prop, receiver) {
|
|
24
33
|
switch (prop) {
|
|
@@ -29,43 +38,24 @@ function makeMapProxy<TKeyStored, TKeyRuntime, TValueStored, TValueRuntime>(
|
|
|
29
38
|
return undefined
|
|
30
39
|
}
|
|
31
40
|
|
|
32
|
-
return
|
|
33
|
-
target.get(storedKey) as TValueStored,
|
|
34
|
-
(newStoredValue) => {
|
|
35
|
-
target.set(storedKey, newStoredValue)
|
|
36
|
-
}
|
|
37
|
-
)
|
|
41
|
+
return getValue(storedKey)
|
|
38
42
|
}
|
|
39
43
|
case "getOrInsert":
|
|
40
44
|
return (key: TKeyRuntime, defaultValue: TValueRuntime) => {
|
|
41
45
|
const storedKey = keyAdapter.toStored(key)
|
|
42
|
-
if (target.has(storedKey)) {
|
|
43
|
-
|
|
44
|
-
target.get(storedKey) as TValueStored,
|
|
45
|
-
(newStoredValue) => {
|
|
46
|
-
target.set(storedKey, newStoredValue)
|
|
47
|
-
}
|
|
48
|
-
)
|
|
46
|
+
if (!target.has(storedKey)) {
|
|
47
|
+
target.set(storedKey, valueAdapter.toStored(defaultValue))
|
|
49
48
|
}
|
|
50
|
-
|
|
51
|
-
target.set(storedKey, valueAdapter.toStored(defaultValue))
|
|
52
|
-
return defaultValue
|
|
49
|
+
return getValue(storedKey)
|
|
53
50
|
}
|
|
54
51
|
case "getOrInsertComputed":
|
|
55
52
|
return (key: TKeyRuntime, callback: (key: TKeyRuntime) => TValueRuntime) => {
|
|
56
53
|
const storedKey = keyAdapter.toStored(key)
|
|
57
|
-
if (target.has(storedKey)) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
(newStoredValue) => {
|
|
61
|
-
target.set(storedKey, newStoredValue)
|
|
62
|
-
}
|
|
63
|
-
)
|
|
54
|
+
if (!target.has(storedKey)) {
|
|
55
|
+
const value = callback(key)
|
|
56
|
+
target.set(storedKey, valueAdapter.toStored(value))
|
|
64
57
|
}
|
|
65
|
-
|
|
66
|
-
const value = callback(key)
|
|
67
|
-
target.set(storedKey, valueAdapter.toStored(value))
|
|
68
|
-
return value
|
|
58
|
+
return getValue(storedKey)
|
|
69
59
|
}
|
|
70
60
|
case "set":
|
|
71
61
|
return (key: TKeyRuntime, value: TValueRuntime) => {
|
|
@@ -92,9 +82,7 @@ function makeMapProxy<TKeyStored, TKeyRuntime, TValueStored, TValueRuntime>(
|
|
|
92
82
|
target.forEach((value, key) => {
|
|
93
83
|
callback.call(
|
|
94
84
|
thisArg,
|
|
95
|
-
|
|
96
|
-
target.set(key, newStoredValue)
|
|
97
|
-
}),
|
|
85
|
+
toRuntimeValue(key, value),
|
|
98
86
|
keyAdapter.toRuntime(key),
|
|
99
87
|
receiver
|
|
100
88
|
)
|
|
@@ -104,12 +92,7 @@ function makeMapProxy<TKeyStored, TKeyRuntime, TValueStored, TValueRuntime>(
|
|
|
104
92
|
case Symbol.iterator:
|
|
105
93
|
return function* () {
|
|
106
94
|
for (const [key, value] of target.entries()) {
|
|
107
|
-
yield [
|
|
108
|
-
keyAdapter.toRuntime(key),
|
|
109
|
-
valueAdapter.toRuntime(value, (newStoredValue) => {
|
|
110
|
-
target.set(key, newStoredValue)
|
|
111
|
-
}),
|
|
112
|
-
] as const
|
|
95
|
+
yield [keyAdapter.toRuntime(key), toRuntimeValue(key, value)] as const
|
|
113
96
|
}
|
|
114
97
|
}
|
|
115
98
|
case "keys":
|
|
@@ -121,9 +104,7 @@ function makeMapProxy<TKeyStored, TKeyRuntime, TValueStored, TValueRuntime>(
|
|
|
121
104
|
case "values":
|
|
122
105
|
return function* () {
|
|
123
106
|
for (const [key, value] of target.entries()) {
|
|
124
|
-
yield
|
|
125
|
-
target.set(key, newStoredValue)
|
|
126
|
-
})
|
|
107
|
+
yield toRuntimeValue(key, value)
|
|
127
108
|
}
|
|
128
109
|
}
|
|
129
110
|
default:
|
|
@@ -158,7 +139,9 @@ function makeObjectBackedMapTransform<TStoredValue, TRuntimeValue>(
|
|
|
158
139
|
|
|
159
140
|
const result: Record<string, TStoredValue> = {}
|
|
160
141
|
transformedValue.forEach((value, key) => {
|
|
161
|
-
|
|
142
|
+
const storedValue = valueAdapter.toStored(value)
|
|
143
|
+
if (key === "__proto__") setProtoProp(result, storedValue)
|
|
144
|
+
else result[key] = storedValue
|
|
162
145
|
})
|
|
163
146
|
return result
|
|
164
147
|
},
|
|
@@ -41,8 +41,8 @@ import {
|
|
|
41
41
|
* @template T Base type.
|
|
42
42
|
* @param baseType Base type.
|
|
43
43
|
* @param checkFn Function that will receive the data (if it passes the base type
|
|
44
|
-
* check) and return null or
|
|
45
|
-
*
|
|
44
|
+
* check) and return null or true if there were no errors or either a TypeCheckError instance or
|
|
45
|
+
* false if there were.
|
|
46
46
|
* @returns
|
|
47
47
|
*/
|
|
48
48
|
export function typesRefinement<T extends AnyType>(
|
|
@@ -89,6 +89,7 @@ export function typesRefinement<T extends AnyType>(
|
|
|
89
89
|
// override typeCheckedValue
|
|
90
90
|
return new TypeCheckError({
|
|
91
91
|
path: refinementErr.path,
|
|
92
|
+
modelTrail: refinementErr.modelTrail,
|
|
92
93
|
expectedTypeName: refinementErr.expectedTypeName,
|
|
93
94
|
actualValue: refinementErr.actualValue,
|
|
94
95
|
typeCheckedValue,
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import type { ObservableSet } from "mobx"
|
|
2
2
|
import type { ModelPropTransform } from "../../modelShared/prop"
|
|
3
3
|
import { isSet } from "../../utils"
|
|
4
|
+
import {
|
|
5
|
+
isSetLikeDisjointFrom,
|
|
6
|
+
isSetLikeSubsetOf,
|
|
7
|
+
isSetLikeSupersetOf,
|
|
8
|
+
setLikeDifference,
|
|
9
|
+
setLikeIntersection,
|
|
10
|
+
setLikeSymmetricDifference,
|
|
11
|
+
setLikeUnion,
|
|
12
|
+
} from "../../utils/setLike"
|
|
4
13
|
import { asSet } from "../../wrappers/asSet"
|
|
5
14
|
import { typesArray } from "../arrayBased/typesArray"
|
|
6
15
|
import type { AnyType, ArrayType, TypeToData } from "../schemas"
|
|
@@ -52,6 +61,21 @@ function makeArrayBackedSetTransform<TStored, TRuntime>(
|
|
|
52
61
|
callback.call(thisArg, runtimeValue, runtimeValue, receiver)
|
|
53
62
|
})
|
|
54
63
|
}
|
|
64
|
+
case "union":
|
|
65
|
+
return (other: ReadonlySetLike<unknown>) => setLikeUnion(receiver, other)
|
|
66
|
+
case "intersection":
|
|
67
|
+
return (other: ReadonlySetLike<unknown>) => setLikeIntersection(receiver, other)
|
|
68
|
+
case "difference":
|
|
69
|
+
return (other: ReadonlySetLike<unknown>) => setLikeDifference(receiver, other)
|
|
70
|
+
case "symmetricDifference":
|
|
71
|
+
return (other: ReadonlySetLike<unknown>) =>
|
|
72
|
+
setLikeSymmetricDifference(receiver, other)
|
|
73
|
+
case "isSubsetOf":
|
|
74
|
+
return (other: ReadonlySetLike<unknown>) => isSetLikeSubsetOf(receiver, other)
|
|
75
|
+
case "isSupersetOf":
|
|
76
|
+
return (other: ReadonlySetLike<unknown>) => isSetLikeSupersetOf(receiver, other)
|
|
77
|
+
case "isDisjointFrom":
|
|
78
|
+
return (other: ReadonlySetLike<unknown>) => isSetLikeDisjointFrom(receiver, other)
|
|
55
79
|
case "entries":
|
|
56
80
|
return function* () {
|
|
57
81
|
for (const value of target.values()) {
|
package/src/utils/ModelPool.ts
CHANGED
|
@@ -24,7 +24,7 @@ export class ModelPool {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
findModelByTypeAndId(modelType: string, modelId: string | undefined): AnyModel | undefined {
|
|
27
|
-
return modelId ? this.pool.get(modelType)?.get(modelId) : undefined
|
|
27
|
+
return modelId !== undefined ? this.pool.get(modelType)?.get(modelId) : undefined
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
findModelForSnapshot(sn: any): AnyModel | undefined {
|
|
@@ -36,7 +36,7 @@ export class ModelPool {
|
|
|
36
36
|
const modelInfo = getModelInfoForName(modelType)!
|
|
37
37
|
const modelIdPropertyName = getModelIdPropertyName(modelInfo.class as ModelClass<AnyModel>)
|
|
38
38
|
|
|
39
|
-
return modelIdPropertyName
|
|
39
|
+
return modelIdPropertyName !== undefined
|
|
40
40
|
? this.findModelByTypeAndId(modelType, (sn as any)[modelIdPropertyName])
|
|
41
41
|
: undefined
|
|
42
42
|
}
|
|
@@ -56,7 +56,7 @@ let getDeepChildrenModels: GetDeepChildrenModels = (data) => {
|
|
|
56
56
|
addNode(node, extensionData) {
|
|
57
57
|
if (isModel(node)) {
|
|
58
58
|
const id = node[modelIdKey]
|
|
59
|
-
if (id) {
|
|
59
|
+
if (id !== undefined) {
|
|
60
60
|
const modelType = node[modelTypeKey]
|
|
61
61
|
let modelsById = extensionData.get(modelType)
|
|
62
62
|
if (!modelsById) {
|
package/src/utils/chainFns.ts
CHANGED
package/src/utils/decorators.ts
CHANGED
|
@@ -110,7 +110,7 @@ export function decorateWrapMethodOrField(
|
|
|
110
110
|
const baseDescriptor: PropertyDescriptor | undefined = args[2]
|
|
111
111
|
|
|
112
112
|
checkModelDecoratorTaget(decoratorName, target)
|
|
113
|
-
checkDecoratorContext(
|
|
113
|
+
checkDecoratorContext(decoratorName, propertyKey, false)
|
|
114
114
|
|
|
115
115
|
const data = getActionNameAndContextOverride(target, propertyKey, true)
|
|
116
116
|
|
|
@@ -190,7 +190,7 @@ function formatErrorPathForMessage(path: Path | undefined = getErrorPathSnapshot
|
|
|
190
190
|
/**
|
|
191
191
|
* @internal
|
|
192
192
|
*/
|
|
193
|
-
function getSafeErrorValuePreview(value: unknown, maxLen = 200): string {
|
|
193
|
+
export function getSafeErrorValuePreview(value: unknown, maxLen = 200): string {
|
|
194
194
|
let str: string | undefined
|
|
195
195
|
try {
|
|
196
196
|
str = JSON.stringify(value)
|
|
@@ -203,7 +203,11 @@ function getSafeErrorValuePreview(value: unknown, maxLen = 200): string {
|
|
|
203
203
|
try {
|
|
204
204
|
str = String(value)
|
|
205
205
|
} catch {
|
|
206
|
-
|
|
206
|
+
try {
|
|
207
|
+
str = Object.prototype.toString.call(value)
|
|
208
|
+
} catch {
|
|
209
|
+
str = "<unprintable value>"
|
|
210
|
+
}
|
|
207
211
|
}
|
|
208
212
|
}
|
|
209
213
|
|