mobx-keystone 1.22.0 → 1.24.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 +12 -0
- package/LICENSE +21 -21
- package/README.md +1 -1
- package/dist/mobx-keystone.esm.js +7198 -6242
- package/dist/mobx-keystone.esm.mjs +7198 -6242
- package/dist/mobx-keystone.umd.js +7217 -6243
- package/dist/types/action/runUnprotected.d.ts +8 -4
- package/dist/types/model/Model.d.ts +5 -0
- package/dist/types/modelShared/modelDecorator.d.ts +1 -1
- package/dist/types/modelShared/prop.d.ts +8 -4
- package/dist/types/snapshot/modelInitialData.d.ts +1 -0
- package/dist/types/tweaker/treeNodeMetadata.d.ts +1 -0
- package/dist/types/types/createCachedTypeCheck.d.ts +1 -0
- package/dist/types/utils/index.d.ts +24 -0
- package/package.json +15 -11
- package/src/action/middleware.ts +5 -18
- package/src/action/mutationBatch.ts +72 -0
- package/src/action/runUnprotected.ts +21 -8
- package/src/action/wrapInAction.ts +45 -15
- package/src/actionMiddlewares/undoMiddleware.ts +19 -13
- package/src/dataModel/BaseDataModel.ts +4 -8
- package/src/deepChange/onDeepChange.ts +246 -16
- package/src/model/BaseModel.ts +4 -12
- package/src/model/Model.ts +5 -0
- package/src/model/newModel.ts +68 -36
- package/src/modelShared/modelDecorator.ts +64 -53
- package/src/modelShared/prop.ts +105 -63
- package/src/modelShared/sharedInternalModel.ts +91 -60
- package/src/parent/core.ts +16 -10
- package/src/parent/coreObjectChildren.ts +219 -21
- package/src/parent/path.ts +6 -5
- package/src/parent/setParent.ts +5 -5
- package/src/patch/emitPatch.ts +102 -20
- package/src/ref/Ref.ts +4 -5
- package/src/ref/core.ts +2 -2
- package/src/snapshot/fromArraySnapshot.ts +11 -2
- package/src/snapshot/fromModelSnapshot.ts +10 -3
- package/src/snapshot/fromPlainObjectSnapshot.ts +18 -7
- package/src/snapshot/fromSnapshot.ts +31 -9
- package/src/snapshot/getSnapshot.ts +8 -3
- package/src/snapshot/internal.ts +243 -82
- package/src/snapshot/modelInitialData.ts +41 -0
- package/src/snapshot/reconcileArraySnapshot.ts +9 -3
- package/src/snapshot/reconcileModelSnapshot.ts +97 -17
- package/src/snapshot/reconcilePlainObjectSnapshot.ts +9 -3
- package/src/treeUtils/draft.ts +7 -8
- package/src/tweaker/core.ts +30 -5
- package/src/tweaker/treeNodeMetadata.ts +38 -0
- package/src/tweaker/tweak.ts +15 -4
- package/src/tweaker/tweakArray.ts +159 -121
- package/src/tweaker/tweakFrozen.ts +2 -2
- package/src/tweaker/tweakModel.ts +2 -2
- package/src/tweaker/tweakPlainObject.ts +117 -124
- package/src/tweaker/typeChecking.ts +10 -1
- package/src/types/TypeChecker.ts +261 -15
- package/src/types/arrayBased/typesArray.ts +38 -40
- package/src/types/arrayBased/typesTuple.ts +51 -34
- package/src/types/createCachedTypeCheck.ts +181 -0
- package/src/types/objectBased/typesArraySet.ts +42 -32
- package/src/types/objectBased/typesDataModelData.ts +18 -11
- package/src/types/objectBased/typesModel.ts +1 -1
- package/src/types/objectBased/typesObject.ts +57 -28
- package/src/types/objectBased/typesObjectMap.ts +51 -40
- package/src/types/objectBased/typesRecord.ts +59 -39
- package/src/types/objectBased/typesRef.ts +1 -1
- package/src/types/primitiveBased/typesPrimitive.ts +9 -9
- package/src/types/tProp.ts +80 -44
- package/src/types/utility/typesOr.ts +35 -24
- package/src/types/utility/typesRefinement.ts +21 -8
- package/src/types/utility/typesSkipCheck.ts +21 -8
- package/src/types/utility/typesTag.ts +21 -9
- package/src/types/utility/typesUnchecked.ts +2 -3
- package/src/utils/ModelPool.ts +34 -19
- package/src/utils/errorDiagnostics.ts +60 -18
- package/src/utils/index.ts +142 -9
- package/src/types/createPerEntryCachedCheck.ts +0 -166
- /package/dist/types/{types/createPerEntryCachedCheck.d.ts → action/mutationBatch.d.ts} +0 -0
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { isObservableObject, remove } from "mobx"
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
isTypeCheckingAfterChangeEnabled,
|
|
4
|
+
runTypeCheckingAfterChange,
|
|
5
|
+
} from "../tweaker/typeChecking"
|
|
3
6
|
import { withoutTypeChecking } from "../tweaker/withoutTypeChecking"
|
|
4
7
|
import { isPlainObject } from "../utils"
|
|
5
8
|
import { withErrorPathSegment } from "../utils/errorDiagnostics"
|
|
@@ -23,7 +26,8 @@ function reconcilePlainObjectSnapshot(
|
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
const plainObj = value
|
|
26
|
-
const
|
|
29
|
+
const typeCheckingAfterChangeEnabled = isTypeCheckingAfterChangeEnabled()
|
|
30
|
+
const snapshotBeforeChanges = typeCheckingAfterChangeEnabled ? getSnapshot(plainObj) : undefined
|
|
27
31
|
|
|
28
32
|
withoutTypeChecking(() => {
|
|
29
33
|
// remove excess props
|
|
@@ -54,7 +58,9 @@ function reconcilePlainObjectSnapshot(
|
|
|
54
58
|
}
|
|
55
59
|
})
|
|
56
60
|
|
|
57
|
-
|
|
61
|
+
if (typeCheckingAfterChangeEnabled) {
|
|
62
|
+
runTypeCheckingAfterChange(plainObj, undefined, snapshotBeforeChanges)
|
|
63
|
+
}
|
|
58
64
|
|
|
59
65
|
return plainObj
|
|
60
66
|
}
|
package/src/treeUtils/draft.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { action, computed } from "mobx"
|
|
2
1
|
import { pathToTargetPathIds } from "../actionMiddlewares/utils"
|
|
3
2
|
import { resolvePath, resolvePathCheckingIds, skipIdChecking } from "../parent/path"
|
|
4
3
|
import type { Path } from "../parent/pathTypes"
|
|
@@ -7,7 +6,7 @@ import { applySnapshot } from "../snapshot/applySnapshot"
|
|
|
7
6
|
import { fromSnapshot } from "../snapshot/fromSnapshot"
|
|
8
7
|
import { getSnapshot } from "../snapshot/getSnapshot"
|
|
9
8
|
import { assertTweakedObject } from "../tweaker/core"
|
|
10
|
-
import { failure } from "../utils"
|
|
9
|
+
import { failure, mobxAction, mobxComputed } from "../utils"
|
|
11
10
|
import { deepEquals } from "./deepEquals"
|
|
12
11
|
|
|
13
12
|
/**
|
|
@@ -25,7 +24,7 @@ export class Draft<T extends object> {
|
|
|
25
24
|
/**
|
|
26
25
|
* Commits current draft changes to the original object.
|
|
27
26
|
*/
|
|
28
|
-
@
|
|
27
|
+
@mobxAction
|
|
29
28
|
commit(): void {
|
|
30
29
|
applySnapshot(this.originalData, getSnapshot(this.data))
|
|
31
30
|
}
|
|
@@ -37,7 +36,7 @@ export class Draft<T extends object> {
|
|
|
37
36
|
*
|
|
38
37
|
* @param path Path to commit.
|
|
39
38
|
*/
|
|
40
|
-
@
|
|
39
|
+
@mobxAction
|
|
41
40
|
commitByPath(path: Path): void {
|
|
42
41
|
const draftTarget = resolvePath(this.data, path)
|
|
43
42
|
if (!draftTarget.resolved) {
|
|
@@ -63,7 +62,7 @@ export class Draft<T extends object> {
|
|
|
63
62
|
/**
|
|
64
63
|
* Resets the draft to be an exact copy of the current state of the original object.
|
|
65
64
|
*/
|
|
66
|
-
@
|
|
65
|
+
@mobxAction
|
|
67
66
|
reset(): void {
|
|
68
67
|
applySnapshot(this.data, this.originalSnapshot)
|
|
69
68
|
}
|
|
@@ -75,7 +74,7 @@ export class Draft<T extends object> {
|
|
|
75
74
|
*
|
|
76
75
|
* @param path Path to reset.
|
|
77
76
|
*/
|
|
78
|
-
@
|
|
77
|
+
@mobxAction
|
|
79
78
|
resetByPath(path: Path): void {
|
|
80
79
|
const originalTarget = resolvePath(this.originalData, path)
|
|
81
80
|
if (!originalTarget.resolved) {
|
|
@@ -101,7 +100,7 @@ export class Draft<T extends object> {
|
|
|
101
100
|
/**
|
|
102
101
|
* Returns `true` if the draft has changed compared to the original object, `false` otherwise.
|
|
103
102
|
*/
|
|
104
|
-
@
|
|
103
|
+
@mobxComputed
|
|
105
104
|
get isDirty(): boolean {
|
|
106
105
|
return !deepEquals(getSnapshot(this.data), this.originalSnapshot)
|
|
107
106
|
}
|
|
@@ -135,7 +134,7 @@ export class Draft<T extends object> {
|
|
|
135
134
|
*/
|
|
136
135
|
readonly originalData: T
|
|
137
136
|
|
|
138
|
-
@
|
|
137
|
+
@mobxComputed
|
|
139
138
|
private get originalSnapshot() {
|
|
140
139
|
return getSnapshot(this.originalData)
|
|
141
140
|
}
|
package/src/tweaker/core.ts
CHANGED
|
@@ -1,20 +1,45 @@
|
|
|
1
1
|
import { runInAction } from "mobx"
|
|
2
|
-
import {
|
|
2
|
+
import { hasDataObjectParent } from "../parent/core"
|
|
3
3
|
import { failure, isPrimitive } from "../utils"
|
|
4
|
+
import { treeNodeMetadata } from "./treeNodeMetadata"
|
|
5
|
+
|
|
6
|
+
type Untweaker = (() => void) & {
|
|
7
|
+
[secondaryUntweakerSymbol]?: () => void
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const secondaryUntweakerSymbol = Symbol("secondaryUntweaker")
|
|
4
11
|
|
|
5
12
|
/**
|
|
13
|
+
* Stores two existing cleanup functions without allocating a third function to
|
|
14
|
+
* close over them. The primary function is internal and never exposed.
|
|
15
|
+
*
|
|
6
16
|
* @internal
|
|
7
17
|
*/
|
|
8
|
-
export
|
|
18
|
+
export function setTweakedObjectUntweakers(
|
|
19
|
+
value: object,
|
|
20
|
+
primaryUntweaker: Untweaker,
|
|
21
|
+
secondaryUntweaker: () => void
|
|
22
|
+
): void {
|
|
23
|
+
primaryUntweaker[secondaryUntweakerSymbol] = secondaryUntweaker
|
|
24
|
+
treeNodeMetadata.get(value)!.untweaker = primaryUntweaker
|
|
25
|
+
}
|
|
9
26
|
|
|
10
27
|
/**
|
|
11
28
|
* @internal
|
|
12
29
|
*/
|
|
13
30
|
export function isTweakedObject(value: unknown, canBeDataObject: boolean): value is object {
|
|
14
|
-
if (!canBeDataObject &&
|
|
31
|
+
if (!canBeDataObject && hasDataObjectParent(value as object)) {
|
|
15
32
|
return false
|
|
16
33
|
}
|
|
17
|
-
return
|
|
34
|
+
return treeNodeMetadata.get(value as object)?.tweaked === true
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @internal
|
|
39
|
+
*/
|
|
40
|
+
export function runTweakedObjectUntweakers(untweaker: Untweaker): void {
|
|
41
|
+
untweaker()
|
|
42
|
+
untweaker[secondaryUntweakerSymbol]?.()
|
|
18
43
|
}
|
|
19
44
|
|
|
20
45
|
/**
|
|
@@ -35,7 +60,7 @@ export function assertTweakedObject(
|
|
|
35
60
|
argName: string,
|
|
36
61
|
canBeDataObject = false
|
|
37
62
|
): asserts treeNode is object {
|
|
38
|
-
if (!canBeDataObject &&
|
|
63
|
+
if (!canBeDataObject && hasDataObjectParent(treeNode as object)) {
|
|
39
64
|
throw failure(`${argName} must be the model object instance instead of the '$' sub-object`)
|
|
40
65
|
}
|
|
41
66
|
if (isPrimitive(treeNode) || !isTweakedObject(treeNode, true)) {
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ObjectChildrenData } from "../parent/coreObjectChildren"
|
|
2
|
+
import type { ParentPath } from "../parent/path"
|
|
3
|
+
import type { SnapshotData } from "../snapshot/internal"
|
|
4
|
+
|
|
5
|
+
/** @internal */
|
|
6
|
+
export interface TreeNodeMetadata {
|
|
7
|
+
tweaked: boolean
|
|
8
|
+
untweaker: (() => void) | undefined
|
|
9
|
+
parentPath: ParentPath<object> | undefined
|
|
10
|
+
dataObjectParent: object | undefined
|
|
11
|
+
objectChildren: ObjectChildrenData | undefined
|
|
12
|
+
snapshot: SnapshotData | undefined
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** @internal */
|
|
16
|
+
export const treeNodeMetadata = new WeakMap<object, TreeNodeMetadata>()
|
|
17
|
+
|
|
18
|
+
/** @internal */
|
|
19
|
+
export function getOrCreateTreeNodeMetadata(value: object): TreeNodeMetadata {
|
|
20
|
+
let metadata = treeNodeMetadata.get(value)
|
|
21
|
+
if (!metadata) {
|
|
22
|
+
metadata = {
|
|
23
|
+
tweaked: false,
|
|
24
|
+
untweaker: undefined,
|
|
25
|
+
parentPath: undefined,
|
|
26
|
+
dataObjectParent: undefined,
|
|
27
|
+
objectChildren: undefined,
|
|
28
|
+
snapshot: undefined,
|
|
29
|
+
}
|
|
30
|
+
treeNodeMetadata.set(value, metadata)
|
|
31
|
+
}
|
|
32
|
+
return metadata
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** @internal */
|
|
36
|
+
export function markAsTweakedObject(value: object): void {
|
|
37
|
+
getOrCreateTreeNodeMetadata(value).tweaked = true
|
|
38
|
+
}
|
package/src/tweaker/tweak.ts
CHANGED
|
@@ -8,8 +8,9 @@ import { unsetInternalSnapshot } from "../snapshot/internal"
|
|
|
8
8
|
import type { AnyStandardType, TypeToData } from "../types/schemas"
|
|
9
9
|
import { typeCheck } from "../types/typeCheck"
|
|
10
10
|
import { failure, inDevMode, isMap, isObject, isPrimitive, isSet } from "../utils"
|
|
11
|
-
import { isTweakedObject,
|
|
11
|
+
import { isTweakedObject, runTweakedObjectUntweakers } from "./core"
|
|
12
12
|
import { registerDefaultTweakers } from "./registerDefaultTweakers"
|
|
13
|
+
import { treeNodeMetadata } from "./treeNodeMetadata"
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Turns an object (array, plain object) into a tree node,
|
|
@@ -153,7 +154,8 @@ export function tryUntweak(value: any): (() => void) | undefined {
|
|
|
153
154
|
}
|
|
154
155
|
}
|
|
155
156
|
|
|
156
|
-
const
|
|
157
|
+
const metadata = treeNodeMetadata.get(value)
|
|
158
|
+
const untweaker = metadata?.untweaker
|
|
157
159
|
if (!untweaker) {
|
|
158
160
|
return undefined
|
|
159
161
|
}
|
|
@@ -176,9 +178,18 @@ export function tryUntweak(value: any): (() => void) | undefined {
|
|
|
176
178
|
|
|
177
179
|
return () => {
|
|
178
180
|
// post-untweaking, call the untweaker
|
|
179
|
-
untweaker
|
|
181
|
+
runTweakedObjectUntweakers(untweaker)
|
|
180
182
|
|
|
181
|
-
|
|
183
|
+
// Match the former independent-map ordering: the node stops being tweaked
|
|
184
|
+
// before its snapshot is unset, but the shared record must stay alive until
|
|
185
|
+
// snapshot cleanup has consumed it.
|
|
186
|
+
metadata.tweaked = false
|
|
187
|
+
metadata.untweaker = undefined
|
|
182
188
|
unsetInternalSnapshot(value)
|
|
189
|
+
// These associations previously lived in independent WeakMaps and remain
|
|
190
|
+
// valid across untweak/retweak, so keep their shared record when present.
|
|
191
|
+
if (metadata.dataObjectParent === undefined && metadata.objectChildren === undefined) {
|
|
192
|
+
treeNodeMetadata.delete(value)
|
|
193
|
+
}
|
|
183
194
|
}
|
|
184
195
|
}
|