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.
Files changed (174) hide show
  1. package/CHANGELOG.md +864 -853
  2. package/README.md +61 -61
  3. package/dist/mobx-keystone.esm.js +11336 -11148
  4. package/dist/mobx-keystone.esm.mjs +11336 -11148
  5. package/dist/mobx-keystone.umd.js +12229 -11738
  6. package/dist/types/actionMiddlewares/undoMiddleware.d.ts +1 -1
  7. package/dist/types/modelShared/prop.d.ts +5 -0
  8. package/dist/types/redux/connectReduxDevTools.d.ts +17 -4
  9. package/dist/types/ref/Ref.d.ts +1 -1
  10. package/dist/types/treeUtils/sandbox.d.ts +1 -1
  11. package/dist/types/types/TypeChecker.d.ts +1 -1
  12. package/dist/types/types/arrayBased/typesArray.d.ts +1 -1
  13. package/dist/types/types/arrayBased/typesTuple.d.ts +1 -1
  14. package/dist/types/types/objectBased/typesArraySet.d.ts +1 -1
  15. package/dist/types/types/objectBased/typesDataModelData.d.ts +1 -1
  16. package/dist/types/types/objectBased/typesModel.d.ts +1 -1
  17. package/dist/types/types/objectBased/typesObject.d.ts +3 -3
  18. package/dist/types/types/objectBased/typesObjectMap.d.ts +1 -1
  19. package/dist/types/types/objectBased/typesRecord.d.ts +1 -1
  20. package/dist/types/types/primitiveBased/typesPrimitive.d.ts +1 -1
  21. package/dist/types/types/types.d.ts +3 -3
  22. package/dist/types/types/utility/typesCodec.d.ts +1 -6
  23. package/dist/types/types/utility/typesCodecCore.d.ts +1 -1
  24. package/dist/types/types/utility/typesOr.d.ts +1 -1
  25. package/dist/types/types/utility/typesRefinement.d.ts +1 -1
  26. package/dist/types/types/utility/typesSkipCheck.d.ts +1 -1
  27. package/dist/types/types/utility/typesTag.d.ts +1 -1
  28. package/dist/types/wrappers/ObjectMap.d.ts +2 -0
  29. package/dist/types/wrappers/asMap.d.ts +10 -6
  30. package/package.json +14 -12
  31. package/src/action/applyAction.ts +125 -114
  32. package/src/action/applyMethodCall.ts +37 -37
  33. package/src/action/isModelAction.ts +16 -16
  34. package/src/action/middleware.ts +137 -137
  35. package/src/action/modelFlow.ts +240 -240
  36. package/src/action/modelFlowPromiseGenerator.ts +127 -125
  37. package/src/action/pendingActions.ts +42 -42
  38. package/src/action/wrapInAction.ts +156 -156
  39. package/src/actionMiddlewares/actionSerialization/actionSerialization.ts +1 -1
  40. package/src/actionMiddlewares/actionSerialization/applySerializedAction.ts +172 -172
  41. package/src/actionMiddlewares/actionSerialization/arraySerializer.ts +20 -20
  42. package/src/actionMiddlewares/actionSerialization/dateSerializer.ts +17 -17
  43. package/src/actionMiddlewares/actionSerialization/mapSerializer.ts +42 -42
  44. package/src/actionMiddlewares/actionSerialization/objectPathSerializer.ts +50 -50
  45. package/src/actionMiddlewares/actionSerialization/objectSnapshotSerializer.ts +21 -21
  46. package/src/actionMiddlewares/actionSerialization/plainObjectSerializer.ts +24 -32
  47. package/src/actionMiddlewares/actionSerialization/primitiveSerializer.ts +51 -51
  48. package/src/actionMiddlewares/actionSerialization/setSerializer.ts +37 -37
  49. package/src/actionMiddlewares/actionTrackingMiddleware.ts +3 -3
  50. package/src/actionMiddlewares/onActionMiddleware.ts +2 -2
  51. package/src/actionMiddlewares/readonlyMiddleware.ts +2 -2
  52. package/src/actionMiddlewares/transactionMiddleware.ts +4 -4
  53. package/src/actionMiddlewares/undoMiddleware.ts +804 -796
  54. package/src/actionMiddlewares/utils.ts +2 -2
  55. package/src/computedTree/computedTree.ts +143 -143
  56. package/src/context/context.ts +1 -1
  57. package/src/dataModel/BaseDataModel.ts +194 -192
  58. package/src/dataModel/actions.ts +1 -1
  59. package/src/dataModel/newDataModel.ts +57 -57
  60. package/src/deepChange/index.ts +1 -1
  61. package/src/deepChange/onDeepChange.ts +244 -244
  62. package/src/frozen/Frozen.ts +146 -146
  63. package/src/globalConfig/globalConfig.ts +107 -107
  64. package/src/index.ts +24 -24
  65. package/src/model/BaseModel.ts +275 -273
  66. package/src/model/ModelConstructorOptions.ts +15 -15
  67. package/src/model/getModelMetadata.ts +51 -51
  68. package/src/model/index.ts +6 -6
  69. package/src/model/mixins.ts +288 -288
  70. package/src/model/newModel.ts +301 -301
  71. package/src/model/utils.ts +249 -249
  72. package/src/modelShared/modelDecorator.ts +260 -253
  73. package/src/modelShared/modelInfo.ts +50 -50
  74. package/src/modelShared/modelSymbols.ts +3 -3
  75. package/src/modelShared/newModel.ts +25 -25
  76. package/src/modelShared/prop.ts +713 -684
  77. package/src/modelShared/sharedInternalModel.ts +427 -417
  78. package/src/modelShared/utils.ts +24 -24
  79. package/src/parent/core.ts +65 -65
  80. package/src/parent/coreObjectChildren.ts +180 -180
  81. package/src/parent/detach.ts +47 -47
  82. package/src/parent/findParent.ts +1 -1
  83. package/src/parent/getChildrenObjects.ts +25 -25
  84. package/src/parent/path.ts +386 -381
  85. package/src/parent/setParent.ts +149 -149
  86. package/src/parent/walkTree.ts +1 -1
  87. package/src/patch/applyPatches.ts +187 -187
  88. package/src/patch/jsonPatch.ts +108 -108
  89. package/src/patch/patchRecorder.ts +6 -1
  90. package/src/redux/connectReduxDevTools.ts +39 -7
  91. package/src/redux/redux.ts +6 -2
  92. package/src/ref/Ref.ts +1 -1
  93. package/src/ref/core.ts +339 -345
  94. package/src/ref/customRef.ts +3 -3
  95. package/src/ref/rootRef.ts +100 -100
  96. package/src/rootStore/attachDetach.ts +89 -89
  97. package/src/rootStore/rootStore.ts +1 -1
  98. package/src/snapshot/SnapshotOf.ts +104 -104
  99. package/src/snapshot/SnapshotProcessingError.ts +45 -45
  100. package/src/snapshot/applySnapshot.ts +177 -181
  101. package/src/snapshot/cloneTreeValue.ts +30 -30
  102. package/src/snapshot/fromArraySnapshot.ts +27 -33
  103. package/src/snapshot/fromModelSnapshot.ts +70 -70
  104. package/src/snapshot/fromPlainObjectSnapshot.ts +47 -42
  105. package/src/snapshot/fromSnapshot.ts +198 -198
  106. package/src/snapshot/getSnapshot.ts +80 -79
  107. package/src/snapshot/index.ts +8 -8
  108. package/src/snapshot/internal.ts +230 -230
  109. package/src/snapshot/reconcileArraySnapshot.ts +70 -70
  110. package/src/snapshot/reconcileModelSnapshot.ts +155 -150
  111. package/src/snapshot/reconcilePlainObjectSnapshot.ts +72 -72
  112. package/src/snapshot/reconcileSnapshot.ts +88 -88
  113. package/src/standardActions/actions.ts +64 -64
  114. package/src/standardActions/objectActions.ts +60 -60
  115. package/src/transforms/ImmutableDate.ts +93 -93
  116. package/src/transforms/asMap.ts +50 -50
  117. package/src/transforms/asSet.ts +22 -22
  118. package/src/transforms/bigint.ts +20 -20
  119. package/src/transforms/date.ts +40 -40
  120. package/src/treeUtils/deepEquals.ts +55 -55
  121. package/src/treeUtils/sandbox.ts +6 -3
  122. package/src/tweaker/TweakerPriority.ts +9 -9
  123. package/src/tweaker/tweak.ts +4 -3
  124. package/src/tweaker/tweakArray.ts +530 -475
  125. package/src/tweaker/tweakFrozen.ts +42 -42
  126. package/src/tweaker/tweakModel.ts +1 -1
  127. package/src/tweaker/tweakPlainObject.ts +355 -355
  128. package/src/tweaker/typeChecking.ts +101 -101
  129. package/src/types/SnapshotTypeMismatchError.ts +46 -46
  130. package/src/types/TypeCheckError.ts +183 -184
  131. package/src/types/TypeChecker.ts +202 -185
  132. package/src/types/arrayBased/typesArray.ts +136 -137
  133. package/src/types/arrayBased/typesTuple.ts +138 -139
  134. package/src/types/createPerEntryCachedCheck.ts +166 -160
  135. package/src/types/index.ts +6 -6
  136. package/src/types/objectBased/typesArraySet.ts +133 -134
  137. package/src/types/objectBased/typesDataModelData.ts +203 -204
  138. package/src/types/objectBased/typesModel.ts +220 -221
  139. package/src/types/objectBased/typesObject.ts +308 -310
  140. package/src/types/objectBased/typesObjectMap.ts +142 -143
  141. package/src/types/objectBased/typesRecord.ts +156 -157
  142. package/src/types/objectBased/typesRef.ts +89 -89
  143. package/src/types/primitiveBased/typesEnum.ts +63 -63
  144. package/src/types/primitiveBased/typesPrimitive.ts +219 -220
  145. package/src/types/registerDefaultStandardTypeResolvers.ts +21 -21
  146. package/src/types/resolveTypeChecker.ts +78 -78
  147. package/src/types/schemas.ts +208 -208
  148. package/src/types/tProp.ts +277 -268
  149. package/src/types/typeCheck.ts +21 -21
  150. package/src/types/typeCheckErrorUtils.ts +23 -23
  151. package/src/types/types.ts +142 -142
  152. package/src/types/utility/typeToStoredData.ts +37 -37
  153. package/src/types/utility/typesBigInt.ts +15 -15
  154. package/src/types/utility/typesCodec.ts +41 -38
  155. package/src/types/utility/typesCodecCore.ts +178 -178
  156. package/src/types/utility/typesCodecSupport.ts +806 -806
  157. package/src/types/utility/typesDate.ts +27 -27
  158. package/src/types/utility/typesMap.ts +253 -222
  159. package/src/types/utility/typesOr.ts +263 -259
  160. package/src/types/utility/typesRefinement.ts +131 -125
  161. package/src/types/utility/typesSet.ts +110 -110
  162. package/src/types/utility/typesSkipCheck.ts +69 -70
  163. package/src/types/utility/typesTag.ts +88 -82
  164. package/src/types/utility/typesUnchecked.ts +40 -40
  165. package/src/utils/AnyFunction.ts +4 -4
  166. package/src/utils/ModelPool.ts +59 -59
  167. package/src/utils/chainFns.ts +18 -18
  168. package/src/utils/decorators.ts +274 -274
  169. package/src/utils/errorDiagnostics.ts +204 -204
  170. package/src/utils/index.ts +443 -372
  171. package/src/wrappers/ArraySet.ts +156 -156
  172. package/src/wrappers/ObjectMap.ts +155 -136
  173. package/src/wrappers/asMap.ts +65 -30
  174. package/src/wrappers/asSet.ts +3 -3
