mobx 6.1.8 → 6.3.2

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 (45) hide show
  1. package/CHANGELOG.md +57 -5
  2. package/README.md +2 -1
  3. package/dist/api/annotation.d.ts +6 -12
  4. package/dist/api/flow.d.ts +1 -0
  5. package/dist/api/object-api.d.ts +2 -0
  6. package/dist/errors.d.ts +2 -0
  7. package/dist/internal.d.ts +1 -0
  8. package/dist/mobx.cjs.development.js +322 -310
  9. package/dist/mobx.cjs.development.js.map +1 -1
  10. package/dist/mobx.cjs.production.min.js +1 -1
  11. package/dist/mobx.cjs.production.min.js.map +1 -1
  12. package/dist/mobx.d.ts +1 -1
  13. package/dist/mobx.esm.development.js +320 -311
  14. package/dist/mobx.esm.development.js.map +1 -1
  15. package/dist/mobx.esm.js +320 -311
  16. package/dist/mobx.esm.js.map +1 -1
  17. package/dist/mobx.esm.production.min.js +1 -1
  18. package/dist/mobx.esm.production.min.js.map +1 -1
  19. package/dist/mobx.umd.development.js +322 -310
  20. package/dist/mobx.umd.development.js.map +1 -1
  21. package/dist/mobx.umd.production.min.js +1 -1
  22. package/dist/mobx.umd.production.min.js.map +1 -1
  23. package/dist/types/actionannotation.d.ts +7 -1
  24. package/dist/types/autoannotation.d.ts +3 -0
  25. package/dist/types/observableobject.d.ts +4 -7
  26. package/package.json +1 -1
  27. package/src/api/annotation.ts +13 -42
  28. package/src/api/flow.ts +6 -1
  29. package/src/api/makeObservable.ts +25 -34
  30. package/src/api/object-api.ts +14 -0
  31. package/src/api/observable.ts +3 -8
  32. package/src/api/tojs.ts +10 -7
  33. package/src/core/observable.ts +7 -6
  34. package/src/errors.ts +14 -1
  35. package/src/internal.ts +1 -0
  36. package/src/mobx.ts +4 -0
  37. package/src/types/actionannotation.ts +27 -51
  38. package/src/types/autoannotation.ts +107 -0
  39. package/src/types/computedannotation.ts +7 -37
  40. package/src/types/dynamicobject.ts +1 -1
  41. package/src/types/flowannotation.ts +31 -42
  42. package/src/types/modifiers.ts +13 -2
  43. package/src/types/observableannotation.ts +7 -34
  44. package/src/types/observableobject.ts +34 -63
  45. package/src/types/overrideannotation.ts +4 -2
@@ -1,12 +1,4 @@
1
- import {
2
- ObservableObjectAdministration,
3
- getDescriptor,
4
- objectPrototype,
5
- die,
6
- Annotation,
7
- recordAnnotationApplied,
8
- storedAnnotationsSymbol
9
- } from "../internal"
1
+ import { ObservableObjectAdministration, die, Annotation, MakeResult } from "../internal"
10
2
 
11
3
  export function createComputedAnnotation(name: string, options?: object): Annotation {
12
4
  return {
@@ -17,34 +9,12 @@ export function createComputedAnnotation(name: string, options?: object): Annota
17
9
  }
18
10
  }
19
11
 
