mobx 6.1.8 → 6.9.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 +224 -7
- package/README.md +54 -52
- package/dist/api/annotation.d.ts +6 -12
- package/dist/api/autorun.d.ts +4 -4
- package/dist/api/flow.d.ts +1 -0
- package/dist/api/intercept.d.ts +5 -5
- package/dist/api/object-api.d.ts +2 -0
- package/dist/api/observable.d.ts +5 -1
- package/dist/api/observe.d.ts +4 -4
- package/dist/api/tojs.d.ts +4 -1
- package/dist/api/when.d.ts +8 -0
- package/dist/core/atom.d.ts +1 -1
- package/dist/core/computedvalue.d.ts +0 -1
- package/dist/core/globalstate.d.ts +4 -0
- package/dist/core/reaction.d.ts +2 -2
- package/dist/errors.d.ts +4 -2
- package/dist/internal.d.ts +1 -0
- package/dist/mobx.cjs.development.js +1477 -1719
- 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.d.ts +1 -1
- package/dist/mobx.esm.development.js +1475 -1720
- package/dist/mobx.esm.development.js.map +1 -1
- package/dist/mobx.esm.js +1492 -1726
- 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 +1477 -1719
- 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/actionannotation.d.ts +7 -1
- package/dist/types/autoannotation.d.ts +3 -0
- package/dist/types/observablemap.d.ts +5 -4
- package/dist/types/observableobject.d.ts +6 -9
- package/dist/types/observableset.d.ts +4 -4
- package/dist/types/observablevalue.d.ts +3 -5
- package/dist/utils/utils.d.ts +4 -4
- package/package.json +1 -1
- package/src/api/action.ts +8 -3
- package/src/api/annotation.ts +14 -44
- package/src/api/autorun.ts +38 -17
- package/src/api/computed.ts +5 -2
- package/src/api/configure.ts +6 -2
- package/src/api/decorators.ts +1 -1
- package/src/api/extendobservable.ts +12 -6
- package/src/api/extras.ts +4 -2
- package/src/api/flow.ts +17 -5
- package/src/api/intercept-read.ts +4 -2
- package/src/api/intercept.ts +10 -7
- package/src/api/iscomputed.ts +14 -8
- package/src/api/isobservable.ts +10 -4
- package/src/api/makeObservable.ts +35 -36
- package/src/api/object-api.ts +42 -14
- package/src/api/observable.ts +39 -25
- package/src/api/observe.ts +9 -6
- package/src/api/tojs.ts +20 -10
- package/src/api/trace.ts +6 -2
- package/src/api/when.ts +34 -9
- package/src/core/action.ts +11 -5
- package/src/core/atom.ts +9 -2
- package/src/core/computedvalue.ts +48 -27
- package/src/core/derivation.ts +34 -12
- package/src/core/globalstate.ts +25 -7
- package/src/core/observable.ts +23 -13
- package/src/core/reaction.ts +16 -7
- package/src/core/spy.ts +20 -7
- package/src/errors.ts +16 -3
- package/src/internal.ts +1 -0
- package/src/mobx.ts +6 -2
- package/src/types/actionannotation.ts +30 -52
- package/src/types/autoannotation.ts +107 -0
- package/src/types/computedannotation.ts +7 -37
- package/src/types/dynamicobject.ts +12 -6
- package/src/types/flowannotation.ts +40 -41
- package/src/types/intercept-utils.ts +9 -3
- package/src/types/legacyobservablearray.ts +26 -3
- package/src/types/listen-utils.ts +6 -2
- package/src/types/modifiers.ts +52 -16
- package/src/types/observableannotation.ts +7 -34
- package/src/types/observablearray.ts +106 -45
- package/src/types/observablemap.ts +71 -35
- package/src/types/observableobject.ts +88 -82
- package/src/types/observableset.ts +32 -13
- package/src/types/observablevalue.ts +16 -10
- package/src/types/overrideannotation.ts +4 -2
- package/src/types/type-utils.ts +34 -12
- package/src/utils/comparer.ts +5 -1
- package/src/utils/eq.ts +45 -15
- package/src/utils/utils.ts +39 -16
package/src/types/modifiers.ts
CHANGED
|
@@ -9,7 +9,12 @@ import {
|
|
|
9
9
|
isObservableObject,
|
|
10
10
|
isPlainObject,
|
|
11
11
|
observable,
|
|
12
|
-
die
|
|
12
|
+
die,
|
|
13
|
+
isAction,
|
|
14
|
+
autoAction,
|
|
15
|
+
flow,
|
|
16
|
+
isFlow,
|
|
17
|
+
isGenerator
|
|
13
18
|
} from "../internal"
|
|
14
19
|
|
|
15
20
|
export interface IEnhancer<T> {
|
|
@@ -18,30 +23,58 @@ export interface IEnhancer<T> {
|
|
|
18
23
|
|
|
19
24
|
export function deepEnhancer(v, _, name) {
|
|
20
25
|
// it is an observable already, done
|
|
21
|
-
if (isObservable(v))
|
|
26
|
+
if (isObservable(v)) {
|
|
27
|
+
return v
|
|
28
|
+
}
|
|
22
29
|
|
|
23
30
|
// something that can be converted and mutated?
|
|
24
|
-
if (Array.isArray(v))
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (
|
|
28
|
-
|
|
31
|
+
if (Array.isArray(v)) {
|
|
32
|
+
return observable.array(v, { name })
|
|
33
|
+
}
|
|
34
|
+
if (isPlainObject(v)) {
|
|
35
|
+
return observable.object(v, undefined, { name })
|
|
36
|
+
}
|
|
37
|
+
if (isES6Map(v)) {
|
|
38
|
+
return observable.map(v, { name })
|
|
39
|
+
}
|
|
40
|
+
if (isES6Set(v)) {
|
|
41
|
+
return observable.set(v, { name })
|
|
42
|
+
}
|
|
43
|
+
if (typeof v === "function" && !isAction(v) && !isFlow(v)) {
|
|
44
|
+
if (isGenerator(v)) {
|
|
45
|
+
return flow(v)
|
|
46
|
+
} else {
|
|
47
|
+
return autoAction(name, v)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
29
50
|
return v
|
|
30
51
|
}
|
|
31
52
|
|
|
32
53
|
export function shallowEnhancer(v, _, name): any {
|
|
33
|
-
if (v === undefined || v === null)
|
|
34
|
-
|
|
54
|
+
if (v === undefined || v === null) {
|
|
55
|
+
return v
|
|
56
|
+
}
|
|
57
|
+
if (isObservableObject(v) || isObservableArray(v) || isObservableMap(v) || isObservableSet(v)) {
|
|
35
58
|
return v
|
|
36
|
-
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
|
|
59
|
+
}
|
|
60
|
+
if (Array.isArray(v)) {
|
|
61
|
+
return observable.array(v, { name, deep: false })
|
|
62
|
+
}
|
|
63
|
+
if (isPlainObject(v)) {
|
|
64
|
+
return observable.object(v, undefined, { name, deep: false })
|
|
65
|
+
}
|
|
66
|
+
if (isES6Map(v)) {
|
|
67
|
+
return observable.map(v, { name, deep: false })
|
|
68
|
+
}
|
|
69
|
+
if (isES6Set(v)) {
|
|
70
|
+
return observable.set(v, { name, deep: false })
|
|
71
|
+
}
|
|
40
72
|
|
|
41
|
-
if (__DEV__)
|
|
73
|
+
if (__DEV__) {
|
|
42
74
|
die(
|
|
43
75
|
"The shallow modifier / decorator can only used in combination with arrays, objects, maps and sets"
|
|
44
76
|
)
|
|
77
|
+
}
|
|
45
78
|
}
|
|
46
79
|
|
|
47
80
|
export function referenceEnhancer(newValue?) {
|
|
@@ -50,8 +83,11 @@ export function referenceEnhancer(newValue?) {
|
|
|
50
83
|
}
|
|
51
84
|
|
|
52
85
|
export function refStructEnhancer(v, oldValue): any {
|
|
53
|
-
if (__DEV__ && isObservable(v))
|
|
86
|
+
if (__DEV__ && isObservable(v)) {
|
|
54
87
|
die(`observable.struct should not be used with observable values`)
|
|
55
|
-
|
|
88
|
+
}
|
|
89
|
+
if (deepEqual(v, oldValue)) {
|
|
90
|
+
return oldValue
|
|
91
|
+
}
|
|
56
92
|
return v
|
|
57
93
|
}
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ObservableObjectAdministration,
|
|
3
|
-
getDescriptor,
|
|
4
3
|
deepEnhancer,
|
|
5
4
|
die,
|
|
6
5
|
Annotation,
|
|
7
|
-
|
|
8
|
-
objectPrototype,
|
|
9
|
-
storedAnnotationsSymbol
|
|
6
|
+
MakeResult
|
|
10
7
|
} from "../internal"
|
|
11
8
|
|
|
12
9
|
export function createObservableAnnotation(name: string, options?: object): Annotation {
|
|
@@ -18,36 +15,12 @@ export function createObservableAnnotation(name: string, options?: object): Anno
|
|
|
18
15
|
}
|
|
19
16
|
}
|
|
20
17
|
|
|
21
|
-
function make_(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (descriptor) {
|
|
28
|
-
assertObservableDescriptor(adm, this, key, descriptor)
|
|
29
|
-
const definePropertyOutcome = adm.defineObservableProperty_(
|
|
30
|
-
key,
|
|
31
|
-
descriptor.value,
|
|
32
|
-
this.options_?.enhancer ?? deepEnhancer
|
|
33
|
-
)
|
|
34
|
-
if (!definePropertyOutcome) {
|
|
35
|
-
// Intercepted
|
|
36
|
-
return
|
|
37
|
-
}
|
|
38
|
-
recordAnnotationApplied(adm, this, key)
|
|
39
|
-
return
|
|
40
|
-
}
|
|
41
|
-
source = Object.getPrototypeOf(source)
|
|
42
|
-
}
|
|
43
|
-
if (!adm.target_[storedAnnotationsSymbol]?.[key]) {
|
|
44
|
-
// Throw on missing key, except for decorators:
|
|
45
|
-
// Decorator annotations are collected from whole prototype chain.
|
|
46
|
-
// When called from super() some props may not exist yet.
|
|
47
|
-
// However we don't have to worry about missing prop,
|
|
48
|
-
// because the decorator must have been applied to something.
|
|
49
|
-
die(1, this.annotationType_, `${adm.name_}.${key.toString()}`)
|
|
50
|
-
}
|
|
18
|
+
function make_(
|
|
19
|
+
adm: ObservableObjectAdministration,
|
|
20
|
+
key: PropertyKey,
|
|
21
|
+
descriptor: PropertyDescriptor
|
|
22
|
+
): MakeResult {
|
|
23
|
+
return this.extend_(adm, key, descriptor, false) === null ? MakeResult.Cancel : MakeResult.Break
|
|
51
24
|
}
|
|
52
25
|
|
|
53
26
|
function extend_(
|
|
@@ -84,8 +84,12 @@ export interface IArrayWillSplice<T = any> {
|
|
|
84
84
|
const arrayTraps = {
|
|
85
85
|
get(target, name) {
|
|
86
86
|
const adm: ObservableArrayAdministration = target[$mobx]
|
|
87
|
-
if (name === $mobx)
|
|
88
|
-
|
|
87
|
+
if (name === $mobx) {
|
|
88
|
+
return adm
|
|
89
|
+
}
|
|
90
|
+
if (name === "length") {
|
|
91
|
+
return adm.getArrayLength_()
|
|
92
|
+
}
|
|
89
93
|
if (typeof name === "string" && !isNaN(name as any)) {
|
|
90
94
|
return adm.get_(parseInt(name))
|
|
91
95
|
}
|
|
@@ -113,7 +117,8 @@ const arrayTraps = {
|
|
|
113
117
|
}
|
|
114
118
|
|
|
115
119
|
export class ObservableArrayAdministration
|
|
116
|
-
implements IInterceptable<IArrayWillChange<any> | IArrayWillSplice<any>>, IListenable
|
|
120
|
+
implements IInterceptable<IArrayWillChange<any> | IArrayWillSplice<any>>, IListenable
|
|
121
|
+
{
|
|
117
122
|
atom_: IAtom
|
|
118
123
|
readonly values_: any[] = [] // this is the prop that gets proxied, so can't replace it!
|
|
119
124
|
interceptors_
|
|
@@ -135,13 +140,16 @@ export class ObservableArrayAdministration
|
|
|
135
140
|
}
|
|
136
141
|
|
|
137
142
|
dehanceValue_(value: any): any {
|
|
138
|
-
if (this.dehancer !== undefined)
|
|
143
|
+
if (this.dehancer !== undefined) {
|
|
144
|
+
return this.dehancer(value)
|
|
145
|
+
}
|
|
139
146
|
return value
|
|
140
147
|
}
|
|
141
148
|
|
|
142
149
|
dehanceValues_(values: any[]): any[] {
|
|
143
|
-
if (this.dehancer !== undefined && values.length > 0)
|
|
150
|
+
if (this.dehancer !== undefined && values.length > 0) {
|
|
144
151
|
return values.map(this.dehancer) as any
|
|
152
|
+
}
|
|
145
153
|
return values
|
|
146
154
|
}
|
|
147
155
|
|
|
@@ -175,35 +183,56 @@ export class ObservableArrayAdministration
|
|
|
175
183
|
}
|
|
176
184
|
|
|
177
185
|
setArrayLength_(newLength: number) {
|
|
178
|
-
if (typeof newLength !== "number" || newLength < 0)
|
|
186
|
+
if (typeof newLength !== "number" || isNaN(newLength) || newLength < 0) {
|
|
187
|
+
die("Out of range: " + newLength)
|
|
188
|
+
}
|
|
179
189
|
let currentLength = this.values_.length
|
|
180
|
-
if (newLength === currentLength)
|
|
181
|
-
|
|
190
|
+
if (newLength === currentLength) {
|
|
191
|
+
return
|
|
192
|
+
} else if (newLength > currentLength) {
|
|
182
193
|
const newItems = new Array(newLength - currentLength)
|
|
183
|
-
for (let i = 0; i < newLength - currentLength; i++)
|
|
194
|
+
for (let i = 0; i < newLength - currentLength; i++) {
|
|
195
|
+
newItems[i] = undefined
|
|
196
|
+
} // No Array.fill everywhere...
|
|
184
197
|
this.spliceWithArray_(currentLength, 0, newItems)
|
|
185
|
-
} else
|
|
198
|
+
} else {
|
|
199
|
+
this.spliceWithArray_(newLength, currentLength - newLength)
|
|
200
|
+
}
|
|
186
201
|
}
|
|
187
202
|
|
|
188
203
|
updateArrayLength_(oldLength: number, delta: number) {
|
|
189
|
-
if (oldLength !== this.lastKnownLength_)
|
|
204
|
+
if (oldLength !== this.lastKnownLength_) {
|
|
205
|
+
die(16)
|
|
206
|
+
}
|
|
190
207
|
this.lastKnownLength_ += delta
|
|
191
|
-
if (this.legacyMode_ && delta > 0)
|
|
208
|
+
if (this.legacyMode_ && delta > 0) {
|
|
209
|
+
reserveArrayBuffer(oldLength + delta + 1)
|
|
210
|
+
}
|
|
192
211
|
}
|
|
193
212
|
|
|
194
213
|
spliceWithArray_(index: number, deleteCount?: number, newItems?: any[]): any[] {
|
|
195
214
|
checkIfStateModificationsAreAllowed(this.atom_)
|
|
196
215
|
const length = this.values_.length
|
|
197
216
|
|
|
198
|
-
if (index === undefined)
|
|
199
|
-
|
|
200
|
-
else if (index
|
|
217
|
+
if (index === undefined) {
|
|
218
|
+
index = 0
|
|
219
|
+
} else if (index > length) {
|
|
220
|
+
index = length
|
|
221
|
+
} else if (index < 0) {
|
|
222
|
+
index = Math.max(0, length + index)
|
|
223
|
+
}
|
|
201
224
|
|
|
202
|
-
if (arguments.length === 1)
|
|
203
|
-
|
|
204
|
-
else deleteCount
|
|
225
|
+
if (arguments.length === 1) {
|
|
226
|
+
deleteCount = length - index
|
|
227
|
+
} else if (deleteCount === undefined || deleteCount === null) {
|
|
228
|
+
deleteCount = 0
|
|
229
|
+
} else {
|
|
230
|
+
deleteCount = Math.max(0, Math.min(deleteCount, length - index))
|
|
231
|
+
}
|
|
205
232
|
|
|
206
|
-
if (newItems === undefined)
|
|
233
|
+
if (newItems === undefined) {
|
|
234
|
+
newItems = EMPTY_ARRAY
|
|
235
|
+
}
|
|
207
236
|
|
|
208
237
|
if (hasInterceptors(this)) {
|
|
209
238
|
const change = interceptChange<IArrayWillSplice<any>>(this as any, {
|
|
@@ -213,7 +242,9 @@ export class ObservableArrayAdministration
|
|
|
213
242
|
removedCount: deleteCount,
|
|
214
243
|
added: newItems
|
|
215
244
|
})
|
|
216
|
-
if (!change)
|
|
245
|
+
if (!change) {
|
|
246
|
+
return EMPTY_ARRAY
|
|
247
|
+
}
|
|
217
248
|
deleteCount = change.removedCount
|
|
218
249
|
newItems = change.added
|
|
219
250
|
}
|
|
@@ -226,8 +257,9 @@ export class ObservableArrayAdministration
|
|
|
226
257
|
}
|
|
227
258
|
const res = this.spliceItemsIntoValues_(index, deleteCount, newItems)
|
|
228
259
|
|
|
229
|
-
if (deleteCount !== 0 || newItems.length !== 0)
|
|
260
|
+
if (deleteCount !== 0 || newItems.length !== 0) {
|
|
230
261
|
this.notifyArraySplice_(index, newItems, res)
|
|
262
|
+
}
|
|
231
263
|
return this.dehanceValues_(res)
|
|
232
264
|
}
|
|
233
265
|
|
|
@@ -235,12 +267,18 @@ export class ObservableArrayAdministration
|
|
|
235
267
|
if (newItems.length < MAX_SPLICE_SIZE) {
|
|
236
268
|
return this.values_.splice(index, deleteCount, ...newItems)
|
|
237
269
|
} else {
|
|
270
|
+
// The items removed by the splice
|
|
238
271
|
const res = this.values_.slice(index, index + deleteCount)
|
|
272
|
+
// The items that that should remain at the end of the array
|
|
239
273
|
let oldItems = this.values_.slice(index + deleteCount)
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
for (let i = 0; i <
|
|
274
|
+
// New length is the previous length + addition count - deletion count
|
|
275
|
+
this.values_.length += newItems.length - deleteCount
|
|
276
|
+
for (let i = 0; i < newItems.length; i++) {
|
|
277
|
+
this.values_[index + i] = newItems[i]
|
|
278
|
+
}
|
|
279
|
+
for (let i = 0; i < oldItems.length; i++) {
|
|
243
280
|
this.values_[index + newItems.length + i] = oldItems[i]
|
|
281
|
+
}
|
|
244
282
|
return res
|
|
245
283
|
}
|
|
246
284
|
}
|
|
@@ -263,10 +301,16 @@ export class ObservableArrayAdministration
|
|
|
263
301
|
|
|
264
302
|
// The reason why this is on right hand side here (and not above), is this way the uglifier will drop it, but it won't
|
|
265
303
|
// cause any runtime overhead in development mode without NODE_ENV set, unless spying is enabled
|
|
266
|
-
if (__DEV__ && notifySpy)
|
|
304
|
+
if (__DEV__ && notifySpy) {
|
|
305
|
+
spyReportStart(change!)
|
|
306
|
+
}
|
|
267
307
|
this.atom_.reportChanged()
|
|
268
|
-
if (notify)
|
|
269
|
-
|
|
308
|
+
if (notify) {
|
|
309
|
+
notifyListeners(this, change)
|
|
310
|
+
}
|
|
311
|
+
if (__DEV__ && notifySpy) {
|
|
312
|
+
spyReportEnd()
|
|
313
|
+
}
|
|
270
314
|
}
|
|
271
315
|
|
|
272
316
|
notifyArraySplice_(index: number, added: any[], removed: any[]) {
|
|
@@ -287,27 +331,38 @@ export class ObservableArrayAdministration
|
|
|
287
331
|
} as const)
|
|
288
332
|
: null
|
|
289
333
|
|
|
290
|
-
if (__DEV__ && notifySpy)
|
|
334
|
+
if (__DEV__ && notifySpy) {
|
|
335
|
+
spyReportStart(change!)
|
|
336
|
+
}
|
|
291
337
|
this.atom_.reportChanged()
|
|
292
338
|
// conform: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/observe
|
|
293
|
-
if (notify)
|
|
294
|
-
|
|
339
|
+
if (notify) {
|
|
340
|
+
notifyListeners(this, change)
|
|
341
|
+
}
|
|
342
|
+
if (__DEV__ && notifySpy) {
|
|
343
|
+
spyReportEnd()
|
|
344
|
+
}
|
|
295
345
|
}
|
|
296
346
|
|
|
297
347
|
get_(index: number): any | undefined {
|
|
298
|
-
if (index
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
)
|
|
348
|
+
if (this.legacyMode_ && index >= this.values_.length) {
|
|
349
|
+
console.warn(
|
|
350
|
+
__DEV__
|
|
351
|
+
? `[mobx.array] Attempt to read an array index (${index}) that is out of bounds (${this.values_.length}). Please check length first. Out of bound indices will not be tracked by MobX`
|
|
352
|
+
: `[mobx] Out of bounds read: ${index}`
|
|
353
|
+
)
|
|
354
|
+
return undefined
|
|
355
|
+
}
|
|
356
|
+
this.atom_.reportObserved()
|
|
357
|
+
return this.dehanceValue_(this.values_[index])
|
|
307
358
|
}
|
|
308
359
|
|
|
309
360
|
set_(index: number, newValue: any) {
|
|
310
361
|
const values = this.values_
|
|
362
|
+
if (this.legacyMode_ && index > values.length) {
|
|
363
|
+
// out of bounds
|
|
364
|
+
die(17, index, values.length)
|
|
365
|
+
}
|
|
311
366
|
if (index < values.length) {
|
|
312
367
|
// update at index in range
|
|
313
368
|
checkIfStateModificationsAreAllowed(this.atom_)
|
|
@@ -319,7 +374,9 @@ export class ObservableArrayAdministration
|
|
|
319
374
|
index,
|
|
320
375
|
newValue
|
|
321
376
|
})
|
|
322
|
-
if (!change)
|
|
377
|
+
if (!change) {
|
|
378
|
+
return
|
|
379
|
+
}
|
|
323
380
|
newValue = change.newValue
|
|
324
381
|
}
|
|
325
382
|
newValue = this.enhancer_(newValue, oldValue)
|
|
@@ -328,12 +385,16 @@ export class ObservableArrayAdministration
|
|
|
328
385
|
values[index] = newValue
|
|
329
386
|
this.notifyArrayChildUpdate_(index, newValue, oldValue)
|
|
330
387
|
}
|
|
331
|
-
} else if (index === values.length) {
|
|
332
|
-
// add a new item
|
|
333
|
-
this.spliceWithArray_(index, 0, [newValue])
|
|
334
388
|
} else {
|
|
335
|
-
// out of
|
|
336
|
-
|
|
389
|
+
// For out of bound index, we don't create an actual sparse array,
|
|
390
|
+
// but rather fill the holes with undefined (same as setArrayLength_).
|
|
391
|
+
// This could be considered a bug.
|
|
392
|
+
const newItems = new Array(index + 1 - values.length)
|
|
393
|
+
for (let i = 0; i < newItems.length - 1; i++) {
|
|
394
|
+
newItems[i] = undefined
|
|
395
|
+
} // No Array.fill everywhere...
|
|
396
|
+
newItems[newItems.length - 1] = newValue
|
|
397
|
+
this.spliceWithArray_(values.length, 0, newItems)
|
|
337
398
|
}
|
|
338
399
|
}
|
|
339
400
|
}
|
|
@@ -33,7 +33,9 @@ import {
|
|
|
33
33
|
die,
|
|
34
34
|
isFunction,
|
|
35
35
|
UPDATE,
|
|
36
|
-
IAtom
|
|
36
|
+
IAtom,
|
|
37
|
+
PureSpyEvent,
|
|
38
|
+
allowStateChanges
|
|
37
39
|
} from "../internal"
|
|
38
40
|
|
|
39
41
|
export interface IKeyValueMap<V = any> {
|
|
@@ -41,7 +43,9 @@ export interface IKeyValueMap<V = any> {
|
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
export type IMapEntry<K = any, V = any> = [K, V]
|
|
46
|
+
export type IReadonlyMapEntry<K = any, V = any> = readonly [K, V]
|
|
44
47
|
export type IMapEntries<K = any, V = any> = IMapEntry<K, V>[]
|
|
48
|
+
export type IReadonlyMapEntries<K = any, V = any> = IReadonlyMapEntry<K, V>[]
|
|
45
49
|
|
|
46
50
|
export type IMapDidChange<K = any, V = any> = { observableKind: "map"; debugObjectName: string } & (
|
|
47
51
|
| {
|
|
@@ -79,6 +83,7 @@ export const DELETE = "delete"
|
|
|
79
83
|
|
|
80
84
|
export type IObservableMapInitialValues<K = any, V = any> =
|
|
81
85
|
| IMapEntries<K, V>
|
|
86
|
+
| IReadonlyMapEntries<K, V>
|
|
82
87
|
| IKeyValueMap<V>
|
|
83
88
|
| Map<K, V>
|
|
84
89
|
|
|
@@ -105,7 +110,9 @@ export class ObservableMap<K = any, V = any>
|
|
|
105
110
|
this.keysAtom_ = createAtom(__DEV__ ? `${this.name_}.keys()` : "ObservableMap.keys()")
|
|
106
111
|
this.data_ = new Map()
|
|
107
112
|
this.hasMap_ = new Map()
|
|
108
|
-
|
|
113
|
+
allowStateChanges(true, () => {
|
|
114
|
+
this.merge(initialData)
|
|
115
|
+
})
|
|
109
116
|
}
|
|
110
117
|
|
|
111
118
|
private has_(key: K): boolean {
|
|
@@ -113,7 +120,9 @@ export class ObservableMap<K = any, V = any>
|
|
|
113
120
|
}
|
|
114
121
|
|
|
115
122
|
has(key: K): boolean {
|
|
116
|
-
if (!globalState.trackingDerivation)
|
|
123
|
+
if (!globalState.trackingDerivation) {
|
|
124
|
+
return this.has_(key)
|
|
125
|
+
}
|
|
117
126
|
|
|
118
127
|
let entry = this.hasMap_.get(key)
|
|
119
128
|
if (!entry) {
|
|
@@ -139,7 +148,9 @@ export class ObservableMap<K = any, V = any>
|
|
|
139
148
|
newValue: value,
|
|
140
149
|
name: key
|
|
141
150
|
})
|
|
142
|
-
if (!change)
|
|
151
|
+
if (!change) {
|
|
152
|
+
return this
|
|
153
|
+
}
|
|
143
154
|
value = change.newValue!
|
|
144
155
|
}
|
|
145
156
|
if (hasKey) {
|
|
@@ -158,7 +169,9 @@ export class ObservableMap<K = any, V = any>
|
|
|
158
169
|
object: this,
|
|
159
170
|
name: key
|
|
160
171
|
})
|
|
161
|
-
if (!change)
|
|
172
|
+
if (!change) {
|
|
173
|
+
return false
|
|
174
|
+
}
|
|
162
175
|
}
|
|
163
176
|
if (this.has_(key)) {
|
|
164
177
|
const notifySpy = isSpyEnabled()
|
|
@@ -175,28 +188,27 @@ export class ObservableMap<K = any, V = any>
|
|
|
175
188
|
}
|
|
176
189
|
: null
|
|
177
190
|
|
|
178
|
-
if (__DEV__ && notifySpy)
|
|
191
|
+
if (__DEV__ && notifySpy) {
|
|
192
|
+
spyReportStart(change! as PureSpyEvent)
|
|
193
|
+
} // TODO fix type
|
|
179
194
|
transaction(() => {
|
|
180
195
|
this.keysAtom_.reportChanged()
|
|
181
|
-
this.
|
|
196
|
+
this.hasMap_.get(key)?.setNewValue_(false)
|
|
182
197
|
const observable = this.data_.get(key)!
|
|
183
198
|
observable.setNewValue_(undefined as any)
|
|
184
199
|
this.data_.delete(key)
|
|
185
200
|
})
|
|
186
|
-
if (notify)
|
|
187
|
-
|
|
201
|
+
if (notify) {
|
|
202
|
+
notifyListeners(this, change)
|
|
203
|
+
}
|
|
204
|
+
if (__DEV__ && notifySpy) {
|
|
205
|
+
spyReportEnd()
|
|
206
|
+
}
|
|
188
207
|
return true
|
|
189
208
|
}
|
|
190
209
|
return false
|
|
191
210
|
}
|
|
192
211
|
|
|
193
|
-
private updateHasMapEntry_(key: K, value: boolean) {
|
|
194
|
-
let entry = this.hasMap_.get(key)
|
|
195
|
-
if (entry) {
|
|
196
|
-
entry.setNewValue_(value)
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
212
|
private updateValue_(key: K, newValue: V | undefined) {
|
|
201
213
|
const observable = this.data_.get(key)!
|
|
202
214
|
newValue = (observable as any).prepareNewValue_(newValue) as V
|
|
@@ -215,10 +227,16 @@ export class ObservableMap<K = any, V = any>
|
|
|
215
227
|
newValue
|
|
216
228
|
}
|
|
217
229
|
: null
|
|
218
|
-
if (__DEV__ && notifySpy)
|
|
230
|
+
if (__DEV__ && notifySpy) {
|
|
231
|
+
spyReportStart(change! as PureSpyEvent)
|
|
232
|
+
} // TODO fix type
|
|
219
233
|
observable.setNewValue_(newValue as V)
|
|
220
|
-
if (notify)
|
|
221
|
-
|
|
234
|
+
if (notify) {
|
|
235
|
+
notifyListeners(this, change)
|
|
236
|
+
}
|
|
237
|
+
if (__DEV__ && notifySpy) {
|
|
238
|
+
spyReportEnd()
|
|
239
|
+
}
|
|
222
240
|
}
|
|
223
241
|
}
|
|
224
242
|
|
|
@@ -233,7 +251,7 @@ export class ObservableMap<K = any, V = any>
|
|
|
233
251
|
)
|
|
234
252
|
this.data_.set(key, observable)
|
|
235
253
|
newValue = (observable as any).value_ // value might have been changed
|
|
236
|
-
this.
|
|
254
|
+
this.hasMap_.get(key)?.setNewValue_(true)
|
|
237
255
|
this.keysAtom_.reportChanged()
|
|
238
256
|
})
|
|
239
257
|
const notifySpy = isSpyEnabled()
|
|
@@ -249,13 +267,21 @@ export class ObservableMap<K = any, V = any>
|
|
|
249
267
|
newValue
|
|
250
268
|
}
|
|
251
269
|
: null
|
|
252
|
-
if (__DEV__ && notifySpy)
|
|
253
|
-
|
|
254
|
-
|
|
270
|
+
if (__DEV__ && notifySpy) {
|
|
271
|
+
spyReportStart(change! as PureSpyEvent)
|
|
272
|
+
} // TODO fix type
|
|
273
|
+
if (notify) {
|
|
274
|
+
notifyListeners(this, change)
|
|
275
|
+
}
|
|
276
|
+
if (__DEV__ && notifySpy) {
|
|
277
|
+
spyReportEnd()
|
|
278
|
+
}
|
|
255
279
|
}
|
|
256
280
|
|
|
257
281
|
get(key: K): V | undefined {
|
|
258
|
-
if (this.has(key))
|
|
282
|
+
if (this.has(key)) {
|
|
283
|
+
return this.dehanceValue_(this.data_.get(key)!.get())
|
|
284
|
+
}
|
|
259
285
|
return this.dehanceValue_(undefined)
|
|
260
286
|
}
|
|
261
287
|
|
|
@@ -304,24 +330,31 @@ export class ObservableMap<K = any, V = any>
|
|
|
304
330
|
}
|
|
305
331
|
|
|
306
332
|
forEach(callback: (value: V, key: K, object: Map<K, V>) => void, thisArg?) {
|
|
307
|
-
for (const [key, value] of this)
|
|
333
|
+
for (const [key, value] of this) {
|
|
334
|
+
callback.call(thisArg, value, key, this)
|
|
335
|
+
}
|
|
308
336
|
}
|
|
309
337
|
|
|
310
338
|
/** Merge another object into this object, returns this. */
|
|
311
|
-
merge(other
|
|
339
|
+
merge(other?: IObservableMapInitialValues<K, V>): ObservableMap<K, V> {
|
|
312
340
|
if (isObservableMap(other)) {
|
|
313
341
|
other = new Map(other)
|
|
314
342
|
}
|
|
315
343
|
transaction(() => {
|
|
316
|
-
if (isPlainObject(other))
|
|
344
|
+
if (isPlainObject(other)) {
|
|
317
345
|
getPlainObjectKeys(other).forEach((key: any) =>
|
|
318
|
-
this.set(
|
|
346
|
+
this.set(key as K, (other as IKeyValueMap)[key])
|
|
319
347
|
)
|
|
320
|
-
else if (Array.isArray(other))
|
|
321
|
-
|
|
322
|
-
|
|
348
|
+
} else if (Array.isArray(other)) {
|
|
349
|
+
other.forEach(([key, value]) => this.set(key, value))
|
|
350
|
+
} else if (isES6Map(other)) {
|
|
351
|
+
if (other.constructor !== Map) {
|
|
352
|
+
die(19, other)
|
|
353
|
+
}
|
|
323
354
|
other.forEach((value, key) => this.set(key, value))
|
|
324
|
-
} else if (other !== null && other !== undefined)
|
|
355
|
+
} else if (other !== null && other !== undefined) {
|
|
356
|
+
die(20, other)
|
|
357
|
+
}
|
|
325
358
|
})
|
|
326
359
|
return this
|
|
327
360
|
}
|
|
@@ -329,12 +362,14 @@ export class ObservableMap<K = any, V = any>
|
|
|
329
362
|
clear() {
|
|
330
363
|
transaction(() => {
|
|
331
364
|
untracked(() => {
|
|
332
|
-
for (const key of this.keys())
|
|
365
|
+
for (const key of this.keys()) {
|
|
366
|
+
this.delete(key)
|
|
367
|
+
}
|
|
333
368
|
})
|
|
334
369
|
})
|
|
335
370
|
}
|
|
336
371
|
|
|
337
|
-
replace(values:
|
|
372
|
+
replace(values: IObservableMapInitialValues<K, V>): ObservableMap<K, V> {
|
|
338
373
|
// Implementation requirements:
|
|
339
374
|
// - respect ordering of replacement map
|
|
340
375
|
// - allow interceptors to run and potentially prevent individual operations
|
|
@@ -435,8 +470,9 @@ export class ObservableMap<K = any, V = any>
|
|
|
435
470
|
* for callback details
|
|
436
471
|
*/
|
|
437
472
|
observe_(listener: (changes: IMapDidChange<K, V>) => void, fireImmediately?: boolean): Lambda {
|
|
438
|
-
if (__DEV__ && fireImmediately === true)
|
|
473
|
+
if (__DEV__ && fireImmediately === true) {
|
|
439
474
|
die("`observe` doesn't support fireImmediately=true in combination with maps.")
|
|
475
|
+
}
|
|
440
476
|
return registerListener(this, listener)
|
|
441
477
|
}
|
|
442
478
|
|