mobx 6.3.11 → 6.4.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 +28 -0
- package/README.md +1 -0
- package/dist/api/intercept.d.ts +1 -1
- package/dist/api/observe.d.ts +1 -1
- package/dist/errors.d.ts +2 -2
- package/dist/mobx.cjs.development.js +991 -303
- 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 +991 -303
- package/dist/mobx.esm.development.js.map +1 -1
- package/dist/mobx.esm.js +1006 -306
- 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 +991 -303
- 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 -2
- package/dist/utils/utils.d.ts +1 -1
- package/package.json +1 -1
- package/src/api/action.ts +8 -3
- package/src/api/annotation.ts +1 -2
- package/src/api/autorun.ts +22 -8
- package/src/api/computed.ts +5 -2
- package/src/api/configure.ts +6 -2
- package/src/api/extendobservable.ts +11 -5
- package/src/api/extras.ts +4 -2
- package/src/api/flow.ts +11 -4
- package/src/api/intercept-read.ts +4 -2
- package/src/api/intercept.ts +6 -3
- package/src/api/iscomputed.ts +10 -4
- package/src/api/isobservable.ts +10 -4
- package/src/api/makeObservable.ts +4 -2
- package/src/api/object-api.ts +30 -16
- package/src/api/observable.ts +23 -9
- package/src/api/observe.ts +5 -3
- package/src/api/tojs.ts +7 -3
- package/src/api/trace.ts +6 -2
- package/src/api/when.ts +12 -5
- package/src/core/action.ts +8 -3
- package/src/core/computedvalue.ts +29 -9
- package/src/core/derivation.ts +25 -9
- package/src/core/globalstate.ts +18 -7
- package/src/core/observable.ts +14 -5
- package/src/core/reaction.ts +15 -6
- package/src/core/spy.ts +20 -7
- package/src/errors.ts +2 -2
- package/src/types/actionannotation.ts +2 -2
- package/src/types/dynamicobject.ts +10 -4
- package/src/types/flowannotation.ts +14 -4
- package/src/types/intercept-utils.ts +9 -3
- package/src/types/legacyobservablearray.ts +5 -3
- package/src/types/listen-utils.ts +6 -2
- package/src/types/modifiers.ts +39 -14
- package/src/types/observablearray.ts +78 -30
- package/src/types/observablemap.ts +65 -26
- package/src/types/observableobject.ts +52 -18
- package/src/types/observableset.ts +29 -10
- package/src/types/observablevalue.ts +13 -5
- package/src/types/type-utils.ts +33 -11
- package/src/utils/comparer.ts +4 -4
- package/src/utils/eq.ts +45 -15
- package/src/utils/utils.ts +42 -20
package/src/api/when.ts
CHANGED
|
@@ -25,8 +25,9 @@ export function when(
|
|
|
25
25
|
opts?: IWhenOptions
|
|
26
26
|
): IReactionDisposer
|
|
27
27
|
export function when(predicate: any, arg1?: any, arg2?: any): any {
|
|
28
|
-
if (arguments.length === 1 || (arg1 && typeof arg1 === "object"))
|
|
28
|
+
if (arguments.length === 1 || (arg1 && typeof arg1 === "object")) {
|
|
29
29
|
return whenPromise(predicate, arg1)
|
|
30
|
+
}
|
|
30
31
|
return _when(predicate, arg1, arg2 || {})
|
|
31
32
|
}
|
|
32
33
|
|
|
@@ -37,8 +38,11 @@ function _when(predicate: () => boolean, effect: Lambda, opts: IWhenOptions): IR
|
|
|
37
38
|
timeoutHandle = setTimeout(() => {
|
|
38
39
|
if (!disposer[$mobx].isDisposed_) {
|
|
39
40
|
disposer()
|
|
40
|
-
if (opts.onError)
|
|
41
|
-
|
|
41
|
+
if (opts.onError) {
|
|
42
|
+
opts.onError(error)
|
|
43
|
+
} else {
|
|
44
|
+
throw error
|
|
45
|
+
}
|
|
42
46
|
}
|
|
43
47
|
}, opts.timeout)
|
|
44
48
|
}
|
|
@@ -54,7 +58,9 @@ function _when(predicate: () => boolean, effect: Lambda, opts: IWhenOptions): IR
|
|
|
54
58
|
let cond = allowStateChanges(false, predicate)
|
|
55
59
|
if (cond) {
|
|
56
60
|
r.dispose()
|
|
57
|
-
if (timeoutHandle)
|
|
61
|
+
if (timeoutHandle) {
|
|
62
|
+
clearTimeout(timeoutHandle)
|
|
63
|
+
}
|
|
58
64
|
effectAction()
|
|
59
65
|
}
|
|
60
66
|
}, opts)
|
|
@@ -65,8 +71,9 @@ function whenPromise(
|
|
|
65
71
|
predicate: () => boolean,
|
|
66
72
|
opts?: IWhenOptions
|
|
67
73
|
): Promise<void> & { cancel(): void } {
|
|
68
|
-
if (__DEV__ && opts && opts.onError)
|
|
74
|
+
if (__DEV__ && opts && opts.onError) {
|
|
69
75
|
return die(`the options 'onError' and 'promise' cannot be combined`)
|
|
76
|
+
}
|
|
70
77
|
let cancel
|
|
71
78
|
const res = new Promise((resolve, reject) => {
|
|
72
79
|
let disposer = _when(predicate, resolve as Lambda, { ...opts, onError: reject })
|
package/src/core/action.ts
CHANGED
|
@@ -38,9 +38,12 @@ export function createAction(
|
|
|
38
38
|
ref?: Object
|
|
39
39
|
): Function {
|
|
40
40
|
if (__DEV__) {
|
|
41
|
-
if (!isFunction(fn))
|
|
42
|
-
|
|
41
|
+
if (!isFunction(fn)) {
|
|
42
|
+
die("`action` can only be invoked on functions")
|
|
43
|
+
}
|
|
44
|
+
if (typeof actionName !== "string" || !actionName) {
|
|
43
45
|
die(`actions should have valid names, got: '${actionName}'`)
|
|
46
|
+
}
|
|
44
47
|
}
|
|
45
48
|
function res() {
|
|
46
49
|
return executeAction(actionName, autoAction, fn, ref || this, arguments)
|
|
@@ -136,7 +139,9 @@ export function _endAction(runInfo: IActionRunInfo) {
|
|
|
136
139
|
allowStateChangesEnd(runInfo.prevAllowStateChanges_)
|
|
137
140
|
allowStateReadsEnd(runInfo.prevAllowStateReads_)
|
|
138
141
|
endBatch()
|
|
139
|
-
if (runInfo.runAsAction_)
|
|
142
|
+
if (runInfo.runAsAction_) {
|
|
143
|
+
untrackedEnd(runInfo.prevDerivation_)
|
|
144
|
+
}
|
|
140
145
|
if (__DEV__ && runInfo.notifySpy_) {
|
|
141
146
|
spyReportEnd({ time: Date.now() - runInfo.startTime_ })
|
|
142
147
|
}
|
|
@@ -114,7 +114,9 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
114
114
|
* This is useful for working with vectors, mouse coordinates etc.
|
|
115
115
|
*/
|
|
116
116
|
constructor(options: IComputedValueOptions<T>) {
|
|
117
|
-
if (!options.get)
|
|
117
|
+
if (!options.get) {
|
|
118
|
+
die(31)
|
|
119
|
+
}
|
|
118
120
|
this.derivation = options.get!
|
|
119
121
|
this.name_ = options.name || (__DEV__ ? "ComputedValue@" + getNextId() : "ComputedValue")
|
|
120
122
|
if (options.set) {
|
|
@@ -157,7 +159,9 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
157
159
|
* Will evaluate its computation first if needed.
|
|
158
160
|
*/
|
|
159
161
|
public get(): T {
|
|
160
|
-
if (this.isComputing_)
|
|
162
|
+
if (this.isComputing_) {
|
|
163
|
+
die(32, this.name_, this.derivation)
|
|
164
|
+
}
|
|
161
165
|
if (
|
|
162
166
|
globalState.inBatch === 0 &&
|
|
163
167
|
// !globalState.trackingDerivatpion &&
|
|
@@ -174,27 +178,37 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
174
178
|
reportObserved(this)
|
|
175
179
|
if (shouldCompute(this)) {
|
|
176
180
|
let prevTrackingContext = globalState.trackingContext
|
|
177
|
-
if (this.keepAlive_ && !prevTrackingContext)
|
|
178
|
-
|
|
181
|
+
if (this.keepAlive_ && !prevTrackingContext) {
|
|
182
|
+
globalState.trackingContext = this
|
|
183
|
+
}
|
|
184
|
+
if (this.trackAndCompute()) {
|
|
185
|
+
propagateChangeConfirmed(this)
|
|
186
|
+
}
|
|
179
187
|
globalState.trackingContext = prevTrackingContext
|
|
180
188
|
}
|
|
181
189
|
}
|
|
182
190
|
const result = this.value_!
|
|
183
191
|
|
|
184
|
-
if (isCaughtException(result))
|
|
192
|
+
if (isCaughtException(result)) {
|
|
193
|
+
throw result.cause
|
|
194
|
+
}
|
|
185
195
|
return result
|
|
186
196
|
}
|
|
187
197
|
|
|
188
198
|
public set(value: T) {
|
|
189
199
|
if (this.setter_) {
|
|
190
|
-
if (this.isRunningSetter_)
|
|
200
|
+
if (this.isRunningSetter_) {
|
|
201
|
+
die(33, this.name_)
|
|
202
|
+
}
|
|
191
203
|
this.isRunningSetter_ = true
|
|
192
204
|
try {
|
|
193
205
|
this.setter_.call(this.scope_, value)
|
|
194
206
|
} finally {
|
|
195
207
|
this.isRunningSetter_ = false
|
|
196
208
|
}
|
|
197
|
-
} else
|
|
209
|
+
} else {
|
|
210
|
+
die(34, this.name_)
|
|
211
|
+
}
|
|
198
212
|
}
|
|
199
213
|
|
|
200
214
|
trackAndCompute(): boolean {
|
|
@@ -287,13 +301,19 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
|
|
|
287
301
|
}
|
|
288
302
|
|
|
289
303
|
warnAboutUntrackedRead_() {
|
|
290
|
-
if (!__DEV__)
|
|
304
|
+
if (!__DEV__) {
|
|
305
|
+
return
|
|
306
|
+
}
|
|
291
307
|
if (this.isTracing_ !== TraceMode.NONE) {
|
|
292
308
|
console.log(
|
|
293
309
|
`[mobx.trace] Computed value '${this.name_}' is being read outside a reactive context. Doing a full recompute.`
|
|
294
310
|
)
|
|
295
311
|
}
|
|
296
|
-
if (
|
|
312
|
+
if (
|
|
313
|
+
typeof this.requiresReaction_ === "boolean"
|
|
314
|
+
? this.requiresReaction_
|
|
315
|
+
: globalState.computedRequiresReaction
|
|
316
|
+
) {
|
|
297
317
|
console.warn(
|
|
298
318
|
`[mobx] Computed value '${this.name_}' is being read outside a reactive context. Doing a full recompute.`
|
|
299
319
|
)
|
package/src/core/derivation.ts
CHANGED
|
@@ -137,7 +137,10 @@ export function checkIfStateModificationsAreAllowed(atom: IAtom) {
|
|
|
137
137
|
}
|
|
138
138
|
const hasObservers = atom.observers_.size > 0
|
|
139
139
|
// Should not be possible to change observed state outside strict mode, except during initialization, see #563
|
|
140
|
-
if (
|
|
140
|
+
if (
|
|
141
|
+
!globalState.allowStateChanges &&
|
|
142
|
+
(hasObservers || globalState.enforceActions === "always")
|
|
143
|
+
) {
|
|
141
144
|
console.warn(
|
|
142
145
|
"[MobX] " +
|
|
143
146
|
(globalState.enforceActions
|
|
@@ -145,6 +148,7 @@ export function checkIfStateModificationsAreAllowed(atom: IAtom) {
|
|
|
145
148
|
: "Side effects like changing state are not allowed at this point. Are you trying to modify state from, for example, a computed value or the render function of a React component? You can wrap side effects in 'runInAction' (or decorate functions with 'action') if needed. Tried to modify: ") +
|
|
146
149
|
atom.name_
|
|
147
150
|
)
|
|
151
|
+
}
|
|
148
152
|
}
|
|
149
153
|
|
|
150
154
|
export function checkIfStateReadsAreAllowed(observable: IObservable) {
|
|
@@ -191,9 +195,13 @@ export function trackDerivedFunction<T>(derivation: IDerivation, f: () => T, con
|
|
|
191
195
|
}
|
|
192
196
|
|
|
193
197
|
function warnAboutDerivationWithoutDependencies(derivation: IDerivation) {
|
|
194
|
-
if (!__DEV__)
|
|
198
|
+
if (!__DEV__) {
|
|
199
|
+
return
|
|
200
|
+
}
|
|
195
201
|
|
|
196
|
-
if (derivation.observing_.length !== 0)
|
|
202
|
+
if (derivation.observing_.length !== 0) {
|
|
203
|
+
return
|
|
204
|
+
}
|
|
197
205
|
|
|
198
206
|
if (globalState.reactionRequiresObservable || derivation.requiresObservable_) {
|
|
199
207
|
console.warn(
|
|
@@ -222,14 +230,16 @@ function bindDependencies(derivation: IDerivation) {
|
|
|
222
230
|
const dep = observing[i]
|
|
223
231
|
if (dep.diffValue_ === 0) {
|
|
224
232
|
dep.diffValue_ = 1
|
|
225
|
-
if (i0 !== i)
|
|
233
|
+
if (i0 !== i) {
|
|
234
|
+
observing[i0] = dep
|
|
235
|
+
}
|
|
226
236
|
i0++
|
|
227
237
|
}
|
|
228
238
|
|
|
229
239
|
// Upcast is 'safe' here, because if dep is IObservable, `dependenciesState` will be undefined,
|
|
230
240
|
// not hitting the condition
|
|
231
|
-
if ((
|
|
232
|
-
lowestNewObservingDerivationState = (
|
|
241
|
+
if ((dep as any as IDerivation).dependenciesState_ > lowestNewObservingDerivationState) {
|
|
242
|
+
lowestNewObservingDerivationState = (dep as any as IDerivation).dependenciesState_
|
|
233
243
|
}
|
|
234
244
|
}
|
|
235
245
|
observing.length = i0
|
|
@@ -272,7 +282,9 @@ export function clearObserving(derivation: IDerivation) {
|
|
|
272
282
|
const obs = derivation.observing_
|
|
273
283
|
derivation.observing_ = []
|
|
274
284
|
let i = obs.length
|
|
275
|
-
while (i--)
|
|
285
|
+
while (i--) {
|
|
286
|
+
removeObserver(obs[i], derivation)
|
|
287
|
+
}
|
|
276
288
|
|
|
277
289
|
derivation.dependenciesState_ = IDerivationState_.NOT_TRACKING_
|
|
278
290
|
}
|
|
@@ -311,10 +323,14 @@ export function allowStateReadsEnd(prev: boolean) {
|
|
|
311
323
|
*
|
|
312
324
|
*/
|
|
313
325
|
export function changeDependenciesStateTo0(derivation: IDerivation) {
|
|
314
|
-
if (derivation.dependenciesState_ === IDerivationState_.UP_TO_DATE_)
|
|
326
|
+
if (derivation.dependenciesState_ === IDerivationState_.UP_TO_DATE_) {
|
|
327
|
+
return
|
|
328
|
+
}
|
|
315
329
|
derivation.dependenciesState_ = IDerivationState_.UP_TO_DATE_
|
|
316
330
|
|
|
317
331
|
const obs = derivation.observing_
|
|
318
332
|
let i = obs.length
|
|
319
|
-
while (i--)
|
|
333
|
+
while (i--) {
|
|
334
|
+
obs[i].lowestObserverState_ = IDerivationState_.UP_TO_DATE_
|
|
335
|
+
}
|
|
320
336
|
}
|
package/src/core/globalstate.ts
CHANGED
|
@@ -157,9 +157,12 @@ let isolateCalled = false
|
|
|
157
157
|
|
|
158
158
|
export let globalState: MobXGlobals = (function () {
|
|
159
159
|
let global = getGlobal()
|
|
160
|
-
if (global.__mobxInstanceCount > 0 && !global.__mobxGlobals)
|
|
161
|
-
if (global.__mobxGlobals && global.__mobxGlobals.version !== new MobXGlobals().version)
|
|
160
|
+
if (global.__mobxInstanceCount > 0 && !global.__mobxGlobals) {
|
|
162
161
|
canMergeGlobalState = false
|
|
162
|
+
}
|
|
163
|
+
if (global.__mobxGlobals && global.__mobxGlobals.version !== new MobXGlobals().version) {
|
|
164
|
+
canMergeGlobalState = false
|
|
165
|
+
}
|
|
163
166
|
|
|
164
167
|
if (!canMergeGlobalState) {
|
|
165
168
|
// Because this is a IIFE we need to let isolateCalled a chance to change
|
|
@@ -172,7 +175,9 @@ export let globalState: MobXGlobals = (function () {
|
|
|
172
175
|
return new MobXGlobals()
|
|
173
176
|
} else if (global.__mobxGlobals) {
|
|
174
177
|
global.__mobxInstanceCount += 1
|
|
175
|
-
if (!global.__mobxGlobals.UNCHANGED)
|
|
178
|
+
if (!global.__mobxGlobals.UNCHANGED) {
|
|
179
|
+
global.__mobxGlobals.UNCHANGED = {}
|
|
180
|
+
} // make merge backward compatible
|
|
176
181
|
return global.__mobxGlobals
|
|
177
182
|
} else {
|
|
178
183
|
global.__mobxInstanceCount = 1
|
|
@@ -185,12 +190,15 @@ export function isolateGlobalState() {
|
|
|
185
190
|
globalState.pendingReactions.length ||
|
|
186
191
|
globalState.inBatch ||
|
|
187
192
|
globalState.isRunningReactions
|
|
188
|
-
)
|
|
193
|
+
) {
|
|
189
194
|
die(36)
|
|
195
|
+
}
|
|
190
196
|
isolateCalled = true
|
|
191
197
|
if (canMergeGlobalState) {
|
|
192
198
|
let global = getGlobal()
|
|
193
|
-
if (--global.__mobxInstanceCount === 0)
|
|
199
|
+
if (--global.__mobxInstanceCount === 0) {
|
|
200
|
+
global.__mobxGlobals = undefined
|
|
201
|
+
}
|
|
194
202
|
globalState = new MobXGlobals()
|
|
195
203
|
}
|
|
196
204
|
}
|
|
@@ -205,7 +213,10 @@ export function getGlobalState(): any {
|
|
|
205
213
|
*/
|
|
206
214
|
export function resetGlobalState() {
|
|
207
215
|
const defaultGlobals = new MobXGlobals()
|
|
208
|
-
for (let key in defaultGlobals)
|
|
209
|
-
if (persistentKeys.indexOf(key as any) === -1)
|
|
216
|
+
for (let key in defaultGlobals) {
|
|
217
|
+
if (persistentKeys.indexOf(key as any) === -1) {
|
|
218
|
+
globalState[key] = defaultGlobals[key]
|
|
219
|
+
}
|
|
220
|
+
}
|
|
210
221
|
globalState.allowStateChanges = !globalState.enforceActions
|
|
211
222
|
}
|
package/src/core/observable.ts
CHANGED
|
@@ -69,8 +69,9 @@ export function addObserver(observable: IObservable, node: IDerivation) {
|
|
|
69
69
|
// invariantObservers(observable);
|
|
70
70
|
|
|
71
71
|
observable.observers_.add(node)
|
|
72
|
-
if (observable.lowestObserverState_ > node.dependenciesState_)
|
|
72
|
+
if (observable.lowestObserverState_ > node.dependenciesState_) {
|
|
73
73
|
observable.lowestObserverState_ = node.dependenciesState_
|
|
74
|
+
}
|
|
74
75
|
|
|
75
76
|
// invariantObservers(observable);
|
|
76
77
|
// invariant(observable._observers.indexOf(node) !== -1, "INTERNAL ERROR didn't add node");
|
|
@@ -183,7 +184,9 @@ export function reportObserved(observable: IObservable): boolean {
|
|
|
183
184
|
// Called by Atom when its value changes
|
|
184
185
|
export function propagateChanged(observable: IObservable) {
|
|
185
186
|
// invariantLOS(observable, "changed start");
|
|
186
|
-
if (observable.lowestObserverState_ === IDerivationState_.STALE_)
|
|
187
|
+
if (observable.lowestObserverState_ === IDerivationState_.STALE_) {
|
|
188
|
+
return
|
|
189
|
+
}
|
|
187
190
|
observable.lowestObserverState_ = IDerivationState_.STALE_
|
|
188
191
|
|
|
189
192
|
// Ideally we use for..of here, but the downcompiled version is really slow...
|
|
@@ -202,7 +205,9 @@ export function propagateChanged(observable: IObservable) {
|
|
|
202
205
|
// Called by ComputedValue when it recalculate and its value changed
|
|
203
206
|
export function propagateChangeConfirmed(observable: IObservable) {
|
|
204
207
|
// invariantLOS(observable, "confirmed start");
|
|
205
|
-
if (observable.lowestObserverState_ === IDerivationState_.STALE_)
|
|
208
|
+
if (observable.lowestObserverState_ === IDerivationState_.STALE_) {
|
|
209
|
+
return
|
|
210
|
+
}
|
|
206
211
|
observable.lowestObserverState_ = IDerivationState_.STALE_
|
|
207
212
|
|
|
208
213
|
observable.observers_.forEach(d => {
|
|
@@ -223,7 +228,9 @@ export function propagateChangeConfirmed(observable: IObservable) {
|
|
|
223
228
|
// Used by computed when its dependency changed, but we don't wan't to immediately recompute.
|
|
224
229
|
export function propagateMaybeChanged(observable: IObservable) {
|
|
225
230
|
// invariantLOS(observable, "maybe start");
|
|
226
|
-
if (observable.lowestObserverState_ !== IDerivationState_.UP_TO_DATE_)
|
|
231
|
+
if (observable.lowestObserverState_ !== IDerivationState_.UP_TO_DATE_) {
|
|
232
|
+
return
|
|
233
|
+
}
|
|
227
234
|
observable.lowestObserverState_ = IDerivationState_.POSSIBLY_STALE_
|
|
228
235
|
|
|
229
236
|
observable.observers_.forEach(d => {
|
|
@@ -269,5 +276,7 @@ function printDepTree(tree: IDependencyTree, lines: string[], depth: number) {
|
|
|
269
276
|
return
|
|
270
277
|
}
|
|
271
278
|
lines.push(`${"\t".repeat(depth - 1)}${tree.name}`)
|
|
272
|
-
if (tree.dependencies)
|
|
279
|
+
if (tree.dependencies) {
|
|
280
|
+
tree.dependencies.forEach(child => printDepTree(child, lines, depth + 1))
|
|
281
|
+
}
|
|
273
282
|
}
|
package/src/core/reaction.ts
CHANGED
|
@@ -142,7 +142,9 @@ export class Reaction implements IDerivation, IReactionPublic {
|
|
|
142
142
|
// disposed during last run. Clean up everything that was bound after the dispose call.
|
|
143
143
|
clearObserving(this)
|
|
144
144
|
}
|
|
145
|
-
if (isCaughtException(result))
|
|
145
|
+
if (isCaughtException(result)) {
|
|
146
|
+
this.reportExceptionInDerivation_(result.cause)
|
|
147
|
+
}
|
|
146
148
|
if (__DEV__ && notify) {
|
|
147
149
|
spyReportEnd({
|
|
148
150
|
time: Date.now() - startTime
|
|
@@ -157,7 +159,9 @@ export class Reaction implements IDerivation, IReactionPublic {
|
|
|
157
159
|
return
|
|
158
160
|
}
|
|
159
161
|
|
|
160
|
-
if (globalState.disableErrorBoundaries)
|
|
162
|
+
if (globalState.disableErrorBoundaries) {
|
|
163
|
+
throw error
|
|
164
|
+
}
|
|
161
165
|
|
|
162
166
|
const message = __DEV__
|
|
163
167
|
? `[mobx] Encountered an uncaught exception that was thrown by a reaction or observer component, in: '${this}'`
|
|
@@ -165,7 +169,7 @@ export class Reaction implements IDerivation, IReactionPublic {
|
|
|
165
169
|
if (!globalState.suppressReactionErrors) {
|
|
166
170
|
console.error(message, error)
|
|
167
171
|
/** If debugging brought you here, please, read the above message :-). Tnx! */
|
|
168
|
-
} else if (__DEV__) console.warn(`[mobx] (error in reaction '${this.name_}' suppressed, fix error of causing action below)`) // prettier-ignore
|
|
172
|
+
} else if (__DEV__) {console.warn(`[mobx] (error in reaction '${this.name_}' suppressed, fix error of causing action below)`)} // prettier-ignore
|
|
169
173
|
|
|
170
174
|
if (__DEV__ && isSpyEnabled()) {
|
|
171
175
|
spyReport({
|
|
@@ -210,7 +214,9 @@ export function onReactionError(handler: (error: any, derivation: IDerivation) =
|
|
|
210
214
|
globalState.globalReactionErrorHandlers.push(handler)
|
|
211
215
|
return () => {
|
|
212
216
|
const idx = globalState.globalReactionErrorHandlers.indexOf(handler)
|
|
213
|
-
if (idx >= 0)
|
|
217
|
+
if (idx >= 0) {
|
|
218
|
+
globalState.globalReactionErrorHandlers.splice(idx, 1)
|
|
219
|
+
}
|
|
214
220
|
}
|
|
215
221
|
}
|
|
216
222
|
|
|
@@ -225,7 +231,9 @@ let reactionScheduler: (fn: () => void) => void = f => f()
|
|
|
225
231
|
|
|
226
232
|
export function runReactions() {
|
|
227
233
|
// Trampolining, if runReactions are already running, new reactions will be picked up
|
|
228
|
-
if (globalState.inBatch > 0 || globalState.isRunningReactions)
|
|
234
|
+
if (globalState.inBatch > 0 || globalState.isRunningReactions) {
|
|
235
|
+
return
|
|
236
|
+
}
|
|
229
237
|
reactionScheduler(runReactionsHelper)
|
|
230
238
|
}
|
|
231
239
|
|
|
@@ -248,8 +256,9 @@ function runReactionsHelper() {
|
|
|
248
256
|
allReactions.splice(0) // clear reactions
|
|
249
257
|
}
|
|
250
258
|
let remainingReactions = allReactions.splice(0)
|
|
251
|
-
for (let i = 0, l = remainingReactions.length; i < l; i++)
|
|
259
|
+
for (let i = 0, l = remainingReactions.length; i < l; i++) {
|
|
252
260
|
remainingReactions[i].runReaction_()
|
|
261
|
+
}
|
|
253
262
|
}
|
|
254
263
|
globalState.isRunningReactions = false
|
|
255
264
|
}
|
package/src/core/spy.ts
CHANGED
|
@@ -25,14 +25,22 @@ export type PureSpyEvent =
|
|
|
25
25
|
type SpyEvent = PureSpyEvent & { spyReportStart?: true }
|
|
26
26
|
|
|
27
27
|
export function spyReport(event: SpyEvent) {
|
|
28
|
-
if (!__DEV__)
|
|
29
|
-
|
|
28
|
+
if (!__DEV__) {
|
|
29
|
+
return
|
|
30
|
+
} // dead code elimination can do the rest
|
|
31
|
+
if (!globalState.spyListeners.length) {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
30
34
|
const listeners = globalState.spyListeners
|
|
31
|
-
for (let i = 0, l = listeners.length; i < l; i++)
|
|
35
|
+
for (let i = 0, l = listeners.length; i < l; i++) {
|
|
36
|
+
listeners[i](event)
|
|
37
|
+
}
|
|
32
38
|
}
|
|
33
39
|
|
|
34
40
|
export function spyReportStart(event: PureSpyEvent) {
|
|
35
|
-
if (!__DEV__)
|
|
41
|
+
if (!__DEV__) {
|
|
42
|
+
return
|
|
43
|
+
}
|
|
36
44
|
const change = { ...event, spyReportStart: true as const }
|
|
37
45
|
spyReport(change)
|
|
38
46
|
}
|
|
@@ -40,9 +48,14 @@ export function spyReportStart(event: PureSpyEvent) {
|
|
|
40
48
|
const END_EVENT: SpyEvent = { type: "report-end", spyReportEnd: true }
|
|
41
49
|
|
|
42
50
|
export function spyReportEnd(change?: { time?: number }) {
|
|
43
|
-
if (!__DEV__)
|
|
44
|
-
|
|
45
|
-
|
|
51
|
+
if (!__DEV__) {
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
if (change) {
|
|
55
|
+
spyReport({ ...change, type: "report-end", spyReportEnd: true })
|
|
56
|
+
} else {
|
|
57
|
+
spyReport(END_EVENT)
|
|
58
|
+
}
|
|
46
59
|
}
|
|
47
60
|
|
|
48
61
|
export function spy(listener: (change: SpyEvent) => void): Lambda {
|
package/src/errors.ts
CHANGED
|
@@ -22,9 +22,9 @@ const niceErrors = {
|
|
|
22
22
|
10: "'has()' can only be used on observable objects, arrays and maps",
|
|
23
23
|
11: "'get()' can only be used on observable objects, arrays and maps",
|
|
24
24
|
12: `Invalid annotation`,
|
|
25
|
-
13: `Dynamic observable objects cannot be frozen`,
|
|
25
|
+
13: `Dynamic observable objects cannot be frozen. If you're passing observables to 3rd party component/function that calls Object.freeze, pass copy instead: toJS(observable)`,
|
|
26
26
|
14: "Intercept handlers should return nothing or a change object",
|
|
27
|
-
15: `Observable arrays cannot be frozen`,
|
|
27
|
+
15: `Observable arrays cannot be frozen. If you're passing observables to 3rd party component/function that calls Object.freeze, pass copy instead: toJS(observable)`,
|
|
28
28
|
16: `Modification exception: the internal structure of an observable array was changed.`,
|
|
29
29
|
17(index, length) {
|
|
30
30
|
return `[mobx.array] Index out of bounds, ${index} is larger than ${length}`
|
|
@@ -67,7 +67,7 @@ function assertActionDescriptor(
|
|
|
67
67
|
if (__DEV__ && !isFunction(value)) {
|
|
68
68
|
die(
|
|
69
69
|
`Cannot apply '${annotationType_}' to '${adm.name_}.${key.toString()}':` +
|
|
70
|
-
|
|
70
|
+
`\n'${annotationType_}' can only be used on properties with a function value.`
|
|
71
71
|
)
|
|
72
72
|
}
|
|
73
73
|
}
|
|
@@ -91,7 +91,7 @@ export function createActionDescriptor(
|
|
|
91
91
|
value,
|
|
92
92
|
annotation.options_?.autoAction ?? false,
|
|
93
93
|
// https://github.com/mobxjs/mobx/discussions/3140
|
|
94
|
-
annotation.options_?.bound ?
|
|
94
|
+
annotation.options_?.bound ? adm.proxy_ ?? adm.target_ : undefined
|
|
95
95
|
),
|
|
96
96
|
// Non-configurable for classes
|
|
97
97
|
// prevents accidental field redefinition in subclass
|
|
@@ -19,17 +19,20 @@ function getAdm(target): ObservableObjectAdministration {
|
|
|
19
19
|
// and skip either the internal values map, or the base object with its property descriptors!
|
|
20
20
|
const objectProxyTraps: ProxyHandler<any> = {
|
|
21
21
|
has(target: IIsObservableObject, name: PropertyKey): boolean {
|
|
22
|
-
if (__DEV__ && globalState.trackingDerivation)
|
|
22
|
+
if (__DEV__ && globalState.trackingDerivation) {
|
|
23
23
|
warnAboutProxyRequirement(
|
|
24
24
|
"detect new properties using the 'in' operator. Use 'has' from 'mobx' instead."
|
|
25
25
|
)
|
|
26
|
+
}
|
|
26
27
|
return getAdm(target).has_(name)
|
|
27
28
|
},
|
|
28
29
|
get(target: IIsObservableObject, name: PropertyKey): any {
|
|
29
30
|
return getAdm(target).get_(name)
|
|
30
31
|
},
|
|
31
32
|
set(target: IIsObservableObject, name: PropertyKey, value: any): boolean {
|
|
32
|
-
if (!isStringish(name))
|
|
33
|
+
if (!isStringish(name)) {
|
|
34
|
+
return false
|
|
35
|
+
}
|
|
33
36
|
if (__DEV__ && !getAdm(target).values_.has(name)) {
|
|
34
37
|
warnAboutProxyRequirement(
|
|
35
38
|
"add a new observable property through direct assignment. Use 'set' from 'mobx' instead."
|
|
@@ -44,7 +47,9 @@ const objectProxyTraps: ProxyHandler<any> = {
|
|
|
44
47
|
"delete properties from an observable object. Use 'remove' from 'mobx' instead."
|
|
45
48
|
)
|
|
46
49
|
}
|
|
47
|
-
if (!isStringish(name))
|
|
50
|
+
if (!isStringish(name)) {
|
|
51
|
+
return false
|
|
52
|
+
}
|
|
48
53
|
// null (intercepted) -> true (success)
|
|
49
54
|
return getAdm(target).delete_(name, true) ?? true
|
|
50
55
|
},
|
|
@@ -62,10 +67,11 @@ const objectProxyTraps: ProxyHandler<any> = {
|
|
|
62
67
|
return getAdm(target).defineProperty_(name, descriptor) ?? true
|
|
63
68
|
},
|
|
64
69
|
ownKeys(target: IIsObservableObject): ArrayLike<string | symbol> {
|
|
65
|
-
if (__DEV__ && globalState.trackingDerivation)
|
|
70
|
+
if (__DEV__ && globalState.trackingDerivation) {
|
|
66
71
|
warnAboutProxyRequirement(
|
|
67
72
|
"iterate keys to detect added / removed properties. Use 'keys' from 'mobx' instead."
|
|
68
73
|
)
|
|
74
|
+
}
|
|
69
75
|
return getAdm(target).ownKeys_()
|
|
70
76
|
},
|
|
71
77
|
preventExtensions(target) {
|
|
@@ -7,7 +7,8 @@ import {
|
|
|
7
7
|
isFlow,
|
|
8
8
|
isFunction,
|
|
9
9
|
globalState,
|
|
10
|
-
MakeResult
|
|
10
|
+
MakeResult,
|
|
11
|
+
hasProp
|
|
11
12
|
} from "../internal"
|
|
12
13
|
|
|
13
14
|
export function createFlowAnnotation(name: string, options?: object): Annotation {
|
|
@@ -33,8 +34,10 @@ function make_(
|
|
|
33
34
|
}
|
|
34
35
|
// prototype
|
|
35
36
|
// bound - must annotate protos to support super.flow()
|
|
36
|
-
if (this.options_?.bound && !isFlow(adm.target_[key])) {
|
|
37
|
-
if (this.extend_(adm, key, descriptor, false) === null)
|
|
37
|
+
if (this.options_?.bound && (!hasProp(adm.target_, key) || !isFlow(adm.target_[key]))) {
|
|
38
|
+
if (this.extend_(adm, key, descriptor, false) === null) {
|
|
39
|
+
return MakeResult.Cancel
|
|
40
|
+
}
|
|
38
41
|
}
|
|
39
42
|
if (isFlow(descriptor.value)) {
|
|
40
43
|
// A prototype could have been annotated already by other constructor,
|
|
@@ -81,11 +84,18 @@ function createFlowDescriptor(
|
|
|
81
84
|
): PropertyDescriptor {
|
|
82
85
|
assertFlowDescriptor(adm, annotation, key, descriptor)
|
|
83
86
|
let { value } = descriptor
|
|
87
|
+
// In case of flow.bound, the descriptor can be from already annotated prototype
|
|
88
|
+
if (!isFlow(value)) {
|
|
89
|
+
value = flow(value)
|
|
90
|
+
}
|
|
84
91
|
if (bound) {
|
|
92
|
+
// We do not keep original function around, so we bind the existing flow
|
|
85
93
|
value = value.bind(adm.proxy_ ?? adm.target_)
|
|
94
|
+
// This is normally set by `flow`, but `bind` returns new function...
|
|
95
|
+
value.isMobXFlow = true
|
|
86
96
|
}
|
|
87
97
|
return {
|
|
88
|
-
value
|
|
98
|
+
value,
|
|
89
99
|
// Non-configurable for classes
|
|
90
100
|
// prevents accidental field redefinition in subclass
|
|
91
101
|
configurable: safeDescriptors ? adm.isPlainObject_ : true,
|
|
@@ -18,7 +18,9 @@ export function registerInterceptor<T>(
|
|
|
18
18
|
interceptors.push(handler)
|
|
19
19
|
return once(() => {
|
|
20
20
|
const idx = interceptors.indexOf(handler)
|
|
21
|
-
if (idx !== -1)
|
|
21
|
+
if (idx !== -1) {
|
|
22
|
+
interceptors.splice(idx, 1)
|
|
23
|
+
}
|
|
22
24
|
})
|
|
23
25
|
}
|
|
24
26
|
|
|
@@ -32,8 +34,12 @@ export function interceptChange<T>(
|
|
|
32
34
|
const interceptors = [...(interceptable.interceptors_ || [])]
|
|
33
35
|
for (let i = 0, l = interceptors.length; i < l; i++) {
|
|
34
36
|
change = interceptors[i](change)
|
|
35
|
-
if (change && !(change as any).type)
|
|
36
|
-
|
|
37
|
+
if (change && !(change as any).type) {
|
|
38
|
+
die(14)
|
|
39
|
+
}
|
|
40
|
+
if (!change) {
|
|
41
|
+
break
|
|
42
|
+
}
|
|
37
43
|
}
|
|
38
44
|
return change
|
|
39
45
|
} finally {
|
|
@@ -85,7 +85,6 @@ class LegacyObservableArray<T> extends StubArray {
|
|
|
85
85
|
let nextIndex = 0
|
|
86
86
|
return makeIterable({
|
|
87
87
|
next() {
|
|
88
|
-
// @ts-ignore
|
|
89
88
|
return nextIndex < self.length
|
|
90
89
|
? { value: self[nextIndex++], done: false }
|
|
91
90
|
: { done: true, value: undefined }
|
|
@@ -95,7 +94,9 @@ class LegacyObservableArray<T> extends StubArray {
|
|
|
95
94
|
}
|
|
96
95
|
|
|
97
96
|
Object.entries(arrayExtensions).forEach(([prop, fn]) => {
|
|
98
|
-
if (prop !== "concat")
|
|
97
|
+
if (prop !== "concat") {
|
|
98
|
+
addHiddenProp(LegacyObservableArray.prototype, prop, fn)
|
|
99
|
+
}
|
|
99
100
|
})
|
|
100
101
|
|
|
101
102
|
function createArrayEntryDescriptor(index: number) {
|
|
@@ -117,8 +118,9 @@ function createArrayBufferItem(index: number) {
|
|
|
117
118
|
|
|
118
119
|
export function reserveArrayBuffer(max: number) {
|
|
119
120
|
if (max > OBSERVABLE_ARRAY_BUFFER_SIZE) {
|
|
120
|
-
for (let index = OBSERVABLE_ARRAY_BUFFER_SIZE; index < max + 100; index++)
|
|
121
|
+
for (let index = OBSERVABLE_ARRAY_BUFFER_SIZE; index < max + 100; index++) {
|
|
121
122
|
createArrayBufferItem(index)
|
|
123
|
+
}
|
|
122
124
|
OBSERVABLE_ARRAY_BUFFER_SIZE = max
|
|
123
125
|
}
|
|
124
126
|
}
|
|
@@ -13,14 +13,18 @@ export function registerListener(listenable: IListenable, handler: Function): La
|
|
|
13
13
|
listeners.push(handler)
|
|
14
14
|
return once(() => {
|
|
15
15
|
const idx = listeners.indexOf(handler)
|
|
16
|
-
if (idx !== -1)
|
|
16
|
+
if (idx !== -1) {
|
|
17
|
+
listeners.splice(idx, 1)
|
|
18
|
+
}
|
|
17
19
|
})
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
export function notifyListeners<T>(listenable: IListenable, change: T) {
|
|
21
23
|
const prevU = untrackedStart()
|
|
22
24
|
let listeners = listenable.changeListeners_
|
|
23
|
-
if (!listeners)
|
|
25
|
+
if (!listeners) {
|
|
26
|
+
return
|
|
27
|
+
}
|
|
24
28
|
listeners = listeners.slice()
|
|
25
29
|
for (let i = 0, l = listeners.length; i < l; i++) {
|
|
26
30
|
listeners[i](change)
|