mobx 6.6.1 → 6.7.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.
@@ -3,7 +3,9 @@ export interface IKeyValueMap<V = any> {
3
3
  [key: string]: V;
4
4
  }
5
5
  export declare type IMapEntry<K = any, V = any> = [K, V];
6
+ export declare type IReadonlyMapEntry<K = any, V = any> = readonly [K, V];
6
7
  export declare type IMapEntries<K = any, V = any> = IMapEntry<K, V>[];
8
+ export declare type IReadonlyMapEntries<K = any, V = any> = IReadonlyMapEntry<K, V>[];
7
9
  export declare type IMapDidChange<K = any, V = any> = {
8
10
  observableKind: "map";
9
11
  debugObjectName: string;
@@ -32,7 +34,7 @@ export interface IMapWillChange<K = any, V = any> {
32
34
  }
33
35
  export declare const ADD = "add";
34
36
  export declare const DELETE = "delete";
35
- export declare type IObservableMapInitialValues<K = any, V = any> = IMapEntries<K, V> | IKeyValueMap<V> | Map<K, V>;
37
+ export declare type IObservableMapInitialValues<K = any, V = any> = IMapEntries<K, V> | IReadonlyMapEntries<K, V> | IKeyValueMap<V> | Map<K, V>;
36
38
  export declare class ObservableMap<K = any, V = any> implements Map<K, V>, IInterceptable<IMapWillChange<K, V>>, IListenable {
37
39
  enhancer_: IEnhancer<V>;
38
40
  name_: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mobx",
3
- "version": "6.6.1",
3
+ "version": "6.7.0",
4
4
  "description": "Simple, scalable state management.",
5
5
  "source": "src/mobx.ts",
6
6
  "main": "dist/index.js",
@@ -51,7 +51,7 @@ function assertNotDecorated(prototype: object, annotation: Annotation, key: Prop
51
51
  `Cannot apply '@${requestedAnnotationType}' to '${fieldName}':` +
52
52
  `\nThe field is already decorated with '@${currentAnnotationType}'.` +
53
53
  `\nRe-decorating fields is not allowed.` +
54
- `\nUse '@override' decorator for methods overriden by subclass.`
54
+ `\nUse '@override' decorator for methods overridden by subclass.`
55
55
  )
56
56
  }
57
57
  }
package/src/api/when.ts CHANGED
@@ -13,6 +13,7 @@ export interface IWhenOptions {
13
13
  name?: string
14
14
  timeout?: number
15
15
  onError?: (error: any) => void
16
+ signal?: AbortSignal
16
17
  }
17
18
 
18
19
  export function when(
@@ -74,14 +75,23 @@ function whenPromise(
74
75
  if (__DEV__ && opts && opts.onError) {
75
76
  return die(`the options 'onError' and 'promise' cannot be combined`)
76
77
  }
78
+ if (opts?.signal?.aborted) {
79
+ return Object.assign(Promise.reject(new Error("WHEN_ABORTED")), { cancel: () => null })
80
+ }
77
81
  let cancel
82
+ let abort
78
83
  const res = new Promise((resolve, reject) => {
79
84
  let disposer = _when(predicate, resolve as Lambda, { ...opts, onError: reject })
80
85
  cancel = () => {
81
86
  disposer()
82
87
  reject(new Error("WHEN_CANCELLED"))
83
88
  }
84
- })
89
+ abort = () => {
90
+ disposer()
91
+ reject(new Error("WHEN_ABORTED"))
92
+ }
93
+ opts?.signal?.addEventListener("abort", abort)
94
+ }).finally(() => opts?.signal?.removeEventListener("abort", abort))
85
95
  ;(res as any).cancel = cancel
86
96
  return res as any
87
97
  }
@@ -151,7 +151,7 @@ export function reportObserved(observable: IObservable): boolean {
151
151
  observable.onBO()
152
152
  }
153
153
  }
154
- return true
154
+ return observable.isBeingObserved_
155
155
  } else if (observable.observers_.size === 0 && globalState.inBatch > 0) {
156
156
  queueForUnobservation(observable)
157
157
  }
@@ -14,6 +14,21 @@ import {
14
14
  defineProperty
15
15
  } from "../internal"
16
16
 
