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.
- package/CHANGELOG.md +9 -0
- package/README.md +12 -11
- package/dist/mobx-keystone.esm.js +187 -144
- package/dist/mobx-keystone.esm.mjs +187 -144
- package/dist/mobx-keystone.umd.js +189 -143
- package/dist/types/modelShared/BaseModelShared.d.ts +7 -1
- package/dist/types/modelShared/modelDecorator.d.ts +1 -1
- package/dist/types/modelShared/prop.d.ts +5 -0
- package/dist/types/types/TypeChecker.d.ts +79 -0
- package/dist/types/types/schemas.d.ts +15 -0
- package/dist/types/utils/index.d.ts +24 -0
- package/package.json +10 -6
- package/src/actionMiddlewares/undoMiddleware.ts +19 -13
- package/src/modelShared/BaseModelShared.ts +1 -1
- package/src/modelShared/modelDecorator.ts +64 -53
- package/src/modelShared/prop.ts +1 -1
- package/src/ref/Ref.ts +4 -5
- package/src/ref/core.ts +2 -2
- package/src/treeUtils/draft.ts +7 -8
- package/src/tweaker/tweakPlainObject.ts +3 -2
- package/src/types/TypeChecker.ts +6 -6
- package/src/types/schemas.ts +2 -2
- package/src/utils/index.ts +134 -3
|
@@ -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,
|
|
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.
|
|
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.
|
|
76
|
+
"@swc/core": "^1.16.0",
|
|
75
77
|
"@types/babel__core": "^7.20.5",
|
|
76
|
-
"@types/node": "^26.
|
|
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
|
|
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 {
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
|
|
628
|
+
makeObservableCompat(this)
|
|
623
629
|
}
|
|
624
630
|
|
|
625
631
|
this.store = store ?? new UndoStore({})
|
|
@@ -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
|
-
|
|
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>>(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
-
|
|
63
|
+
makeObservableCompat(instance)
|
|
63
64
|
} else if (tag.needsMakeObservable === undefined) {
|
|
64
65
|
if (getMobxVersion() >= 6) {
|
|
65
66
|
try {
|
|
66
|
-
|
|
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
|
-
|
|
155
|
-
|
|
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
|
-
|
|
157
|
+
decoratedClass.prototype.constructor = decoratedClass
|
|
168
158
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
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
|
-
|
|
164
|
+
modelInfoByName[name] = modelInfo
|
|
188
165
|
|
|
189
|
-
|
|
190
|
-
|
|
166
|
+
modelInfoByClass.set(decoratedClass, modelInfo)
|
|
167
|
+
modelInfoByClass.set(clazz, modelInfo)
|
|
191
168
|
|
|
192
|
-
|
|
169
|
+
runLateInitializationFunctions(clazz, runAfterModelDecoratorSymbol)
|
|
193
170
|
|
|
194
|
-
|
|
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
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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
|
+
}
|
package/src/modelShared/prop.ts
CHANGED
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
106
|
+
@mobxAction
|
|
107
107
|
forceUpdateBackRefs() {
|
|
108
108
|
const currentTarget = this.maybeCurrent
|
|
109
109
|
if (!this.startTracking(currentTarget)) {
|