mobx 6.15.4 → 6.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/mobx.cjs.development.js +101 -46
- package/dist/mobx.cjs.development.js.map +1 -1
- package/dist/mobx.cjs.production.min.js +1 -1
- package/dist/mobx.cjs.production.min.js.map +1 -1
- package/dist/mobx.esm.development.js +101 -46
- package/dist/mobx.esm.development.js.map +1 -1
- package/dist/mobx.esm.js +101 -46
- package/dist/mobx.esm.js.map +1 -1
- package/dist/mobx.esm.production.min.js +1 -1
- package/dist/mobx.esm.production.min.js.map +1 -1
- package/dist/mobx.umd.development.js +101 -46
- package/dist/mobx.umd.development.js.map +1 -1
- package/dist/mobx.umd.production.min.js +1 -1
- package/dist/mobx.umd.production.min.js.map +1 -1
- package/dist/types/observablemap.d.ts +2 -0
- package/dist/types/observableobject.d.ts +6 -2
- package/package.json +7 -6
- package/src/api/iscomputed.ts +5 -1
- package/src/api/isobservable.ts +6 -1
- package/src/types/computedannotation.ts +15 -9
- package/src/types/observableannotation.ts +32 -38
- package/src/types/observablemap.ts +14 -0
- package/src/types/observableobject.ts +40 -2
- package/src/types/type-utils.ts +5 -1
|
@@ -53,6 +53,8 @@ export declare class ObservableMap<K = any, V = any> implements Map<K, V>, IInte
|
|
|
53
53
|
private updateValue_;
|
|
54
54
|
private addValue_;
|
|
55
55
|
get(key: K): V | undefined;
|
|
56
|
+
getOrInsert(key: K, value: V): V;
|
|
57
|
+
getOrInsertComputed(key: K, callback: (key: K) => V): V;
|
|
56
58
|
private dehanceValue_;
|
|
57
59
|
keys(): MapIterator<K>;
|
|
58
60
|
values(): MapIterator<V>;
|
|
@@ -27,7 +27,7 @@ export type IObjectWillChange<T = any> = {
|
|
|
27
27
|
};
|
|
28
28
|
export declare class ObservableObjectAdministration implements IInterceptable<IObjectWillChange>, IListenable {
|
|
29
29
|
target_: any;
|
|
30
|
-
values_: Map<PropertyKey,
|
|
30
|
+
values_: Map<PropertyKey, ComputedValue<any> | ObservableValue<any>>;
|
|
31
31
|
name_: string;
|
|
32
32
|
defaultAnnotation_: Annotation;
|
|
33
33
|
keysAtom_: IAtom;
|
|
@@ -37,8 +37,12 @@ export declare class ObservableObjectAdministration implements IInterceptable<IO
|
|
|
37
37
|
isPlainObject_: boolean;
|
|
38
38
|
appliedAnnotations_?: object;
|
|
39
39
|
private pendingKeys_;
|
|
40
|
-
|
|
40
|
+
lazyComputedKeys_: undefined | Map<PropertyKey, () => ComputedValue<any>>;
|
|
41
|
+
lazyObservableKeys_: undefined | Map<PropertyKey, () => ObservableValue<any>>;
|
|
42
|
+
constructor(target_: any, values_: Map<PropertyKey, ComputedValue<any> | ObservableValue<any>> | undefined, name_: string, defaultAnnotation_?: Annotation);
|
|
41
43
|
getObservablePropValue_(key: PropertyKey): any;
|
|
44
|
+
materializeLazyComputed_(key: PropertyKey): ComputedValue<any> | undefined;
|
|
45
|
+
materializeLazyObservable_(key: PropertyKey): ObservableValue<any> | undefined;
|
|
42
46
|
setObservablePropValue_(key: PropertyKey, newValue: any): boolean | null;
|
|
43
47
|
get_(key: PropertyKey): any;
|
|
44
48
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mobx",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.16.0",
|
|
4
4
|
"description": "Simple, scalable state management.",
|
|
5
5
|
"source": "src/mobx.ts",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -68,13 +68,14 @@
|
|
|
68
68
|
"perf": "scripts/perf.sh",
|
|
69
69
|
"perf-legacy": "node --expose-gc ./__tests__/perf/index.js legacy",
|
|
70
70
|
"perf-proxy": "node --expose-gc ./__tests__/perf/index.js proxy",
|
|
71
|
-
"
|
|
72
|
-
"test:
|
|
71
|
+
"perf-decorator": "tsc -p ./__tests__/perf/tsconfig.decorator.json && node --expose-gc ./__tests__/perf/compiled/lazy-computed-decorator.js && node --expose-gc ./__tests__/perf/compiled/lazy-observable-decorator.js",
|
|
72
|
+
"test:performance": "npm run perf -- proxy && npm run perf -- legacy && npm run perf-decorator",
|
|
73
|
+
"test:mixed-versions": "npm test -- --testRegex mixed-versions",
|
|
73
74
|
"test:types": "tsc --noEmit",
|
|
74
75
|
"test:flow": "flow check",
|
|
75
|
-
"test:coverage": "
|
|
76
|
-
"test:size": "
|
|
77
|
-
"test:check": "
|
|
76
|
+
"test:coverage": "npm test -- -i --coverage",
|
|
77
|
+
"test:size": "import-size --report . observable computed autorun action",
|
|
78
|
+
"test:check": "npm run test:types",
|
|
78
79
|
"prepublishOnly": "node ./scripts/prepublish.js && npm run build -- --target publish"
|
|
79
80
|
}
|
|
80
81
|
}
|
package/src/api/iscomputed.ts
CHANGED
|
@@ -7,7 +7,11 @@ export function _isComputed(value, property?: PropertyKey): boolean {
|
|
|
7
7
|
if (isObservableObject(value) === false) {
|
|
8
8
|
return false
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
const adm = value[$mobx]
|
|
11
|
+
if (adm.lazyComputedKeys_?.has(property)) {
|
|
12
|
+
return true
|
|
13
|
+
}
|
|
14
|
+
if (!adm.values_.has(property)) {
|
|
11
15
|
return false
|
|
12
16
|
}
|
|
13
17
|
const atom = getAtom(value, property)
|
package/src/api/isobservable.ts
CHANGED
|
@@ -21,7 +21,12 @@ function _isObservable(value, property?: PropertyKey): boolean {
|
|
|
21
21
|
)
|
|
22
22
|
}
|
|
23
23
|
if (isObservableObject(value)) {
|
|
24
|
-
|
|
24
|
+
const adm = value[$mobx]
|
|
25
|
+
return (
|
|
26
|
+
adm.values_.has(property) ||
|
|
27
|
+
!!adm.lazyComputedKeys_?.has(property) ||
|
|
28
|
+
!!adm.lazyObservableKeys_?.has(property)
|
|
29
|
+
)
|
|
25
30
|
}
|
|
26
31
|
return false
|
|
27
32
|
}
|
|
@@ -54,17 +54,23 @@ function decorate_20223_(this: Annotation, get, context: ClassGetterDecoratorCon
|
|
|
54
54
|
const ann = this
|
|
55
55
|
const { name: key, addInitializer } = context
|
|
56
56
|
|
|
57
|
+
// Defer ComputedValue creation until first access — avoids allocating
|
|
58
|
+
// ComputedValues for getters that are never read on a given instance.
|
|
59
|
+
// The factory is materialised by ObservableObjectAdministration on demand.
|
|
57
60
|
addInitializer(function () {
|
|
58
61
|
const adm: ObservableObjectAdministration = asObservableObject(this)[$mobx]
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
62
|
+
const target = this
|
|
63
|
+
;(adm.lazyComputedKeys_ ??= new Map()).set(key, () => {
|
|
64
|
+
const options = {
|
|
65
|
+
...ann.options_,
|
|
66
|
+
get,
|
|
67
|
+
context: target
|
|
68
|
+
}
|
|
69
|
+
options.name ||= __DEV__
|
|
70
|
+
? `${adm.name_}.${key.toString()}`
|
|
71
|
+
: `ObservableObject.${key.toString()}`
|
|
72
|
+
return new ComputedValue(options)
|
|
73
|
+
})
|
|
68
74
|
})
|
|
69
75
|
|
|
70
76
|
return function () {
|
|
@@ -64,51 +64,45 @@ function decorate_20223_(
|
|
|
64
64
|
const ann = this
|
|
65
65
|
const { kind, name } = context
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
// before it has been initialized. The runtime doesn't like that and throws a `Cannot read private member
|
|
71
|
-
// from an object whose class did not declare it` error.
|
|
72
|
-
// TODO: it seems that this will not be required anymore in the final version of the spec
|
|
73
|
-
// See TODO: link
|
|
74
|
-
const initializedObjects = new WeakSet()
|
|
67
|
+
if (kind !== "accessor") {
|
|
68
|
+
return
|
|
69
|
+
}
|
|
75
70
|
|
|
76
|
-
|
|
71
|
+
// Defer ObservableValue construction until first access. The factory is
|
|
72
|
+
// materialised by ObservableObjectAdministration on demand, so unused
|
|
73
|
+
// fields on wide classes never pay the per-instance allocation cost.
|
|
74
|
+
function registerLazy(target: any, value: any): ObservableObjectAdministration {
|
|
77
75
|
const adm: ObservableObjectAdministration = asObservableObject(target)[$mobx]
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
76
|
+
;(adm.lazyObservableKeys_ ??= new Map()).set(
|
|
77
|
+
name,
|
|
78
|
+
() =>
|
|
79
|
+
new ObservableValue(
|
|
80
|
+
value,
|
|
81
|
+
ann.options_?.enhancer ?? deepEnhancer,
|
|
82
|
+
__DEV__
|
|
83
|
+
? `${adm.name_}.${name.toString()}`
|
|
84
|
+
: `ObservableObject.${name.toString()}`,
|
|
85
|
+
false
|
|
86
|
+
)
|
|
83
87
|
)
|
|
84
|
-
adm
|
|
85
|
-
initializedObjects.add(target)
|
|
88
|
+
return adm
|
|
86
89
|
}
|
|
87
90
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
},
|
|
102
|
-
init(value) {
|
|
103
|
-
if (!initializedObjects.has(this)) {
|
|
104
|
-
initializeObservable(this, value)
|
|
105
|
-
}
|
|
106
|
-
return value
|
|
107
|
-
}
|
|
91
|
+
return {
|
|
92
|
+
get() {
|
|
93
|
+
const adm: ObservableObjectAdministration =
|
|
94
|
+
this[$mobx] ?? registerLazy(this, desc.get.call(this))
|
|
95
|
+
return adm.getObservablePropValue_(name)
|
|
96
|
+
},
|
|
97
|
+
set(value) {
|
|
98
|
+
const adm: ObservableObjectAdministration = this[$mobx] ?? registerLazy(this, value)
|
|
99
|
+
return adm.setObservablePropValue_(name, value)
|
|
100
|
+
},
|
|
101
|
+
init(value) {
|
|
102
|
+
registerLazy(this, value)
|
|
103
|
+
return value
|
|
108
104
|
}
|
|
109
105
|
}
|
|
110
|
-
|
|
111
|
-
return
|
|
112
106
|
}
|
|
113
107
|
|
|
114
108
|
function assertObservableDescriptor(
|
|
@@ -289,6 +289,20 @@ export class ObservableMap<K = any, V = any>
|
|
|
289
289
|
return this.dehanceValue_(undefined)
|
|
290
290
|
}
|
|
291
291
|
|
|
292
|
+
getOrInsert(key: K, value: V): V {
|
|
293
|
+
if (!this.has(key)) {
|
|
294
|
+
this.set(key, value)
|
|
295
|
+
}
|
|
296
|
+
return this.get(key)!
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
getOrInsertComputed(key: K, callback: (key: K) => V): V {
|
|
300
|
+
if (!this.has(key)) {
|
|
301
|
+
this.set(key, callback(key))
|
|
302
|
+
}
|
|
303
|
+
return this.get(key)!
|
|
304
|
+
}
|
|
305
|
+
|
|
292
306
|
private dehanceValue_<X extends V | undefined>(value: X): X {
|
|
293
307
|
if (this.dehancer !== undefined) {
|
|
294
308
|
return this.dehancer(value)
|
|
@@ -98,6 +98,8 @@ export class ObservableObjectAdministration
|
|
|
98
98
|
isPlainObject_: boolean
|
|
99
99
|
appliedAnnotations_?: object
|
|
100
100
|
private pendingKeys_: undefined | Map<PropertyKey, ObservableValue<boolean>>
|
|
101
|
+
lazyComputedKeys_: undefined | Map<PropertyKey, () => ComputedValue<any>>
|
|
102
|
+
lazyObservableKeys_: undefined | Map<PropertyKey, () => ObservableValue<any>>
|
|
101
103
|
|
|
102
104
|
constructor(
|
|
103
105
|
public target_: any,
|
|
@@ -119,11 +121,47 @@ export class ObservableObjectAdministration
|
|
|
119
121
|
}
|
|
120
122
|
|
|
121
123
|
getObservablePropValue_(key: PropertyKey): any {
|
|
122
|
-
|
|
124
|
+
// Hot path: single map lookup. Lazy entries (rare) take the materialise branch.
|
|
125
|
+
const observable =
|
|
126
|
+
this.values_.get(key) ??
|
|
127
|
+
this.materializeLazyComputed_(key) ??
|
|
128
|
+
this.materializeLazyObservable_(key)
|
|
129
|
+
return observable!.get()
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
materializeLazyComputed_(key: PropertyKey): ComputedValue<any> | undefined {
|
|
133
|
+
const factory = this.lazyComputedKeys_?.get(key)
|
|
134
|
+
if (!factory) {
|
|
135
|
+
return undefined
|
|
136
|
+
}
|
|
137
|
+
this.lazyComputedKeys_!.delete(key)
|
|
138
|
+
if (this.lazyComputedKeys_!.size === 0) {
|
|
139
|
+
this.lazyComputedKeys_ = undefined
|
|
140
|
+
}
|
|
141
|
+
const computed = factory()
|
|
142
|
+
this.values_.set(key, computed)
|
|
143
|
+
return computed
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
materializeLazyObservable_(key: PropertyKey): ObservableValue<any> | undefined {
|
|
147
|
+
const factory = this.lazyObservableKeys_?.get(key)
|
|
148
|
+
if (!factory) {
|
|
149
|
+
return undefined
|
|
150
|
+
}
|
|
151
|
+
this.lazyObservableKeys_!.delete(key)
|
|
152
|
+
if (this.lazyObservableKeys_!.size === 0) {
|
|
153
|
+
this.lazyObservableKeys_ = undefined
|
|
154
|
+
}
|
|
155
|
+
const observable = factory()
|
|
156
|
+
this.values_.set(key, observable)
|
|
157
|
+
return observable
|
|
123
158
|
}
|
|
124
159
|
|
|
125
160
|
setObservablePropValue_(key: PropertyKey, newValue): boolean | null {
|
|
126
|
-
const observable =
|
|
161
|
+
const observable =
|
|
162
|
+
this.values_.get(key) ??
|
|
163
|
+
this.materializeLazyComputed_(key) ??
|
|
164
|
+
this.materializeLazyObservable_(key)
|
|
127
165
|
if (observable instanceof ComputedValue) {
|
|
128
166
|
observable.set(newValue)
|
|
129
167
|
return true
|
package/src/types/type-utils.ts
CHANGED
|
@@ -47,7 +47,11 @@ export function getAtom(thing: any, property?: PropertyKey): IDepTreeNode {
|
|
|
47
47
|
if (!property) {
|
|
48
48
|
return die(26)
|
|
49
49
|
}
|
|
50
|
-
const
|
|
50
|
+
const adm = (thing as any)[$mobx]
|
|
51
|
+
const observable =
|
|
52
|
+
adm.values_.get(property) ??
|
|
53
|
+
adm.materializeLazyComputed_(property) ??
|
|
54
|
+
adm.materializeLazyObservable_(property)
|
|
51
55
|
if (!observable) {
|
|
52
56
|
die(27, property, getDebugName(thing))
|
|
53
57
|
}
|