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
package/src/treeUtils/draft.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { action, computed } from "mobx"
|
|
2
1
|
import { pathToTargetPathIds } from "../actionMiddlewares/utils"
|
|
3
2
|
import { resolvePath, resolvePathCheckingIds, skipIdChecking } from "../parent/path"
|
|
4
3
|
import type { Path } from "../parent/pathTypes"
|
|
@@ -7,7 +6,7 @@ import { applySnapshot } from "../snapshot/applySnapshot"
|
|
|
7
6
|
import { fromSnapshot } from "../snapshot/fromSnapshot"
|
|
8
7
|
import { getSnapshot } from "../snapshot/getSnapshot"
|
|
9
8
|
import { assertTweakedObject } from "../tweaker/core"
|
|
10
|
-
import { failure } from "../utils"
|
|
9
|
+
import { failure, mobxAction, mobxComputed } from "../utils"
|
|
11
10
|
import { deepEquals } from "./deepEquals"
|
|
12
11
|
|
|
13
12
|
/**
|
|
@@ -25,7 +24,7 @@ export class Draft<T extends object> {
|
|
|
25
24
|
/**
|
|
26
25
|
* Commits current draft changes to the original object.
|
|
27
26
|
*/
|
|
28
|
-
@
|
|
27
|
+
@mobxAction
|
|
29
28
|
commit(): void {
|
|
30
29
|
applySnapshot(this.originalData, getSnapshot(this.data))
|
|
31
30
|
}
|
|
@@ -37,7 +36,7 @@ export class Draft<T extends object> {
|
|
|
37
36
|
*
|
|
38
37
|
* @param path Path to commit.
|
|
39
38
|
*/
|
|
40
|
-
@
|
|
39
|
+
@mobxAction
|
|
41
40
|
commitByPath(path: Path): void {
|
|
42
41
|
const draftTarget = resolvePath(this.data, path)
|
|
43
42
|
if (!draftTarget.resolved) {
|
|
@@ -63,7 +62,7 @@ export class Draft<T extends object> {
|
|
|
63
62
|
/**
|
|
64
63
|
* Resets the draft to be an exact copy of the current state of the original object.
|
|
65
64
|
*/
|
|
66
|
-
@
|
|
65
|
+
@mobxAction
|
|
67
66
|
reset(): void {
|
|
68
67
|
applySnapshot(this.data, this.originalSnapshot)
|
|
69
68
|
}
|
|
@@ -75,7 +74,7 @@ export class Draft<T extends object> {
|
|
|
75
74
|
*
|
|
76
75
|
* @param path Path to reset.
|
|
77
76
|
*/
|
|
78
|
-
@
|
|
77
|
+
@mobxAction
|
|
79
78
|
resetByPath(path: Path): void {
|
|
80
79
|
const originalTarget = resolvePath(this.originalData, path)
|
|
81
80
|
if (!originalTarget.resolved) {
|
|
@@ -101,7 +100,7 @@ export class Draft<T extends object> {
|
|
|
101
100
|
/**
|
|
102
101
|
* Returns `true` if the draft has changed compared to the original object, `false` otherwise.
|
|
103
102
|
*/
|
|
104
|
-
@
|
|
103
|
+
@mobxComputed
|
|
105
104
|
get isDirty(): boolean {
|
|
106
105
|
return !deepEquals(getSnapshot(this.data), this.originalSnapshot)
|
|
107
106
|
}
|
|
@@ -135,7 +134,7 @@ export class Draft<T extends object> {
|
|
|
135
134
|
*/
|
|
136
135
|
readonly originalData: T
|
|
137
136
|
|
|
138
|
-
@
|
|
137
|
+
@mobxComputed
|
|
139
138
|
private get originalSnapshot() {
|
|
140
139
|
return getSnapshot(this.originalData)
|
|
141
140
|
}
|
|
@@ -48,7 +48,8 @@ export function tweakPlainObject<T extends Record<string, any>>(
|
|
|
48
48
|
isDataObject: boolean
|
|
49
49
|
): T {
|
|
50
50
|
const originalObj: Record<string, any> = value
|
|
51
|
-
const
|
|
51
|
+
const originalIsObservableObject = isObservableObject(originalObj)
|
|
52
|
+
const tweakedObj = originalIsObservableObject
|
|
52
53
|
? originalObj
|
|
53
54
|
: observable.object({}, undefined, observableOptions)
|
|
54
55
|
|
|
@@ -78,7 +79,7 @@ export function tweakPlainObject<T extends Record<string, any>>(
|
|
|
78
79
|
const v = originalObj[k]
|
|
79
80
|
|
|
80
81
|
if (isPrimitive(v)) {
|
|
81
|
-
if (!doNotTweakChildren) {
|
|
82
|
+
if (!doNotTweakChildren && !originalIsObservableObject) {
|
|
82
83
|
setIfDifferent(tweakedObj, k, v)
|
|
83
84
|
}
|
|
84
85
|
if (k === "__proto__") {
|
package/src/types/TypeChecker.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { TypeCheckError } from "./TypeCheckError"
|
|
|
6
6
|
|
|
7
7
|
type CheckFunction = (value: any, path: Path, typeCheckedValue: any) => TypeCheckError | null
|
|
8
8
|
|
|
9
|
-
/** @
|
|
9
|
+
/** @ignore */
|
|
10
10
|
export type SnapshotProcessor = (snapshot: any) => unknown
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -14,7 +14,7 @@ export type SnapshotProcessor = (snapshot: any) => unknown
|
|
|
14
14
|
* TypeCheckers rather than processors so recursive graphs can be discovered
|
|
15
15
|
* before any processor body is compiled.
|
|
16
16
|
*
|
|
17
|
-
* @
|
|
17
|
+
* @ignore
|
|
18
18
|
*/
|
|
19
19
|
export interface SnapshotProcessorPlan {
|
|
20
20
|
readonly intrinsic?: boolean
|
|
@@ -36,7 +36,7 @@ export function snapshotProcessorPlan(
|
|
|
36
36
|
type SnapshotProcessorSource = SnapshotProcessor | SnapshotProcessorPlan | undefined
|
|
37
37
|
type SnapshotProcessorDirection = "from" | "to"
|
|
38
38
|
|
|
39
|
-
/** @
|
|
39
|
+
/** @ignore */
|
|
40
40
|
export class SnapshotProcessorPlanNode {
|
|
41
41
|
private readonly owner: TypeChecker | undefined
|
|
42
42
|
private readonly direction: SnapshotProcessorDirection
|
|
@@ -196,7 +196,7 @@ export class SnapshotProcessorPlanNode {
|
|
|
196
196
|
const absentSnapshotProcessorPlanNode = new SnapshotProcessorPlanNode(undefined, "from", undefined)
|
|
197
197
|
|
|
198
198
|
/**
|
|
199
|
-
* @
|
|
199
|
+
* @ignore
|
|
200
200
|
*/
|
|
201
201
|
export enum TypeCheckerBaseType {
|
|
202
202
|
Object = "object",
|
|
@@ -243,7 +243,7 @@ export function invalidateCachedToSnapshotProcessorResult(obj: object) {
|
|
|
243
243
|
}
|
|
244
244
|
|
|
245
245
|
/**
|
|
246
|
-
* @
|
|
246
|
+
* @ignore
|
|
247
247
|
*/
|
|
248
248
|
export class TypeChecker {
|
|
249
249
|
unchecked: boolean
|
|
@@ -443,6 +443,6 @@ export class TypeInfo {
|
|
|
443
443
|
}
|
|
444
444
|
|
|
445
445
|
/**
|
|
446
|
-
* @
|
|
446
|
+
* @ignore
|
|
447
447
|
*/
|
|
448
448
|
export type TypeInfoGen = (t: AnyStandardType) => TypeInfo
|
package/src/types/schemas.ts
CHANGED
|
@@ -64,7 +64,7 @@ export interface ObjectOfTypes {
|
|
|
64
64
|
|
|
65
65
|
/**
|
|
66
66
|
* Name of the properties of an object that can be set to undefined, any or unknown.
|
|
67
|
-
* @
|
|
67
|
+
* @ignore
|
|
68
68
|
*/
|
|
69
69
|
export type UndefinablePropsNames<T> = {
|
|
70
70
|
[K in keyof T]: IsOptionalValue<T[K], K, never>
|
|
@@ -72,7 +72,7 @@ export type UndefinablePropsNames<T> = {
|
|
|
72
72
|
|
|
73
73
|
/**
|
|
74
74
|
* Computes the optional keys for an object type schema.
|
|
75
|
-
* @
|
|
75
|
+
* @ignore
|
|
76
76
|
*/
|
|
77
77
|
export type ObjectOptionalKeys<S> = UndefinablePropsNames<{
|
|
78
78
|
[k in keyof S]: TypeToDataOpt<S[k]> extends infer R ? R : never
|
package/src/utils/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as mobx from "mobx"
|
|
2
2
|
import {
|
|
3
|
+
type IComputedValue,
|
|
3
4
|
type IObservableArray,
|
|
4
5
|
isObservableArray,
|
|
5
6
|
isObservableMap,
|
|
@@ -419,6 +420,127 @@ export const mobx6 = {
|
|
|
419
420
|
],
|
|
420
421
|
}
|
|
421
422
|
|
|
423
|
+
/**
|
|
424
|
+
* MobX method action decorator compatible with both legacy decorators and
|
|
425
|
+
* MobX 7's standard decorator API.
|
|
426
|
+
*
|
|
427
|
+
* This is a decorator compatibility helper, not a replacement for other
|
|
428
|
+
* `action` overloads such as `action(fn)`. Field decorators are not supported.
|
|
429
|
+
*
|
|
430
|
+
* @hidden
|
|
431
|
+
*/
|
|
432
|
+
export function mobxAction<This, Args extends unknown[], Return>(
|
|
433
|
+
value: (this: This, ...args: Args) => Return,
|
|
434
|
+
context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>
|
|
435
|
+
): (this: This, ...args: Args) => Return
|
|
436
|
+
export function mobxAction<This, Args extends unknown[], Return>(
|
|
437
|
+
target: object,
|
|
438
|
+
propertyKey: string | symbol,
|
|
439
|
+
descriptor: TypedPropertyDescriptor<(this: This, ...args: Args) => Return>
|
|
440
|
+
): TypedPropertyDescriptor<(this: This, ...args: Args) => Return> | void
|
|
441
|
+
export function mobxAction(...args: any[]): any {
|
|
442
|
+
if (isStandardDecoratorContext(args[1])) {
|
|
443
|
+
return (mobx.action as any)(args[0], args[1])
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
if (getMobxVersion() < 7) {
|
|
447
|
+
return (mobx.action as any)(...args)
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
const descriptor = args[2] as PropertyDescriptor | undefined
|
|
451
|
+
if (!descriptor?.value) {
|
|
452
|
+
return descriptor
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (mobx.isAction(descriptor.value)) {
|
|
456
|
+
return descriptor
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
return {
|
|
460
|
+
...descriptor,
|
|
461
|
+
value: mobx.action(String(args[1]), descriptor.value),
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* MobX getter computed decorator compatible with both legacy decorators and
|
|
467
|
+
* MobX 7's standard decorator API.
|
|
468
|
+
*
|
|
469
|
+
* This is a decorator compatibility helper, not a replacement for other
|
|
470
|
+
* `computed` overloads. Field decorators and decorator options are not supported.
|
|
471
|
+
* Under MobX 7's legacy decorator transform the getter is backed by a computed
|
|
472
|
+
* value, but is not registered as a computed property for MobX introspection.
|
|
473
|
+
*
|
|
474
|
+
* @hidden
|
|
475
|
+
*/
|
|
476
|
+
export function mobxComputed<This, Value>(
|
|
477
|
+
value: (this: This) => Value,
|
|
478
|
+
context: ClassGetterDecoratorContext<This, Value>
|
|
479
|
+
): ((this: This) => Value) | void
|
|
480
|
+
export function mobxComputed<Value>(
|
|
481
|
+
target: object,
|
|
482
|
+
propertyKey: string | symbol,
|
|
483
|
+
descriptor: TypedPropertyDescriptor<Value>
|
|
484
|
+
): TypedPropertyDescriptor<Value> | void
|
|
485
|
+
export function mobxComputed(...args: any[]): any {
|
|
486
|
+
if (isStandardDecoratorContext(args[1])) {
|
|
487
|
+
return (mobx.computed as any)(args[0], args[1])
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
if (getMobxVersion() < 7) {
|
|
491
|
+
return (mobx.computed as any)(...args)
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
const descriptor = args[2] as PropertyDescriptor | undefined
|
|
495
|
+
if (!descriptor?.get) {
|
|
496
|
+
return descriptor
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
const getter = descriptor.get
|
|
500
|
+
const computedValues = new WeakMap<object, IComputedValue<unknown>>()
|
|
501
|
+
|
|
502
|
+
return {
|
|
503
|
+
...descriptor,
|
|
504
|
+
get(this: object) {
|
|
505
|
+
let computedValue = computedValues.get(this)
|
|
506
|
+
if (!computedValue) {
|
|
507
|
+
const newComputedValue = mobx.computed(() => getter.call(this), {
|
|
508
|
+
name: String(args[1]),
|
|
509
|
+
})
|
|
510
|
+
computedValues.set(this, newComputedValue)
|
|
511
|
+
computedValue = newComputedValue
|
|
512
|
+
}
|
|
513
|
+
return computedValue.get()
|
|
514
|
+
},
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Mirrors MobX's standard-decorator call detection. Legacy decorator calls use
|
|
519
|
+
// a string or symbol property key as their second argument, so checking `kind`
|
|
520
|
+
// distinguishes the call shapes without claiming to validate the full context.
|
|
521
|
+
function isStandardDecoratorContext(value: unknown): boolean {
|
|
522
|
+
return (
|
|
523
|
+
typeof value === "object" &&
|
|
524
|
+
value !== null &&
|
|
525
|
+
typeof (value as { kind?: unknown }).kind === "string"
|
|
526
|
+
)
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Calls `makeObservable` across MobX versions. MobX 7 requires an annotations
|
|
531
|
+
* object, while MobX 6 and older versions use decorator metadata when no
|
|
532
|
+
* annotations are passed.
|
|
533
|
+
*
|
|
534
|
+
* @internal
|
|
535
|
+
*/
|
|
536
|
+
export function makeObservableCompat(target: object, annotations?: object): void {
|
|
537
|
+
if (getMobxVersion() >= 7) {
|
|
538
|
+
mobx6.makeObservable(target, annotations ?? {})
|
|
539
|
+
} else {
|
|
540
|
+
mobx6.makeObservable(target)
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
422
544
|
/**
|
|
423
545
|
* @internal
|
|
424
546
|
*/
|
|
@@ -426,17 +548,26 @@ export function propNameToSetterName(propName: string): string {
|
|
|
426
548
|
return `set${propName[0].toUpperCase()}${propName.slice(1)}`
|
|
427
549
|
}
|
|
428
550
|
|
|
551
|
+
let cachedMobxVersion: number | undefined
|
|
552
|
+
|
|
429
553
|
/**
|
|
430
554
|
* @internal
|
|
431
555
|
*/
|
|
432
556
|
export function getMobxVersion(): number {
|
|
557
|
+
if (cachedMobxVersion !== undefined) {
|
|
558
|
+
return cachedMobxVersion
|
|
559
|
+
}
|
|
560
|
+
|
|
433
561
|
if (mobx6.makeObservable!) {
|
|
434
|
-
|
|
562
|
+
const version = (mobx as any)._getGlobalState?.().version
|
|
563
|
+
cachedMobxVersion = typeof version === "number" && version >= 7 ? version : 6
|
|
435
564
|
} else if ("extendShallowObservable" in mobx) {
|
|
436
|
-
|
|
565
|
+
cachedMobxVersion = 4
|
|
437
566
|
} else {
|
|
438
|
-
|
|
567
|
+
cachedMobxVersion = 5
|
|
439
568
|
}
|
|
569
|
+
|
|
570
|
+
return cachedMobxVersion
|
|
440
571
|
}
|
|
441
572
|
|
|
442
573
|
/**
|