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.
Files changed (91) hide show
  1. package/CHANGELOG.md +224 -7
  2. package/README.md +54 -52
  3. package/dist/api/annotation.d.ts +6 -12
  4. package/dist/api/autorun.d.ts +4 -4
  5. package/dist/api/flow.d.ts +1 -0
  6. package/dist/api/intercept.d.ts +5 -5
  7. package/dist/api/object-api.d.ts +2 -0
  8. package/dist/api/observable.d.ts +5 -1
  9. package/dist/api/observe.d.ts +4 -4
  10. package/dist/api/tojs.d.ts +4 -1
  11. package/dist/api/when.d.ts +8 -0
  12. package/dist/core/atom.d.ts +1 -1
  13. package/dist/core/computedvalue.d.ts +0 -1
  14. package/dist/core/globalstate.d.ts +4 -0
  15. package/dist/core/reaction.d.ts +2 -2
  16. package/dist/errors.d.ts +4 -2
  17. package/dist/internal.d.ts +1 -0
  18. package/dist/mobx.cjs.development.js +1477 -1719
  19. package/dist/mobx.cjs.development.js.map +1 -1
  20. package/dist/mobx.cjs.production.min.js +1 -1
  21. package/dist/mobx.cjs.production.min.js.map +1 -1
  22. package/dist/mobx.d.ts +1 -1
  23. package/dist/mobx.esm.development.js +1475 -1720
  24. package/dist/mobx.esm.development.js.map +1 -1
  25. package/dist/mobx.esm.js +1492 -1726
  26. package/dist/mobx.esm.js.map +1 -1
  27. package/dist/mobx.esm.production.min.js +1 -1
  28. package/dist/mobx.esm.production.min.js.map +1 -1
  29. package/dist/mobx.umd.development.js +1477 -1719
  30. package/dist/mobx.umd.development.js.map +1 -1
  31. package/dist/mobx.umd.production.min.js +1 -1
  32. package/dist/mobx.umd.production.min.js.map +1 -1
  33. package/dist/types/actionannotation.d.ts +7 -1
  34. package/dist/types/autoannotation.d.ts +3 -0
  35. package/dist/types/observablemap.d.ts +5 -4
  36. package/dist/types/observableobject.d.ts +6 -9
  37. package/dist/types/observableset.d.ts +4 -4
  38. package/dist/types/observablevalue.d.ts +3 -5
  39. package/dist/utils/utils.d.ts +4 -4
  40. package/package.json +1 -1
  41. package/src/api/action.ts +8 -3
  42. package/src/api/annotation.ts +14 -44
  43. package/src/api/autorun.ts +38 -17
  44. package/src/api/computed.ts +5 -2
  45. package/src/api/configure.ts +6 -2
  46. package/src/api/decorators.ts +1 -1
  47. package/src/api/extendobservable.ts +12 -6
  48. package/src/api/extras.ts +4 -2
  49. package/src/api/flow.ts +17 -5
  50. package/src/api/intercept-read.ts +4 -2
  51. package/src/api/intercept.ts +10 -7
  52. package/src/api/iscomputed.ts +14 -8
  53. package/src/api/isobservable.ts +10 -4
  54. package/src/api/makeObservable.ts +35 -36
  55. package/src/api/object-api.ts +42 -14
  56. package/src/api/observable.ts +39 -25
  57. package/src/api/observe.ts +9 -6
  58. package/src/api/tojs.ts +20 -10
  59. package/src/api/trace.ts +6 -2
  60. package/src/api/when.ts +34 -9
  61. package/src/core/action.ts +11 -5
  62. package/src/core/atom.ts +9 -2
  63. package/src/core/computedvalue.ts +48 -27
  64. package/src/core/derivation.ts +34 -12
  65. package/src/core/globalstate.ts +25 -7
  66. package/src/core/observable.ts +23 -13
  67. package/src/core/reaction.ts +16 -7
  68. package/src/core/spy.ts +20 -7
  69. package/src/errors.ts +16 -3
  70. package/src/internal.ts +1 -0
  71. package/src/mobx.ts +6 -2
  72. package/src/types/actionannotation.ts +30 -52
  73. package/src/types/autoannotation.ts +107 -0
  74. package/src/types/computedannotation.ts +7 -37
  75. package/src/types/dynamicobject.ts +12 -6
  76. package/src/types/flowannotation.ts +40 -41
  77. package/src/types/intercept-utils.ts +9 -3
  78. package/src/types/legacyobservablearray.ts +26 -3
  79. package/src/types/listen-utils.ts +6 -2
  80. package/src/types/modifiers.ts +52 -16
  81. package/src/types/observableannotation.ts +7 -34
  82. package/src/types/observablearray.ts +106 -45
  83. package/src/types/observablemap.ts +71 -35
  84. package/src/types/observableobject.ts +88 -82
  85. package/src/types/observableset.ts +32 -13
  86. package/src/types/observablevalue.ts +16 -10
  87. package/src/types/overrideannotation.ts +4 -2
  88. package/src/types/type-utils.ts +34 -12
  89. package/src/utils/comparer.ts +5 -1
  90. package/src/utils/eq.ts +45 -15
  91. package/src/utils/utils.ts +39 -16
