mobx-keystone 2.1.0 → 2.2.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 +11 -0
- package/README.md +1 -1
- package/dist/mobx-keystone.esm.js +275 -489
- package/dist/mobx-keystone.esm.mjs +275 -489
- package/dist/mobx-keystone.umd.js +274 -492
- package/dist/types/actionMiddlewares/undoMiddleware.d.ts +2 -10
- package/dist/types/modelShared/modelDecorator.d.ts +5 -2
- package/dist/types/modelShared/prop.d.ts +42 -29
- package/dist/types/ref/Ref.d.ts +1 -4
- package/dist/types/snapshot/SnapshotOf.d.ts +4 -4
- package/dist/types/snapshot/applySnapshot.d.ts +1 -1
- package/dist/types/snapshot/fromSnapshot.d.ts +2 -2
- package/dist/types/snapshot/getSnapshot.d.ts +1 -1
- package/dist/types/types/index.d.ts +1 -0
- package/dist/types/types/schemas.d.ts +41 -37
- package/dist/types/types/tProp.d.ts +12 -6
- package/dist/types/types/types.d.ts +6 -6
- package/dist/types/types/utility/typeToStoredData.d.ts +14 -10
- package/dist/types/types/utility/typesCodecCore.d.ts +3 -0
- package/dist/types/utils/ModelPool.d.ts +0 -1
- package/dist/types/utils/types.d.ts +6 -0
- package/dist/types/wrappers/ArraySet.d.ts +1 -0
- package/package.json +4 -2
- package/src/action/modelFlow.ts +35 -66
- package/src/actionMiddlewares/actionTrackingMiddleware.ts +41 -71
- package/src/actionMiddlewares/transactionMiddleware.ts +1 -1
- package/src/actionMiddlewares/undoMiddleware.ts +16 -22
- package/src/context/context.ts +15 -36
- package/src/dataModel/utils.ts +5 -28
- package/src/deepChange/onDeepChange.ts +44 -126
- package/src/model/BaseModel.ts +1 -1
- package/src/model/utils.ts +5 -10
- package/src/modelShared/modelDecorator.ts +11 -5
- package/src/modelShared/prop.ts +115 -111
- package/src/modelShared/sharedInternalModel.ts +2 -2
- package/src/parent/arrayPaths.ts +1 -4
- package/src/parent/path.ts +0 -10
- package/src/patch/patchRecorder.ts +13 -28
- package/src/ref/core.ts +6 -19
- package/src/rootStore/rootStore.ts +1 -3
- package/src/snapshot/SnapshotOf.ts +24 -48
- package/src/snapshot/applySnapshot.ts +1 -1
- package/src/snapshot/fromSnapshot.ts +10 -3
- package/src/snapshot/getSnapshot.ts +1 -1
- package/src/snapshot/internal.ts +0 -2
- package/src/snapshot/reconcileModelSnapshot.ts +5 -3
- package/src/snapshot/reconcilePlainObjectSnapshot.ts +3 -1
- package/src/treeUtils/draft.ts +6 -1
- package/src/treeUtils/sandbox.ts +10 -7
- package/src/tweaker/tweakArray.ts +20 -50
- package/src/tweaker/tweakPlainObject.ts +9 -15
- package/src/types/arrayBased/typesArray.ts +13 -19
- package/src/types/arrayBased/typesTuple.ts +16 -25
- package/src/types/createCachedTypeCheck.ts +17 -30
- package/src/types/index.ts +1 -0
- package/src/types/objectBased/typesDataModelData.ts +7 -8
- package/src/types/objectBased/typesObject.ts +11 -15
- package/src/types/objectBased/typesRecord.ts +11 -15
- package/src/types/schemas.ts +59 -71
- package/src/types/tProp.ts +29 -29
- package/src/types/utility/typeToStoredData.ts +22 -21
- package/src/types/utility/typesCodecCore.ts +5 -0
- package/src/types/utility/typesCodecSupport.ts +3 -3
- package/src/types/utility/typesMap.ts +43 -51
- package/src/types/utility/typesRefinement.ts +7 -8
- package/src/types/utility/typesSkipCheck.ts +7 -8
- package/src/types/utility/typesTag.ts +7 -8
- package/src/utils/ModelPool.ts +1 -18
- package/src/utils/decorators.ts +5 -5
- package/src/utils/index.ts +1 -20
- package/src/utils/types.ts +5 -0
- package/src/wrappers/ArraySet.ts +27 -14
- package/src/wrappers/ObjectMap.ts +1 -6
- package/src/wrappers/asMap.ts +1 -21
- package/src/wrappers/asSet.ts +0 -8
|
@@ -108,36 +108,21 @@ export function internalPatchRecorder(
|
|
|
108
108
|
deep: false,
|
|
109
109
|
})
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
patches: p,
|
|
121
|
-
inversePatches: invP,
|
|
122
|
-
})
|
|
123
|
-
opts?.onPatches?.(p, invP)
|
|
124
|
-
}
|
|
125
|
-
},
|
|
126
|
-
true
|
|
127
|
-
)
|
|
128
|
-
} else {
|
|
129
|
-
onPatchesDisposer = internalOnGlobalPatches((target, p, invP) => {
|
|
130
|
-
if (recording && filter(p, invP)) {
|
|
131
|
-
events.push({
|
|
132
|
-
target,
|
|
133
|
-
patches: p,
|
|
134
|
-
inversePatches: invP,
|
|
135
|
-
})
|
|
136
|
-
opts?.onPatches?.(p, invP)
|
|
137
|
-
}
|
|
138
|
-
}, true)
|
|
111
|
+
const record = (target: object, p: Patch[], invP: Patch[]) => {
|
|
112
|
+
if (recording && filter(p, invP)) {
|
|
113
|
+
events.push({
|
|
114
|
+
target,
|
|
115
|
+
patches: p,
|
|
116
|
+
inversePatches: invP,
|
|
117
|
+
})
|
|
118
|
+
opts?.onPatches?.(p, invP)
|
|
119
|
+
}
|
|
139
120
|
}
|
|
140
121
|
|
|
122
|
+
const onPatchesDisposer: OnPatchesDisposer = subtreeRoot
|
|
123
|
+
? internalOnPatches(subtreeRoot, (p, invP) => record(subtreeRoot, p, invP), true)
|
|
124
|
+
: internalOnGlobalPatches(record, true)
|
|
125
|
+
|
|
141
126
|
return {
|
|
142
127
|
get recording() {
|
|
143
128
|
return recording
|
package/src/ref/core.ts
CHANGED
|
@@ -220,29 +220,16 @@ export function resolveId<T extends object>(
|
|
|
220
220
|
return resolveRefIdByIndex(root, id, getId) as T | undefined
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
+
const createRefSet = () => observable.set<Ref<any>>(undefined, { deep: false })
|
|
224
|
+
|
|
225
|
+
const createBackRefs = (): BackRefs<any> => ({ all: createRefSet(), byType: new WeakMap() })
|
|
226
|
+
|
|
223
227
|
function getBackRefs<T extends object>(
|
|
224
228
|
target: T,
|
|
225
229
|
refType?: RefConstructor<T>
|
|
226
230
|
): ObservableSet<Ref<T>> {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
backRefs = {
|
|
230
|
-
all: observable.set(undefined, { deep: false }),
|
|
231
|
-
byType: new WeakMap(),
|
|
232
|
-
}
|
|
233
|
-
objectBackRefs.set(target, backRefs)
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (refType) {
|
|
237
|
-
let byType = backRefs.byType.get(refType)
|
|
238
|
-
if (!byType) {
|
|
239
|
-
byType = observable.set(undefined, { deep: false })
|
|
240
|
-
backRefs.byType.set(refType, byType)
|
|
241
|
-
}
|
|
242
|
-
return byType
|
|
243
|
-
} else {
|
|
244
|
-
return backRefs.all
|
|
245
|
-
}
|
|
231
|
+
const backRefs: BackRefs<T> = getOrCreate(objectBackRefs, target, createBackRefs)
|
|
232
|
+
return refType ? getOrCreate(backRefs.byType, refType, createRefSet) : backRefs.all
|
|
246
233
|
}
|
|
247
234
|
|
|
248
235
|
/**
|
|
@@ -84,9 +84,7 @@ export function isRootStore(node: object): boolean {
|
|
|
84
84
|
assertTweakedObject(node, "node")
|
|
85
85
|
|
|
86
86
|
const entry = getOrCreateRootStoreEntry(node)
|
|
87
|
-
|
|
88
|
-
entry.atom = createAtom("rootStore")
|
|
89
|
-
}
|
|
87
|
+
entry.atom ??= createAtom("rootStore")
|
|
90
88
|
entry.atom.reportObserved()
|
|
91
89
|
return entry.is
|
|
92
90
|
}
|
|
@@ -13,10 +13,8 @@ export type FrozenData<D> = {
|
|
|
13
13
|
|
|
14
14
|
// snapshot out
|
|
15
15
|
|
|
16
|
-
// infer is there just to cache type generation
|
|
17
|
-
|
|
18
16
|
export type SnapshotOutOfObject<T> = {
|
|
19
|
-
[k in keyof T]: SnapshotOutOf<T[k]>
|
|
17
|
+
[k in keyof T]: SnapshotOutOf<T[k]>
|
|
20
18
|
}
|
|
21
19
|
|
|
22
20
|
export type SnapshotOutOfModel<M extends AnyModel> = ModelToSnapshot<M>
|
|
@@ -35,33 +33,22 @@ export interface SnapshotOutOfArraySet<V> {
|
|
|
35
33
|
[modelIdKey]: string
|
|
36
34
|
}
|
|
37
35
|
|
|
38
|
-
export type SnapshotOutOf<T> =
|
|
39
|
-
T extends
|
|
40
|
-
?
|
|
41
|
-
?
|
|
42
|
-
:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
: T
|
|
48
|
-
|
|
49
|
-
? R
|
|
50
|
-
: never
|
|
51
|
-
: T extends Frozen<any>
|
|
52
|
-
? SnapshotOutOfFrozen<T> extends infer R
|
|
53
|
-
? R
|
|
54
|
-
: never
|
|
55
|
-
: T extends object
|
|
56
|
-
? SnapshotOutOfObject<T> extends infer R
|
|
57
|
-
? R
|
|
58
|
-
: never
|
|
59
|
-
: T
|
|
36
|
+
export type SnapshotOutOf<T> = T extends object
|
|
37
|
+
? T extends AnyModel
|
|
38
|
+
? T extends ObjectMap<infer V>
|
|
39
|
+
? SnapshotOutOfObjectMap<V>
|
|
40
|
+
: T extends ArraySet<infer V>
|
|
41
|
+
? SnapshotOutOfArraySet<V>
|
|
42
|
+
: SnapshotOutOfModel<T>
|
|
43
|
+
: T extends Frozen<any>
|
|
44
|
+
? SnapshotOutOfFrozen<T>
|
|
45
|
+
: SnapshotOutOfObject<T>
|
|
46
|
+
: T
|
|
60
47
|
|
|
61
48
|
// snapshot in
|
|
62
49
|
|
|
63
50
|
export type SnapshotInOfObject<T> = {
|
|
64
|
-
[k in keyof T]: SnapshotInOf<T[k]>
|
|
51
|
+
[k in keyof T]: SnapshotInOf<T[k]>
|
|
65
52
|
}
|
|
66
53
|
|
|
67
54
|
export type SnapshotInOfModel<M extends AnyModel> = ModelFromSnapshot<M>
|
|
@@ -80,25 +67,14 @@ export interface SnapshotInOfArraySet<V> {
|
|
|
80
67
|
[modelIdKey]: string
|
|
81
68
|
}
|
|
82
69
|
|
|
83
|
-
export type SnapshotInOf<T> =
|
|
84
|
-
T extends
|
|
85
|
-
?
|
|
86
|
-
?
|
|
87
|
-
:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
: T
|
|
93
|
-
|
|
94
|
-
? R
|
|
95
|
-
: never
|
|
96
|
-
: T extends Frozen<any>
|
|
97
|
-
? SnapshotInOfFrozen<T> extends infer R
|
|
98
|
-
? R
|
|
99
|
-
: never
|
|
100
|
-
: T extends object
|
|
101
|
-
? SnapshotInOfObject<T> extends infer R
|
|
102
|
-
? R
|
|
103
|
-
: never
|
|
104
|
-
: T
|
|
70
|
+
export type SnapshotInOf<T> = T extends object
|
|
71
|
+
? T extends AnyModel
|
|
72
|
+
? T extends ObjectMap<infer V>
|
|
73
|
+
? SnapshotInOfObjectMap<V>
|
|
74
|
+
: T extends ArraySet<infer V>
|
|
75
|
+
? SnapshotInOfArraySet<V>
|
|
76
|
+
: SnapshotInOfModel<T>
|
|
77
|
+
: T extends Frozen<any>
|
|
78
|
+
? SnapshotInOfFrozen<T>
|
|
79
|
+
: SnapshotInOfObject<T>
|
|
80
|
+
: T
|
|
@@ -33,7 +33,7 @@ import { SnapshotProcessingError } from "./SnapshotProcessingError"
|
|
|
33
33
|
*/
|
|
34
34
|
export function applySnapshot<T extends object>(
|
|
35
35
|
node: T,
|
|
36
|
-
snapshot: SnapshotInOf<T> | SnapshotOutOf<T
|
|
36
|
+
snapshot: NoInfer<SnapshotInOf<T> | SnapshotOutOf<T>>
|
|
37
37
|
): void
|
|
38
38
|
|
|
39
39
|
export function applySnapshot(node: object, snapshot: unknown): void {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { action, observable } from "mobx"
|
|
2
2
|
import type { AnyModel } from "../model/BaseModel"
|
|
3
3
|
import { isReservedModelKey } from "../model/metadata"
|
|
4
|
+
import { isTweakedObject } from "../tweaker/core"
|
|
4
5
|
import { resolveStandardTypeNoThrow, resolveTypeChecker } from "../types/resolveTypeChecker"
|
|
5
|
-
import type { AnyType, TypeToData, TypeToSnapshotIn } from "../types/schemas"
|
|
6
|
+
import type { AnyType, TypeToData, TypeToSnapshotIn, TypeToSnapshotOut } from "../types/schemas"
|
|
6
7
|
import { isLateTypeChecker, TypeChecker } from "../types/TypeChecker"
|
|
7
8
|
import { resolveCodecSupport } from "../types/utility/typesCodec"
|
|
8
9
|
import { isMap, isPrimitive, isSet, nodeObservableOptions, setProtoProp } from "../utils"
|
|
@@ -60,7 +61,7 @@ export interface FromSnapshotContext {
|
|
|
60
61
|
*/
|
|
61
62
|
export function fromSnapshot<TType extends AnyType>(
|
|
62
63
|
type: TType,
|
|
63
|
-
snapshot: TypeToSnapshotIn<TType
|
|
64
|
+
snapshot: NoInfer<TypeToSnapshotIn<TType> | TypeToSnapshotOut<TType>>,
|
|
64
65
|
options?: Partial<FromSnapshotOptions>
|
|
65
66
|
): TypeToData<TType>
|
|
66
67
|
|
|
@@ -122,7 +123,6 @@ const fromSnapshotAction = action(
|
|
|
122
123
|
): T => {
|
|
123
124
|
const opts = {
|
|
124
125
|
generateNewIds: false,
|
|
125
|
-
overrideRootModelId: undefined,
|
|
126
126
|
...options,
|
|
127
127
|
}
|
|
128
128
|
|
|
@@ -172,6 +172,13 @@ export function internalFromSnapshot<T>(
|
|
|
172
172
|
})
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
+
if (isTweakedObject(sn, true)) {
|
|
176
|
+
throw new SnapshotProcessingError({
|
|
177
|
+
message: "a snapshot must not contain tree nodes (use getSnapshot to get their snapshots)",
|
|
178
|
+
actualSnapshot: sn,
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
|
|
175
182
|
throw new SnapshotProcessingError({
|
|
176
183
|
message: "unsupported snapshot",
|
|
177
184
|
actualSnapshot: sn,
|
package/src/snapshot/internal.ts
CHANGED
|
@@ -156,7 +156,9 @@ function reconcileModelSnapshot(
|
|
|
156
156
|
if (!isReservedModelKey(k)) {
|
|
157
157
|
const v = processedSn[k]
|
|
158
158
|
|
|
159
|
-
|
|
159
|
+
// an inherited member such as `toString` is no old value (but `__proto__`
|
|
160
|
+
// still reads the prototype, which is rejected as it is no tree node)
|
|
161
|
+
const oldValue = k === "__proto__" || hasOwnProp(data, k) ? data[k] : undefined
|
|
160
162
|
// Non-null primitives need neither reconciliation nor detachment.
|
|
161
163
|
// Nullish values must still pass through default handling below.
|
|
162
164
|
if (v != null && isPrimitive(v)) {
|
|
@@ -216,10 +218,10 @@ function snapshotSlotsAreEqual(
|
|
|
216
218
|
for (let i = 0; i < currentKeys.length; i++) {
|
|
217
219
|
const key = currentKeys[i]
|
|
218
220
|
// a matching key at the same index proves the key is an own property of
|
|
219
|
-
// the incoming snapshot without an
|
|
221
|
+
// the incoming snapshot without an own-property check; canonical snapshots
|
|
220
222
|
// keep key order, so the fallback is rare (never trust inherited values,
|
|
221
223
|
// e.g. a crafted __proto__ chain, without an own-property proof)
|
|
222
|
-
if (incomingKeys[i] !== key && !
|
|
224
|
+
if (incomingKeys[i] !== key && !hasOwnProp(incomingSnapshot, key)) {
|
|
223
225
|
return false
|
|
224
226
|
}
|
|
225
227
|
if (currentSnapshot[key] !== incomingSnapshot[key]) {
|
|
@@ -48,7 +48,9 @@ function reconcilePlainObjectSnapshot(
|
|
|
48
48
|
const k = snKeys[i]
|
|
49
49
|
const v = sn[k]
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
// an inherited member such as `toString` is no old value (but `__proto__`
|
|
52
|
+
// still reads the prototype, which is rejected as it is no tree node)
|
|
53
|
+
const oldValue = k === "__proto__" || hasOwnProp(plainObj, k) ? plainObj[k] : undefined
|
|
52
54
|
const newValue = withErrorPathSegment(k, () =>
|
|
53
55
|
reconcileSnapshot(oldValue, v, modelPool, plainObj)
|
|
54
56
|
)
|
package/src/treeUtils/draft.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { applySnapshot } from "../snapshot/applySnapshot"
|
|
|
6
6
|
import { fromSnapshot } from "../snapshot/fromSnapshot"
|
|
7
7
|
import { getSnapshot } from "../snapshot/getSnapshot"
|
|
8
8
|
import { assertTweakedObject } from "../tweaker/core"
|
|
9
|
-
import { failure, mobxAction, mobxComputed } from "../utils"
|
|
9
|
+
import { failure, getMobxVersion, makeObservableCompat, mobxAction, mobxComputed } from "../utils"
|
|
10
10
|
import { deepEquals } from "./deepEquals"
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -157,6 +157,11 @@ export class Draft<T extends object> {
|
|
|
157
157
|
assertTweakedObject(original, "original")
|
|
158
158
|
|
|
159
159
|
this.originalData = original
|
|
160
|
+
|
|
161
|
+
if (getMobxVersion() >= 6) {
|
|
162
|
+
makeObservableCompat(this)
|
|
163
|
+
}
|
|
164
|
+
|
|
160
165
|
this.data = fromSnapshot(this.originalSnapshot, { generateNewIds: false })
|
|
161
166
|
}
|
|
162
167
|
}
|
package/src/treeUtils/sandbox.ts
CHANGED
|
@@ -233,9 +233,11 @@ export class SandboxManager {
|
|
|
233
233
|
// see the reverted intermediate state.
|
|
234
234
|
runInAction(() => {
|
|
235
235
|
this.allowWrite(() => {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
236
|
+
applyPatches(
|
|
237
|
+
this.subtreeRootClone,
|
|
238
|
+
events.map((event) => event.inversePatches),
|
|
239
|
+
true
|
|
240
|
+
)
|
|
239
241
|
})
|
|
240
242
|
applyPatches(
|
|
241
243
|
this.subtreeRoot,
|
|
@@ -249,10 +251,11 @@ export class SandboxManager {
|
|
|
249
251
|
const wasRecording = recorder.recording
|
|
250
252
|
recorder.recording = false
|
|
251
253
|
try {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
254
|
+
applyPatches(
|
|
255
|
+
this.subtreeRootClone,
|
|
256
|
+
recorder.events.slice(numRecorderEvents).map((event) => event.inversePatches),
|
|
257
|
+
true
|
|
258
|
+
)
|
|
256
259
|
recorder.events.splice(numRecorderEvents)
|
|
257
260
|
} finally {
|
|
258
261
|
recorder.recording = wasRecording
|
|
@@ -289,7 +289,6 @@ function arrayDidChangeUpdate(
|
|
|
289
289
|
) {
|
|
290
290
|
const k = change.index
|
|
291
291
|
const val = change.newValue
|
|
292
|
-
const oldVal = oldSnapshot[k]
|
|
293
292
|
let newVal: any
|
|
294
293
|
if (isPrimitive(val)) {
|
|
295
294
|
newVal = val
|
|
@@ -299,15 +298,14 @@ function arrayDidChangeUpdate(
|
|
|
299
298
|
}
|
|
300
299
|
const mutate = mutateSet.bind(undefined, k, newVal)
|
|
301
300
|
|
|
302
|
-
if (
|
|
301
|
+
if (shouldBuildInversePatches) {
|
|
303
302
|
const path = [k]
|
|
304
303
|
const patches = shouldEmitPatches
|
|
305
304
|
? [{ op: "replace" as const, path, value: freezeInternalSnapshot(newVal) }]
|
|
306
305
|
: undefined
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
patchRecorder.record(patches, invPatches)
|
|
306
|
+
patchRecorder.record(patches, [
|
|
307
|
+
{ op: "replace" as const, path, value: freezeInternalSnapshot(oldSnapshot[k]) },
|
|
308
|
+
])
|
|
311
309
|
}
|
|
312
310
|
return mutate
|
|
313
311
|
}
|
|
@@ -335,17 +333,16 @@ function arrayDidChangeSplice(
|
|
|
335
333
|
|
|
336
334
|
const mutate = mutateSplice.bind(undefined, index, removedCount, addedItems)
|
|
337
335
|
|
|
338
|
-
// With neither patch listeners nor type checking, there is no
|
|
339
|
-
//
|
|
340
|
-
|
|
341
|
-
if (!shouldEmitPatches && !shouldBuildInversePatches) {
|
|
336
|
+
// With neither patch listeners nor type checking, there is no patch data to
|
|
337
|
+
// build. The snapshot mutation above is all the post-change work we need.
|
|
338
|
+
if (!shouldBuildInversePatches) {
|
|
342
339
|
return mutate
|
|
343
340
|
}
|
|
344
341
|
|
|
345
342
|
const oldLen = oldSnapshot.length
|
|
346
343
|
|
|
347
344
|
const patches: Patch[] | undefined = shouldEmitPatches ? [] : undefined
|
|
348
|
-
const invPatches: Patch[]
|
|
345
|
+
const invPatches: Patch[] = []
|
|
349
346
|
|
|
350
347
|
// optimization: if we add as many as we remove then remove/readd instead
|
|
351
348
|
|
|
@@ -357,13 +354,13 @@ function arrayDidChangeSplice(
|
|
|
357
354
|
|
|
358
355
|
if (addedCount === removedCount) {
|
|
359
356
|
const readdPatches: Patch[] | undefined = shouldEmitPatches ? [] : undefined
|
|
360
|
-
const readdInvPatches: Patch[]
|
|
357
|
+
const readdInvPatches: Patch[] = []
|
|
361
358
|
let removed = 0
|
|
362
359
|
|
|
363
360
|
for (let i = 0; i < addedCount; i++) {
|
|
364
361
|
const realIndex = index + i
|
|
365
362
|
|
|
366
|
-
const newVal =
|
|
363
|
+
const newVal = addedItems[i]
|
|
367
364
|
const oldVal = oldSnapshot[realIndex]
|
|
368
365
|
|
|
369
366
|
if (newVal !== oldVal) {
|
|
@@ -372,7 +369,7 @@ function arrayDidChangeSplice(
|
|
|
372
369
|
op: "remove",
|
|
373
370
|
path: removePath,
|
|
374
371
|
})
|
|
375
|
-
invPatches
|
|
372
|
+
invPatches.push({
|
|
376
373
|
op: "remove",
|
|
377
374
|
path: removePath,
|
|
378
375
|
})
|
|
@@ -386,7 +383,7 @@ function arrayDidChangeSplice(
|
|
|
386
383
|
value: freezeInternalSnapshot(newVal),
|
|
387
384
|
})
|
|
388
385
|
|
|
389
|
-
readdInvPatches
|
|
386
|
+
readdInvPatches.push({
|
|
390
387
|
op: "add",
|
|
391
388
|
path: readdPath,
|
|
392
389
|
value: freezeInternalSnapshot(oldVal),
|
|
@@ -394,17 +391,13 @@ function arrayDidChangeSplice(
|
|
|
394
391
|
}
|
|
395
392
|
}
|
|
396
393
|
|
|
397
|
-
if (patches && readdPatches
|
|
394
|
+
if (patches && readdPatches) {
|
|
398
395
|
for (const patch of readdPatches) patches.push(patch)
|
|
399
396
|
}
|
|
400
|
-
|
|
401
|
-
for (const patch of readdInvPatches) invPatches.push(patch)
|
|
402
|
-
}
|
|
397
|
+
for (const patch of readdInvPatches) invPatches.push(patch)
|
|
403
398
|
// We need to reverse once since inverse patches are applied in reverse.
|
|
404
399
|
// Repeated unshift calls here would make a large splice quadratic.
|
|
405
|
-
|
|
406
|
-
invPatches.reverse()
|
|
407
|
-
}
|
|
400
|
+
invPatches.reverse()
|
|
408
401
|
} else {
|
|
409
402
|
const interimLen = oldLen - removedCount
|
|
410
403
|
|
|
@@ -433,7 +426,7 @@ function arrayDidChangeSplice(
|
|
|
433
426
|
}
|
|
434
427
|
|
|
435
428
|
// add 0, 1, 2... since inverse patches are applied in reverse
|
|
436
|
-
invPatches
|
|
429
|
+
invPatches.push({
|
|
437
430
|
op: "add",
|
|
438
431
|
path,
|
|
439
432
|
value: freezeInternalSnapshot(oldSnapshot[realIndex]),
|
|
@@ -446,7 +439,7 @@ function arrayDidChangeSplice(
|
|
|
446
439
|
// optimization, for inverse patches, when adding from the end set the length to restore instead
|
|
447
440
|
const restoreUsingSetLength = index >= interimLen
|
|
448
441
|
if (restoreUsingSetLength) {
|
|
449
|
-
invPatches
|
|
442
|
+
invPatches.push({
|
|
450
443
|
op: "replace",
|
|
451
444
|
path: ["length"],
|
|
452
445
|
value: interimLen,
|
|
@@ -461,14 +454,12 @@ function arrayDidChangeSplice(
|
|
|
461
454
|
patches?.push({
|
|
462
455
|
op: "add",
|
|
463
456
|
path,
|
|
464
|
-
value: freezeInternalSnapshot(
|
|
465
|
-
getValueAfterSplice(oldSnapshot, realIndex, index, removedCount, addedItems)
|
|
466
|
-
),
|
|
457
|
+
value: freezeInternalSnapshot(addedItems[i]),
|
|
467
458
|
})
|
|
468
459
|
|
|
469
460
|
// remove ...2, 1, 0 since inverse patches are applied in reverse
|
|
470
461
|
if (!restoreUsingSetLength) {
|
|
471
|
-
invPatches
|
|
462
|
+
invPatches.push({
|
|
472
463
|
op: "remove",
|
|
473
464
|
path,
|
|
474
465
|
})
|
|
@@ -477,9 +468,7 @@ function arrayDidChangeSplice(
|
|
|
477
468
|
}
|
|
478
469
|
}
|
|
479
470
|
|
|
480
|
-
|
|
481
|
-
patchRecorder.record(patches, invPatches)
|
|
482
|
-
}
|
|
471
|
+
patchRecorder.record(patches, invPatches)
|
|
483
472
|
return mutate
|
|
484
473
|
}
|
|
485
474
|
|
|
@@ -676,22 +665,3 @@ class ObservableArrayReplacementQueue {
|
|
|
676
665
|
}
|
|
677
666
|
}
|
|
678
667
|
}
|
|
679
|
-
|
|
680
|
-
function getValueAfterSplice<T>(
|
|
681
|
-
array: readonly T[],
|
|
682
|
-
i: number,
|
|
683
|
-
index: number,
|
|
684
|
-
remove: number,
|
|
685
|
-
addedItems: readonly T[]
|
|
686
|
-
) {
|
|
687
|
-
const base = i - index
|
|
688
|
-
if (base < 0) {
|
|
689
|
-
return array[i]
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
if (base < addedItems.length) {
|
|
693
|
-
return addedItems[base]
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
return array[i - addedItems.length + remove]
|
|
697
|
-
}
|
|
@@ -295,16 +295,14 @@ function objectDidChangeRemove(
|
|
|
295
295
|
shouldBuildInversePatches: boolean
|
|
296
296
|
) {
|
|
297
297
|
const k = change.name
|
|
298
|
-
const oldVal = oldUntransformedSn[k]
|
|
299
298
|
const mutate = mutateDelete.bind(undefined, k)
|
|
300
299
|
|
|
301
|
-
if (
|
|
300
|
+
if (shouldBuildInversePatches) {
|
|
302
301
|
const path = [k as string]
|
|
303
302
|
const patches = shouldEmitPatches ? [{ op: "remove" as const, path }] : undefined
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
patchRecorder.record(patches, invPatches)
|
|
303
|
+
patchRecorder.record(patches, [
|
|
304
|
+
{ op: "add" as const, path, value: freezeInternalSnapshot(oldUntransformedSn[k]) },
|
|
305
|
+
])
|
|
308
306
|
}
|
|
309
307
|
return mutate
|
|
310
308
|
}
|
|
@@ -318,8 +316,6 @@ function objectDidChangeAddOrUpdate(
|
|
|
318
316
|
const k = change.name
|
|
319
317
|
const val = change.newValue
|
|
320
318
|
|
|
321
|
-
const oldVal = oldUntransformedSn[k]
|
|
322
|
-
|
|
323
319
|
let newVal: any
|
|
324
320
|
if (isPrimitive(val)) {
|
|
325
321
|
newVal = val
|
|
@@ -330,22 +326,20 @@ function objectDidChangeAddOrUpdate(
|
|
|
330
326
|
|
|
331
327
|
const mutate = mutateSet.bind(undefined, k, newVal)
|
|
332
328
|
|
|
333
|
-
if (
|
|
329
|
+
if (shouldBuildInversePatches) {
|
|
334
330
|
const path = [k as string]
|
|
335
331
|
if (change.type === "add") {
|
|
336
332
|
const patches = shouldEmitPatches
|
|
337
333
|
? [{ op: "add" as const, path, value: freezeInternalSnapshot(newVal) }]
|
|
338
334
|
: undefined
|
|
339
|
-
|
|
340
|
-
patchRecorder.record(patches, invPatches)
|
|
335
|
+
patchRecorder.record(patches, [{ op: "remove" as const, path }])
|
|
341
336
|
} else {
|
|
342
337
|
const patches = shouldEmitPatches
|
|
343
338
|
? [{ op: "replace" as const, path, value: freezeInternalSnapshot(newVal) }]
|
|
344
339
|
: undefined
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
patchRecorder.record(patches, invPatches)
|
|
340
|
+
patchRecorder.record(patches, [
|
|
341
|
+
{ op: "replace" as const, path, value: freezeInternalSnapshot(oldUntransformedSn[k]) },
|
|
342
|
+
])
|
|
349
343
|
}
|
|
350
344
|
}
|
|
351
345
|
|
|
@@ -50,6 +50,16 @@ export function typesArray<T extends AnyType>(itemType: T): ArrayType<T[]> {
|
|
|
50
50
|
}
|
|
51
51
|
)
|
|
52
52
|
|
|
53
|
+
const processorPlan = snapshotProcessorPlan(
|
|
54
|
+
() => [itemChecker],
|
|
55
|
+
([itemProcessor]) =>
|
|
56
|
+
itemProcessor
|
|
57
|
+
? (sn: unknown[]) => {
|
|
58
|
+
return sn.map((item, i) => withErrorPathSegment(i, () => itemProcessor(item)))
|
|
59
|
+
}
|
|
60
|
+
: undefined
|
|
61
|
+
)
|
|
62
|
+
|
|
53
63
|
const thisTc: TypeChecker = new TypeChecker(
|
|
54
64
|
TypeCheckerBaseType.Array,
|
|
55
65
|
|
|
@@ -89,25 +99,9 @@ export function typesArray<T extends AnyType>(itemType: T): ArrayType<T[]> {
|
|
|
89
99
|
return thisTc
|
|
90
100
|
},
|
|
91
101
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
itemProcessor
|
|
96
|
-
? (sn: unknown[]) => {
|
|
97
|
-
return sn.map((item, i) => withErrorPathSegment(i, () => itemProcessor(item)))
|
|
98
|
-
}
|
|
99
|
-
: undefined
|
|
100
|
-
),
|
|
101
|
-
|
|
102
|
-
snapshotProcessorPlan(
|
|
103
|
-
() => [itemChecker],
|
|
104
|
-
([itemProcessor]) =>
|
|
105
|
-
itemProcessor
|
|
106
|
-
? (sn: unknown[]) => {
|
|
107
|
-
return sn.map((item, i) => withErrorPathSegment(i, () => itemProcessor(item)))
|
|
108
|
-
}
|
|
109
|
-
: undefined
|
|
110
|
-
)
|
|
102
|
+
processorPlan,
|
|
103
|
+
|
|
104
|
+
processorPlan
|
|
111
105
|
)
|
|
112
106
|
|
|
113
107
|
return thisTc
|