mobx-keystone 2.3.1 → 2.4.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 +16 -0
- package/dist/mobx-keystone.esm.js +5157 -3981
- package/dist/mobx-keystone.esm.mjs +5157 -3981
- package/dist/mobx-keystone.umd.js +5170 -3980
- package/dist/types/action/CallKind.d.ts +29 -0
- package/dist/types/action/applyAction.d.ts +7 -1
- package/dist/types/action/index.d.ts +1 -0
- package/dist/types/action/resolveCallName.d.ts +1 -0
- package/dist/types/actionMiddlewares/actionSerialization/actionSerialization.d.ts +14 -0
- package/dist/types/actionMiddlewares/actionSerialization/applySerializedAction.d.ts +6 -0
- package/dist/types/actionMiddlewares/actionSerialization/core.d.ts +7 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/patch/emitPatch.d.ts +6 -0
- package/dist/types/serialization/Call.d.ts +55 -0
- package/dist/types/serialization/CallError.d.ts +96 -0
- package/dist/types/serialization/JsonValue.d.ts +6 -0
- package/dist/types/serialization/Serializer.d.ts +84 -0
- package/dist/types/serialization/ValueSerializer.d.ts +88 -0
- package/dist/types/serialization/applyCall.d.ts +54 -0
- package/dist/types/serialization/builtinSerializers.d.ts +49 -0
- package/dist/types/serialization/codec.d.ts +1 -0
- package/dist/types/serialization/index.d.ts +8 -0
- package/dist/types/serialization/references.d.ts +74 -0
- package/dist/types/serialization/resolvedCall.d.ts +1 -0
- package/package.json +1 -1
- package/src/action/CallKind.ts +29 -0
- package/src/action/applyAction.ts +22 -49
- package/src/action/applySet.ts +21 -1
- package/src/action/index.ts +1 -0
- package/src/action/resolveCallName.ts +207 -0
- package/src/actionMiddlewares/actionSerialization/actionSerialization.ts +14 -0
- package/src/actionMiddlewares/actionSerialization/applySerializedAction.ts +6 -0
- package/src/actionMiddlewares/actionSerialization/core.ts +7 -0
- package/src/actionMiddlewares/actionSerialization/index.ts +2 -0
- package/src/actionMiddlewares/actionSerialization/objectPathSerializer.ts +3 -2
- package/src/index.ts +1 -0
- package/src/parent/path.ts +45 -12
- package/src/patch/emitPatch.ts +6 -0
- package/src/serialization/Call.ts +58 -0
- package/src/serialization/CallError.ts +153 -0
- package/src/serialization/JsonValue.ts +12 -0
- package/src/serialization/Serializer.ts +321 -0
- package/src/serialization/ValueSerializer.ts +98 -0
- package/src/serialization/applyCall.ts +190 -0
- package/src/serialization/builtinSerializers.ts +261 -0
- package/src/serialization/codec.ts +338 -0
- package/src/serialization/index.ts +15 -0
- package/src/serialization/references.ts +225 -0
- package/src/serialization/resolvedCall.ts +169 -0
- package/src/standardActions/actions.ts +11 -3
- package/src/utils/errorDiagnostics.ts +9 -4
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { AnyModel } from "../model/BaseModel";
|
|
2
|
+
import type { PathElement } from "../parent/pathTypes";
|
|
3
|
+
import type { ValueSerializer } from "./ValueSerializer";
|
|
4
|
+
/**
|
|
5
|
+
* What a reference serializer's `when` option is told about a node.
|
|
6
|
+
*/
|
|
7
|
+
export interface ReferenceNodeInfo {
|
|
8
|
+
/**
|
|
9
|
+
* Whether the node is a model.
|
|
10
|
+
*/
|
|
11
|
+
readonly isModel: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Whether the node is a value-type model (`Model({...}, { valueType: true })`).
|
|
14
|
+
*/
|
|
15
|
+
readonly isValueType: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Options of the built-in reference serializers.
|
|
19
|
+
*/
|
|
20
|
+
export interface ReferenceSerializerOptions {
|
|
21
|
+
/**
|
|
22
|
+
* Decides, for every node the serializer could reference, whether it does. A node it declines
|
|
23
|
+
* falls through the list like any other value: a model ends up as its snapshot, a tree array
|
|
24
|
+
* or plain object is walked. The call's target ignores it: it is always a reference.
|
|
25
|
+
*
|
|
26
|
+
* Defaults to declining value-type models: `(node, { isValueType }) => !isValueType`.
|
|
27
|
+
*/
|
|
28
|
+
when?(node: object, info: ReferenceNodeInfo): boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* A path reference, the payload of `{ "$mobxKeystone": "pathRef", "v": ... }`.
|
|
32
|
+
*/
|
|
33
|
+
export type PathRefJson = {
|
|
34
|
+
/**
|
|
35
|
+
* Path from the root to the node, through data nodes (as in patches).
|
|
36
|
+
*/
|
|
37
|
+
path: PathElement[];
|
|
38
|
+
/**
|
|
39
|
+
* Id of the model reached by each step of the path (`null` for non-models).
|
|
40
|
+
* Optional when decoding: without it, ids aren't checked.
|
|
41
|
+
*/
|
|
42
|
+
ids?: (string | null)[];
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* An id reference, the payload of `{ "$mobxKeystone": "idRef", "v": ... }`.
|
|
46
|
+
*/
|
|
47
|
+
export type IdRefJson = {
|
|
48
|
+
/**
|
|
49
|
+
* The model type (`$modelType`).
|
|
50
|
+
*/
|
|
51
|
+
type: string;
|
|
52
|
+
/**
|
|
53
|
+
* The model id.
|
|
54
|
+
*/
|
|
55
|
+
id: string;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* References nodes of the tree by their path from the root, checking the ids of the models along
|
|
59
|
+
* it: `{ "$mobxKeystone": "pathRef", "v": { "path": ["cards", 2], "ids": [null, "c1"] } }`.
|
|
60
|
+
* It reaches any node, including tree arrays and plain objects.
|
|
61
|
+
*
|
|
62
|
+
* @param options Options.
|
|
63
|
+
* @returns The reference serializer.
|
|
64
|
+
*/
|
|
65
|
+
export declare function pathRefs(options?: ReferenceSerializerOptions): ValueSerializer<object, PathRefJson>;
|
|
66
|
+
/**
|
|
67
|
+
* References models of the tree that have an id by their type and id:
|
|
68
|
+
* `{ "$mobxKeystone": "idRef", "v": { "type": "app/Card", "id": "c1" } }`. Ids are read and
|
|
69
|
+
* resolved as `getModelRefId` and `resolveId` do, and the type must match.
|
|
70
|
+
*
|
|
71
|
+
* @param options Options.
|
|
72
|
+
* @returns The reference serializer.
|
|
73
|
+
*/
|
|
74
|
+
export declare function idRefs(options?: ReferenceSerializerOptions): ValueSerializer<AnyModel, IdRefJson>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a call's name resolved to on its target.
|
|
3
|
+
*/
|
|
4
|
+
export enum CallKind {
|
|
5
|
+
/**
|
|
6
|
+
* An action declared on a class: a model's `@modelAction` / `@modelFlow` (including
|
|
7
|
+
* `withSetter()` setters), or a data model's action.
|
|
8
|
+
*/
|
|
9
|
+
ModelAction = "modelAction",
|
|
10
|
+
/**
|
|
11
|
+
* An action the app defines with `standaloneAction` / `standaloneFlow`, under a global name.
|
|
12
|
+
*/
|
|
13
|
+
StandaloneAction = "standaloneAction",
|
|
14
|
+
/**
|
|
15
|
+
* A standalone action the library ships for editing any array or plain object
|
|
16
|
+
* (`arrayActions`, `objectActions`).
|
|
17
|
+
*/
|
|
18
|
+
StandardAction = "standardAction",
|
|
19
|
+
/**
|
|
20
|
+
* A built-in action, as library functions record when they change a node: `$$applySnapshot`,
|
|
21
|
+
* `$$applyPatches`, `$$detach`, `$$applySet`, `$$applyDelete`, `$$applyMethodCall` (see
|
|
22
|
+
* `BuiltInAction`).
|
|
23
|
+
*/
|
|
24
|
+
BuiltInAction = "builtInAction",
|
|
25
|
+
/**
|
|
26
|
+
* Not an action: a method, getter or function field of a model's or data model's own classes.
|
|
27
|
+
*/
|
|
28
|
+
View = "view",
|
|
29
|
+
}
|
|
@@ -1,20 +1,10 @@
|
|
|
1
|
-
import { getDataModelAction } from "../dataModel/actions"
|
|
2
|
-
import { detach } from "../parent/detach"
|
|
3
1
|
import { resolvePathCheckingIds } from "../parent/path"
|
|
4
2
|
import type { Path } from "../parent/pathTypes"
|
|
5
|
-
import { applyPatches } from "../patch/applyPatches"
|
|
6
|
-
import { applySnapshot } from "../snapshot/applySnapshot"
|
|
7
3
|
import { getStandaloneAction } from "../standardActions/actions"
|
|
8
4
|
import { assertTweakedObject } from "../tweaker/core"
|
|
9
5
|
import { failure } from "../utils"
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
import { applyMethodCall } from "./applyMethodCall"
|
|
13
|
-
import { applySet } from "./applySet"
|
|
14
|
-
import { BuiltInAction, isBuiltInAction } from "./builtInActions"
|
|
15
|
-
import { isHookAction } from "./hookActions"
|
|
16
|
-
import { isModelAction } from "./isModelAction"
|
|
17
|
-
import { isModelFlow } from "./modelFlow"
|
|
6
|
+
import { CallKind } from "./CallKind"
|
|
7
|
+
import { resolveCallName } from "./resolveCallName"
|
|
18
8
|
|
|
19
9
|
/**
|
|
20
10
|
* An action call.
|
|
@@ -42,23 +32,20 @@ export interface ActionCall {
|
|
|
42
32
|
|
|
43
33
|
/**
|
|
44
34
|
* Marks this action call as non-serialized.
|
|
35
|
+
*
|
|
36
|
+
* @deprecated Not needed with `createSerializer`: a `Call` is never serialized, an
|
|
37
|
+
* `EncodedCall` always is.
|
|
45
38
|
*/
|
|
46
39
|
readonly serialized?: boolean
|
|
47
40
|
}
|
|
48
41
|
|
|
49
|
-
const builtInActionToFunction = {
|
|
50
|
-
[BuiltInAction.ApplySnapshot]: applySnapshot,
|
|
51
|
-
[BuiltInAction.ApplyPatches]: applyPatches,
|
|
52
|
-
[BuiltInAction.Detach]: detach,
|
|
53
|
-
[BuiltInAction.ApplySet]: applySet,
|
|
54
|
-
[BuiltInAction.ApplyDelete]: applyDelete,
|
|
55
|
-
[BuiltInAction.ApplyMethodCall]: applyMethodCall,
|
|
56
|
-
}
|
|
57
|
-
|
|
58
42
|
/**
|
|
59
43
|
* Applies (runs) an action over a target object.
|
|
60
44
|
*
|
|
61
|
-
*
|
|
45
|
+
* It runs any kind of action (built-in, standalone, model actions and flows), but not views.
|
|
46
|
+
* To apply calls that come from outside (e.g. as JSON), decode them with a serializer
|
|
47
|
+
* (`defaultSerializer.decodeCall`) and use `applyCall` / `applyCallAsync` instead, which check
|
|
48
|
+
* what may be called.
|
|
62
49
|
*
|
|
63
50
|
* @param subtreeRoot Subtree root target object to run the action over.
|
|
64
51
|
* @param call The action, usually as coming from `onActionMiddleware`.
|
|
@@ -88,38 +75,24 @@ export function applyAction<TRet = any>(subtreeRoot: object, call: ActionCall):
|
|
|
88
75
|
}
|
|
89
76
|
assertTweakedObject(current, "resolved target", true)
|
|
90
77
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (!fnToCall) {
|
|
94
|
-
throw failure(`assertion failed: unknown built-in action - ${call.actionName}`)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return fnToCall.apply(current, [current, ...call.args])
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (isHookAction(call.actionName)) {
|
|
78
|
+
const resolution = resolveCallName(current, call.actionName)
|
|
79
|
+
if (resolution === "hook") {
|
|
101
80
|
throw failure(`calls to hooks (${call.actionName}) cannot be applied`)
|
|
102
81
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (dataModelAction) {
|
|
106
|
-
const instance: any = new dataModelAction.modelClass(current)
|
|
107
|
-
return instance[dataModelAction.fnName](...call.args)
|
|
82
|
+
if (resolution === "unknown") {
|
|
83
|
+
throw failure(`action '${call.actionName}' could not be resolved to a function`)
|
|
108
84
|
}
|
|
109
85
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
86
|
+
switch (resolution.kind) {
|
|
87
|
+
case CallKind.View:
|
|
88
|
+
throw failure(`action '${call.actionName}' is not a model action`)
|
|
114
89
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
90
|
+
case CallKind.StandaloneAction:
|
|
91
|
+
case CallKind.StandardAction:
|
|
92
|
+
// the target is already the first argument
|
|
93
|
+
return getStandaloneAction(call.actionName)!.fn(...call.args)
|
|
119
94
|
|
|
120
|
-
|
|
121
|
-
|
|
95
|
+
default:
|
|
96
|
+
return resolution.run(call.args) as TRet
|
|
122
97
|
}
|
|
123
|
-
|
|
124
|
-
return actionFn.apply(current, call.args)
|
|
125
98
|
}
|
package/src/action/applySet.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isObservable } from "mobx"
|
|
2
2
|
import { isModel } from "../model/utils"
|
|
3
3
|
import { assertTweakedObject } from "../tweaker/core"
|
|
4
|
-
import { lazy } from "../utils"
|
|
4
|
+
import { failure, hasOwnProp, lazy } from "../utils"
|
|
5
5
|
import { setIfDifferent } from "../utils/setIfDifferent"
|
|
6
6
|
import { BuiltInAction } from "./builtInActions"
|
|
7
7
|
import { ActionContextActionType } from "./context"
|
|
@@ -30,10 +30,30 @@ function internalApplySet<O extends object>(this: O, fieldName: string | number,
|
|
|
30
30
|
if (!isModel(this) && isObservable(this)) {
|
|
31
31
|
setIfDifferent(this, fieldName, value)
|
|
32
32
|
} else {
|
|
33
|
+
// assigning '__proto__' would replace the prototype of the model instead of setting a field,
|
|
34
|
+
// and assigning an inherited method (e.g. an action) would shadow it on this instance
|
|
35
|
+
if (fieldName === "__proto__" || isInheritedDataProp(this, fieldName)) {
|
|
36
|
+
throw failure(`applySet cannot set '${String(fieldName)}' on a model`)
|
|
37
|
+
}
|
|
33
38
|
;(this as any)[fieldName] = value
|
|
34
39
|
}
|
|
35
40
|
}
|
|
36
41
|
|
|
42
|
+
function isInheritedDataProp(obj: object, fieldName: string | number): boolean {
|
|
43
|
+
if (hasOwnProp(obj, fieldName)) {
|
|
44
|
+
return false
|
|
45
|
+
}
|
|
46
|
+
let proto = Object.getPrototypeOf(obj)
|
|
47
|
+
while (proto) {
|
|
48
|
+
const descriptor = Object.getOwnPropertyDescriptor(proto, fieldName)
|
|
49
|
+
if (descriptor) {
|
|
50
|
+
return !descriptor.get && !descriptor.set
|
|
51
|
+
}
|
|
52
|
+
proto = Object.getPrototypeOf(proto)
|
|
53
|
+
}
|
|
54
|
+
return false
|
|
55
|
+
}
|
|
56
|
+
|
|
37
57
|
const wrappedInternalApplySet = lazy(() =>
|
|
38
58
|
wrapInAction({
|
|
39
59
|
nameOrNameFn: BuiltInAction.ApplySet,
|
package/src/action/index.ts
CHANGED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { getDataModelAction } from "../dataModel/actions"
|
|
2
|
+
import { BaseDataModel } from "../dataModel/BaseDataModel"
|
|
3
|
+
import { isDataModelClass } from "../dataModel/utils"
|
|
4
|
+
import { BaseModel } from "../model/BaseModel"
|
|
5
|
+
import { isModel } from "../model/utils"
|
|
6
|
+
import type { ModelClass } from "../modelShared/BaseModelShared"
|
|
7
|
+
import { getModelInfoForName } from "../modelShared/modelInfo"
|
|
8
|
+
import { detach } from "../parent/detach"
|
|
9
|
+
import { applyPatches } from "../patch/applyPatches"
|
|
10
|
+
import { applySnapshot } from "../snapshot/applySnapshot"
|
|
11
|
+
import { getStandaloneAction } from "../standardActions/actions"
|
|
12
|
+
import { failure, namespace } from "../utils"
|
|
13
|
+
import type { AnyFunction } from "../utils/AnyFunction"
|
|
14
|
+
import { applyDelete } from "./applyDelete"
|
|
15
|
+
import { applyMethodCall } from "./applyMethodCall"
|
|
16
|
+
import { applySet } from "./applySet"
|
|
17
|
+
import { BuiltInAction, isBuiltInAction } from "./builtInActions"
|
|
18
|
+
import { CallKind } from "./CallKind"
|
|
19
|
+
import { isHookAction } from "./hookActions"
|
|
20
|
+
import { isModelAction } from "./isModelAction"
|
|
21
|
+
import { isModelFlow } from "./modelFlow"
|
|
22
|
+
|
|
23
|
+
const builtInActionToFunction = {
|
|
24
|
+
[BuiltInAction.ApplySnapshot]: applySnapshot,
|
|
25
|
+
[BuiltInAction.ApplyPatches]: applyPatches,
|
|
26
|
+
[BuiltInAction.Detach]: detach,
|
|
27
|
+
[BuiltInAction.ApplySet]: applySet,
|
|
28
|
+
[BuiltInAction.ApplyDelete]: applyDelete,
|
|
29
|
+
[BuiltInAction.ApplyMethodCall]: applyMethodCall,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const standardActionPrefixes = [`${namespace}/arrayActions::`, `${namespace}/objectActions::`]
|
|
33
|
+
|
|
34
|
+
const dataModelMemberPrefix = "fn::"
|
|
35
|
+
|
|
36
|
+
// members that are never callable, even when defined below the base classes
|
|
37
|
+
const nonCallableMemberNames: ReadonlySet<string> = new Set([
|
|
38
|
+
"constructor",
|
|
39
|
+
"onInit",
|
|
40
|
+
"onLazyInit",
|
|
41
|
+
"onAttachedToRootStore",
|
|
42
|
+
"onLazyAttachedToRootStore",
|
|
43
|
+
])
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @internal
|
|
47
|
+
*
|
|
48
|
+
* How a view is used: a getter is read (no `args`), a method is called (with `args`).
|
|
49
|
+
*/
|
|
50
|
+
export type ViewForm = "getter" | "method"
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @internal
|
|
54
|
+
*
|
|
55
|
+
* What a call's name resolved to on its target.
|
|
56
|
+
*/
|
|
57
|
+
export interface CallResolution {
|
|
58
|
+
readonly kind: CallKind
|
|
59
|
+
readonly isFlow: boolean
|
|
60
|
+
/**
|
|
61
|
+
* Only for views.
|
|
62
|
+
*/
|
|
63
|
+
readonly viewForm: ViewForm | undefined
|
|
64
|
+
/**
|
|
65
|
+
* Runs the call on the target it was resolved for (args are ignored when reading a getter).
|
|
66
|
+
*/
|
|
67
|
+
run(args: readonly unknown[]): unknown
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @internal
|
|
72
|
+
*
|
|
73
|
+
* Why a name couldn't be resolved: a hook (never callable) or nothing callable by that name.
|
|
74
|
+
*/
|
|
75
|
+
export type CallResolutionFailure = "hook" | "unknown"
|
|
76
|
+
|
|
77
|
+
type FoundMember = { readonly get: AnyFunction } | { readonly fn: AnyFunction }
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Finds a callable member without running any getter: a method, getter or function field of the
|
|
81
|
+
* object or of its prototype chain below `stopProto`.
|
|
82
|
+
*/
|
|
83
|
+
function findMember(obj: object, name: string, stopProto: object): FoundMember | undefined {
|
|
84
|
+
if (nonCallableMemberNames.has(name)) {
|
|
85
|
+
return undefined
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// own accessors too, e.g. computeds MobX defines on the instance with legacy decorators
|
|
89
|
+
for (
|
|
90
|
+
let current: object | null = obj;
|
|
91
|
+
current && current !== stopProto;
|
|
92
|
+
current = Object.getPrototypeOf(current)
|
|
93
|
+
) {
|
|
94
|
+
const desc = Object.getOwnPropertyDescriptor(current, name)
|
|
95
|
+
if (desc) {
|
|
96
|
+
if (desc.get) {
|
|
97
|
+
return { get: desc.get }
|
|
98
|
+
}
|
|
99
|
+
return typeof desc.value === "function" ? { fn: desc.value } : undefined
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return undefined
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function resolveMember(member: FoundMember, self: object): CallResolution {
|
|
106
|
+
if ("get" in member) {
|
|
107
|
+
const get = member.get
|
|
108
|
+
return {
|
|
109
|
+
kind: CallKind.View,
|
|
110
|
+
isFlow: false,
|
|
111
|
+
viewForm: "getter",
|
|
112
|
+
run: () => get.call(self),
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const fn = member.fn
|
|
117
|
+
const run = (args: readonly unknown[]) => fn.apply(self, args as unknown[])
|
|
118
|
+
if (isModelAction(fn) || isModelFlow(fn)) {
|
|
119
|
+
return { kind: CallKind.ModelAction, isFlow: isModelFlow(fn), viewForm: undefined, run }
|
|
120
|
+
}
|
|
121
|
+
return { kind: CallKind.View, isFlow: false, viewForm: "method", run }
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function getDataModelClassAndMember(
|
|
125
|
+
name: string
|
|
126
|
+
): { modelClass: ModelClass<any>; memberName: string } | undefined {
|
|
127
|
+
// data model actions are registered under their name
|
|
128
|
+
const registered = getDataModelAction(name)
|
|
129
|
+
if (registered) {
|
|
130
|
+
return { modelClass: registered.modelClass, memberName: registered.fnName }
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// other members are named the same way: fn::<data model name>::<member>
|
|
134
|
+
if (!name.startsWith(dataModelMemberPrefix)) {
|
|
135
|
+
return undefined
|
|
136
|
+
}
|
|
137
|
+
const separatorIndex = name.lastIndexOf("::")
|
|
138
|
+
if (separatorIndex < dataModelMemberPrefix.length) {
|
|
139
|
+
return undefined
|
|
140
|
+
}
|
|
141
|
+
const modelInfo = getModelInfoForName(name.slice(dataModelMemberPrefix.length, separatorIndex))
|
|
142
|
+
if (!modelInfo || !isDataModelClass(modelInfo.class)) {
|
|
143
|
+
return undefined
|
|
144
|
+
}
|
|
145
|
+
return { modelClass: modelInfo.class, memberName: name.slice(separatorIndex + 2) }
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* @internal
|
|
150
|
+
*
|
|
151
|
+
* Resolves what a call's name refers to on its target, in this order: built-in actions, hooks
|
|
152
|
+
* (refused), data model members, standalone actions, the target's own model actions and flows,
|
|
153
|
+
* and finally the target's own methods, getters and function fields (views).
|
|
154
|
+
*
|
|
155
|
+
* Getters are never run while resolving.
|
|
156
|
+
*/
|
|
157
|
+
export function resolveCallName(
|
|
158
|
+
target: object,
|
|
159
|
+
name: string
|
|
160
|
+
): CallResolution | CallResolutionFailure {
|
|
161
|
+
if (isBuiltInAction(name)) {
|
|
162
|
+
const fn = builtInActionToFunction[name] as AnyFunction | undefined
|
|
163
|
+
if (!fn) {
|
|
164
|
+
throw failure(`assertion failed: unknown built-in action - ${name}`)
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
kind: CallKind.BuiltInAction,
|
|
168
|
+
isFlow: false,
|
|
169
|
+
viewForm: undefined,
|
|
170
|
+
run: (args) => fn.apply(target, [target, ...args]),
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (isHookAction(name)) {
|
|
175
|
+
return "hook"
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const dataModelMember = getDataModelClassAndMember(name)
|
|
179
|
+
if (dataModelMember) {
|
|
180
|
+
// the instance is created (or reused, since they are cached) first, so decorators that
|
|
181
|
+
// initialize on first use have run; it throws when the target isn't valid data for the class
|
|
182
|
+
const instance: object = new dataModelMember.modelClass(target)
|
|
183
|
+
const member = findMember(instance, dataModelMember.memberName, BaseDataModel.prototype)
|
|
184
|
+
return member ? resolveMember(member, instance) : "unknown"
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const standaloneAction = getStandaloneAction(name)
|
|
188
|
+
if (standaloneAction) {
|
|
189
|
+
return {
|
|
190
|
+
kind: standardActionPrefixes.some((prefix) => name.startsWith(prefix))
|
|
191
|
+
? CallKind.StandardAction
|
|
192
|
+
: CallKind.StandaloneAction,
|
|
193
|
+
isFlow: standaloneAction.isFlow,
|
|
194
|
+
viewForm: undefined,
|
|
195
|
+
run: (args) => standaloneAction.fn(target, ...args),
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (isModel(target)) {
|
|
200
|
+
const member = findMember(target, name, BaseModel.prototype)
|
|
201
|
+
if (member) {
|
|
202
|
+
return resolveMember(member, target)
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return "unknown"
|
|
207
|
+
}
|
|
@@ -24,6 +24,8 @@ const serializersMap = new Map<string, ActionCallArgumentSerializer<any, any>>()
|
|
|
24
24
|
*
|
|
25
25
|
* @param serializer Serializer to register.
|
|
26
26
|
* @returns A disposer to unregister the serializer.
|
|
27
|
+
*
|
|
28
|
+
* @deprecated Use a `ValueSerializer` in the list passed to `createSerializer` instead.
|
|
27
29
|
*/
|
|
28
30
|
export function registerActionCallArgumentSerializer(
|
|
29
31
|
serializer: ActionCallArgumentSerializer<any, any>
|
|
@@ -54,6 +56,8 @@ export function registerActionCallArgumentSerializer(
|
|
|
54
56
|
|
|
55
57
|
/**
|
|
56
58
|
* Serialized action call argument.
|
|
59
|
+
*
|
|
60
|
+
* @deprecated Replaced by the marked value `{ "$mobxKeystone": tag, "v": payload }` of `createSerializer`.
|
|
57
61
|
*/
|
|
58
62
|
export interface SerializedActionCallArgument {
|
|
59
63
|
/**
|
|
@@ -68,6 +72,8 @@ export interface SerializedActionCallArgument {
|
|
|
68
72
|
|
|
69
73
|
/**
|
|
70
74
|
* A serialized action call.
|
|
75
|
+
*
|
|
76
|
+
* @deprecated Use `EncodedCall` instead.
|
|
71
77
|
*/
|
|
72
78
|
export interface SerializedActionCall extends Omit<ActionCall, "serialized"> {
|
|
73
79
|
/**
|
|
@@ -99,6 +105,8 @@ export interface SerializedActionCall extends Omit<ActionCall, "serialized"> {
|
|
|
99
105
|
* @param argValue Argument value to be transformed into its serializable form.
|
|
100
106
|
* @param [targetRoot] Target root node of the model where this action is being performed.
|
|
101
107
|
* @returns The serializable form of the passed value.
|
|
108
|
+
*
|
|
109
|
+
* @deprecated Use `serializer.encodeValue(root, value)` instead (e.g. with `defaultSerializer`).
|
|
102
110
|
*/
|
|
103
111
|
export function serializeActionCallArgument(
|
|
104
112
|
argValue: any,
|
|
@@ -137,6 +145,8 @@ export function serializeActionCallArgument(
|
|
|
137
145
|
* @param actionCall Action call to convert.
|
|
138
146
|
* @param [targetRoot] Target root node of the model where this action is being performed.
|
|
139
147
|
* @returns The serializable action call.
|
|
148
|
+
*
|
|
149
|
+
* @deprecated Use `serializer.encodeCall(root, call)` instead (e.g. with `defaultSerializer`).
|
|
140
150
|
*/
|
|
141
151
|
export function serializeActionCall(
|
|
142
152
|
actionCall: ActionCall,
|
|
@@ -165,6 +175,8 @@ export function serializeActionCall(
|
|
|
165
175
|
* @param argValue Argument value to be transformed into its deserialized form.
|
|
166
176
|
* @param [targetRoot] Target root node of the model where this action is being performed.
|
|
167
177
|
* @returns The deserialized form of the passed value.
|
|
178
|
+
*
|
|
179
|
+
* @deprecated Use `serializer.decodeValue(root, json)` instead (e.g. with `defaultSerializer`).
|
|
168
180
|
*/
|
|
169
181
|
export function deserializeActionCallArgument(
|
|
170
182
|
argValue: SerializedActionCallArgument | JSONPrimitiveValue,
|
|
@@ -200,6 +212,8 @@ export function deserializeActionCallArgument(
|
|
|
200
212
|
* @param actionCall Action call to convert.
|
|
201
213
|
* @param [targetRoot] Target root node of the model where this action is being performed.
|
|
202
214
|
* @returns The deserialized action call.
|
|
215
|
+
*
|
|
216
|
+
* @deprecated Use `serializer.decodeCall(root, json)` instead (e.g. with `defaultSerializer`), then `applyCall`.
|
|
203
217
|
*/
|
|
204
218
|
export function deserializeActionCall(
|
|
205
219
|
actionCall: SerializedActionCall,
|
|
@@ -17,6 +17,8 @@ import { deserializeActionCall, type SerializedActionCall } from "./actionSerial
|
|
|
17
17
|
* Serialized action call with model ID overrides.
|
|
18
18
|
* Can be generated with `applySerializedActionAndTrackNewModelIds`.
|
|
19
19
|
* To be applied with `applySerializedActionAndSyncNewModelIds`.
|
|
20
|
+
*
|
|
21
|
+
* @deprecated Use `EncodedCall` instead; model id overrides aren't needed when replicas apply the patches the server broadcasts.
|
|
20
22
|
*/
|
|
21
23
|
export interface SerializedActionCallWithModelIdOverrides extends SerializedActionCall {
|
|
22
24
|
/**
|
|
@@ -38,6 +40,8 @@ export interface SerializedActionCallWithModelIdOverrides extends SerializedActi
|
|
|
38
40
|
* @param call The serialized action, usually as coming from the server/client.
|
|
39
41
|
* @returns The return value of the action, if any, plus a new serialized action
|
|
40
42
|
* with model overrides.
|
|
43
|
+
*
|
|
44
|
+
* @deprecated Use `applyCall` / `applyCallAsync` on the server instead, broadcasting the patches the call produces.
|
|
41
45
|
*/
|
|
42
46
|
export function applySerializedActionAndTrackNewModelIds<TRet = any>(
|
|
43
47
|
subtreeRoot: object,
|
|
@@ -156,6 +160,8 @@ function deepScanValueForModelIdChanges(
|
|
|
156
160
|
* @param subtreeRoot Subtree root target object to run the action over.
|
|
157
161
|
* @param call The serialized action, usually as coming from the server/client.
|
|
158
162
|
* @returns The return value of the action, if any.
|
|
163
|
+
*
|
|
164
|
+
* @deprecated Use `applyPatches` on the patches the server broadcasts instead.
|
|
159
165
|
*/
|
|
160
166
|
export function applySerializedActionAndSyncNewModelIds<TRet = any>(
|
|
161
167
|
subtreeRoot: object,
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returned by an `ActionCallArgumentSerializer` that can't serialize a value.
|
|
3
|
+
*
|
|
4
|
+
* @deprecated Use `ValueSerializer.is` returning false instead.
|
|
5
|
+
*/
|
|
1
6
|
export const cannotSerialize = Symbol("cannotSerialize")
|
|
2
7
|
|
|
3
8
|
/**
|
|
4
9
|
* Serializer of action call arguments.
|
|
10
|
+
*
|
|
11
|
+
* @deprecated Use `ValueSerializer` instead.
|
|
5
12
|
*/
|
|
6
13
|
export interface ActionCallArgumentSerializer<TOriginal, TSerialized> {
|
|
7
14
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { fastGetRootPath, resolvePathCheckingIds } from "../../parent/path"
|
|
2
2
|
import type { Path } from "../../parent/pathTypes"
|
|
3
|
-
import { isTweakedObject } from "../../tweaker/core"
|
|
3
|
+
import { isTreeNode, isTweakedObject } from "../../tweaker/core"
|
|
4
4
|
import { failure, namespace } from "../../utils"
|
|
5
5
|
import { rootPathToTargetPathIds } from "../utils"
|
|
6
6
|
import { type ActionCallArgumentSerializer, cannotSerialize } from "./core"
|
|
@@ -36,7 +36,8 @@ export const objectPathSerializer: ActionCallArgumentSerializer<object, ObjectPa
|
|
|
36
36
|
// try to resolve the node back
|
|
37
37
|
if (targetRoot) {
|
|
38
38
|
const result = resolvePathCheckingIds(targetRoot, ref.targetPath, ref.targetPathIds)
|
|
39
|
-
|
|
39
|
+
// only tree nodes can be serialized as paths, so anything else is not a valid target
|
|
40
|
+
if (result.resolved && isTreeNode(result.value)) {
|
|
40
41
|
return result.value
|
|
41
42
|
}
|
|
42
43
|
}
|
package/src/index.ts
CHANGED