@@ -14,7 +14,8 @@ import {
14
14
  ACTION,
15
15
  EMPTY_ARRAY,
16
16
  die,
17
- getDescriptor
17
+ getDescriptor,
18
+ defineProperty
18
19
  } from "../internal"
19
20
 
20
21
  // we don't use globalState for these in order to avoid possible issues with multiple
@@ -38,9 +39,12 @@ export function createAction(
38
39
  ref?: Object
39
40
  ): Function {
40
41
  if (__DEV__) {
41
- if (!isFunction(fn)) die("`action` can only be invoked on functions")
42
- if (typeof actionName !== "string" || !actionName)
42
+ if (!isFunction(fn)) {
43
+ die("`action` can only be invoked on functions")
44
+ }
45
+ if (typeof actionName !== "string" || !actionName) {
43
46
  die(`actions should have valid names, got: '${actionName}'`)
47
+ }
44
48
  }
45
49
  function res() {
46
50
  return executeAction(actionName, autoAction, fn, ref || this, arguments)
@@ -48,7 +52,7 @@ export function createAction(
48
52
  res.isMobxAction = true
49
53
  if (isFunctionNameConfigurable) {
50
54
  tmpNameDescriptor.value = actionName
51
- Object.defineProperty(res, "name", tmpNameDescriptor)
55
+ defineProperty(res, "name", tmpNameDescriptor)
52
56
  }
53
57
  return res
54
58
  }
@@ -136,7 +140,9 @@ export function _endAction(runInfo: IActionRunInfo) {
136
140
  allowStateChangesEnd(runInfo.prevAllowStateChanges_)
137
141
  allowStateReadsEnd(runInfo.prevAllowStateReads_)
138
142
  endBatch()
139
- if (runInfo.runAsAction_) untrackedEnd(runInfo.prevDerivation_)
143
+ if (runInfo.runAsAction_) {
144
+ untrackedEnd(runInfo.prevDerivation_)
145
+ }
140
146
  if (__DEV__ && runInfo.notifySpy_) {
141
147
  spyReportEnd({ time: Date.now() - runInfo.startTime_ })
142
148
  }
package/src/core/atom.ts CHANGED
@@ -11,13 +11,14 @@ import {
11
11
  propagateChanged,
12
12
  reportObserved,
13
13
  startBatch,
14
- Lambda
14
+ Lambda,
15
+ globalState
15
16
  } from "../internal"
16
17
 
17
18
  export const $mobx = Symbol("mobx administration")
18
19
 
19
20
  export interface IAtom extends IObservable {
20
- reportObserved()
21
+ reportObserved(): boolean
21
22
  reportChanged()
22
23
  }
23
24
 
@@ -66,6 +67,12 @@ export class Atom implements IAtom {
66
67
  public reportChanged() {
67
68
  startBatch()
68
69
  propagateChanged(this)
70
+ // We could update state version only at the end of batch,
71
+ // but we would still have to switch some global flag here to signal a change.
72
+ globalState.stateVersion =
73
+ globalState.stateVersion < Number.MAX_SAFE_INTEGER
74
+ ? globalState.stateVersion + 1
75
+ : Number.MIN_SAFE_INTEGER
69
76
  endBatch()
70
77
  }
71
78
 
@@ -35,7 +35,6 @@ import {
35
35
  export interface IComputedValue<T> {
36
36
  get(): T
37
37
  set(value: T): void
38
- observe_(listener: (change: IComputedDidChange<T>) => void, fireImmediately?: boolean): Lambda
39
38
  }
40
39
 
41
40
  export interface IComputedValueOptions<T> {
@@ -98,7 +97,7 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
98
97
  isTracing_: TraceMode = TraceMode.NONE
99
98
  scope_: Object | undefined
100
99
  private equals_: IEqualsComparer<any>
101
- private requiresReaction_: boolean
100
+ private requiresReaction_: boolean | undefined
102
101
  keepAlive_: boolean
103
102
 
104
103
  /**
@@ -114,7 +113,9 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
114
113
  * This is useful for working with vectors, mouse coordinates etc.
115
114
  */
116
115
  constructor(options: IComputedValueOptions<T>) {
117
- if (!options.get) die(31)
116
+ if (!options.get) {
117
+ die(31)
118
+ }
118
119
  this.derivation = options.get!
119
120
  this.name_ = options.name || (__DEV__ ? "ComputedValue@" + getNextId() : "ComputedValue")
120
121
  if (options.set) {
@@ -129,7 +130,7 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
129
130
  ? comparer.structural
130
131
  : comparer.default)
131
132
  this.scope_ = options.context
132
- this.requiresReaction_ = !!options.requiresReaction
133
+ this.requiresReaction_ = options.requiresReaction
133
134
  this.keepAlive_ = !!options.keepAlive
134
135
  }
135
136
 
@@ -157,7 +158,9 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
157
158
  * Will evaluate its computation first if needed.
158
159
  */
159
160
  public get(): T {
160
- if (this.isComputing_) die(32, this.name_, this.derivation)
161
+ if (this.isComputing_) {
162
+ die(32, this.name_, this.derivation)
163
+ }
161
164
  if (
162
165
  globalState.inBatch === 0 &&
163
166
  // !globalState.trackingDerivatpion &&
@@ -174,27 +177,37 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
174
177
  reportObserved(this)
175
178
  if (shouldCompute(this)) {
176
179
  let prevTrackingContext = globalState.trackingContext
177
- if (this.keepAlive_ && !prevTrackingContext) globalState.trackingContext = this
178
- if (this.trackAndCompute()) propagateChangeConfirmed(this)
180
+ if (this.keepAlive_ && !prevTrackingContext) {
181
+ globalState.trackingContext = this
182
+ }
183
+ if (this.trackAndCompute()) {
184
+ propagateChangeConfirmed(this)
185
+ }
179
186
  globalState.trackingContext = prevTrackingContext
180
187
  }
181
188
  }
182
189
  const result = this.value_!
183
190
 
184
- if (isCaughtException(result)) throw result.cause
191
+ if (isCaughtException(result)) {
192
+ throw result.cause
193
+ }
185
194
  return result
186
195
  }
187
196
 
188
197
  public set(value: T) {
189
198
  if (this.setter_) {
190
- if (this.isRunningSetter_) die(33, this.name_)
199
+ if (this.isRunningSetter_) {
200
+ die(33, this.name_)
201
+ }
191
202
  this.isRunningSetter_ = true
192
203
  try {
193
204
  this.setter_.call(this.scope_, value)
194
205
  } finally {
195
206
  this.isRunningSetter_ = false
196
207
  }
197
- } else die(34, this.name_)
208
+ } else {
209
+ die(34, this.name_)
210
+ }
198
211
  }
199
212
 
200
213
  trackAndCompute(): boolean {
@@ -204,17 +217,6 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
204
217
  /* see #1208 */ this.dependenciesState_ === IDerivationState_.NOT_TRACKING_
205
218
  const newValue = this.computeValue_(true)
206
219
 
207
- if (__DEV__ && isSpyEnabled()) {
208
- spyReport({
209
- observableKind: "computed",
210
- debugObjectName: this.name_,
211
- object: this.scope_,
212
- type: "update",
213
- oldValue: this.value_,
214
- newValue
215
- } as IComputedDidChange)
216
- }
217
-
218
220
  const changed =
219
221
  wasSuspended ||
220
222
  isCaughtException(oldValue) ||
@@ -223,6 +225,17 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
223
225
 
224
226
  if (changed) {
225
227
  this.value_ = newValue
228
+
229
+ if (__DEV__ && isSpyEnabled()) {
230
+ spyReport({
231
+ observableKind: "computed",
232
+ debugObjectName: this.name_,
233
+ object: this.scope_,
234
+ type: "update",
235
+ oldValue,
236
+ newValue
237
+ } as IComputedDidChange)
238
+ }
226
239
  }
227
240
 
228
241
  return changed
@@ -255,6 +268,11 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
255
268
  if (!this.keepAlive_) {
256
269
  clearObserving(this)
257
270
  this.value_ = undefined // don't hold on to computed value!
271
+ if (__DEV__ && this.isTracing_ !== TraceMode.NONE) {
272
+ console.log(
273
+ `[mobx.trace] Computed value '${this.name_}' was suspended and it will recompute on the next access.`
274
+ )
275
+ }
258
276
  }
259
277
  }
260
278
 
@@ -282,18 +300,21 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
282
300
  }
283
301
 
284
302
  warnAboutUntrackedRead_() {
285
- if (!__DEV__) return
286
- if (this.requiresReaction_ === true) {
287
- die(`[mobx] Computed value ${this.name_} is read outside a reactive context`)
303
+ if (!__DEV__) {
304
+ return
288
305
  }
289
306
  if (this.isTracing_ !== TraceMode.NONE) {
290
307
  console.log(
291
- `[mobx.trace] '${this.name_}' is being read outside a reactive context. Doing a full recompute`
308
+ `[mobx.trace] Computed value '${this.name_}' is being read outside a reactive context. Doing a full recompute.`
292
309
  )
293
310
  }
294
- if (globalState.computedRequiresReaction) {
311
+ if (
312
+ typeof this.requiresReaction_ === "boolean"
313
+ ? this.requiresReaction_
314
+ : globalState.computedRequiresReaction
315
+ ) {
295
316
  console.warn(
296
- `[mobx] Computed value ${this.name_} is being read outside a reactive context. Doing a full recompute`
317
+ `[mobx] Computed value '${this.name_}' is being read outside a reactive context. Doing a full recompute.`
297
318
  )
298
319
  }
299
320
  }
@@ -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 (!globalState.allowStateChanges && (hasObservers || globalState.enforceActions === "always"))
140
+ if (
141
+ !globalState.allowStateChanges &&
142
+ (hasObservers || globalState.enforceActions === "always")
143
+ ) {
141
144
  console.warn(
142
145
  "[MobX] " +
143
146
  (globalState.enforceActions
@@ -145,11 +148,14 @@ 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) {
151
155
  if (__DEV__ && !globalState.allowStateReads && globalState.observableRequiresReaction) {
152
- console.warn(`[mobx] Observable ${observable.name_} being read outside a reactive context`)
156
+ console.warn(
157
+ `[mobx] Observable '${observable.name_}' being read outside a reactive context.`
158
+ )
153
159
  }
154
160
  }
155
161
 
@@ -189,13 +195,21 @@ export function trackDerivedFunction<T>(derivation: IDerivation, f: () => T, con
189
195
  }
190
196
 
191
197
  function warnAboutDerivationWithoutDependencies(derivation: IDerivation) {
192
- if (!__DEV__) return
198
+ if (!__DEV__) {
199
+ return
200
+ }
193
201
 
194
- if (derivation.observing_.length !== 0) return
202
+ if (derivation.observing_.length !== 0) {
203
+ return
204
+ }
195
205
 
196
- if (globalState.reactionRequiresObservable || derivation.requiresObservable_) {
206
+ if (
207
+ typeof derivation.requiresObservable_ === "boolean"
208
+ ? derivation.requiresObservable_
209
+ : globalState.reactionRequiresObservable
210
+ ) {
197
211
  console.warn(
198
- `[mobx] Derivation ${derivation.name_} is created/updated without reading any observable value`
212
+ `[mobx] Derivation '${derivation.name_}' is created/updated without reading any observable value.`
199
213
  )
200
214
  }
201
215
  }
@@ -220,14 +234,16 @@ function bindDependencies(derivation: IDerivation) {
220
234
  const dep = observing[i]
221
235
  if (dep.diffValue_ === 0) {
222
236
  dep.diffValue_ = 1
223
- if (i0 !== i) observing[i0] = dep
237
+ if (i0 !== i) {
238
+ observing[i0] = dep
239
+ }
224
240
  i0++
225
241
  }
226
242
 
227
243
  // Upcast is 'safe' here, because if dep is IObservable, `dependenciesState` will be undefined,
228
244
  // not hitting the condition
229
- if (((dep as any) as IDerivation).dependenciesState_ > lowestNewObservingDerivationState) {
230
- lowestNewObservingDerivationState = ((dep as any) as IDerivation).dependenciesState_
245
+ if ((dep as any as IDerivation).dependenciesState_ > lowestNewObservingDerivationState) {
246
+ lowestNewObservingDerivationState = (dep as any as IDerivation).dependenciesState_
231
247
  }
232
248
  }
233
249
  observing.length = i0
@@ -270,7 +286,9 @@ export function clearObserving(derivation: IDerivation) {
270
286
  const obs = derivation.observing_
271
287
  derivation.observing_ = []
272
288
  let i = obs.length
273
- while (i--) removeObserver(obs[i], derivation)
289
+ while (i--) {
290
+ removeObserver(obs[i], derivation)
291
+ }
274
292
 
275
293
  derivation.dependenciesState_ = IDerivationState_.NOT_TRACKING_
276
294
  }
@@ -309,10 +327,14 @@ export function allowStateReadsEnd(prev: boolean) {
309
327
  *
310
328
  */
311
329
  export function changeDependenciesStateTo0(derivation: IDerivation) {
312
- if (derivation.dependenciesState_ === IDerivationState_.UP_TO_DATE_) return
330
+ if (derivation.dependenciesState_ === IDerivationState_.UP_TO_DATE_) {
331
+ return
332
+ }
313
333
  derivation.dependenciesState_ = IDerivationState_.UP_TO_DATE_
314
334
 
315
335
  const obs = derivation.observing_
316
336
  let i = obs.length
317
- while (i--) obs[i].lowestObserverState_ = IDerivationState_.UP_TO_DATE_
337
+ while (i--) {
338
+ obs[i].lowestObserverState_ = IDerivationState_.UP_TO_DATE_
339
+ }
318
340
  }
@@ -150,6 +150,11 @@ export class MobXGlobals {
150
150
  * configurable: true
151
151
  */
152
152
  safeDescriptors = true
153
+
154
+ /**
155
+ * Changes with each state update, used by useSyncExternalStore
156
+ */
157
+ stateVersion = Number.MIN_SAFE_INTEGER
153
158
  }
154
159
 
155
160
  let canMergeGlobalState = true
@@ -157,11 +162,16 @@ let isolateCalled = false
157
162
 
158
163
  export let globalState: MobXGlobals = (function () {
159
164
  let global = getGlobal()
160
- if (global.__mobxInstanceCount > 0 && !global.__mobxGlobals) canMergeGlobalState = false
161
- if (global.__mobxGlobals && global.__mobxGlobals.version !== new MobXGlobals().version)
165
+ if (global.__mobxInstanceCount > 0 && !global.__mobxGlobals) {
166
+ canMergeGlobalState = false
167
+ }
168
+ if (global.__mobxGlobals && global.__mobxGlobals.version !== new MobXGlobals().version) {
162
169
  canMergeGlobalState = false
170
+ }
163
171
 
164
172
  if (!canMergeGlobalState) {
173
+ // Because this is a IIFE we need to let isolateCalled a chance to change
174
+ // so we run it after the event loop completed at least 1 iteration
165
175
  setTimeout(() => {
166
176
  if (!isolateCalled) {
167
177
  die(35)
@@ -170,7 +180,9 @@ export let globalState: MobXGlobals = (function () {
170
180
  return new MobXGlobals()
171
181
  } else if (global.__mobxGlobals) {
172
182
  global.__mobxInstanceCount += 1
173
- if (!global.__mobxGlobals.UNCHANGED) global.__mobxGlobals.UNCHANGED = {} // make merge backward compatible
183
+ if (!global.__mobxGlobals.UNCHANGED) {
184
+ global.__mobxGlobals.UNCHANGED = {}
185
+ } // make merge backward compatible
174
186
  return global.__mobxGlobals
175
187
  } else {
176
188
  global.__mobxInstanceCount = 1
@@ -183,12 +195,15 @@ export function isolateGlobalState() {
183
195
  globalState.pendingReactions.length ||
184
196
  globalState.inBatch ||
185
197
  globalState.isRunningReactions
186
- )
198
+ ) {
187
199
  die(36)
200
+ }
188
201
  isolateCalled = true
189
202
  if (canMergeGlobalState) {
190
203
  let global = getGlobal()
191
- if (--global.__mobxInstanceCount === 0) global.__mobxGlobals = undefined
204
+ if (--global.__mobxInstanceCount === 0) {
205
+ global.__mobxGlobals = undefined
206
+ }
192
207
  globalState = new MobXGlobals()
193
208
  }
194
209
  }
@@ -203,7 +218,10 @@ export function getGlobalState(): any {
203
218
  */
204
219
  export function resetGlobalState() {
205
220
  const defaultGlobals = new MobXGlobals()
206
- for (let key in defaultGlobals)
207
- if (persistentKeys.indexOf(key as any) === -1) globalState[key] = defaultGlobals[key]
221
+ for (let key in defaultGlobals) {
222
+ if (persistentKeys.indexOf(key as any) === -1) {
223
+ globalState[key] = defaultGlobals[key]
224
+ }
225
+ }
208
226
  globalState.allowStateChanges = !globalState.enforceActions
209
227
  }
@@ -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");
@@ -150,7 +151,7 @@ export function reportObserved(observable: IObservable): boolean {
150
151
  observable.onBO()
151
152
  }
152
153
  }
153
- return true
154
+ return observable.isBeingObserved_
154
155
  } else if (observable.observers_.size === 0 && globalState.inBatch > 0) {
155
156
  queueForUnobservation(observable)
156
157
  }
@@ -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_) return
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,16 +205,22 @@ 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_) return
208
+ if (observable.lowestObserverState_ === IDerivationState_.STALE_) {
209
+ return
210
+ }
206
211
  observable.lowestObserverState_ = IDerivationState_.STALE_
207
212
 
208
213
  observable.observers_.forEach(d => {
209
- if (d.dependenciesState_ === IDerivationState_.POSSIBLY_STALE_)
214
+ if (d.dependenciesState_ === IDerivationState_.POSSIBLY_STALE_) {
210
215
  d.dependenciesState_ = IDerivationState_.STALE_
211
- else if (
216
+ if (__DEV__ && d.isTracing_ !== TraceMode.NONE) {
217
+ logTraceInfo(d, observable)
218
+ }
219
+ } else if (
212
220
  d.dependenciesState_ === IDerivationState_.UP_TO_DATE_ // this happens during computing of `d`, just keep lowestObserverState up to date.
213
- )
221
+ ) {
214
222
  observable.lowestObserverState_ = IDerivationState_.UP_TO_DATE_
223
+ }
215
224
  })
216
225
  // invariantLOS(observable, "confirmed end");
217
226
  }
@@ -219,15 +228,14 @@ export function propagateChangeConfirmed(observable: IObservable) {
219
228
  // Used by computed when its dependency changed, but we don't wan't to immediately recompute.
220
229
  export function propagateMaybeChanged(observable: IObservable) {
221
230
  // invariantLOS(observable, "maybe start");
222
- if (observable.lowestObserverState_ !== IDerivationState_.UP_TO_DATE_) return
231
+ if (observable.lowestObserverState_ !== IDerivationState_.UP_TO_DATE_) {
232
+ return
233
+ }
223
234
  observable.lowestObserverState_ = IDerivationState_.POSSIBLY_STALE_
224
235
 
225
236
  observable.observers_.forEach(d => {
226
237
  if (d.dependenciesState_ === IDerivationState_.UP_TO_DATE_) {
227
238
  d.dependenciesState_ = IDerivationState_.POSSIBLY_STALE_
228
- if (__DEV__ && d.isTracing_ !== TraceMode.NONE) {
229
- logTraceInfo(d, observable)
230
- }
231
239
  d.onBecomeStale_()
232
240
  }
233
241
  })
@@ -267,6 +275,8 @@ function printDepTree(tree: IDependencyTree, lines: string[], depth: number) {
267
275
  lines.push("(and many more)")
268
276
  return
269
277
  }
270
- lines.push(`${new Array(depth).join("\t")}${tree.name}`) // MWE: not the fastest, but the easiest way :)
271
- if (tree.dependencies) tree.dependencies.forEach(child => printDepTree(child, lines, depth + 1))
278
+ lines.push(`${"\t".repeat(depth - 1)}${tree.name}`)
279
+ if (tree.dependencies) {
280
+ tree.dependencies.forEach(child => printDepTree(child, lines, depth + 1))
281
+ }
272
282
  }
@@ -67,7 +67,7 @@ export class Reaction implements IDerivation, IReactionPublic {
67
67
  public name_: string = __DEV__ ? "Reaction@" + getNextId() : "Reaction",
68
68
  private onInvalidate_: () => void,
69
69
  private errorHandler_?: (error: any, derivation: IDerivation) => void,
70
- public requiresObservable_ = false
70
+ public requiresObservable_?
71
71
  ) {}
72
72
 
73
73
  onBecomeStale_() {
@@ -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)) this.reportExceptionInDerivation_(result.cause)
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) throw error
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) globalState.globalReactionErrorHandlers.splice(idx, 1)
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) return
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__) return // dead code elimination can do the rest
29
- if (!globalState.spyListeners.length) return
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++) listeners[i](event)
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__) return
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__) return
44
- if (change) spyReport({ ...change, type: "report-end", spyReportEnd: true })
45
- else spyReport(END_EVENT)
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
@@ -3,6 +3,17 @@ const niceErrors = {
3
3
  1(annotationType, key: PropertyKey) {
4
4
  return `Cannot apply '${annotationType}' to '${key.toString()}': Field not found.`
5
5
  },
6
+ /*
7
+ 2(prop) {
8
+ return `invalid decorator for '${prop.toString()}'`
9
+ },
10
+ 3(prop) {
11
+ return `Cannot decorate '${prop.toString()}': action can only be used on properties with a function value.`
12
+ },
13
+ 4(prop) {
14
+ return `Cannot decorate '${prop.toString()}': computed can only be used on getter properties.`
15
+ },
16
+ */
6
17
  5: "'keys()' can only be used on observable objects, arrays, sets and maps",
7
18
  6: "'values()' can only be used on observable objects, arrays, sets and maps",
8
19
  7: "'entries()' can only be used on observable objects, arrays and maps",
@@ -11,9 +22,9 @@ const niceErrors = {
11
22
  10: "'has()' can only be used on observable objects, arrays and maps",
12
23
  11: "'get()' can only be used on observable objects, arrays and maps",
13
24
  12: `Invalid annotation`,
14
- 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)`,
15
26
  14: "Intercept handlers should return nothing or a change object",
16
- 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)`,
17
28
  16: `Modification exception: the internal structure of an observable array was changed.`,
18
29
  17(index, length) {
19
30
  return `[mobx.array] Index out of bounds, ${index} is larger than ${length}`
@@ -59,7 +70,9 @@ const niceErrors = {
59
70
  36: "isolateGlobalState should be called before MobX is running any reactions",
60
71
  37(method) {
61
72
  return `[mobx] \`observableArray.${method}()\` mutates the array in-place, which is not allowed inside a derivation. Use \`array.slice().${method}()\` instead`
62
- }
73
+ },
74
+ 38: "'ownKeys()' can only be used on observable objects",
75
+ 39: "'defineProperty()' can only be used on observable objects"
63
76
  } as const
64
77
 
65
78
  const errors: typeof niceErrors = __DEV__ ? niceErrors : ({} as any)
package/src/internal.ts CHANGED
@@ -17,6 +17,7 @@ export * from "./types/actionannotation"
17
17
  export * from "./types/flowannotation"
18
18
  export * from "./types/computedannotation"
19
19
  export * from "./types/observableannotation"
20
+ export * from "./types/autoannotation"
20
21
  export * from "./api/observable"
21
22
  export * from "./api/computed"
22
23
  export * from "./core/action"