17
+ // Bug in safari 9.* (or iOS 9 safari mobile). See #364
18
+ const ENTRY_0 = createArrayEntryDescriptor(0)
19
+
20
+ const safariPrototypeSetterInheritanceBug = (() => {
21
+ let v = false
22
+ const p = {}
23
+ Object.defineProperty(p, "0", {
24
+ set: () => {
25
+ v = true
26
+ }
27
+ })
28
+ Object.create(p)["0"] = 1
29
+ return v === false
30
+ })()
31
+
17
32
  /**
18
33
  * This array buffer contains two lists of properties, so that all arrays
19
34
  * can recycle their property definitions, which significantly improves performance of creating
@@ -57,6 +72,12 @@ class LegacyObservableArray<T> extends StubArray {
57
72
  this.spliceWithArray(0, 0, initialValues)
58
73
  allowStateChangesEnd(prev)
59
74
  }
75
+
76
+ if (safariPrototypeSetterInheritanceBug) {
77
+ // Seems that Safari won't use numeric prototype setter untill any * numeric property is
78
+ // defined on the instance. After that it works fine, even if this property is deleted.
79
+ Object.defineProperty(this, "0", ENTRY_0)
80
+ }
60
81
  }
61
82
 
62
83
  concat(...arrays: T[][]): T[] {
@@ -345,19 +345,24 @@ export class ObservableArrayAdministration
345
345
  }
346
346
 
347
347
  get_(index: number): any | undefined {
348
- if (index < this.values_.length) {
349
- this.atom_.reportObserved()
350
- return this.dehanceValue_(this.values_[index])
351
- }
352
- console.warn(
353
- __DEV__
354
- ? `[mobx] Out of bounds read: ${index}`
355
- : `[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`
356
- )
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])
357
358
  }
358
359
 
359
360
  set_(index: number, newValue: any) {
360
361
  const values = this.values_
362
+ if (this.legacyMode_ && index > values.length) {
363
+ // out of bounds
364
+ die(17, index, values.length)
365
+ }
361
366
  if (index < values.length) {
362
367
  // update at index in range
363
368
  checkIfStateModificationsAreAllowed(this.atom_)
@@ -380,12 +385,16 @@ export class ObservableArrayAdministration
380
385
  values[index] = newValue
381
386
  this.notifyArrayChildUpdate_(index, newValue, oldValue)
382
387
  }
383
- } else if (index === values.length) {
384
- // add a new item
385
- this.spliceWithArray_(index, 0, [newValue])
386
388
  } else {
387
- // out of bounds
388
- die(17, index, values.length)
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)
389
398
  }
390
399
  }
391
400
  }
@@ -43,7 +43,9 @@ export interface IKeyValueMap<V = any> {
43
43
  }
44
44
 
45
45
  export type IMapEntry<K = any, V = any> = [K, V]
46
+ export type IReadonlyMapEntry<K = any, V = any> = readonly [K, V]
46
47
  export type IMapEntries<K = any, V = any> = IMapEntry<K, V>[]
48
+ export type IReadonlyMapEntries<K = any, V = any> = IReadonlyMapEntry<K, V>[]
47
49
 
48
50
  export type IMapDidChange<K = any, V = any> = { observableKind: "map"; debugObjectName: string } & (
49
51
  | {
@@ -81,14 +83,14 @@ export const DELETE = "delete"
81
83
 
82
84
  export type IObservableMapInitialValues<K = any, V = any> =
83
85
  | IMapEntries<K, V>
86
+ | IReadonlyMapEntries<K, V>
84
87
  | IKeyValueMap<V>
85
88
  | Map<K, V>
86
89
 
87
90
  // just extend Map? See also https://gist.github.com/nestharus/13b4d74f2ef4a2f4357dbd3fc23c1e54
88
91
  // But: https://github.com/mobxjs/mobx/issues/1556
89
92
  export class ObservableMap<K = any, V = any>
90
- implements Map<K, V>, IInterceptable<IMapWillChange<K, V>>, IListenable
91
- {
93
+ implements Map<K, V>, IInterceptable<IMapWillChange<K, V>>, IListenable {
92
94
  [$mobx] = ObservableMapMarker
93
95
  data_: Map<K, ObservableValue<V>>
94
96
  hasMap_: Map<K, ObservableValue<boolean>> // hasMap, not hashMap >-).
@@ -776,7 +776,7 @@ function assertAnnotable(
776
776
  `Cannot apply '${requestedAnnotationType}' to '${fieldName}':` +
777
777
  `\nThe field is already annotated with '${currentAnnotationType}'.` +
778
778
  `\nRe-annotating fields is not allowed.` +
779
- `\nUse 'override' annotation for methods overriden by subclass.`
779
+ `\nUse 'override' annotation for methods overridden by subclass.`
780
780
  )
781
781
  }
782
782
  }