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
package/src/action/modelFlow.ts
CHANGED
|
@@ -1,240 +1,240 @@
|
|
|
1
|
-
import type { O } from "ts-toolbelt"
|
|
2
|
-
import { failure } from "../utils"
|
|
3
|
-
import { copyFunctionMetadata, decorateWrapMethodOrField } from "../utils/decorators"
|
|
4
|
-
import { ActionContext, ActionContextActionType, ActionContextAsyncStepType } from "./context"
|
|
5
|
-
import { promiseGenerator } from "./modelFlowPromiseGenerator"
|
|
6
|
-
import { WrapInActionOverrideContextFn, wrapInAction } from "./wrapInAction"
|
|
7
|
-
|
|
8
|
-
const modelFlowSymbol = Symbol("modelFlow")
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* @internal
|
|
12
|
-
*/
|
|
13
|
-
export function flow<R, Args extends any[]>({
|
|
14
|
-
nameOrNameFn,
|
|
15
|
-
generator,
|
|
16
|
-
overrideContext,
|
|
17
|
-
}: {
|
|
18
|
-
nameOrNameFn: string | (() => string)
|
|
19
|
-
generator: (...args: Args) => IterableIterator<any>
|
|
20
|
-
overrideContext?: WrapInActionOverrideContextFn
|
|
21
|
-
}): (...args: Args) => Promise<any> {
|
|
22
|
-
// Implementation based on https://github.com/tj/co/blob/master/index.js
|
|
23
|
-
const flowFn = function (this: any, ...args: any[]) {
|
|
24
|
-
const name = typeof nameOrNameFn === "function" ? nameOrNameFn() : nameOrNameFn
|
|
25
|
-
|
|
26
|
-
const target = this
|
|
27
|
-
|
|
28
|
-
let previousAsyncStepContext: ActionContext | undefined
|
|
29
|
-
|
|
30
|
-
const ctxOverride = (stepType: ActionContextAsyncStepType): WrapInActionOverrideContextFn => {
|
|
31
|
-
return (ctx: O.Writable<ActionContext>, self) => {
|
|
32
|
-
if (overrideContext) {
|
|
33
|
-
overrideContext(ctx, self)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
ctx.previousAsyncStepContext = previousAsyncStepContext
|
|
37
|
-
ctx.spawnAsyncStepContext = previousAsyncStepContext
|
|
38
|
-
? previousAsyncStepContext.spawnAsyncStepContext
|
|
39
|
-
: ctx
|
|
40
|
-
ctx.asyncStepType = stepType
|
|
41
|
-
ctx.args = args
|
|
42
|
-
|
|
43
|
-
previousAsyncStepContext = ctx
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
let generatorRun = false
|
|
48
|
-
const gen = wrapInAction({
|
|
49
|
-
nameOrNameFn: name,
|
|
50
|
-
fn: () => {
|
|
51
|
-
generatorRun = true
|
|
52
|
-
return generator.apply(target, args as Args)
|
|
53
|
-
},
|
|
54
|
-
actionType: ActionContextActionType.Async,
|
|
55
|
-
overrideContext: ctxOverride(ActionContextAsyncStepType.Spawn),
|
|
56
|
-
}).apply(target)
|
|
57
|
-
|
|
58
|
-
if (!generatorRun) {
|
|
59
|
-
// maybe it got overridden into a sync action
|
|
60
|
-
|
|
61
|
-
return gen instanceof Promise ? gen : Promise.resolve(gen)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// use bound functions to fix es6 compilation
|
|
65
|
-
const genNext = gen.next.bind(gen)
|
|
66
|
-
const genThrow = gen.throw!.bind(gen)
|
|
67
|
-
|
|
68
|
-
const promise = new Promise<R>((resolve, reject) => {
|
|
69
|
-
function onFulfilled(res: any): void {
|
|
70
|
-
let ret: unknown
|
|
71
|
-
try {
|
|
72
|
-
ret = wrapInAction({
|
|
73
|
-
nameOrNameFn: name,
|
|
74
|
-
fn: genNext,
|
|
75
|
-
actionType: ActionContextActionType.Async,
|
|
76
|
-
overrideContext: ctxOverride(ActionContextAsyncStepType.Resume),
|
|
77
|
-
}).call(target, res)
|
|
78
|
-
} catch (e) {
|
|
79
|
-
wrapInAction({
|
|
80
|
-
nameOrNameFn: name,
|
|
81
|
-
fn: (err: any) => {
|
|
82
|
-
// we use a flow finisher to allow middlewares to tweak the return value before resolution
|
|
83
|
-
return {
|
|
84
|
-
value: err,
|
|
85
|
-
resolution: "reject",
|
|
86
|
-
|
|
87
|
-
accepter: resolve,
|
|
88
|
-
rejecter: reject,
|
|
89
|
-
} as FlowFinisher
|
|
90
|
-
},
|
|
91
|
-
actionType: ActionContextActionType.Async,
|
|
92
|
-
overrideContext: ctxOverride(ActionContextAsyncStepType.Throw),
|
|
93
|
-
isFlowFinisher: true,
|
|
94
|
-
}).call(target, e)
|
|
95
|
-
return
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
next(ret)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function onRejected(err: unknown): void {
|
|
102
|
-
let ret: unknown
|
|
103
|
-
try {
|
|
104
|
-
ret = wrapInAction({
|
|
105
|
-
nameOrNameFn: name,
|
|
106
|
-
fn: genThrow,
|
|
107
|
-
actionType: ActionContextActionType.Async,
|
|
108
|
-
overrideContext: ctxOverride(ActionContextAsyncStepType.ResumeError),
|
|
109
|
-
}).call(target, err)
|
|
110
|
-
} catch (e) {
|
|
111
|
-
wrapInAction({
|
|
112
|
-
nameOrNameFn: name,
|
|
113
|
-
fn: (err: any) => {
|
|
114
|
-
// we use a flow finisher to allow middlewares to tweak the return value before resolution
|
|
115
|
-
return {
|
|
116
|
-
value: err,
|
|
117
|
-
resolution: "reject",
|
|
118
|
-
|
|
119
|
-
accepter: resolve,
|
|
120
|
-
rejecter: reject,
|
|
121
|
-
} as FlowFinisher
|
|
122
|
-
},
|
|
123
|
-
actionType: ActionContextActionType.Async,
|
|
124
|
-
overrideContext: ctxOverride(ActionContextAsyncStepType.Throw),
|
|
125
|
-
isFlowFinisher: true,
|
|
126
|
-
}).call(target, e)
|
|
127
|
-
return
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
next(ret)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function next(ret: any): void {
|
|
134
|
-
if (ret && typeof ret.then === "function") {
|
|
135
|
-
// an async iterator
|
|
136
|
-
ret.then(next, reject)
|
|
137
|
-
} else if (ret.done) {
|
|
138
|
-
// done
|
|
139
|
-
wrapInAction({
|
|
140
|
-
nameOrNameFn: name,
|
|
141
|
-
fn: (val: any) => {
|
|
142
|
-
// we use a flow finisher to allow middlewares to tweak the return value before resolution
|
|
143
|
-
return {
|
|
144
|
-
value: val,
|
|
145
|
-
resolution: "accept",
|
|
146
|
-
|
|
147
|
-
accepter: resolve,
|
|
148
|
-
rejecter: reject,
|
|
149
|
-
} as FlowFinisher
|
|
150
|
-
},
|
|
151
|
-
actionType: ActionContextActionType.Async,
|
|
152
|
-
overrideContext: ctxOverride(ActionContextAsyncStepType.Return),
|
|
153
|
-
isFlowFinisher: true,
|
|
154
|
-
}).call(target, ret.value)
|
|
155
|
-
} else {
|
|
156
|
-
// continue
|
|
157
|
-
Promise.resolve(ret.value).then(onFulfilled, onRejected)
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
onFulfilled(undefined) // kick off the process
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
return promise
|
|
165
|
-
}
|
|
166
|
-
;(flowFn as any)[modelFlowSymbol] = true
|
|
167
|
-
|
|
168
|
-
copyFunctionMetadata(generator, flowFn)
|
|
169
|
-
|
|
170
|
-
return flowFn
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* @internal
|
|
175
|
-
*/
|
|
176
|
-
export interface FlowFinisher {
|
|
177
|
-
value: any
|
|
178
|
-
resolution: "accept" | "reject"
|
|
179
|
-
|
|
180
|
-
accepter(value: any): void
|
|
181
|
-
rejecter(value: any): void
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Returns if the given function is a model flow or not.
|
|
186
|
-
*
|
|
187
|
-
* @param fn Function to check.
|
|
188
|
-
* @returns
|
|
189
|
-
*/
|
|
190
|
-
export function isModelFlow(fn: unknown) {
|
|
191
|
-
return typeof fn === "function" && modelFlowSymbol in fn
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Decorator that turns a function generator into a model flow.
|
|
196
|
-
*/
|
|
197
|
-
export function modelFlow(...args: any[]): void {
|
|
198
|
-
// biome-ignore lint/correctness/noVoidTypeReturn: proper way to declare a decorator
|
|
199
|
-
return decorateWrapMethodOrField("modelFlow", args, (data, fn) => {
|
|
200
|
-
if (isModelFlow(fn)) {
|
|
201
|
-
return fn
|
|
202
|
-
} else {
|
|
203
|
-
if (typeof fn !== "function") {
|
|
204
|
-
throw failure("modelFlow has to be used over functions")
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
return flow({
|
|
208
|
-
nameOrNameFn: data.actionName,
|
|
209
|
-
generator: fn,
|
|
210
|
-
overrideContext: data.overrideContext,
|
|
211
|
-
})
|
|
212
|
-
}
|
|
213
|
-
})
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Tricks the TS compiler into thinking that a model flow generator function can be awaited
|
|
218
|
-
* (is a promise).
|
|
219
|
-
*
|
|
220
|
-
* @template A Function arguments.
|
|
221
|
-
* @template R Return value.
|
|
222
|
-
* @param fn Flow function.
|
|
223
|
-
* @returns
|
|
224
|
-
*/
|
|
225
|
-
export function _async<A extends any[], R>(
|
|
226
|
-
fn: (...args: A) => Generator<any, R, any>
|
|
227
|
-
): (...args: A) => Promise<R> {
|
|
228
|
-
return fn as any
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Makes a promise a flow, so it can be awaited with yield*.
|
|
233
|
-
*
|
|
234
|
-
* @template T Promise return type.
|
|
235
|
-
* @param promise Promise.
|
|
236
|
-
* @returns
|
|
237
|
-
*/
|
|
238
|
-
export function _await<T>(promise: Promise<T>): Generator<Promise<T>, T, unknown> {
|
|
239
|
-
return promiseGenerator.call(promise)
|
|
240
|
-
}
|
|
1
|
+
import type { O } from "ts-toolbelt"
|
|
2
|
+
import { failure } from "../utils"
|
|
3
|
+
import { copyFunctionMetadata, decorateWrapMethodOrField } from "../utils/decorators"
|
|
4
|
+
import { type ActionContext, ActionContextActionType, ActionContextAsyncStepType } from "./context"
|
|
5
|
+
import { promiseGenerator } from "./modelFlowPromiseGenerator"
|
|
6
|
+
import { type WrapInActionOverrideContextFn, wrapInAction } from "./wrapInAction"
|
|
7
|
+
|
|
8
|
+
const modelFlowSymbol = Symbol("modelFlow")
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
export function flow<R, Args extends any[]>({
|
|
14
|
+
nameOrNameFn,
|
|
15
|
+
generator,
|
|
16
|
+
overrideContext,
|
|
17
|
+
}: {
|
|
18
|
+
nameOrNameFn: string | (() => string)
|
|
19
|
+
generator: (...args: Args) => IterableIterator<any>
|
|
20
|
+
overrideContext?: WrapInActionOverrideContextFn
|
|
21
|
+
}): (...args: Args) => Promise<any> {
|
|
22
|
+
// Implementation based on https://github.com/tj/co/blob/master/index.js
|
|
23
|
+
const flowFn = function (this: any, ...args: any[]) {
|
|
24
|
+
const name = typeof nameOrNameFn === "function" ? nameOrNameFn() : nameOrNameFn
|
|
25
|
+
|
|
26
|
+
const target = this
|
|
27
|
+
|
|
28
|
+
let previousAsyncStepContext: ActionContext | undefined
|
|
29
|
+
|
|
30
|
+
const ctxOverride = (stepType: ActionContextAsyncStepType): WrapInActionOverrideContextFn => {
|
|
31
|
+
return (ctx: O.Writable<ActionContext>, self) => {
|
|
32
|
+
if (overrideContext) {
|
|
33
|
+
overrideContext(ctx, self)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
ctx.previousAsyncStepContext = previousAsyncStepContext
|
|
37
|
+
ctx.spawnAsyncStepContext = previousAsyncStepContext
|
|
38
|
+
? previousAsyncStepContext.spawnAsyncStepContext
|
|
39
|
+
: ctx
|
|
40
|
+
ctx.asyncStepType = stepType
|
|
41
|
+
ctx.args = args
|
|
42
|
+
|
|
43
|
+
previousAsyncStepContext = ctx
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let generatorRun = false
|
|
48
|
+
const gen = wrapInAction({
|
|
49
|
+
nameOrNameFn: name,
|
|
50
|
+
fn: () => {
|
|
51
|
+
generatorRun = true
|
|
52
|
+
return generator.apply(target, args as Args)
|
|
53
|
+
},
|
|
54
|
+
actionType: ActionContextActionType.Async,
|
|
55
|
+
overrideContext: ctxOverride(ActionContextAsyncStepType.Spawn),
|
|
56
|
+
}).apply(target)
|
|
57
|
+
|
|
58
|
+
if (!generatorRun) {
|
|
59
|
+
// maybe it got overridden into a sync action
|
|
60
|
+
|
|
61
|
+
return gen instanceof Promise ? gen : Promise.resolve(gen)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// use bound functions to fix es6 compilation
|
|
65
|
+
const genNext = gen.next.bind(gen)
|
|
66
|
+
const genThrow = gen.throw!.bind(gen)
|
|
67
|
+
|
|
68
|
+
const promise = new Promise<R>((resolve, reject) => {
|
|
69
|
+
function onFulfilled(res: any): void {
|
|
70
|
+
let ret: unknown
|
|
71
|
+
try {
|
|
72
|
+
ret = wrapInAction({
|
|
73
|
+
nameOrNameFn: name,
|
|
74
|
+
fn: genNext,
|
|
75
|
+
actionType: ActionContextActionType.Async,
|
|
76
|
+
overrideContext: ctxOverride(ActionContextAsyncStepType.Resume),
|
|
77
|
+
}).call(target, res)
|
|
78
|
+
} catch (e) {
|
|
79
|
+
wrapInAction({
|
|
80
|
+
nameOrNameFn: name,
|
|
81
|
+
fn: (err: any) => {
|
|
82
|
+
// we use a flow finisher to allow middlewares to tweak the return value before resolution
|
|
83
|
+
return {
|
|
84
|
+
value: err,
|
|
85
|
+
resolution: "reject",
|
|
86
|
+
|
|
87
|
+
accepter: resolve,
|
|
88
|
+
rejecter: reject,
|
|
89
|
+
} as FlowFinisher
|
|
90
|
+
},
|
|
91
|
+
actionType: ActionContextActionType.Async,
|
|
92
|
+
overrideContext: ctxOverride(ActionContextAsyncStepType.Throw),
|
|
93
|
+
isFlowFinisher: true,
|
|
94
|
+
}).call(target, e)
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
next(ret)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function onRejected(err: unknown): void {
|
|
102
|
+
let ret: unknown
|
|
103
|
+
try {
|
|
104
|
+
ret = wrapInAction({
|
|
105
|
+
nameOrNameFn: name,
|
|
106
|
+
fn: genThrow,
|
|
107
|
+
actionType: ActionContextActionType.Async,
|
|
108
|
+
overrideContext: ctxOverride(ActionContextAsyncStepType.ResumeError),
|
|
109
|
+
}).call(target, err)
|
|
110
|
+
} catch (e) {
|
|
111
|
+
wrapInAction({
|
|
112
|
+
nameOrNameFn: name,
|
|
113
|
+
fn: (err: any) => {
|
|
114
|
+
// we use a flow finisher to allow middlewares to tweak the return value before resolution
|
|
115
|
+
return {
|
|
116
|
+
value: err,
|
|
117
|
+
resolution: "reject",
|
|
118
|
+
|
|
119
|
+
accepter: resolve,
|
|
120
|
+
rejecter: reject,
|
|
121
|
+
} as FlowFinisher
|
|
122
|
+
},
|
|
123
|
+
actionType: ActionContextActionType.Async,
|
|
124
|
+
overrideContext: ctxOverride(ActionContextAsyncStepType.Throw),
|
|
125
|
+
isFlowFinisher: true,
|
|
126
|
+
}).call(target, e)
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
next(ret)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function next(ret: any): void {
|
|
134
|
+
if (ret && typeof ret.then === "function") {
|
|
135
|
+
// an async iterator
|
|
136
|
+
ret.then(next, reject)
|
|
137
|
+
} else if (ret.done) {
|
|
138
|
+
// done
|
|
139
|
+
wrapInAction({
|
|
140
|
+
nameOrNameFn: name,
|
|
141
|
+
fn: (val: any) => {
|
|
142
|
+
// we use a flow finisher to allow middlewares to tweak the return value before resolution
|
|
143
|
+
return {
|
|
144
|
+
value: val,
|
|
145
|
+
resolution: "accept",
|
|
146
|
+
|
|
147
|
+
accepter: resolve,
|
|
148
|
+
rejecter: reject,
|
|
149
|
+
} as FlowFinisher
|
|
150
|
+
},
|
|
151
|
+
actionType: ActionContextActionType.Async,
|
|
152
|
+
overrideContext: ctxOverride(ActionContextAsyncStepType.Return),
|
|
153
|
+
isFlowFinisher: true,
|
|
154
|
+
}).call(target, ret.value)
|
|
155
|
+
} else {
|
|
156
|
+
// continue
|
|
157
|
+
Promise.resolve(ret.value).then(onFulfilled, onRejected)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
onFulfilled(undefined) // kick off the process
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
return promise
|
|
165
|
+
}
|
|
166
|
+
;(flowFn as any)[modelFlowSymbol] = true
|
|
167
|
+
|
|
168
|
+
copyFunctionMetadata(generator, flowFn)
|
|
169
|
+
|
|
170
|
+
return flowFn
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* @internal
|
|
175
|
+
*/
|
|
176
|
+
export interface FlowFinisher {
|
|
177
|
+
value: any
|
|
178
|
+
resolution: "accept" | "reject"
|
|
179
|
+
|
|
180
|
+
accepter(value: any): void
|
|
181
|
+
rejecter(value: any): void
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Returns if the given function is a model flow or not.
|
|
186
|
+
*
|
|
187
|
+
* @param fn Function to check.
|
|
188
|
+
* @returns
|
|
189
|
+
*/
|
|
190
|
+
export function isModelFlow(fn: unknown) {
|
|
191
|
+
return typeof fn === "function" && modelFlowSymbol in fn
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Decorator that turns a function generator into a model flow.
|
|
196
|
+
*/
|
|
197
|
+
export function modelFlow(...args: any[]): void {
|
|
198
|
+
// biome-ignore lint/correctness/noVoidTypeReturn: proper way to declare a decorator
|
|
199
|
+
return decorateWrapMethodOrField("modelFlow", args, (data, fn) => {
|
|
200
|
+
if (isModelFlow(fn)) {
|
|
201
|
+
return fn
|
|
202
|
+
} else {
|
|
203
|
+
if (typeof fn !== "function") {
|
|
204
|
+
throw failure("modelFlow has to be used over functions")
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return flow({
|
|
208
|
+
nameOrNameFn: data.actionName,
|
|
209
|
+
generator: fn,
|
|
210
|
+
overrideContext: data.overrideContext,
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
})
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Tricks the TS compiler into thinking that a model flow generator function can be awaited
|
|
218
|
+
* (is a promise).
|
|
219
|
+
*
|
|
220
|
+
* @template A Function arguments.
|
|
221
|
+
* @template R Return value.
|
|
222
|
+
* @param fn Flow function.
|
|
223
|
+
* @returns
|
|
224
|
+
*/
|
|
225
|
+
export function _async<A extends any[], R>(
|
|
226
|
+
fn: (...args: A) => Generator<any, R, any>
|
|
227
|
+
): (...args: A) => Promise<R> {
|
|
228
|
+
return fn as any
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Makes a promise a flow, so it can be awaited with yield*.
|
|
233
|
+
*
|
|
234
|
+
* @template T Promise return type.
|
|
235
|
+
* @param promise Promise.
|
|
236
|
+
* @returns
|
|
237
|
+
*/
|
|
238
|
+
export function _await<T>(promise: Promise<T>): Generator<Promise<T>, T, unknown> {
|
|
239
|
+
return promiseGenerator.call(promise)
|
|
240
|
+
}
|