20
- function make_(adm: ObservableObjectAdministration, key: PropertyKey): void {
21
- let source = adm.target_
22
- while (source && source !== objectPrototype) {
23
- const descriptor = getDescriptor(source, key)
24
- if (descriptor) {
25
- assertComputedDescriptor(adm, this, key, descriptor)
26
- const definePropertyOutcome = adm.defineComputedProperty_(key, {
27
- ...this.options_,
28
- get: descriptor.get,
29
- set: descriptor.set
30
- })
31
- if (!definePropertyOutcome) {
32
- // Intercepted
33
- return
34
- }
35
- recordAnnotationApplied(adm, this, key)
36
- return
37
- }
38
- source = Object.getPrototypeOf(source)
39
- }
40
- if (!adm.target_[storedAnnotationsSymbol]?.[key]) {
41
- // Throw on missing key, except for decorators:
42
- // Decorator annotations are collected from whole prototype chain.
43
- // When called from super() some props may not exist yet.
44
- // However we don't have to worry about missing prop,
45
- // because the decorator must have been applied to something.
46
- die(1, this.annotationType_, `${adm.name_}.${key.toString()}`)
47
- }
12
+ function make_(
13
+ adm: ObservableObjectAdministration,
14
+ key: PropertyKey,
15
+ descriptor: PropertyDescriptor
16
+ ): MakeResult {
17
+ return this.extend_(adm, key, descriptor, false) === null ? MakeResult.Cancel : MakeResult.Break
48
18
  }
49
19
 
50
20
  function extend_(
@@ -64,7 +64,7 @@ const objectProxyTraps: ProxyHandler<any> = {
64
64
  ownKeys(target: IIsObservableObject): PropertyKey[] {
65
65
  if (__DEV__ && globalState.trackingDerivation)
66
66
  warnAboutProxyRequirement(
67
- "iterate keys to detect added / removed properties. Use `keys` from 'mobx' instead."
67
+ "iterate keys to detect added / removed properties. Use 'keys' from 'mobx' instead."
68
68
  )
69
69
  return getAdm(target).ownKeys_()
70
70
  },
@@ -2,15 +2,12 @@ import {
2
2
  ObservableObjectAdministration,
3
3
  Annotation,
4
4
  defineProperty,
5
- getDescriptor,
6
- objectPrototype,
7
5
  die,
8
6
  flow,
9
7
  isFlow,
10
- recordAnnotationApplied,
11
8
  isFunction,
12
9
  globalState,
13
- storedAnnotationsSymbol
10
+ MakeResult
14
11
  } from "../internal"
15
12
 
16
13
  export function createFlowAnnotation(name: string, options?: object): Annotation {
@@ -22,44 +19,31 @@ export function createFlowAnnotation(name: string, options?: object): Annotation
22
19
  }
23
20
  }
24
21
 
25
- function make_(adm: ObservableObjectAdministration, key: PropertyKey): void {
26
- let annotated = false
27
- let source = adm.target_
28
- while (source && source !== objectPrototype) {
29
- const descriptor = getDescriptor(source, key)
30
- if (descriptor) {
31
- if (source !== adm.target_) {
32
- // Prototype
33
- if (isFlow(descriptor.value)) {
34
- // A prototype could have been annotated already by other constructor,
35
- // rest of the proto chain must be annotated already
36
- annotated = true
37
- break
38
- }
39
- const flowDescriptor = createFlowDescriptor(adm, this, key, descriptor, false)
40
- defineProperty(source, key, flowDescriptor)
41
- } else {
42
- const flowDescriptor = createFlowDescriptor(adm, this, key, descriptor)
43
- const definePropertyOutcome = adm.defineProperty_(key, flowDescriptor)
44
- if (!definePropertyOutcome) {
45
- // Intercepted
46
- return
47
- }
48
- }
49
- annotated = true
50
- }
51
- source = Object.getPrototypeOf(source)
22
+ function make_(
23
+ adm: ObservableObjectAdministration,
24
+ key: PropertyKey,
25
+ descriptor: PropertyDescriptor,
26
+ source: object
27
+ ): MakeResult {
28
+ // own
29
+ if (source === adm.target_) {
30
+ return this.extend_(adm, key, descriptor, false) === null
31
+ ? MakeResult.Cancel
32
+ : MakeResult.Continue
52
33
  }
53
- if (annotated) {
54
- recordAnnotationApplied(adm, this, key)
55
- } else if (!adm.target_[storedAnnotationsSymbol]?.[key]) {
56
- // Throw on missing key, except for decorators:
57
- // Decorator annotations are collected from whole prototype chain.
58
- // When called from super() some props may not exist yet.
59
- // However we don't have to worry about missing prop,
60
- // because the decorator must have been applied to something.
61
- die(1, this.annotationType_, `${adm.name_}.${key.toString()}`)
34
+ // prototype
35
+ // 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) return MakeResult.Cancel
62
38
  }
39
+ if (isFlow(descriptor.value)) {
40
+ // A prototype could have been annotated already by other constructor,
41
+ // rest of the proto chain must be annotated already
42
+ return MakeResult.Break
43
+ }
44
+ const flowDescriptor = createFlowDescriptor(adm, this, key, descriptor, false, false)
45
+ defineProperty(source, key, flowDescriptor)
46
+ return MakeResult.Continue
63
47
  }
64
48
 
65
49
  function extend_(
@@ -68,7 +52,7 @@ function extend_(
68
52
  descriptor: PropertyDescriptor,
69
53
  proxyTrap: boolean
70
54
  ): boolean | null {
71
- const flowDescriptor = createFlowDescriptor(adm, this, key, descriptor)
55
+ const flowDescriptor = createFlowDescriptor(adm, this, key, descriptor, this.options_?.bound)
72
56
  return adm.defineProperty_(key, flowDescriptor, proxyTrap)
73
57
  }
74
58
 
@@ -91,12 +75,17 @@ function createFlowDescriptor(
91
75
  annotation: Annotation,
92
76
  key: PropertyKey,
93
77
  descriptor: PropertyDescriptor,
78
+ bound: boolean,
94
79
  // provides ability to disable safeDescriptors for prototypes
95
80
  safeDescriptors: boolean = globalState.safeDescriptors
96
81
  ): PropertyDescriptor {
97
82
  assertFlowDescriptor(adm, annotation, key, descriptor)
83
+ let { value } = descriptor
84
+ if (bound) {
85
+ value = value.bind(adm.proxy_ ?? adm.target_)
86
+ }
98
87
  return {
99
- value: flow(descriptor.value),
88
+ value: flow(value),
100
89
  // Non-configurable for classes
101
90
  // prevents accidental field redefinition in subclass
102
91
  configurable: safeDescriptors ? adm.isPlainObject_ : true,
@@ -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> {
@@ -25,7 +30,13 @@ export function deepEnhancer(v, _, name) {
25
30
  if (isPlainObject(v)) return observable.object(v, undefined, { name })
26
31
  if (isES6Map(v)) return observable.map(v, { name })
27
32
  if (isES6Set(v)) return observable.set(v, { name })
28
-
33
+ if (typeof v === "function" && !isAction(v) && !isFlow(v)) {
34
+ if (isGenerator(v)) {
35
+ return flow(v)
36
+ } else {
37
+ return autoAction(name, v)
38
+ }
39
+ }
29
40
  return v
30
41
  }
31
42
 
@@ -1,12 +1,9 @@
1
1
  import {
2
2
  ObservableObjectAdministration,
3
- getDescriptor,
4
3
  deepEnhancer,
5
4
  die,
6
5
  Annotation,
7
- recordAnnotationApplied,
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_(adm: ObservableObjectAdministration, key: PropertyKey): void {
22
- let source = adm.target_
23
- // Copy props from proto as well, see test:
24
- // "decorate should work with Object.create"
25
- while (source && source !== objectPrototype) {
26
- const descriptor = getDescriptor(source, key)
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_(
@@ -33,7 +33,6 @@ import {
33
33
  startBatch,
34
34
  stringifyKey,
35
35
  globalState,
36
- observable,
37
36
  ADD,
38
37
  UPDATE,
39
38
  die,
@@ -43,15 +42,13 @@ import {
43
42
  ownKeys,
44
43
  isOverride,
45
44
  defineProperty,
46
- inferAnnotationFromDescriptor,
47
- getDebugName,
45
+ autoAnnotation,
48
46
  getAdministration,
49
- objectPrototype
47
+ getDebugName,
48
+ objectPrototype,
49
+ MakeResult
50
50
  } from "../internal"
51
51
 
52
- // closestPrototypeofTarget[inferredAnnotationsSymbol] = new Map<PropertyKes, Annotation>()
53
- export const inferredAnnotationsSymbol = Symbol("mobx-inferred-annotations")
54
-
55
52
  const descriptorCache = Object.create(null)
56
53
 
57
54
  export type IObjectDidChange<T = any> = {
@@ -105,9 +102,7 @@ export class ObservableObjectAdministration
105
102
  public values_ = new Map<PropertyKey, ObservableValue<any> | ComputedValue<any>>(),
106
103
  public name_: string,
107
104
  // Used anytime annotation is not explicitely provided
108
- public defaultAnnotation_: Annotation = observable,
109
- // Bind automatically inferred actions?
110
- public autoBind_: boolean = false
105
+ public defaultAnnotation_: Annotation = autoAnnotation
111
106
  ) {
112
107
  this.keysAtom_ = new Atom(__DEV__ ? `${this.name_}.keys` : "ObservableObject.keys")
113
108
  // Optimization: we use this frequently
@@ -115,9 +110,6 @@ export class ObservableObjectAdministration
115
110
  if (__DEV__ && !isAnnotation(this.defaultAnnotation_)) {
116
111
  die(`defaultAnnotation must be valid annotation`)
117
112
  }
118
- if (__DEV__ && typeof this.autoBind_ !== "boolean") {
119
- die(`autoBind must be boolean`)
120
- }
121
113
  if (__DEV__) {
122
114
  // Prepare structure for tracking which fields were already annotated
123
115
  this.appliedAnnotations_ = {}
@@ -184,7 +176,7 @@ export class ObservableObjectAdministration
184
176
  /**
185
177
  * @param {PropertyKey} key
186
178
  * @param {any} value
187
- * @param {Annotation|boolean} annotation true - infer from descriptor, false - copy as is
179
+ * @param {Annotation|boolean} annotation true - use default annotation, false - copy as is
188
180
  * @param {boolean} proxyTrap whether it's called from proxy trap
189
181
  * @returns {boolean|null} true on success, false on failure (proxyTrap + non-configurable), null when cancelled by interceptor
190
182
  */
@@ -236,23 +228,45 @@ export class ObservableObjectAdministration
236
228
 
237
229
  /**
238
230
  * @param {PropertyKey} key
239
- * @param {Annotation|boolean} annotation true - infer from object or it's prototype, false - ignore
231
+ * @param {Annotation|boolean} annotation true - use default annotation, false - ignore prop
240
232
  */
241
233
  make_(key: PropertyKey, annotation: Annotation | boolean): void {
242
234
  if (annotation === true) {
243
- annotation = this.inferAnnotation_(key)
235
+ annotation = this.defaultAnnotation_
244
236
  }
245
237
  if (annotation === false) {
246
238
  return
247
239
  }
248
240
  assertAnnotable(this, annotation, key)
249
- annotation.make_(this, key)
241
+ if (!(key in this.target_)) {
242
+ // Throw on missing key, except for decorators:
243
+ // Decorator annotations are collected from whole prototype chain.
244
+ // When called from super() some props may not exist yet.
245
+ // However we don't have to worry about missing prop,
246
+ // because the decorator must have been applied to something.
247
+ if (this.target_[storedAnnotationsSymbol]?.[key]) {
248
+ return // will be annotated by subclass constructor
249
+ } else {
250
+ die(1, annotation.annotationType_, `${this.name_}.${key.toString()}`)
251
+ }
252
+ }
253
+ let source = this.target_
254
+ while (source && source !== objectPrototype) {
255
+ const descriptor = getDescriptor(source, key)
256
+ if (descriptor) {
257
+ const outcome = annotation.make_(this, key, descriptor, source)
258
+ if (outcome === MakeResult.Cancel) return
259
+ if (outcome === MakeResult.Break) break
260
+ }
261
+ source = Object.getPrototypeOf(source)
262
+ }
263
+ recordAnnotationApplied(this, annotation, key)
250
264
  }
251
265
 
252
266
  /**
253
267
  * @param {PropertyKey} key
254
268
  * @param {PropertyDescriptor} descriptor
255
- * @param {Annotation|boolean} annotation true - infer from descriptor, false - copy as is
269
+ * @param {Annotation|boolean} annotation true - use default annotation, false - copy as is
256
270
  * @param {boolean} proxyTrap whether it's called from proxy trap
257
271
  * @returns {boolean|null} true on success, false on failure (proxyTrap + non-configurable), null when cancelled by interceptor
258
272
  */
@@ -263,11 +277,7 @@ export class ObservableObjectAdministration
263
277
  proxyTrap: boolean = false
264
278
  ): boolean | null {
265
279
  if (annotation === true) {
266
- annotation = inferAnnotationFromDescriptor(
267
- descriptor,
268
- this.defaultAnnotation_,
269
- this.autoBind_
270
- )
280
+ annotation = this.defaultAnnotation_
271
281
  }
272
282
  if (annotation === false) {
273
283
  return this.defineProperty_(key, descriptor, proxyTrap)
@@ -280,44 +290,6 @@ export class ObservableObjectAdministration
280
290
  return outcome
281
291
  }
282
292
 
283
- inferAnnotation_(key: PropertyKey): Annotation | false {
284
- // Inherited is fine - annotation cannot differ in subclass
285
- let annotation = this.target_[inferredAnnotationsSymbol]?.get(key)
286
- if (annotation) return annotation
287
-
288
- let current = this.target_
289
- while (current && current !== objectPrototype) {
290
- const descriptor = getDescriptor(current, key)
291
- if (descriptor) {
292
- annotation = inferAnnotationFromDescriptor(
293
- descriptor,
294
- this.defaultAnnotation_,
295
- this.autoBind_
296
- )
297
- break
298
- }
299
- current = Object.getPrototypeOf(current)
300
- }
301
-
302
- // Not found (false means ignore)
303
- if (annotation === undefined) {
304
- die(1, "true", key)
305
- }
306
-
307
- // Cache the annotation.
308
- // Note we can do this only because annotation and field can't change.
309
- if (!this.isPlainObject_) {
310
- // We could also place it on furthest proto, shoudn't matter
311
- const closestProto = Object.getPrototypeOf(this.target_)
312
- if (!hasProp(closestProto, inferredAnnotationsSymbol)) {
313
- addHiddenProp(closestProto, inferredAnnotationsSymbol, new Map())
314
- }
315
- closestProto[inferredAnnotationsSymbol].set(key, annotation)
316
- }
317
-
318
- return annotation
319
- }
320
-
321
293
  /**
322
294
  * @param {PropertyKey} key
323
295
  * @param {PropertyDescriptor} descriptor
@@ -673,8 +645,7 @@ export function asObservableObject(
673
645
  target,
674
646
  new Map(),
675
647
  String(name),
676
- getAnnotationFromOptions(options),
677
- options?.autoBind
648
+ getAnnotationFromOptions(options)
678
649
  )
679
650
 
680
651
  addHiddenProp(target, $mobx, adm)
@@ -3,7 +3,8 @@ import {
3
3
  Annotation,
4
4
  hasProp,
5
5
  createDecoratorAnnotation,
6
- ObservableObjectAdministration
6
+ ObservableObjectAdministration,
7
+ MakeResult
7
8
  } from "../internal"
8
9
 
9
10
  const OVERRIDE = "override"
@@ -18,7 +19,7 @@ export function isOverride(annotation: Annotation): boolean {
18
19
  return annotation.annotationType_ === OVERRIDE
19
20
  }
20
21
 
21
- function make_(adm: ObservableObjectAdministration, key): void {
22
+ function make_(adm: ObservableObjectAdministration, key): MakeResult {
22
23
  // Must not be plain object
23
24
  if (__DEV__ && adm.isPlainObject_) {
24
25
  die(
@@ -33,6 +34,7 @@ function make_(adm: ObservableObjectAdministration, key): void {
33
34
  `but no such annotated member was found on prototype.`
34
35
  )
35
36
  }
37
+ return MakeResult.Cancel
36
38
  }
37
39
 
38
40
  function extend_(adm, key, descriptor, proxyTrap): boolean {