mobx-keystone 1.20.0 → 1.22.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 +864 -853
- package/README.md +61 -61
- package/dist/mobx-keystone.esm.js +11336 -11148
- package/dist/mobx-keystone.esm.mjs +11336 -11148
- package/dist/mobx-keystone.umd.js +12229 -11738
- package/dist/types/actionMiddlewares/undoMiddleware.d.ts +1 -1
- package/dist/types/modelShared/prop.d.ts +5 -0
- package/dist/types/redux/connectReduxDevTools.d.ts +17 -4
- package/dist/types/ref/Ref.d.ts +1 -1
- package/dist/types/treeUtils/sandbox.d.ts +1 -1
- package/dist/types/types/TypeChecker.d.ts +1 -1
- package/dist/types/types/arrayBased/typesArray.d.ts +1 -1
- package/dist/types/types/arrayBased/typesTuple.d.ts +1 -1
- package/dist/types/types/objectBased/typesArraySet.d.ts +1 -1
- package/dist/types/types/objectBased/typesDataModelData.d.ts +1 -1
- package/dist/types/types/objectBased/typesModel.d.ts +1 -1
- package/dist/types/types/objectBased/typesObject.d.ts +3 -3
- package/dist/types/types/objectBased/typesObjectMap.d.ts +1 -1
- package/dist/types/types/objectBased/typesRecord.d.ts +1 -1
- package/dist/types/types/primitiveBased/typesPrimitive.d.ts +1 -1
- package/dist/types/types/types.d.ts +3 -3
- package/dist/types/types/utility/typesCodec.d.ts +1 -6
- package/dist/types/types/utility/typesCodecCore.d.ts +1 -1
- package/dist/types/types/utility/typesOr.d.ts +1 -1
- package/dist/types/types/utility/typesRefinement.d.ts +1 -1
- package/dist/types/types/utility/typesSkipCheck.d.ts +1 -1
- package/dist/types/types/utility/typesTag.d.ts +1 -1
- package/dist/types/wrappers/ObjectMap.d.ts +2 -0
- package/dist/types/wrappers/asMap.d.ts +10 -6
- package/package.json +14 -12
- package/src/action/applyAction.ts +125 -114
- package/src/action/applyMethodCall.ts +37 -37
- package/src/action/isModelAction.ts +16 -16
- package/src/action/middleware.ts +137 -137
- package/src/action/modelFlow.ts +240 -240
- package/src/action/modelFlowPromiseGenerator.ts +127 -125
- package/src/action/pendingActions.ts +42 -42
- package/src/action/wrapInAction.ts +156 -156
- package/src/actionMiddlewares/actionSerialization/actionSerialization.ts +1 -1
- package/src/actionMiddlewares/actionSerialization/applySerializedAction.ts +172 -172
- package/src/actionMiddlewares/actionSerialization/arraySerializer.ts +20 -20
- package/src/actionMiddlewares/actionSerialization/dateSerializer.ts +17 -17
- package/src/actionMiddlewares/actionSerialization/mapSerializer.ts +42 -42
- package/src/actionMiddlewares/actionSerialization/objectPathSerializer.ts +50 -50
- package/src/actionMiddlewares/actionSerialization/objectSnapshotSerializer.ts +21 -21
- package/src/actionMiddlewares/actionSerialization/plainObjectSerializer.ts +24 -32
- package/src/actionMiddlewares/actionSerialization/primitiveSerializer.ts +51 -51
- package/src/actionMiddlewares/actionSerialization/setSerializer.ts +37 -37
- package/src/actionMiddlewares/actionTrackingMiddleware.ts +3 -3
- package/src/actionMiddlewares/onActionMiddleware.ts +2 -2
- package/src/actionMiddlewares/readonlyMiddleware.ts +2 -2
- package/src/actionMiddlewares/transactionMiddleware.ts +4 -4
- package/src/actionMiddlewares/undoMiddleware.ts +804 -796
- package/src/actionMiddlewares/utils.ts +2 -2
- package/src/computedTree/computedTree.ts +143 -143
- package/src/context/context.ts +1 -1
- package/src/dataModel/BaseDataModel.ts +194 -192
- package/src/dataModel/actions.ts +1 -1
- package/src/dataModel/newDataModel.ts +57 -57
- package/src/deepChange/index.ts +1 -1
- package/src/deepChange/onDeepChange.ts +244 -244
- package/src/frozen/Frozen.ts +146 -146
- package/src/globalConfig/globalConfig.ts +107 -107
- package/src/index.ts +24 -24
- package/src/model/BaseModel.ts +275 -273
- package/src/model/ModelConstructorOptions.ts +15 -15
- package/src/model/getModelMetadata.ts +51 -51
- package/src/model/index.ts +6 -6
- package/src/model/mixins.ts +288 -288
- package/src/model/newModel.ts +301 -301
- package/src/model/utils.ts +249 -249
- package/src/modelShared/modelDecorator.ts +260 -253
- package/src/modelShared/modelInfo.ts +50 -50
- package/src/modelShared/modelSymbols.ts +3 -3
- package/src/modelShared/newModel.ts +25 -25
- package/src/modelShared/prop.ts +713 -684
- package/src/modelShared/sharedInternalModel.ts +427 -417
- package/src/modelShared/utils.ts +24 -24
- package/src/parent/core.ts +65 -65
- package/src/parent/coreObjectChildren.ts +180 -180
- package/src/parent/detach.ts +47 -47
- package/src/parent/findParent.ts +1 -1
- package/src/parent/getChildrenObjects.ts +25 -25
- package/src/parent/path.ts +386 -381
- package/src/parent/setParent.ts +149 -149
- package/src/parent/walkTree.ts +1 -1
- package/src/patch/applyPatches.ts +187 -187
- package/src/patch/jsonPatch.ts +108 -108
- package/src/patch/patchRecorder.ts +6 -1
- package/src/redux/connectReduxDevTools.ts +39 -7
- package/src/redux/redux.ts +6 -2
- package/src/ref/Ref.ts +1 -1
- package/src/ref/core.ts +339 -345
- package/src/ref/customRef.ts +3 -3
- package/src/ref/rootRef.ts +100 -100
- package/src/rootStore/attachDetach.ts +89 -89
- package/src/rootStore/rootStore.ts +1 -1
- package/src/snapshot/SnapshotOf.ts +104 -104
- package/src/snapshot/SnapshotProcessingError.ts +45 -45
- package/src/snapshot/applySnapshot.ts +177 -181
- package/src/snapshot/cloneTreeValue.ts +30 -30
- package/src/snapshot/fromArraySnapshot.ts +27 -33
- package/src/snapshot/fromModelSnapshot.ts +70 -70
- package/src/snapshot/fromPlainObjectSnapshot.ts +47 -42
- package/src/snapshot/fromSnapshot.ts +198 -198
- package/src/snapshot/getSnapshot.ts +80 -79
- package/src/snapshot/index.ts +8 -8
- package/src/snapshot/internal.ts +230 -230
- package/src/snapshot/reconcileArraySnapshot.ts +70 -70
- package/src/snapshot/reconcileModelSnapshot.ts +155 -150
- package/src/snapshot/reconcilePlainObjectSnapshot.ts +72 -72
- package/src/snapshot/reconcileSnapshot.ts +88 -88
- package/src/standardActions/actions.ts +64 -64
- package/src/standardActions/objectActions.ts +60 -60
- package/src/transforms/ImmutableDate.ts +93 -93
- package/src/transforms/asMap.ts +50 -50
- package/src/transforms/asSet.ts +22 -22
- package/src/transforms/bigint.ts +20 -20
- package/src/transforms/date.ts +40 -40
- package/src/treeUtils/deepEquals.ts +55 -55
- package/src/treeUtils/sandbox.ts +6 -3
- package/src/tweaker/TweakerPriority.ts +9 -9
- package/src/tweaker/tweak.ts +4 -3
- package/src/tweaker/tweakArray.ts +530 -475
- package/src/tweaker/tweakFrozen.ts +42 -42
- package/src/tweaker/tweakModel.ts +1 -1
- package/src/tweaker/tweakPlainObject.ts +355 -355
- package/src/tweaker/typeChecking.ts +101 -101
- package/src/types/SnapshotTypeMismatchError.ts +46 -46
- package/src/types/TypeCheckError.ts +183 -184
- package/src/types/TypeChecker.ts +202 -185
- package/src/types/arrayBased/typesArray.ts +136 -137
- package/src/types/arrayBased/typesTuple.ts +138 -139
- package/src/types/createPerEntryCachedCheck.ts +166 -160
- package/src/types/index.ts +6 -6
- package/src/types/objectBased/typesArraySet.ts +133 -134
- package/src/types/objectBased/typesDataModelData.ts +203 -204
- package/src/types/objectBased/typesModel.ts +220 -221
- package/src/types/objectBased/typesObject.ts +308 -310
- package/src/types/objectBased/typesObjectMap.ts +142 -143
- package/src/types/objectBased/typesRecord.ts +156 -157
- package/src/types/objectBased/typesRef.ts +89 -89
- package/src/types/primitiveBased/typesEnum.ts +63 -63
- package/src/types/primitiveBased/typesPrimitive.ts +219 -220
- package/src/types/registerDefaultStandardTypeResolvers.ts +21 -21
- package/src/types/resolveTypeChecker.ts +78 -78
- package/src/types/schemas.ts +208 -208
- package/src/types/tProp.ts +277 -268
- package/src/types/typeCheck.ts +21 -21
- package/src/types/typeCheckErrorUtils.ts +23 -23
- package/src/types/types.ts +142 -142
- package/src/types/utility/typeToStoredData.ts +37 -37
- package/src/types/utility/typesBigInt.ts +15 -15
- package/src/types/utility/typesCodec.ts +41 -38
- package/src/types/utility/typesCodecCore.ts +178 -178
- package/src/types/utility/typesCodecSupport.ts +806 -806
- package/src/types/utility/typesDate.ts +27 -27
- package/src/types/utility/typesMap.ts +253 -222
- package/src/types/utility/typesOr.ts +263 -259
- package/src/types/utility/typesRefinement.ts +131 -125
- package/src/types/utility/typesSet.ts +110 -110
- package/src/types/utility/typesSkipCheck.ts +69 -70
- package/src/types/utility/typesTag.ts +88 -82
- package/src/types/utility/typesUnchecked.ts +40 -40
- package/src/utils/AnyFunction.ts +4 -4
- package/src/utils/ModelPool.ts +59 -59
- package/src/utils/chainFns.ts +18 -18
- package/src/utils/decorators.ts +274 -274
- package/src/utils/errorDiagnostics.ts +204 -204
- package/src/utils/index.ts +443 -372
- package/src/wrappers/ArraySet.ts +156 -156
- package/src/wrappers/ObjectMap.ts +155 -136
- package/src/wrappers/asMap.ts +65 -30
- package/src/wrappers/asSet.ts +3 -3
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { BuiltInAction } from "./builtInActions"
|
|
5
|
-
import { ActionContextActionType } from "./context"
|
|
6
|
-
import { wrapInAction } from "./wrapInAction"
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Calls an object method wrapped in an action.
|
|
10
|
-
*
|
|
11
|
-
* @param node Target object.
|
|
12
|
-
* @param methodName Method name.
|
|
13
|
-
*/
|
|
14
|
-
export function applyMethodCall<O extends object, K extends keyof O, FN extends O[K]>(
|
|
15
|
-
node: O,
|
|
16
|
-
methodName: K,
|
|
17
|
-
...args: FN extends AnyFunction ? Parameters<FN> : never
|
|
18
|
-
): FN extends AnyFunction ? ReturnType<FN> : never {
|
|
19
|
-
assertTweakedObject(node, "node")
|
|
20
|
-
|
|
21
|
-
return wrappedInternalApplyMethodCall().call(node, methodName as string | number, args)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* @internal
|
|
26
|
-
*/
|
|
27
|
-
export function internalApplyMethodCall(this: any, methodName: string | number, args: any[]): any {
|
|
28
|
-
return this[methodName](...args)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const wrappedInternalApplyMethodCall = lazy(() =>
|
|
32
|
-
wrapInAction({
|
|
33
|
-
nameOrNameFn: BuiltInAction.ApplyMethodCall,
|
|
34
|
-
fn: internalApplyMethodCall,
|
|
35
|
-
actionType: ActionContextActionType.Sync,
|
|
36
|
-
})
|
|
37
|
-
)
|
|
1
|
+
import { assertTweakedObject } from "../tweaker/core"
|
|
2
|
+
import { lazy } from "../utils"
|
|
3
|
+
import type { AnyFunction } from "../utils/AnyFunction"
|
|
4
|
+
import { BuiltInAction } from "./builtInActions"
|
|
5
|
+
import { ActionContextActionType } from "./context"
|
|
6
|
+
import { wrapInAction } from "./wrapInAction"
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Calls an object method wrapped in an action.
|
|
10
|
+
*
|
|
11
|
+
* @param node Target object.
|
|
12
|
+
* @param methodName Method name.
|
|
13
|
+
*/
|
|
14
|
+
export function applyMethodCall<O extends object, K extends keyof O, FN extends O[K]>(
|
|
15
|
+
node: O,
|
|
16
|
+
methodName: K,
|
|
17
|
+
...args: FN extends AnyFunction ? Parameters<FN> : never
|
|
18
|
+
): FN extends AnyFunction ? ReturnType<FN> : never {
|
|
19
|
+
assertTweakedObject(node, "node")
|
|
20
|
+
|
|
21
|
+
return wrappedInternalApplyMethodCall().call(node, methodName as string | number, args)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
export function internalApplyMethodCall(this: any, methodName: string | number, args: any[]): any {
|
|
28
|
+
return this[methodName](...args)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const wrappedInternalApplyMethodCall = lazy(() =>
|
|
32
|
+
wrapInAction({
|
|
33
|
+
nameOrNameFn: BuiltInAction.ApplyMethodCall,
|
|
34
|
+
fn: internalApplyMethodCall,
|
|
35
|
+
actionType: ActionContextActionType.Sync,
|
|
36
|
+
})
|
|
37
|
+
)
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { AnyFunction } from "../utils/AnyFunction"
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @internal
|
|
5
|
-
*/
|
|
6
|
-
export const modelActionSymbol = Symbol("modelAction")
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Returns if the given function is a model action or not.
|
|
10
|
-
*
|
|
11
|
-
* @param fn Function to check.
|
|
12
|
-
* @returns
|
|
13
|
-
*/
|
|
14
|
-
export function isModelAction(fn: AnyFunction): boolean {
|
|
15
|
-
return typeof fn === "function" && modelActionSymbol in fn
|
|
16
|
-
}
|
|
1
|
+
import type { AnyFunction } from "../utils/AnyFunction"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
export const modelActionSymbol = Symbol("modelAction")
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Returns if the given function is a model action or not.
|
|
10
|
+
*
|
|
11
|
+
* @param fn Function to check.
|
|
12
|
+
* @returns
|
|
13
|
+
*/
|
|
14
|
+
export function isModelAction(fn: AnyFunction): boolean {
|
|
15
|
+
return typeof fn === "function" && modelActionSymbol in fn
|
|
16
|
+
}
|
package/src/action/middleware.ts
CHANGED
|
@@ -1,137 +1,137 @@
|
|
|
1
|
-
import { fastGetParent } from "../parent/path"
|
|
2
|
-
import { isChildOfParent } from "../parent/path2"
|
|
3
|
-
import { assertTweakedObject } from "../tweaker/core"
|
|
4
|
-
import { assertIsFunction, assertIsObject, deleteFromArray, failure } from "../utils"
|
|
5
|
-
import type { ActionContext } from "./context"
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* An action middleware.
|
|
9
|
-
*/
|
|
10
|
-
export interface ActionMiddleware {
|
|
11
|
-
/**
|
|
12
|
-
* Subtree root object (object and child objects) this middleware will run for.
|
|
13
|
-
* This target "filter" will be run before the custom filter.
|
|
14
|
-
*/
|
|
15
|
-
readonly subtreeRoot: object
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* A filter function to decide if an action middleware function should be run or not.
|
|
19
|
-
*/
|
|
20
|
-
filter?: (ctx: ActionContext) => boolean
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* An action middleware function.
|
|
24
|
-
* Rember to `return next()` if you want to continue the action or throw if you want to cancel it.
|
|
25
|
-
*/
|
|
26
|
-
middleware: (ctx: ActionContext, next: () => any) => any
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* The disposer of an action middleware.
|
|
31
|
-
*/
|
|
32
|
-
export type ActionMiddlewareDisposer = () => void
|
|
33
|
-
|
|
34
|
-
type PartialActionMiddleware = Pick<ActionMiddleware, "filter" | "middleware">
|
|
35
|
-
|
|
36
|
-
const perObjectActionMiddlewares = new WeakMap<object, PartialActionMiddleware[]>()
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* @internal
|
|
40
|
-
*
|
|
41
|
-
* Runs a callback for each action middlewares to be run over a given object.
|
|
42
|
-
*
|
|
43
|
-
* @returns
|
|
44
|
-
*/
|
|
45
|
-
export function forEachActionMiddleware(
|
|
46
|
-
obj: object,
|
|
47
|
-
callback: (middleware: PartialActionMiddleware) => void
|
|
48
|
-
): void {
|
|
49
|
-
// when we call a middleware we will call the middlewares of that object plus all parent objects
|
|
50
|
-
// the parent object middlewares are run last
|
|
51
|
-
|
|
52
|
-
// since an array like [a, b, c] will be called like c(b(a())) this means that we need to call
|
|
53
|
-
// the parent object ones at the end of the array
|
|
54
|
-
|
|
55
|
-
let current: unknown = obj
|
|
56
|
-
while (current) {
|
|
57
|
-
const objMwares = perObjectActionMiddlewares.get(current)
|
|
58
|
-
if (objMwares && objMwares.length > 0) {
|
|
59
|
-
objMwares.forEach(callback)
|
|
60
|
-
}
|
|
61
|
-
current = fastGetParent(current, false)
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* @internal
|
|
66
|
-
*
|
|
67
|
-
* Returns the action middlewares to be run over a given object.
|
|
68
|
-
*
|
|
69
|
-
* @returns
|
|
70
|
-
*/
|
|
71
|
-
export function getPerObjectActionMiddlewares(obj: object): PartialActionMiddleware[][] {
|
|
72
|
-
const result: PartialActionMiddleware[][] = []
|
|
73
|
-
|
|
74
|
-
let current: unknown = obj
|
|
75
|
-
while (current) {
|
|
76
|
-
const objMwares = perObjectActionMiddlewares.get(current)
|
|
77
|
-
if (objMwares && objMwares.length > 0) {
|
|
78
|
-
result.push(objMwares)
|
|
79
|
-
}
|
|
80
|
-
current = fastGetParent(current, false)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return result
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Adds a global action middleware to be run when an action is performed.
|
|
88
|
-
* It is usually preferable to use `onActionMiddleware` instead to limit it to a given tree and only to topmost level actions
|
|
89
|
-
* or `actionTrackingMiddleware` for a simplified middleware.
|
|
90
|
-
*
|
|
91
|
-
* @param mware Action middleware to be run.
|
|
92
|
-
* @returns A disposer to cancel the middleware. Note that if you don't plan to do an early disposal of the middleware
|
|
93
|
-
* calling this function becomes optional.
|
|
94
|
-
*/
|
|
95
|
-
export function addActionMiddleware(mware: ActionMiddleware): ActionMiddlewareDisposer {
|
|
96
|
-
assertIsObject(mware, "middleware")
|
|
97
|
-
|
|
98
|
-
const { middleware, subtreeRoot } = mware
|
|
99
|
-
let { filter } = mware
|
|
100
|
-
|
|
101
|
-
assertTweakedObject(subtreeRoot, "middleware.subtreeRoot")
|
|
102
|
-
assertIsFunction(middleware, "middleware.middleware")
|
|
103
|
-
if (filter && typeof filter !== "function") {
|
|
104
|
-
throw failure("middleware.filter must be a function or undefined")
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// reminder: never turn middlewares into actions or else
|
|
108
|
-
// reactions will not be picked up by the undo manager
|
|
109
|
-
|
|
110
|
-
if (subtreeRoot) {
|
|
111
|
-
const targetFilter = (ctx: ActionContext) =>
|
|
112
|
-
ctx.target === subtreeRoot || isChildOfParent(ctx.target, subtreeRoot)
|
|
113
|
-
|
|
114
|
-
if (filter) {
|
|
115
|
-
const customFilter = filter
|
|
116
|
-
filter = (ctx) => {
|
|
117
|
-
return targetFilter(ctx) && customFilter(ctx)
|
|
118
|
-
}
|
|
119
|
-
} else {
|
|
120
|
-
filter = targetFilter
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const actualMware = { middleware, filter }
|
|
125
|
-
|
|
126
|
-
let objMwares = perObjectActionMiddlewares.get(subtreeRoot)
|
|
127
|
-
if (objMwares) {
|
|
128
|
-
objMwares.push(actualMware)
|
|
129
|
-
} else {
|
|
130
|
-
objMwares = [actualMware]
|
|
131
|
-
perObjectActionMiddlewares.set(subtreeRoot, objMwares)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return () => {
|
|
135
|
-
deleteFromArray(objMwares, actualMware)
|
|
136
|
-
}
|
|
137
|
-
}
|
|
1
|
+
import { fastGetParent } from "../parent/path"
|
|
2
|
+
import { isChildOfParent } from "../parent/path2"
|
|
3
|
+
import { assertTweakedObject } from "../tweaker/core"
|
|
4
|
+
import { assertIsFunction, assertIsObject, deleteFromArray, failure } from "../utils"
|
|
5
|
+
import type { ActionContext } from "./context"
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* An action middleware.
|
|
9
|
+
*/
|
|
10
|
+
export interface ActionMiddleware {
|
|
11
|
+
/**
|
|
12
|
+
* Subtree root object (object and child objects) this middleware will run for.
|
|
13
|
+
* This target "filter" will be run before the custom filter.
|
|
14
|
+
*/
|
|
15
|
+
readonly subtreeRoot: object
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A filter function to decide if an action middleware function should be run or not.
|
|
19
|
+
*/
|
|
20
|
+
filter?: (ctx: ActionContext) => boolean
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* An action middleware function.
|
|
24
|
+
* Rember to `return next()` if you want to continue the action or throw if you want to cancel it.
|
|
25
|
+
*/
|
|
26
|
+
middleware: (ctx: ActionContext, next: () => any) => any
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The disposer of an action middleware.
|
|
31
|
+
*/
|
|
32
|
+
export type ActionMiddlewareDisposer = () => void
|
|
33
|
+
|
|
34
|
+
type PartialActionMiddleware = Pick<ActionMiddleware, "filter" | "middleware">
|
|
35
|
+
|
|
36
|
+
const perObjectActionMiddlewares = new WeakMap<object, PartialActionMiddleware[]>()
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @internal
|
|
40
|
+
*
|
|
41
|
+
* Runs a callback for each action middlewares to be run over a given object.
|
|
42
|
+
*
|
|
43
|
+
* @returns
|
|
44
|
+
*/
|
|
45
|
+
export function forEachActionMiddleware(
|
|
46
|
+
obj: object,
|
|
47
|
+
callback: (middleware: PartialActionMiddleware) => void
|
|
48
|
+
): void {
|
|
49
|
+
// when we call a middleware we will call the middlewares of that object plus all parent objects
|
|
50
|
+
// the parent object middlewares are run last
|
|
51
|
+
|
|
52
|
+
// since an array like [a, b, c] will be called like c(b(a())) this means that we need to call
|
|
53
|
+
// the parent object ones at the end of the array
|
|
54
|
+
|
|
55
|
+
let current: unknown = obj
|
|
56
|
+
while (current) {
|
|
57
|
+
const objMwares = perObjectActionMiddlewares.get(current)
|
|
58
|
+
if (objMwares && objMwares.length > 0) {
|
|
59
|
+
objMwares.forEach(callback)
|
|
60
|
+
}
|
|
61
|
+
current = fastGetParent(current, false)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* @internal
|
|
66
|
+
*
|
|
67
|
+
* Returns the action middlewares to be run over a given object.
|
|
68
|
+
*
|
|
69
|
+
* @returns
|
|
70
|
+
*/
|
|
71
|
+
export function getPerObjectActionMiddlewares(obj: object): PartialActionMiddleware[][] {
|
|
72
|
+
const result: PartialActionMiddleware[][] = []
|
|
73
|
+
|
|
74
|
+
let current: unknown = obj
|
|
75
|
+
while (current) {
|
|
76
|
+
const objMwares = perObjectActionMiddlewares.get(current)
|
|
77
|
+
if (objMwares && objMwares.length > 0) {
|
|
78
|
+
result.push(objMwares)
|
|
79
|
+
}
|
|
80
|
+
current = fastGetParent(current, false)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return result
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Adds a global action middleware to be run when an action is performed.
|
|
88
|
+
* It is usually preferable to use `onActionMiddleware` instead to limit it to a given tree and only to topmost level actions
|
|
89
|
+
* or `actionTrackingMiddleware` for a simplified middleware.
|
|
90
|
+
*
|
|
91
|
+
* @param mware Action middleware to be run.
|
|
92
|
+
* @returns A disposer to cancel the middleware. Note that if you don't plan to do an early disposal of the middleware
|
|
93
|
+
* calling this function becomes optional.
|
|
94
|
+
*/
|
|
95
|
+
export function addActionMiddleware(mware: ActionMiddleware): ActionMiddlewareDisposer {
|
|
96
|
+
assertIsObject(mware, "middleware")
|
|
97
|
+
|
|
98
|
+
const { middleware, subtreeRoot } = mware
|
|
99
|
+
let { filter } = mware
|
|
100
|
+
|
|
101
|
+
assertTweakedObject(subtreeRoot, "middleware.subtreeRoot")
|
|
102
|
+
assertIsFunction(middleware, "middleware.middleware")
|
|
103
|
+
if (filter && typeof filter !== "function") {
|
|
104
|
+
throw failure("middleware.filter must be a function or undefined")
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// reminder: never turn middlewares into actions or else
|
|
108
|
+
// reactions will not be picked up by the undo manager
|
|
109
|
+
|
|
110
|
+
if (subtreeRoot) {
|
|
111
|
+
const targetFilter = (ctx: ActionContext) =>
|
|
112
|
+
ctx.target === subtreeRoot || isChildOfParent(ctx.target, subtreeRoot)
|
|
113
|
+
|
|
114
|
+
if (filter) {
|
|
115
|
+
const customFilter = filter
|
|
116
|
+
filter = (ctx) => {
|
|
117
|
+
return targetFilter(ctx) && customFilter(ctx)
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
filter = targetFilter
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const actualMware = { middleware, filter }
|
|
125
|
+
|
|
126
|
+
let objMwares = perObjectActionMiddlewares.get(subtreeRoot)
|
|
127
|
+
if (objMwares) {
|
|
128
|
+
objMwares.push(actualMware)
|
|
129
|
+
} else {
|
|
130
|
+
objMwares = [actualMware]
|
|
131
|
+
perObjectActionMiddlewares.set(subtreeRoot, objMwares)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return () => {
|
|
135
|
+
deleteFromArray(objMwares, actualMware)
|
|
136
|
+
}
|
|
137
|
+
}
|