@@ -1,253 +1,260 @@
1
- import { HookAction } from "../action/hookActions"
2
- import { wrapModelMethodInActionIfNeeded } from "../action/wrapInAction"
3
- import type { AnyDataModel } from "../dataModel/BaseDataModel"
4
- import { isDataModelClass } from "../dataModel/utils"
5
- import { enterInitPhase, exitInitPhase } from "../deepChange/onDeepChange"
6
- import { getGlobalConfig } from "../globalConfig"
7
- import type { AnyModel } from "../model/BaseModel"
8
- import { modelTypeKey } from "../model/metadata"
9
- import { isModelClass } from "../model/utils"
10
- import { ModelClass, modelInitializedSymbol } from "../modelShared/BaseModelShared"
11
- import { modelInfoByClass, modelInfoByName } from "../modelShared/modelInfo"
12
- import {
13
- modelUnwrappedClassSymbol,
14
- runAfterModelDecoratorSymbol,
15
- } from "../modelShared/modelSymbols"
16
- import { refreshInternalSnapshot } from "../snapshot/internal"
17
- import {
18
- failure,
19
- getMobxVersion,
20
- logWarning,
21
- mobx6,
22
- runAfterNewSymbol,
23
- runBeforeOnInitSymbol,
24
- runLateInitializationFunctions,
25
- } from "../utils"
26
- import { AnyFunction } from "../utils/AnyFunction"
27
-
28
- /**
29
- * Decorator that marks this class (which MUST inherit from the `Model` or `DataModel` abstract classes)
30
- * as a model.
31
- *
32
- * @param name Unique name for the model type. Note that this name must be unique for your whole
33
- * application, so it is usually a good idea to use some prefix unique to your application domain.
34
- */
35
- export const model =
36
- (name: string) =>
37
- <MC extends ModelClass<AnyModel | AnyDataModel>>(clazz: MC, ...args: any[]): MC => {
38
- const ctx = typeof args[1] === "object" ? (args[1] as ClassDecoratorContext) : undefined
39
-
40
- return internalModel(name, clazz, ctx?.addInitializer) as any
41
- }
42
-
43
- const afterClassInitializationData = new WeakMap<
44
- ModelClass<AnyModel | AnyDataModel>,
45
- {
46
- needsMakeObservable: boolean | undefined
47
- type: "class" | "data"
48
- }
49
- >()
50
-
51
- const runAfterClassInitialization = (
52
- target: ModelClass<AnyModel | AnyDataModel>,
53
- instance: any
54
- ) => {
55
- runLateInitializationFunctions(instance, runAfterNewSymbol)
56
-
57
- const tag = afterClassInitializationData.get(target)!
58
-
59
- // compatibility with mobx 6
60
- if (tag.needsMakeObservable) {
61
- // we know it can be done and shouldn't fail
62
- mobx6.makeObservable(instance)
63
- } else if (tag.needsMakeObservable === undefined) {
64
- if (getMobxVersion() >= 6) {
65
- try {
66
- mobx6.makeObservable(instance)
67
- tag.needsMakeObservable = true
68
- } catch (e) {
69
- const err = e as Error
70
- if (
71
- err.message !==
72
- "[MobX] No annotations were passed to makeObservable, but no decorator members have been found either" &&
73
- err.message !==
74
- "[MobX] No annotations were passed to makeObservable, but no decorated members have been found either"
75
- ) {
76
- throw err
77
- }
78
-
79
- // sadly we need to use this hack since the PR to do this the proper way
80
- // was rejected on the mobx side
81
- tag.needsMakeObservable = false
82
- }
83
- } else {
84
- tag.needsMakeObservable = false
85
- }
86
- }
87
-
88
- // the object is ready
89
- instance[modelInitializedSymbol] = true
90
- refreshInternalSnapshot(instance)
91
-
92
- enterInitPhase()
93
- try {
94
- runLateInitializationFunctions(instance, runBeforeOnInitSymbol)
95
-
96
- if (tag.type === "class" && instance.onInit) {
97
- wrapModelMethodInActionIfNeeded(instance, "onInit", HookAction.OnInit)
98
-
99
- instance.onInit()
100
- }
101
-
102
- if (tag.type === "data" && instance.onLazyInit) {
103
- wrapModelMethodInActionIfNeeded(instance, "onLazyInit", HookAction.OnLazyInit)
104
-
105
- instance.onLazyInit()
106
- }
107
- } finally {
108
- exitInitPhase()
109
- }
110
- }
111
-
112
- const proxyClassHandler: ProxyHandler<ModelClass<AnyModel | AnyDataModel>> = {
113
- construct(clazz, args) {
114
- const instance = new (clazz as any)(...args)
115
-
116
- runAfterClassInitialization(clazz, instance)
117
-
118
- return instance
119
- },
120
- }
121
-
122
- const internalModel = <MC extends ModelClass<AnyModel | AnyDataModel>>(
123
- name: string,
124
- clazz: MC,
125
- addInitializer: ((initializer: (this: any) => void) => void) | undefined
126
- ): MC | void => {
127
- const type = isModelClass(clazz) ? "class" : isDataModelClass(clazz) ? "data" : undefined
128
- if (!type) {
129
- throw failure(`clazz must be a class that extends from Model/DataModel`)
130
- }
131
-
132
- if (modelInfoByName[name]) {
133
- if (getGlobalConfig().showDuplicateModelNameWarnings) {
134
- logWarning(
135
- "warn",
136
- `a model with name "${name}" already exists (if you are using hot-reloading you may safely ignore this warning)`,
137
- `duplicateModelName - ${name}`
138
- )
139
- }
140
- }
141
-
142
- if (modelUnwrappedClassSymbol in clazz && clazz[modelUnwrappedClassSymbol] === clazz) {
143
- throw failure("a class already decorated with `@model` cannot be re-decorated")
144
- }
145
-
146
- clazz.toString = () => `class ${clazz.name}#${name}`
147
- if (type === "class") {
148
- ;(clazz as any)[modelTypeKey] = name
149
- }
150
-
151
- // track if we fail so we only try it once per class
152
- afterClassInitializationData.set(clazz, { needsMakeObservable: undefined, type })
153
-
154
- if (addInitializer) {
155
- // standard decorator API, avoid proxies
156
- addInitializer(function (this: any) {
157
- runAfterClassInitialization(clazz, this)
158
- })
159
-
160
- const modelInfo = {
161
- name,
162
- class: clazz,
163
- }
164
-
165
- modelInfoByName[name] = modelInfo
166
-
167
- modelInfoByClass.set(clazz, modelInfo)
168
-
169
- runLateInitializationFunctions(clazz, runAfterModelDecoratorSymbol)
170
-
171
- return undefined // use same class
172
- } else {
173
- // non-standard decorator API, use proxies
174
-
175
- // trick so plain new works
176
- const proxyClass = new Proxy<MC>(clazz, proxyClassHandler)
177
-
178
- // set or else it points to the undecorated class
179
- proxyClass.prototype.constructor = proxyClass
180
- ;(proxyClass as any)[modelUnwrappedClassSymbol] = clazz
181
-
182
- const modelInfo = {
183
- name,
184
- class: proxyClass,
185
- }
186
-
187
- modelInfoByName[name] = modelInfo
188
-
189
- modelInfoByClass.set(proxyClass, modelInfo)
190
- modelInfoByClass.set(clazz, modelInfo)
191
-
192
- runLateInitializationFunctions(clazz, runAfterModelDecoratorSymbol)
193
-
194
- return proxyClass
195
- }
196
- }
197
-
198
- // basically taken from TS
199
- function tsDecorate(decorators: any, target: any, key: any, desc: any) {
200
- const c = arguments.length
201
- let r =
202
- c < 3 ? target : desc === null ? (desc = Object.getOwnPropertyDescriptor(target, key)) : desc
203
- let d: any
204
- if (typeof Reflect === "object" && typeof (Reflect as any).decorate === "function") {
205
- r = (Reflect as any).decorate(decorators, target, key, desc)
206
- } else {
207
- for (
208
- // biome-ignore lint/correctness/noInnerDeclarations: minified file
209
- var i = decorators.length - 1;
210
- i >= 0;
211
- i--
212
- ) {
213
- if ((d = decorators[i])) {
214
- r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r
215
- }
216
- }
217
- }
218
- // biome-ignore lint/complexity/noCommaOperator: minified file
219
- return c > 3 && r && Object.defineProperty(target, key, r), r
220
- }
221
-
222
- /**
223
- * Marks a class (which MUST inherit from the `Model` abstract class)
224
- * as a model and decorates some of its methods/properties.
225
- *
226
- * @param name Unique name for the model type. Note that this name must be unique for your whole
227
- * application, so it is usually a good idea to use some prefix unique to your application domain.
228
- * If you don't want to assign a name yet (e.g. for a base model) pass `undefined`.
229
- * @param clazz Model class.
230
- * @param decorators Decorators.
231
- */
232
- export function decoratedModel<M, MC extends abstract new (...ags: any) => M>(
233
- name: string | undefined,
234
- clazz: MC,
235
- decorators: {
236
- [k in keyof M]?: AnyFunction | ReadonlyArray<AnyFunction>
237
- }
238
- ): MC {
239
- // decorate class members
240
- for (const [k, decorator] of Object.entries(decorators)) {
241
- const prototypeValueDesc = Object.getOwnPropertyDescriptor(clazz.prototype, k)
242
- // TS seems to send null for methods in the prototype
243
- // (which we substitute for the descriptor to avoid a double look-up) and void 0 (undefined) for props
244
- tsDecorate(
245
- Array.isArray(decorator) ? decorator : [decorator],
246
- clazz.prototype,
247
- k,
248
- prototypeValueDesc ? prototypeValueDesc : void 0
249
- )
250
- }
251
-
252
- return (name ? model(name)(clazz as unknown as ModelClass<AnyModel>) : clazz) as MC
253
- }
1
+ import { HookAction } from "../action/hookActions"
2
+ import { wrapModelMethodInActionIfNeeded } from "../action/wrapInAction"
3
+ import type { AnyDataModel } from "../dataModel/BaseDataModel"
4
+ import { isDataModelClass } from "../dataModel/utils"
5
+ import { enterInitPhase, exitInitPhase } from "../deepChange/onDeepChange"
6
+ import { getGlobalConfig } from "../globalConfig"
7
+ import type { AnyModel } from "../model/BaseModel"
8
+ import { modelTypeKey } from "../model/metadata"
9
+ import { isModelClass } from "../model/utils"
10
+ import { type ModelClass, modelInitializedSymbol } from "../modelShared/BaseModelShared"
11
+ import { modelInfoByClass, modelInfoByName } from "../modelShared/modelInfo"
12
+ import {
13
+ modelUnwrappedClassSymbol,
14
+ runAfterModelDecoratorSymbol,
15
+ } from "../modelShared/modelSymbols"
16
+ import { refreshInternalSnapshot } from "../snapshot/internal"
17
+ import {
18
+ failure,
19
+ getMobxVersion,
20
+ logWarning,
21
+ mobx6,
22
+ runAfterNewSymbol,
23
+ runBeforeOnInitSymbol,
24
+ runLateInitializationFunctions,
25
+ } from "../utils"
26
+ import type { AnyFunction } from "../utils/AnyFunction"
27
+
28
+ /**
29
+ * Decorator that marks this class (which MUST inherit from the `Model` or `DataModel` abstract classes)
30
+ * as a model.
31
+ *
32
+ * @param name Unique name for the model type. Note that this name must be unique for your whole
33
+ * application, so it is usually a good idea to use some prefix unique to your application domain.
34
+ */
35
+ export const model =
36
+ (name: string) =>
37
+ <MC extends ModelClass<AnyModel | AnyDataModel>>(clazz: MC, ...args: any[]): MC => {
38
+ const ctx = typeof args[1] === "object" ? (args[1] as ClassDecoratorContext) : undefined
39
+
40
+ return internalModel(name, clazz, ctx?.addInitializer) as any
41
+ }
42
+
43
+ const afterClassInitializationData = new WeakMap<
44
+ ModelClass<AnyModel | AnyDataModel>,
45
+ {
46
+ needsMakeObservable: boolean | undefined
47
+ type: "class" | "data"
48
+ }
49
+ >()
50
+
51
+ const runAfterClassInitialization = (
52
+ target: ModelClass<AnyModel | AnyDataModel>,
53
+ instance: any
54
+ ) => {
55
+ runLateInitializationFunctions(instance, runAfterNewSymbol)
56
+
57
+ const tag = afterClassInitializationData.get(target)!
58
+
59
+ // compatibility with mobx 6
60
+ if (tag.needsMakeObservable) {
61
+ // we know it can be done and shouldn't fail
62
+ mobx6.makeObservable(instance)
63
+ } else if (tag.needsMakeObservable === undefined) {
64
+ if (getMobxVersion() >= 6) {
65
+ try {
66
+ mobx6.makeObservable(instance)
67
+ tag.needsMakeObservable = true
68
+ } catch (e) {
69
+ const err = e as Error
70
+ if (
71
+ err.message !==
72
+ "[MobX] No annotations were passed to makeObservable, but no decorator members have been found either" &&
73
+ err.message !==
74
+ "[MobX] No annotations were passed to makeObservable, but no decorated members have been found either"
75
+ ) {
76
+ throw err
77
+ }
78
+
79
+ // sadly we need to use this hack since the PR to do this the proper way
80
+ // was rejected on the mobx side
81
+ tag.needsMakeObservable = false
82
+ }
83
+ } else {
84
+ tag.needsMakeObservable = false
85
+ }
86
+ }
87
+
88
+ // the object is ready
89
+ instance[modelInitializedSymbol] = true
90
+ refreshInternalSnapshot(instance)
91
+
92
+ enterInitPhase()
93
+ try {
94
+ runLateInitializationFunctions(instance, runBeforeOnInitSymbol)
95
+
96
+ if (tag.type === "class" && instance.onInit) {
97
+ wrapModelMethodInActionIfNeeded(instance, "onInit", HookAction.OnInit)
98
+
99
+ instance.onInit()
100
+ }
101
+
102
+ if (tag.type === "data" && instance.onLazyInit) {
103
+ wrapModelMethodInActionIfNeeded(instance, "onLazyInit", HookAction.OnLazyInit)
104
+
105
+ instance.onLazyInit()
106
+ }
107
+ } finally {
108
+ exitInitPhase()
109
+ }
110
+ }
111
+
112
+ const proxyClassHandler: ProxyHandler<ModelClass<AnyModel | AnyDataModel>> = {
113
+ construct(clazz, args) {
114
+ const instance = new (clazz as any)(...args)
115
+
116
+ runAfterClassInitialization(clazz, instance)
117
+
118
+ return instance
119
+ },
120
+ }
121
+
122
+ const internalModel = <MC extends ModelClass<AnyModel | AnyDataModel>>(
123
+ name: string,
124
+ clazz: MC,
125
+ addInitializer: ((initializer: (this: any) => void) => void) | undefined
126
+ ): MC | void => {
127
+ const type = isModelClass(clazz) ? "class" : isDataModelClass(clazz) ? "data" : undefined
128
+ if (!type) {
129
+ throw failure(`clazz must be a class that extends from Model/DataModel`)
130
+ }
131
+
132
+ if (modelInfoByName[name]) {
133
+ if (getGlobalConfig().showDuplicateModelNameWarnings) {
134
+ logWarning(
135
+ "warn",
136
+ `a model with name "${name}" already exists (if you are using hot-reloading you may safely ignore this warning)`,
137
+ `duplicateModelName - ${name}`
138
+ )
139
+ }
140
+ }
141
+
142
+ if (modelUnwrappedClassSymbol in clazz && clazz[modelUnwrappedClassSymbol] === clazz) {
143
+ throw failure("a class already decorated with `@model` cannot be re-decorated")
144
+ }
145
+
146
+ clazz.toString = () => `class ${clazz.name}#${name}`
147
+ if (type === "class") {
148
+ ;(clazz as any)[modelTypeKey] = name
149
+ }
150
+
151
+ // track if we fail so we only try it once per class
152
+ afterClassInitializationData.set(clazz, { needsMakeObservable: undefined, type })
153
+
154
+ if (addInitializer) {
155
+ // standard decorator API, avoid proxies
156
+ addInitializer(function (this: any) {
157
+ runAfterClassInitialization(clazz, this)
158
+ })
159
+
160
+ const modelInfo = {
161
+ name,
162
+ class: clazz,
163
+ }
164
+
165
+ modelInfoByName[name] = modelInfo
166
+
167
+ modelInfoByClass.set(clazz, modelInfo)
168
+
169
+ runLateInitializationFunctions(clazz, runAfterModelDecoratorSymbol)
170
+
171
+ return undefined // use same class
172
+ } else {
173
+ // non-standard decorator API, use proxies
174
+
175
+ // trick so plain new works
176
+ const proxyClass = new Proxy<MC>(clazz, proxyClassHandler)
177
+
178
+ // set or else it points to the undecorated class
179
+ proxyClass.prototype.constructor = proxyClass
180
+ ;(proxyClass as any)[modelUnwrappedClassSymbol] = clazz
181
+
182
+ const modelInfo = {
183
+ name,
184
+ class: proxyClass,
185
+ }
186
+
187
+ modelInfoByName[name] = modelInfo
188
+
189
+ modelInfoByClass.set(proxyClass, modelInfo)
190
+ modelInfoByClass.set(clazz, modelInfo)
191
+
192
+ runLateInitializationFunctions(clazz, runAfterModelDecoratorSymbol)
193
+
194
+ return proxyClass
195
+ }
196
+ }
197
+
198
+ // basically taken from TS
199
+ function tsDecorate(
200
+ ...args:
201
+ | [decorators: any, target: any]
202
+ | [decorators: any, target: any, key: any]
203
+ | [decorators: any, target: any, key: any, desc: any]
204
+ ) {
205
+ const [decorators, target, key] = args
206
+ let desc = args[3]
207
+ const c = args.length
208
+ let r =
209
+ c < 3 ? target : desc === null ? (desc = Object.getOwnPropertyDescriptor(target, key)) : desc
210
+ let d: any
211
+ if (typeof Reflect === "object" && typeof (Reflect as any).decorate === "function") {
212
+ r = (Reflect as any).decorate(decorators, target, key, desc)
213
+ } else {
214
+ for (
215
+ // biome-ignore lint/correctness/noInnerDeclarations: minified file
216
+ var i = decorators.length - 1;
217
+ i >= 0;
218
+ i--
219
+ ) {
220
+ if ((d = decorators[i])) {
221
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r
222
+ }
223
+ }
224
+ }
225
+ // biome-ignore lint/complexity/noCommaOperator: minified file
226
+ return c > 3 && r && Object.defineProperty(target, key, r), r
227
+ }
228
+
229
+ /**
230
+ * Marks a class (which MUST inherit from the `Model` abstract class)
231
+ * as a model and decorates some of its methods/properties.
232
+ *
233
+ * @param name Unique name for the model type. Note that this name must be unique for your whole
234
+ * application, so it is usually a good idea to use some prefix unique to your application domain.
235
+ * If you don't want to assign a name yet (e.g. for a base model) pass `undefined`.
236
+ * @param clazz Model class.
237
+ * @param decorators Decorators.
238
+ */
239
+ export function decoratedModel<M, MC extends abstract new (...ags: any) => M>(
240
+ name: string | undefined,
241
+ clazz: MC,
242
+ decorators: {
243
+ [k in keyof M]?: AnyFunction | ReadonlyArray<AnyFunction>
244
+ }
245
+ ): MC {
246
+ // decorate class members
247
+ for (const [k, decorator] of Object.entries(decorators)) {
248
+ const prototypeValueDesc = Object.getOwnPropertyDescriptor(clazz.prototype, k)
249
+ // TS seems to send null for methods in the prototype
250
+ // (which we substitute for the descriptor to avoid a double look-up) and void 0 (undefined) for props
251
+ tsDecorate(
252
+ Array.isArray(decorator) ? decorator : [decorator],
253
+ clazz.prototype,
254
+ k,
255
+ prototypeValueDesc ? prototypeValueDesc : void 0
256
+ )
257
+ }
258
+
259
+ return (name ? model(name)(clazz as unknown as ModelClass<AnyModel>) : clazz) as MC
260
+ }
@@ -1,50 +1,50 @@
1
- import type { AnyDataModel } from "../dataModel/BaseDataModel"
2
- import type { AnyModel } from "../model/BaseModel"
3
- import type { ModelClass } from "./BaseModelShared"
4
-
5
- /**
6
- * Information about a registered model.
7
- */
8
- export interface ModelInfo {
9
- name: string
10
- class: ModelClass<AnyModel | AnyDataModel>
11
- }
12
-
13
- /**
14
- * @internal
15
- */
16
- export const modelInfoByName: {
17
- [name: string]: ModelInfo
18
- } = {}
19
-
20
- /**
21
- * @internal
22
- */
23
- export const modelInfoByClass = new WeakMap<ModelClass<AnyModel | AnyDataModel>, ModelInfo>()
24
-
25
- /**
26
- * Returns the model info for a model type name, or `undefined` if not found.
27
- *
28
- * @param name The model type name (from `$modelType`).
29
- * @returns The model info or `undefined`.
30
- */
31
- export function getModelInfoForName(name: string): ModelInfo | undefined {
32
- return modelInfoByName[name]
33
- }
34
-
35
- /**
36
- * Builds a helpful error message when a model type cannot be resolved from the runtime registry.
37
- *
38
- * @param name The model type name (from `$modelType`).
39
- * @returns A diagnostic message with common remediation steps.
40
- */
41
- export function getModelNotRegisteredErrorMessage(name: string): string {
42
- return (
43
- `model with name "${name}" not found in the registry. ` +
44
- "This usually means the model module was not imported at runtime " +
45
- "(for example, due to type-only imports or import elision). " +
46
- "Import the model module for side effects, use runtime model references " +
47
- "(for example `tProp(types.model(MyModel))` or `fromSnapshot(MyModel, snapshot)`), " +
48
- "or call `registerModels(MyModel)` during startup."
49
- )
50
- }
1
+ import type { AnyDataModel } from "../dataModel/BaseDataModel"
2
+ import type { AnyModel } from "../model/BaseModel"
3
+ import type { ModelClass } from "./BaseModelShared"
4
+
5
+ /**
6
+ * Information about a registered model.
7
+ */
8
+ export interface ModelInfo {
9
+ name: string
10
+ class: ModelClass<AnyModel | AnyDataModel>
11
+ }
12
+
13
+ /**
14
+ * @internal
15
+ */
16
+ export const modelInfoByName: {
17
+ [name: string]: ModelInfo
18
+ } = {}
19
+
20
+ /**
21
+ * @internal
22
+ */
23
+ export const modelInfoByClass = new WeakMap<ModelClass<AnyModel | AnyDataModel>, ModelInfo>()
24
+
25
+ /**
26
+ * Returns the model info for a model type name, or `undefined` if not found.
27
+ *
28
+ * @param name The model type name (from `$modelType`).
29
+ * @returns The model info or `undefined`.
30
+ */
31
+ export function getModelInfoForName(name: string): ModelInfo | undefined {
32
+ return modelInfoByName[name]
33
+ }
34
+
35
+ /**
36
+ * Builds a helpful error message when a model type cannot be resolved from the runtime registry.
37
+ *
38
+ * @param name The model type name (from `$modelType`).
39
+ * @returns A diagnostic message with common remediation steps.
40
+ */
41
+ export function getModelNotRegisteredErrorMessage(name: string): string {
42
+ return (
43
+ `model with name "${name}" not found in the registry. ` +
44
+ "This usually means the model module was not imported at runtime " +
45
+ "(for example, due to type-only imports or import elision). " +
46
+ "Import the model module for side effects, use runtime model references " +
47
+ "(for example `tProp(types.model(MyModel))` or `fromSnapshot(MyModel, snapshot)`), " +
48
+ "or call `registerModels(MyModel)` during startup."
49
+ )
50
+ }
@@ -1,3 +1,3 @@
1
- export const modelMetadataSymbol = Symbol("modelMetadata")
2
- export const modelUnwrappedClassSymbol = Symbol("modelUnwrappedClass")
3
- export const runAfterModelDecoratorSymbol = Symbol("runAfterModelDecorator")
1
+ export const modelMetadataSymbol = Symbol("modelMetadata")
2
+ export const modelUnwrappedClassSymbol = Symbol("modelUnwrappedClass")
3
+ export const runAfterModelDecoratorSymbol = Symbol("runAfterModelDecorator")