mobx-keystone 1.23.0 → 1.24.1

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.
@@ -2,7 +2,7 @@ import { AnyDataModel } from '../dataModel/BaseDataModel';
2
2
  import { AnyModel } from '../model/BaseModel';
3
3
  import { modelTypeKey } from '../model/metadata';
4
4
  import { Flatten, IsNeverType } from '../utils/types';
5
- import { ModelPropsToSnapshotCreationData, ModelPropsToSnapshotData, ModelPropsToTransformedCreationData, ModelPropsToTransformedData, ModelPropsToUntransformedCreationData } from './prop';
5
+ import { ModelProps, ModelPropsToSnapshotCreationData, ModelPropsToSnapshotData, ModelPropsToTransformedCreationData, ModelPropsToTransformedData, ModelPropsToUntransformedCreationData } from './prop';
6
6
  /**
7
7
  * @ignore
8
8
  */
@@ -27,6 +27,12 @@ export interface ModelClass<M extends AnyModel | AnyDataModel> {
27
27
  * Extracts the instance type of an abstract model class.
28
28
  */
29
29
  export type AbstractModelClass<M extends AnyModel | AnyDataModel> = abstract new (initialData: any) => M;
30
+ /**
31
+ * @ignore
32
+ */
33
+ export interface ModelWithProps {
34
+ [propsTypeSymbol]: ModelProps;
35
+ }
30
36
  /**
31
37
  * The props of a model.
32
38
  */
@@ -9,7 +9,7 @@ import { AnyFunction } from '../utils/AnyFunction';
9
9
  * @param name Unique name for the model type. Note that this name must be unique for your whole
10
10
  * application, so it is usually a good idea to use some prefix unique to your application domain.
11
11
  */
12
- export declare const model: (name: string) => <MC extends ModelClass<AnyModel | AnyDataModel>>(clazz: MC, ...args: any[]) => MC;
12
+ export declare const model: (name: string) => <MC extends ModelClass<AnyModel | AnyDataModel>>(clazz: MC, _context?: ClassDecoratorContext<MC>) => MC;
13
13
  /**
14
14
  * Marks a class (which MUST inherit from the `Model` abstract class)
15
15
  * as a model and decorates some of its methods/properties.
@@ -7,6 +7,11 @@ import { Flatten, IsNeverType, IsOptionalValue } from '../utils/types';
7
7
  export declare const noDefaultValue: unique symbol;
8
8
  type SetterMode = boolean | "assign";
9
9
  export type ModelPropSetterValueTransform<T> = (value: T) => T;
10
+ /** @ignore */
11
+ export interface FullModelPropTransform {
12
+ transform: (original: unknown, model: object, propName: PropertyKey, setOriginalValue: (newOriginalValue: unknown) => void) => unknown;
13
+ untransform: (transformed: unknown, model: object, propName: PropertyKey) => unknown;
14
+ }
10
15
  /**
11
16
  * A model property.
12
17
  */
@@ -1,4 +1,78 @@
1
+ import { Path } from '../parent/pathTypes';
1
2
  import { AnyStandardType } from './schemas';
3
+ import { TypeCheckError } from './TypeCheckError';
4
+ type CheckFunction = (value: any, path: Path, typeCheckedValue: any) => TypeCheckError | null;
5
+ /** @ignore */
6
+ export type SnapshotProcessor = (snapshot: any) => unknown;
7
+ /**
8
+ * A lazily discovered snapshot-processor node. Dependencies are deliberately
9
+ * TypeCheckers rather than processors so recursive graphs can be discovered
10
+ * before any processor body is compiled.
11
+ *
12
+ * @ignore
13
+ */
14
+ export interface SnapshotProcessorPlan {
15
+ readonly intrinsic?: boolean;
16
+ readonly getDependencies: () => ReadonlyArray<TypeChecker>;
17
+ readonly compile: (dependencyProcessors: ReadonlyArray<SnapshotProcessor | undefined>) => SnapshotProcessor | undefined;
18
+ }
19
+ type SnapshotProcessorSource = SnapshotProcessor | SnapshotProcessorPlan | undefined;
20
+ type SnapshotProcessorDirection = "from" | "to";
21
+ /** @ignore */
22
+ export declare class SnapshotProcessorPlanNode {
23
+ private readonly owner;
24
+ private readonly direction;
25
+ private readonly source;
26
+ private presence;
27
+ private dependencies;
28
+ private discovering;
29
+ private compiling;
30
+ private compiled;
31
+ private compiledProcessor;
32
+ private forwardingProcessor;
33
+ constructor(owner: TypeChecker | undefined, direction: SnapshotProcessorDirection, source: SnapshotProcessorSource);
34
+ resolve(): SnapshotProcessor | undefined;
35
+ private discover;
36
+ private compile;
37
+ private compileForDependency;
38
+ }
39
+ /**
40
+ * @ignore
41
+ */
42
+ export declare enum TypeCheckerBaseType {
43
+ Object = "object",
44
+ Array = "array",
45
+ Primitive = "primitive",
46
+ Any = "any"
47
+ }
48
+ /**
49
+ * @ignore
50
+ */
51
+ export declare class TypeChecker {
52
+ unchecked: boolean;
53
+ skipCheck: boolean;
54
+ readonly baseType: TypeCheckerBaseType;
55
+ private readonly _check;
56
+ readonly getTypeName: (...recursiveTypeCheckers: TypeChecker[]) => string;
57
+ readonly typeInfoGen: TypeInfoGen;
58
+ readonly snapshotType: (sn: unknown) => TypeChecker | null;
59
+ private readonly fromSnapshotProcessorSource;
60
+ private readonly toSnapshotProcessorSource;
61
+ private fromSnapshotProcessorPlanNode;
62
+ private toSnapshotProcessorPlanNode;
63
+ check(value: any, path: Path, typeCheckedValue: any): TypeCheckError | null;
64
+ private _cachedTypeInfoGen;
65
+ get typeInfo(): TypeInfo;
66
+ constructor(baseType: TypeCheckerBaseType, _check: CheckFunction | null, getTypeName: (...recursiveTypeCheckers: TypeChecker[]) => string, typeInfoGen: TypeInfoGen, snapshotType: (sn: unknown) => TypeChecker | null, fromSnapshotProcessor: SnapshotProcessorSource, toSnapshotProcessor: SnapshotProcessorSource);
67
+ getSnapshotProcessorPlanNode(direction: SnapshotProcessorDirection): SnapshotProcessorPlanNode;
68
+ private resolveSnapshotProcessor;
69
+ getFromSnapshotProcessor(): SnapshotProcessor | undefined;
70
+ getToSnapshotProcessor(): SnapshotProcessor | undefined;
71
+ fromSnapshotProcessor: (sn: any) => unknown;
72
+ private readonly _toSnapshotProcessorCache;
73
+ invalidateSnapshotProcessorCachedResult(obj: object): void;
74
+ toSnapshotProcessor: (sn: any) => unknown;
75
+ }
2
76
  /**
3
77
  * Type info base class.
4
78
  */
@@ -7,3 +81,8 @@ export declare class TypeInfo {
7
81
  readonly thisType: AnyStandardType;
8
82
  constructor(thisType: AnyStandardType);
9
83
  }
84
+ /**
85
+ * @ignore
86
+ */
87
+ export type TypeInfoGen = (t: AnyStandardType) => TypeInfo;
88
+ export {};
@@ -3,6 +3,7 @@ import { AnyDataModel } from '../dataModel/BaseDataModel';
3
3
  import { AnyModel } from '../model/BaseModel';
4
4
  import { ModelClass } from '../modelShared/BaseModelShared';
5
5
  import { SnapshotInOf, SnapshotOutOf } from '../snapshot/SnapshotOf';
6
+ import { IsOptionalValue } from '../utils/types';
6
7
  export interface Type<Name, Data> {
7
8
  /** @ignore */
8
9
  $$type: Name;
@@ -36,6 +37,20 @@ export interface ObjectOfTypes {
36
37
  /** @ignore */
37
38
  [k: string]: AnyType;
38
39
  }
40
+ /**
41
+ * Name of the properties of an object that can be set to undefined, any or unknown.
42
+ * @ignore
43
+ */
44
+ export type UndefinablePropsNames<T> = {
45
+ [K in keyof T]: IsOptionalValue<T[K], K, never>;
46
+ }[keyof T];
47
+ /**
48
+ * Computes the optional keys for an object type schema.
49
+ * @ignore
50
+ */
51
+ export type ObjectOptionalKeys<S> = UndefinablePropsNames<{
52
+ [k in keyof S]: TypeToDataOpt<S[k]> extends infer R ? R : never;
53
+ }>;
39
54
  type ObjectData<S> = O.Optional<{
40
55
  [k in keyof S]: TypeToData<S[k]> extends infer R ? R : never;
41
56
  }, ObjectOptionalKeys<S>>;
@@ -4,3 +4,27 @@
4
4
  export declare class MobxKeystoneError extends Error {
5
5
  constructor(msg: string);
6
6
  }
7
+ /**
8
+ * MobX method action decorator compatible with both legacy decorators and
9
+ * MobX 7's standard decorator API.
10
+ *
11
+ * This is a decorator compatibility helper, not a replacement for other
12
+ * `action` overloads such as `action(fn)`. Field decorators are not supported.
13
+ *
14
+ * @hidden
15
+ */
16
+ export declare function mobxAction<This, Args extends unknown[], Return>(value: (this: This, ...args: Args) => Return, context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>): (this: This, ...args: Args) => Return;
17
+ export declare function mobxAction<This, Args extends unknown[], Return>(target: object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<(this: This, ...args: Args) => Return>): TypedPropertyDescriptor<(this: This, ...args: Args) => Return> | void;
18
+ /**
19
+ * MobX getter computed decorator compatible with both legacy decorators and
20
+ * MobX 7's standard decorator API.
21
+ *
22
+ * This is a decorator compatibility helper, not a replacement for other
23
+ * `computed` overloads. Field decorators and decorator options are not supported.
24
+ * Under MobX 7's legacy decorator transform the getter is backed by a computed
25
+ * value, but is not registered as a computed property for MobX introspection.
26
+ *
27
+ * @hidden
28
+ */
29
+ export declare function mobxComputed<This, Value>(value: (this: This) => Value, context: ClassGetterDecoratorContext<This, Value>): ((this: This) => Value) | void;
30
+ export declare function mobxComputed<Value>(target: object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<Value>): TypedPropertyDescriptor<Value> | void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mobx-keystone",
3
- "version": "1.23.0",
3
+ "version": "1.24.1",
4
4
  "description": "A MobX powered state management solution based on data trees with first class support for TypeScript, snapshots, patches and much more",
5
5
  "keywords": [
6
6
  "mobx",
@@ -54,7 +54,8 @@
54
54
  "quick-build": "tsc",
55
55
  "quick-build-tests": "tsc -p test",
56
56
  "copy-root-files": "shx cp ../../README.md . && shx cp ../../LICENSE . && shx cp ../../CHANGELOG.md .",
57
- "build": "pnpm run quick-build && pnpm run copy-root-files && shx rm -rf dist && vite build && shx cp dist/mobx-keystone.esm.mjs dist/mobx-keystone.esm.js",
57
+ "build": "pnpm run quick-build && pnpm run copy-root-files && shx rm -rf dist && vite build && pnpm run check-declarations && shx cp dist/mobx-keystone.esm.mjs dist/mobx-keystone.esm.js",
58
+ "check-declarations": "tsc -p scripts/tsconfig.check-declarations.json",
58
59
  "test": "vitest run",
59
60
  "test:ci": "vitest run --coverage",
60
61
  "test:perf": "pnpm run build && pnpm run test:perf:run",
@@ -63,27 +64,30 @@
63
64
  "build-docs": "shx rm -rf api-docs && node --import ./scripts/typedoc-typescript6-register.mjs ./node_modules/typedoc/dist/cli.js --options ./typedocconfig.js src/index.ts && shx rm -rf ../../apps/site/generated-static/api && shx mkdir -p ../../apps/site/generated-static/api && shx cp -R ./api-docs/* ../../apps/site/generated-static/api"
64
65
  },
65
66
  "peerDependencies": {
66
- "mobx": "^6.0.0 || ^5.0.0 || ^4.0.0"
67
+ "mobx": "^7.0.0 || ^6.0.0 || ^5.0.0 || ^4.0.0"
67
68
  },
68
69
  "devDependencies": {
69
70
  "@babel/core": "^8.0.1",
70
71
  "@babel/plugin-proposal-decorators": "^8.0.2",
71
72
  "@babel/plugin-transform-class-properties": "^8.0.1",
73
+ "@babel/plugin-transform-class-static-block": "^8.0.1",
72
74
  "@babel/plugin-transform-typescript": "^8.0.1",
73
75
  "@babel/preset-env": "^8.0.2",
74
- "@swc/core": "^1.15.43",
76
+ "@swc/core": "^1.16.0",
75
77
  "@types/babel__core": "^7.20.5",
76
- "@types/node": "^26.1.1",
78
+ "@types/node": "^26.2.0",
77
79
  "@typescript/typescript6": "^6.0.2",
78
80
  "@vitest/coverage-v8": "^4.1.10",
79
81
  "mobx-v4": "npm:mobx@^4.15.7",
80
82
  "mobx-v5": "npm:mobx@^5.15.7",
83
+ "mobx-v6": "npm:mobx@^6.0.0",
84
+ "mobx-v7": "npm:mobx@^7.0.0",
81
85
  "shx": "^0.4.0",
82
86
  "spec.ts": "^1.1.3",
83
87
  "ts-node": "^10.9.2",
84
88
  "typedoc": "^0.28.20",
85
89
  "typescript": "^7.0.2",
86
- "vite": "^8.1.4",
90
+ "vite": "^8.2.1",
87
91
  "vite-plugin-dts": "^5.0.3",
88
92
  "vitest": "^4.1.10"
89
93
  },
@@ -1,4 +1,3 @@
1
- import { action, computed } from "mobx"
2
1
  import type { ActionMiddlewareDisposer } from "../action/middleware"
3
2
  import { modelAction } from "../action/modelAction"
4
3
  import { Model } from "../model/Model"
@@ -10,7 +9,14 @@ import { assertTweakedObject } from "../tweaker/core"
10
9
  import { typesArray } from "../types/arrayBased/typesArray"
11
10
  import { tProp } from "../types/tProp"
12
11
  import { typesUnchecked } from "../types/utility/typesUnchecked"
13
- import { failure, getMobxVersion, mobx6, namespace } from "../utils"
12
+ import {
13
+ failure,
14
+ getMobxVersion,
15
+ makeObservableCompat,
16
+ mobxAction,
17
+ mobxComputed,
18
+ namespace,
19
+ } from "../utils"
14
20
  import { actionTrackingMiddleware, type SimpleActionContext } from "./actionTrackingMiddleware"
15
21
 
16
22
  /**
@@ -306,7 +312,7 @@ export class UndoManager {
306
312
  * The undo stack, where the first operation to undo will be the last of the array.
307
313
  * Do not manipulate this array directly.
308
314
  */
309
- @computed
315
+ @mobxComputed
310
316
  get undoQueue(): ReadonlyArray<UndoEvent> {
311
317
  return this.store.undoEvents
312
318
  }
@@ -315,7 +321,7 @@ export class UndoManager {
315
321
  * The redo stack, where the first operation to redo will be the last of the array.
316
322
  * Do not manipulate this array directly.
317
323
  */
318
- @computed
324
+ @mobxComputed
319
325
  get redoQueue(): ReadonlyArray<UndoEvent> {
320
326
  return this.store.redoEvents
321
327
  }
@@ -323,7 +329,7 @@ export class UndoManager {
323
329
  /**
324
330
  * The number of undo actions available.
325
331
  */
326
- @computed
332
+ @mobxComputed
327
333
  get undoLevels() {
328
334
  return this.undoQueue.length
329
335
  }
@@ -331,7 +337,7 @@ export class UndoManager {
331
337
  /**
332
338
  * If undo can be performed (if there is at least one undo action available).
333
339
  */
334
- @computed
340
+ @mobxComputed
335
341
  get canUndo() {
336
342
  return this.undoLevels > 0
337
343
  }
@@ -339,7 +345,7 @@ export class UndoManager {
339
345
  /**
340
346
  * Clears the undo queue.
341
347
  */
342
- @action
348
+ @mobxAction
343
349
  clearUndo() {
344
350
  this.store._clearUndo()
345
351
  }
@@ -347,7 +353,7 @@ export class UndoManager {
347
353
  /**
348
354
  * The number of redo actions available.
349
355
  */
350
- @computed
356
+ @mobxComputed
351
357
  get redoLevels() {
352
358
  return this.redoQueue.length
353
359
  }
@@ -355,7 +361,7 @@ export class UndoManager {
355
361
  /**
356
362
  * If redo can be performed (if there is at least one redo action available)
357
363
  */
358
- @computed
364
+ @mobxComputed
359
365
  get canRedo() {
360
366
  return this.redoLevels > 0
361
367
  }
@@ -363,7 +369,7 @@ export class UndoManager {
363
369
  /**
364
370
  * Clears the redo queue.
365
371
  */
366
- @action
372
+ @mobxAction
367
373
  clearRedo() {
368
374
  this.store._clearRedo()
369
375
  }
@@ -372,7 +378,7 @@ export class UndoManager {
372
378
  * Undoes the last action.
373
379
  * Will throw if there is no action to undo.
374
380
  */
375
- @action
381
+ @mobxAction
376
382
  undo() {
377
383
  if (!this.canUndo) {
378
384
  throw failure("nothing to undo")
@@ -397,7 +403,7 @@ export class UndoManager {
397
403
  * Redoes the previous action.
398
404
  * Will throw if there is no action to redo.
399
405
  */
400
- @action
406
+ @mobxAction
401
407
  redo() {
402
408
  if (!this.canRedo) {
403
409
  throw failure("nothing to redo")
@@ -619,7 +625,7 @@ export class UndoManager {
619
625
  this.options = options
620
626
 
621
627
  if (getMobxVersion() >= 6) {
622
- mobx6.makeObservable(this)
628
+ makeObservableCompat(this)
623
629
  }
624
630
 
625
631
  this.store = store ?? new UndoStore({})
@@ -49,7 +49,7 @@ export type AbstractModelClass<M extends AnyModel | AnyDataModel> = abstract new
49
49
  ) => M
50
50
 
51
51
  /**
52
- * @internal
52
+ * @ignore
53
53
  */
54
54
  export interface ModelWithProps {
55
55
  [propsTypeSymbol]: ModelProps
@@ -15,10 +15,11 @@ import {
15
15
  } from "../modelShared/modelSymbols"
16
16
  import { refreshInternalSnapshot } from "../snapshot/internal"
17
17
  import {
18
+ addLateInitializationFunction,
18
19
  failure,
19
20
  getMobxVersion,
20
21
  logWarning,
21
- mobx6,
22
+ makeObservableCompat,
22
23
  runAfterNewSymbol,
23
24
  runBeforeOnInitSymbol,
24
25
  runLateInitializationFunctions,
@@ -34,11 +35,11 @@ import type { AnyFunction } from "../utils/AnyFunction"
34
35
  */
35
36
  export const model =
36
37
  (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
- }
38
+ <MC extends ModelClass<AnyModel | AnyDataModel>>(
39
+ clazz: MC,
40
+ _context?: ClassDecoratorContext<MC>
41
+ ): MC =>
42
+ internalModel(name, clazz) as any
42
43
 
43
44
  const afterClassInitializationData = new WeakMap<
44
45
  ModelClass<AnyModel | AnyDataModel>,
@@ -56,14 +57,14 @@ const runAfterClassInitialization = (
56
57
 
57
58
  const tag = afterClassInitializationData.get(target)!
58
59
 
59
- // compatibility with mobx 6
60
+ // compatibility with mobx 6 and 7
60
61
  if (tag.needsMakeObservable) {
61
62
  // we know it can be done and shouldn't fail
62
- mobx6.makeObservable(instance)
63
+ makeObservableCompat(instance)
63
64
  } else if (tag.needsMakeObservable === undefined) {
64
65
  if (getMobxVersion() >= 6) {
65
66
  try {
66
- mobx6.makeObservable(instance)
67
+ makeObservableCompat(instance)
67
68
  tag.needsMakeObservable = true
68
69
  } catch (e) {
69
70
  const err = e as Error
@@ -121,8 +122,7 @@ const proxyClassHandler: ProxyHandler<ModelClass<AnyModel | AnyDataModel>> = {
121
122
 
122
123
  const internalModel = <MC extends ModelClass<AnyModel | AnyDataModel>>(
123
124
  name: string,
124
- clazz: MC,
125
- addInitializer: ((initializer: (this: any) => void) => void) | undefined
125
+ clazz: MC
126
126
  ): MC | void => {
127
127
  const type = isModelClass(clazz) ? "class" : isDataModelClass(clazz) ? "data" : undefined
128
128
  if (!type) {
@@ -151,48 +151,24 @@ const internalModel = <MC extends ModelClass<AnyModel | AnyDataModel>>(
151
151
  // track if we fail so we only try it once per class
152
152
  afterClassInitializationData.set(clazz, { needsMakeObservable: undefined, type })
153
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
154
+ const decoratedClass = new Proxy<MC>(clazz, proxyClassHandler)
155
+ ;(decoratedClass as any)[modelUnwrappedClassSymbol] = clazz
166
156
 
167
- modelInfoByClass.set(clazz, modelInfo)
157
+ decoratedClass.prototype.constructor = decoratedClass
168
158
 
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
- }
159
+ const modelInfo = {
160
+ name,
161
+ class: decoratedClass,
162
+ }
186
163
 
187
- modelInfoByName[name] = modelInfo
164
+ modelInfoByName[name] = modelInfo
188
165
 
189
- modelInfoByClass.set(proxyClass, modelInfo)
190
- modelInfoByClass.set(clazz, modelInfo)
166
+ modelInfoByClass.set(decoratedClass, modelInfo)
167
+ modelInfoByClass.set(clazz, modelInfo)
191
168
 
192
- runLateInitializationFunctions(clazz, runAfterModelDecoratorSymbol)
169
+ runLateInitializationFunctions(clazz, runAfterModelDecoratorSymbol)
193
170
 
194
- return proxyClass
195
- }
171
+ return decoratedClass
196
172
  }
197
173
 
198
174
  // basically taken from TS
@@ -243,18 +219,53 @@ export function decoratedModel<M, MC extends abstract new (...ags: any) => M>(
243
219
  [k in keyof M]?: AnyFunction | ReadonlyArray<AnyFunction>
244
220
  }
245
221
  ): MC {
222
+ const mobx7Annotations: Record<string, unknown> = {}
223
+
246
224
  // decorate class members
247
225
  for (const [k, decorator] of Object.entries(decorators)) {
226
+ const decoratorList = Array.isArray(decorator) ? decorator : [decorator]
227
+ const mobx7Annotation = decoratorList.find(isMobxAnnotation)
228
+ if (getMobxVersion() >= 7 && mobx7Annotation) {
229
+ if (decoratorList.length !== 1) {
230
+ throw failure("MobX 7 decorators cannot be combined in decoratedModel")
231
+ }
232
+ mobx7Annotations[k] = mobx7Annotation
233
+ continue
234
+ }
235
+
248
236
  const prototypeValueDesc = Object.getOwnPropertyDescriptor(clazz.prototype, k)
249
237
  // TS seems to send null for methods in the prototype
250
238
  // (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
- )
239
+ tsDecorate(decoratorList, clazz.prototype, k, prototypeValueDesc ? prototypeValueDesc : void 0)
240
+ }
241
+
242
+ if (getMobxVersion() >= 7 && Object.keys(mobx7Annotations).length > 0) {
243
+ addLateInitializationFunction(clazz.prototype, runAfterNewSymbol, (instance) => {
244
+ makeObservableCompat(instance, mobx7Annotations)
245
+ })
257
246
  }
258
247
 
259
248
  return (name ? model(name)(clazz as unknown as ModelClass<AnyModel>) : clazz) as MC
260
249
  }
250
+
251
+ type MobxAnnotation = {
252
+ annotationType_: string
253
+ make_: AnyFunction
254
+ extend_: AnyFunction
255
+ }
256
+
257
+ // MobX uses this same structural check in its internal `isAnnotation` helper.
258
+ // That helper is not part of MobX's public root API, so mirror it here instead
259
+ // of depending on a private deep import that may not exist in every supported version.
260
+ function isMobxAnnotation(value: unknown): value is MobxAnnotation {
261
+ if ((typeof value !== "object" || value === null) && typeof value !== "function") {
262
+ return false
263
+ }
264
+
265
+ const annotation = value as Partial<MobxAnnotation>
266
+ return (
267
+ typeof annotation.annotationType_ === "string" &&
268
+ typeof annotation.make_ === "function" &&
269
+ typeof annotation.extend_ === "function"
270
+ )
271
+ }
@@ -14,7 +14,7 @@ type SetterMode = boolean | "assign"
14
14
 
15
15
  export type ModelPropSetterValueTransform<T> = (value: T) => T
16
16
 
17
- /** @internal */
17
+ /** @ignore */
18
18
  export interface FullModelPropTransform {
19
19
  transform: (
20
20
  original: unknown,
package/src/ref/Ref.ts CHANGED
@@ -1,10 +1,9 @@
1
- import { computed } from "mobx"
2
1
  import { Model } from "../model/Model"
3
2
  import { modelTypeKey } from "../model/metadata"
4
3
  import type { ModelClass } from "../modelShared/BaseModelShared"
5
4
  import { typesString } from "../types/primitiveBased/typesPrimitive"
6
5
  import { tProp } from "../types/tProp"
7
- import { failure } from "../utils"
6
+ import { failure, mobxComputed } from "../utils"
8
7
 
9
8
  /**
10
9
  * A reference model base type.
@@ -21,7 +20,7 @@ export abstract class Ref<T extends object> extends Model({
21
20
  /**
22
21
  * The object this reference points to, or `undefined` if the reference is currently invalid.
23
22
  */
24
- @computed
23
+ @mobxComputed
25
24
  get maybeCurrent(): T | undefined {
26
25
  return this.resolve()
27
26
  }
@@ -29,7 +28,7 @@ export abstract class Ref<T extends object> extends Model({
29
28
  /**
30
29
  * If the reference is currently valid.
31
30
  */
32
- @computed
31
+ @mobxComputed
33
32
  get isValid(): boolean {
34
33
  return !!this.maybeCurrent
35
34
  }
@@ -37,7 +36,7 @@ export abstract class Ref<T extends object> extends Model({
37
36
  /**
38
37
  * The object this reference points to, or throws if invalid.
39
38
  */
40
- @computed
39
+ @mobxComputed
41
40
  get current(): T {
42
41
  const current = this.maybeCurrent
43
42
 
package/src/ref/core.ts CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  import { fastGetRoot } from "../parent/path"
10
10
  import { type ComputedWalkTreeAggregate, computedWalkTreeAggregate } from "../parent/walkTree"
11
11
  import { assertTweakedObject } from "../tweaker/core"
12
- import { assertIsObject, failure } from "../utils"
12
+ import { assertIsObject, failure, mobxAction } from "../utils"
13
13
  import { getOrCreate } from "../utils/mapUtils"
14
14
  import { Ref, type RefConstructor } from "./Ref"
15
15
 
@@ -103,7 +103,7 @@ export function internalCustomRef<T extends object>(
103
103
  return true
104
104
  }
105
105
 
106
- @action
106
+ @mobxAction
107
107
  forceUpdateBackRefs() {
108
108
  const currentTarget = this.maybeCurrent
109
109
  if (!this.startTracking(currentTarget)) {