mobx 4.9.4 → 4.13.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.
@@ -0,0 +1,4322 @@
1
+ /** MobX - (c) Michel Weststrate 2015 - 2018 - MIT Licensed */
2
+ const OBFUSCATED_ERROR = "An invariant failed, however the error is obfuscated because this is an production build.";
3
+ const EMPTY_ARRAY = [];
4
+ Object.freeze(EMPTY_ARRAY);
5
+ const EMPTY_OBJECT = {};
6
+ Object.freeze(EMPTY_OBJECT);
7
+ function getGlobal() {
8
+ return typeof window !== "undefined" ? window : global;
9
+ }
10
+ function getNextId() {
11
+ return ++globalState.mobxGuid;
12
+ }
13
+ function fail(message) {
14
+ invariant(false, message);
15
+ throw "X"; // unreachable
16
+ }
17
+ function invariant(check, message) {
18
+ if (!check)
19
+ throw new Error("[mobx] " + (message || OBFUSCATED_ERROR));
20
+ }
21
+ /**
22
+ * Prints a deprecation message, but only one time.
23
+ * Returns false if the deprecated message was already printed before
24
+ */
25
+ const deprecatedMessages = [];
26
+ function deprecated(msg, thing) {
27
+ if (process.env.NODE_ENV === "production")
28
+ return false;
29
+ if (thing) {
30
+ return deprecated(`'${msg}', use '${thing}' instead.`);
31
+ }
32
+ if (deprecatedMessages.indexOf(msg) !== -1)
33
+ return false;
34
+ deprecatedMessages.push(msg);
35
+ console.error("[mobx] Deprecated: " + msg);
36
+ return true;
37
+ }
38
+ /**
39
+ * Makes sure that the provided function is invoked at most once.
40
+ */
41
+ function once(func) {
42
+ let invoked = false;
43
+ return function () {
44
+ if (invoked)
45
+ return;
46
+ invoked = true;
47
+ return func.apply(this, arguments);
48
+ };
49
+ }
50
+ const noop = () => { };
51
+ function unique(list) {
52
+ const res = [];
53
+ list.forEach(item => {
54
+ if (res.indexOf(item) === -1)
55
+ res.push(item);
56
+ });
57
+ return res;
58
+ }
59
+ function isObject(value) {
60
+ return value !== null && typeof value === "object";
61
+ }
62
+ function isPlainObject(value) {
63
+ if (value === null || typeof value !== "object")
64
+ return false;
65
+ const proto = Object.getPrototypeOf(value);
66
+ return proto === Object.prototype || proto === null;
67
+ }
68
+ function makeNonEnumerable(object, propNames) {
69
+ for (let i = 0; i < propNames.length; i++) {
70
+ addHiddenProp(object, propNames[i], object[propNames[i]]);
71
+ }
72
+ }
73
+ function addHiddenProp(object, propName, value) {
74
+ Object.defineProperty(object, propName, {
75
+ enumerable: false,
76
+ writable: true,
77
+ configurable: true,
78
+ value
79
+ });
80
+ }
81
+ function addHiddenFinalProp(object, propName, value) {
82
+ Object.defineProperty(object, propName, {
83
+ enumerable: false,
84
+ writable: false,
85
+ configurable: true,
86
+ value
87
+ });
88
+ }
89
+ function isPropertyConfigurable(object, prop) {
90
+ const descriptor = Object.getOwnPropertyDescriptor(object, prop);
91
+ return !descriptor || (descriptor.configurable !== false && descriptor.writable !== false);
92
+ }
93
+ function assertPropertyConfigurable(object, prop) {
94
+ if (process.env.NODE_ENV !== "production" && !isPropertyConfigurable(object, prop))
95
+ fail(`Cannot make property '${prop}' observable, it is not configurable and writable in the target object`);
96
+ }
97
+ function createInstanceofPredicate(name, clazz) {
98
+ const propName = "isMobX" + name;
99
+ clazz.prototype[propName] = true;
100
+ return function (x) {
101
+ return isObject(x) && x[propName] === true;
102
+ };
103
+ }
104
+ function areBothNaN(a, b) {
105
+ return typeof a === "number" && typeof b === "number" && isNaN(a) && isNaN(b);
106
+ }
107
+ /**
108
+ * Returns whether the argument is an array, disregarding observability.
109
+ */
110
+ function isArrayLike(x) {
111
+ return Array.isArray(x) || isObservableArray(x);
112
+ }
113
+ function isES6Map(thing) {
114
+ if (getGlobal().Map !== undefined && thing instanceof getGlobal().Map)
115
+ return true;
116
+ return false;
117
+ }
118
+ function isES6Set(thing) {
119
+ return thing instanceof Set;
120
+ }
121
+ function getMapLikeKeys(map) {
122
+ if (isPlainObject(map))
123
+ return Object.keys(map);
124
+ if (Array.isArray(map))
125
+ return map.map(([key]) => key);
126
+ if (isES6Map(map) || isObservableMap(map))
127
+ return iteratorToArray(map.keys());
128
+ return fail(`Cannot get keys from '${map}'`);
129
+ }
130
+ // use Array.from in Mobx 5
131
+ function iteratorToArray(it) {
132
+ const res = [];
133
+ while (true) {
134
+ const r = it.next();
135
+ if (r.done)
136
+ break;
137
+ res.push(r.value);
138
+ }
139
+ return res;
140
+ }
141
+ function primitiveSymbol() {
142
+ // es-disable-next-line
143
+ return (typeof Symbol === "function" && Symbol.toPrimitive) || "@@toPrimitive";
144
+ }
145
+ function toPrimitive(value) {
146
+ return value === null ? null : typeof value === "object" ? "" + value : value;
147
+ }
148
+
149
+ function iteratorSymbol() {
150
+ return (typeof Symbol === "function" && Symbol.iterator) || "@@iterator";
151
+ }
152
+ function declareIterator(prototType, iteratorFactory) {
153
+ addHiddenFinalProp(prototType, iteratorSymbol(), iteratorFactory);
154
+ }
155
+ function makeIterable(iterator) {
156
+ iterator[iteratorSymbol()] = self;
157
+ return iterator;
158
+ }
159
+ function toStringTagSymbol() {
160
+ return (typeof Symbol === "function" && Symbol.toStringTag) || "@@toStringTag";
161
+ }
162
+ function self() {
163
+ return this;
164
+ }
165
+
166
+ /**
167
+ * Anything that can be used to _store_ state is an Atom in mobx. Atoms have two important jobs
168
+ *
169
+ * 1) detect when they are being _used_ and report this (using reportObserved). This allows mobx to make the connection between running functions and the data they used
170
+ * 2) they should notify mobx whenever they have _changed_. This way mobx can re-run any functions (derivations) that are using this atom.
171
+ */
172
+ class Atom {
173
+ /**
174
+ * Create a new atom. For debugging purposes it is recommended to give it a name.
175
+ * The onBecomeObserved and onBecomeUnobserved callbacks can be used for resource management.
176
+ */
177
+ constructor(name = "Atom@" + getNextId()) {
178
+ this.name = name;
179
+ this.isPendingUnobservation = false; // for effective unobserving. BaseAtom has true, for extra optimization, so its onBecomeUnobserved never gets called, because it's not needed
180
+ this.isBeingObserved = false;
181
+ this.observers = [];
182
+ this.observersIndexes = {};
183
+ this.diffValue = 0;
184
+ this.lastAccessedBy = 0;
185
+ this.lowestObserverState = IDerivationState.NOT_TRACKING;
186
+ }
187
+ onBecomeUnobserved() {
188
+ // noop
189
+ }
190
+ onBecomeObserved() {
191
+ /* noop */
192
+ }
193
+ /**
194
+ * Invoke this method to notify mobx that your atom has been used somehow.
195
+ * Returns true if there is currently a reactive context.
196
+ */
197
+ reportObserved() {
198
+ return reportObserved(this);
199
+ }
200
+ /**
201
+ * Invoke this method _after_ this method has changed to signal mobx that all its observers should invalidate.
202
+ */
203
+ reportChanged() {
204
+ startBatch();
205
+ propagateChanged(this);
206
+ endBatch();
207
+ }
208
+ toString() {
209
+ return this.name;
210
+ }
211
+ }
212
+ const isAtom = createInstanceofPredicate("Atom", Atom);
213
+ function createAtom(name, onBecomeObservedHandler = noop, onBecomeUnobservedHandler = noop) {
214
+ const atom = new Atom(name);
215
+ onBecomeObserved(atom, onBecomeObservedHandler);
216
+ onBecomeUnobserved(atom, onBecomeUnobservedHandler);
217
+ return atom;
218
+ }
219
+
220
+ function identityComparer(a, b) {
221
+ return a === b;
222
+ }
223
+ function structuralComparer(a, b) {
224
+ return deepEqual(a, b);
225
+ }
226
+ function defaultComparer(a, b) {
227
+ return areBothNaN(a, b) || identityComparer(a, b);
228
+ }
229
+ const comparer = {
230
+ identity: identityComparer,
231
+ structural: structuralComparer,
232
+ default: defaultComparer
233
+ };
234
+
235
+ const enumerableDescriptorCache = {};
236
+ const nonEnumerableDescriptorCache = {};
237
+ function createPropertyInitializerDescriptor(prop, enumerable) {
238
+ const cache = enumerable ? enumerableDescriptorCache : nonEnumerableDescriptorCache;
239
+ return (cache[prop] ||
240
+ (cache[prop] = {
241
+ configurable: true,
242
+ enumerable: enumerable,
243
+ get() {
244
+ initializeInstance(this);
245
+ return this[prop];
246
+ },
247
+ set(value) {
248
+ initializeInstance(this);
249
+ this[prop] = value;
250
+ }
251
+ }));
252
+ }
253
+ function initializeInstance(target) {
254
+ if (target.__mobxDidRunLazyInitializers === true)
255
+ return;
256
+ const decorators = target.__mobxDecorators;
257
+ if (decorators) {
258
+ addHiddenProp(target, "__mobxDidRunLazyInitializers", true);
259
+ for (let key in decorators) {
260
+ const d = decorators[key];
261
+ d.propertyCreator(target, d.prop, d.descriptor, d.decoratorTarget, d.decoratorArguments);
262
+ }
263
+ }
264
+ }
265
+ function createPropDecorator(propertyInitiallyEnumerable, propertyCreator) {
266
+ return function decoratorFactory() {
267
+ let decoratorArguments;
268
+ const decorator = function decorate(target, prop, descriptor, applyImmediately
269
+ // This is a special parameter to signal the direct application of a decorator, allow extendObservable to skip the entire type decoration part,
270
+ // as the instance to apply the decorator to equals the target
271
+ ) {
272
+ if (applyImmediately === true) {
273
+ propertyCreator(target, prop, descriptor, target, decoratorArguments);
274
+ return null;
275
+ }
276
+ if (process.env.NODE_ENV !== "production" && !quacksLikeADecorator(arguments))
277
+ fail("This function is a decorator, but it wasn't invoked like a decorator");
278
+ if (!Object.prototype.hasOwnProperty.call(target, "__mobxDecorators")) {
279
+ const inheritedDecorators = target.__mobxDecorators;
280
+ addHiddenProp(target, "__mobxDecorators", Object.assign({}, inheritedDecorators));
281
+ }
282
+ target.__mobxDecorators[prop] = {
283
+ prop,
284
+ propertyCreator,
285
+ descriptor,
286
+ decoratorTarget: target,
287
+ decoratorArguments
288
+ };
289
+ return createPropertyInitializerDescriptor(prop, propertyInitiallyEnumerable);
290
+ };
291
+ if (quacksLikeADecorator(arguments)) {
292
+ // @decorator
293
+ decoratorArguments = EMPTY_ARRAY;
294
+ return decorator.apply(null, arguments);
295
+ }
296
+ else {
297
+ // @decorator(args)
298
+ decoratorArguments = Array.prototype.slice.call(arguments);
299
+ return decorator;
300
+ }
301
+ };
302
+ }
303
+ function quacksLikeADecorator(args) {
304
+ return (((args.length === 2 || args.length === 3) && typeof args[1] === "string") ||
305
+ (args.length === 4 && args[3] === true));
306
+ }
307
+
308
+ function deepEnhancer(v, _, name) {
309
+ // it is an observable already, done
310
+ if (isObservable(v))
311
+ return v;
312
+ // something that can be converted and mutated?
313
+ if (Array.isArray(v))
314
+ return observable.array(v, { name });
315
+ if (isPlainObject(v))
316
+ return observable.object(v, undefined, { name });
317
+ if (isES6Map(v))
318
+ return observable.map(v, { name });
319
+ if (isES6Set(v))
320
+ return observable.set(v, { name });
321
+ return v;
322
+ }
323
+ function shallowEnhancer(v, _, name) {
324
+ if (v === undefined || v === null)
325
+ return v;
326
+ if (isObservableObject(v) || isObservableArray(v) || isObservableMap(v) || isObservableSet(v))
327
+ return v;
328
+ if (Array.isArray(v))
329
+ return observable.array(v, { name, deep: false });
330
+ if (isPlainObject(v))
331
+ return observable.object(v, undefined, { name, deep: false });
332
+ if (isES6Map(v))
333
+ return observable.map(v, { name, deep: false });
334
+ if (isES6Set(v))
335
+ return observable.set(v, { name, deep: false });
336
+ return fail(process.env.NODE_ENV !== "production" &&
337
+ "The shallow modifier / decorator can only used in combination with arrays, objects, maps and sets");
338
+ }
339
+ function referenceEnhancer(newValue) {
340
+ // never turn into an observable
341
+ return newValue;
342
+ }
343
+ function refStructEnhancer(v, oldValue, name) {
344
+ if (process.env.NODE_ENV !== "production" && isObservable(v))
345
+ throw `observable.struct should not be used with observable values`;
346
+ if (deepEqual(v, oldValue))
347
+ return oldValue;
348
+ return v;
349
+ }
350
+
351
+ function createDecoratorForEnhancer(enhancer) {
352
+ const decorator = createPropDecorator(true, (target, propertyName, descriptor, _decoratorTarget, decoratorArgs) => {
353
+ if (process.env.NODE_ENV !== "production") {
354
+ invariant(!descriptor || !descriptor.get, `@observable cannot be used on getter (property "${propertyName}"), use @computed instead.`);
355
+ }
356
+ const initialValue = descriptor
357
+ ? descriptor.initializer
358
+ ? descriptor.initializer.call(target)
359
+ : descriptor.value
360
+ : undefined;
361
+ defineObservableProperty(target, propertyName, initialValue, enhancer);
362
+ });
363
+ const res =
364
+ // Extra process checks, as this happens during module initialization
365
+ typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production"
366
+ ? function observableDecorator() {
367
+ // This wrapper function is just to detect illegal decorator invocations, deprecate in a next version
368
+ // and simply return the created prop decorator
369
+ if (arguments.length < 2)
370
+ return fail("Incorrect decorator invocation. @observable decorator doesn't expect any arguments");
371
+ return decorator.apply(null, arguments);
372
+ }
373
+ : decorator;
374
+ res.enhancer = enhancer;
375
+ return res;
376
+ }
377
+
378
+ // Predefined bags of create observable options, to avoid allocating temporarily option objects
379
+ // in the majority of cases
380
+ const defaultCreateObservableOptions = {
381
+ deep: true,
382
+ name: undefined,
383
+ defaultDecorator: undefined
384
+ };
385
+ const shallowCreateObservableOptions = {
386
+ deep: false,
387
+ name: undefined,
388
+ defaultDecorator: undefined
389
+ };
390
+ Object.freeze(defaultCreateObservableOptions);
391
+ Object.freeze(shallowCreateObservableOptions);
392
+ function assertValidOption(key) {
393
+ if (!/^(deep|name|equals|defaultDecorator)$/.test(key))
394
+ fail(`invalid option for (extend)observable: ${key}`);
395
+ }
396
+ function asCreateObservableOptions(thing) {
397
+ if (thing === null || thing === undefined)
398
+ return defaultCreateObservableOptions;
399
+ if (typeof thing === "string")
400
+ return { name: thing, deep: true };
401
+ if (process.env.NODE_ENV !== "production") {
402
+ if (typeof thing !== "object")
403
+ return fail("expected options object");
404
+ Object.keys(thing).forEach(assertValidOption);
405
+ }
406
+ return thing;
407
+ }
408
+ function getEnhancerFromOptions(options) {
409
+ return options.defaultDecorator
410
+ ? options.defaultDecorator.enhancer
411
+ : options.deep === false
412
+ ? referenceEnhancer
413
+ : deepEnhancer;
414
+ }
415
+ const deepDecorator = createDecoratorForEnhancer(deepEnhancer);
416
+ const shallowDecorator = createDecoratorForEnhancer(shallowEnhancer);
417
+ const refDecorator = createDecoratorForEnhancer(referenceEnhancer);
418
+ const refStructDecorator = createDecoratorForEnhancer(refStructEnhancer);
419
+ /**
420
+ * Turns an object, array or function into a reactive structure.
421
+ * @param v the value which should become observable.
422
+ */
423
+ function createObservable(v, arg2, arg3) {
424
+ // @observable someProp;
425
+ if (typeof arguments[1] === "string") {
426
+ return deepDecorator.apply(null, arguments);
427
+ }
428
+ // it is an observable already, done
429
+ if (isObservable(v))
430
+ return v;
431
+ // something that can be converted and mutated?
432
+ const res = isPlainObject(v)
433
+ ? observable.object(v, arg2, arg3)
434
+ : Array.isArray(v)
435
+ ? observable.array(v, arg2)
436
+ : isES6Map(v)
437
+ ? observable.map(v, arg2)
438
+ : isES6Set(v)
439
+ ? observable.set(v, arg2)
440
+ : v;
441
+ // this value could be converted to a new observable data structure, return it
442
+ if (res !== v)
443
+ return res;
444
+ // otherwise, just box it
445
+ fail(process.env.NODE_ENV !== "production" &&
446
+ `The provided value could not be converted into an observable. If you want just create an observable reference to the object use 'observable.box(value)'`);
447
+ }
448
+ const observableFactories = {
449
+ box(value, options) {
450
+ if (arguments.length > 2)
451
+ incorrectlyUsedAsDecorator("box");
452
+ const o = asCreateObservableOptions(options);
453
+ return new ObservableValue(value, getEnhancerFromOptions(o), o.name, true, o.equals);
454
+ },
455
+ shallowBox(value, name) {
456
+ if (arguments.length > 2)
457
+ incorrectlyUsedAsDecorator("shallowBox");
458
+ deprecated(`observable.shallowBox`, `observable.box(value, { deep: false })`);
459
+ return observable.box(value, { name, deep: false });
460
+ },
461
+ array(initialValues, options) {
462
+ if (arguments.length > 2)
463
+ incorrectlyUsedAsDecorator("array");
464
+ const o = asCreateObservableOptions(options);
465
+ return new ObservableArray(initialValues, getEnhancerFromOptions(o), o.name);
466
+ },
467
+ shallowArray(initialValues, name) {
468
+ if (arguments.length > 2)
469
+ incorrectlyUsedAsDecorator("shallowArray");
470
+ deprecated(`observable.shallowArray`, `observable.array(values, { deep: false })`);
471
+ return observable.array(initialValues, { name, deep: false });
472
+ },
473
+ map(initialValues, options) {
474
+ if (arguments.length > 2)
475
+ incorrectlyUsedAsDecorator("map");
476
+ const o = asCreateObservableOptions(options);
477
+ return new ObservableMap(initialValues, getEnhancerFromOptions(o), o.name);
478
+ },
479
+ shallowMap(initialValues, name) {
480
+ if (arguments.length > 2)
481
+ incorrectlyUsedAsDecorator("shallowMap");
482
+ deprecated(`observable.shallowMap`, `observable.map(values, { deep: false })`);
483
+ return observable.map(initialValues, { name, deep: false });
484
+ },
485
+ set(initialValues, options) {
486
+ if (arguments.length > 2)
487
+ incorrectlyUsedAsDecorator("set");
488
+ const o = asCreateObservableOptions(options);
489
+ return new ObservableSet(initialValues, getEnhancerFromOptions(o), o.name);
490
+ },
491
+ object(props, decorators, options) {
492
+ if (typeof arguments[1] === "string")
493
+ incorrectlyUsedAsDecorator("object");
494
+ const o = asCreateObservableOptions(options);
495
+ return extendObservable({}, props, decorators, o);
496
+ },
497
+ shallowObject(props, name) {
498
+ if (typeof arguments[1] === "string")
499
+ incorrectlyUsedAsDecorator("shallowObject");
500
+ deprecated(`observable.shallowObject`, `observable.object(values, {}, { deep: false })`);
501
+ return observable.object(props, {}, { name, deep: false });
502
+ },
503
+ ref: refDecorator,
504
+ shallow: shallowDecorator,
505
+ deep: deepDecorator,
506
+ struct: refStructDecorator
507
+ };
508
+ const observable = createObservable;
509
+ // weird trick to keep our typings nicely with our funcs, and still extend the observable function
510
+ Object.keys(observableFactories).forEach(name => (observable[name] = observableFactories[name]));
511
+ function incorrectlyUsedAsDecorator(methodName) {
512
+ fail(
513
+ // process.env.NODE_ENV !== "production" &&
514
+ `Expected one or two arguments to observable.${methodName}. Did you accidentally try to use observable.${methodName} as decorator?`);
515
+ }
516
+
517
+ const computedDecorator = createPropDecorator(false, (instance, propertyName, descriptor, decoratorTarget, decoratorArgs) => {
518
+ const { get, set } = descriptor; // initialValue is the descriptor for get / set props
519
+ // Optimization: faster on decorator target or instance? Assuming target
520
+ // Optimization: find out if declaring on instance isn't just faster. (also makes the property descriptor simpler). But, more memory usage..
521
+ // Forcing instance now, fixes hot reloadig issues on React Native:
522
+ const options = decoratorArgs[0] || {};
523
+ defineComputedProperty(instance, propertyName, Object.assign({ get, set }, options));
524
+ });
525
+ const computedStructDecorator = computedDecorator({ equals: comparer.structural });
526
+ /**
527
+ * Decorator for class properties: @computed get value() { return expr; }.
528
+ * For legacy purposes also invokable as ES5 observable created: `computed(() => expr)`;
529
+ */
530
+ const computed = function computed(arg1, arg2, arg3) {
531
+ if (typeof arg2 === "string") {
532
+ // @computed
533
+ return computedDecorator.apply(null, arguments);
534
+ }
535
+ if (arg1 !== null && typeof arg1 === "object" && arguments.length === 1) {
536
+ // @computed({ options })
537
+ return computedDecorator.apply(null, arguments);
538
+ }
539
+ // computed(expr, options?)
540
+ if (process.env.NODE_ENV !== "production") {
541
+ invariant(typeof arg1 === "function", "First argument to `computed` should be an expression.");
542
+ invariant(arguments.length < 3, "Computed takes one or two arguments if used as function");
543
+ }
544
+ const opts = typeof arg2 === "object" ? arg2 : {};
545
+ opts.get = arg1;
546
+ opts.set = typeof arg2 === "function" ? arg2 : opts.set;
547
+ opts.name = opts.name || arg1.name || ""; /* for generated name */
548
+ return new ComputedValue(opts);
549
+ };
550
+ computed.struct = computedStructDecorator;
551
+
552
+ function createAction(actionName, fn) {
553
+ if (process.env.NODE_ENV !== "production") {
554
+ invariant(typeof fn === "function", "`action` can only be invoked on functions");
555
+ if (typeof actionName !== "string" || !actionName)
556
+ fail(`actions should have valid names, got: '${actionName}'`);
557
+ }
558
+ const res = function () {
559
+ return executeAction(actionName, fn, this, arguments);
560
+ };
561
+ res.isMobxAction = true;
562
+ return res;
563
+ }
564
+ function executeAction(actionName, fn, scope, args) {
565
+ const runInfo = startAction(actionName, fn, scope, args);
566
+ let shouldSupressReactionError = true;
567
+ try {
568
+ const res = fn.apply(scope, args);
569
+ shouldSupressReactionError = false;
570
+ return res;
571
+ }
572
+ finally {
573
+ if (shouldSupressReactionError) {
574
+ globalState.suppressReactionErrors = shouldSupressReactionError;
575
+ endAction(runInfo);
576
+ globalState.suppressReactionErrors = false;
577
+ }
578
+ else {
579
+ endAction(runInfo);
580
+ }
581
+ }
582
+ }
583
+ function startAction(actionName, fn, scope, args) {
584
+ const notifySpy = isSpyEnabled() && !!actionName;
585
+ let startTime = 0;
586
+ if (notifySpy) {
587
+ startTime = Date.now();
588
+ const l = (args && args.length) || 0;
589
+ const flattendArgs = new Array(l);
590
+ if (l > 0)
591
+ for (let i = 0; i < l; i++)
592
+ flattendArgs[i] = args[i];
593
+ spyReportStart({
594
+ type: "action",
595
+ name: actionName,
596
+ object: scope,
597
+ arguments: flattendArgs
598
+ });
599
+ }
600
+ const prevDerivation = untrackedStart();
601
+ startBatch();
602
+ const prevAllowStateChanges = allowStateChangesStart(true);
603
+ return {
604
+ prevDerivation,
605
+ prevAllowStateChanges,
606
+ notifySpy,
607
+ startTime
608
+ };
609
+ }
610
+ function endAction(runInfo) {
611
+ allowStateChangesEnd(runInfo.prevAllowStateChanges);
612
+ endBatch();
613
+ untrackedEnd(runInfo.prevDerivation);
614
+ if (runInfo.notifySpy)
615
+ spyReportEnd({ time: Date.now() - runInfo.startTime });
616
+ }
617
+ function allowStateChanges(allowStateChanges, func) {
618
+ const prev = allowStateChangesStart(allowStateChanges);
619
+ let res;
620
+ try {
621
+ res = func();
622
+ }
623
+ finally {
624
+ allowStateChangesEnd(prev);
625
+ }
626
+ return res;
627
+ }
628
+ function allowStateChangesStart(allowStateChanges) {
629
+ const prev = globalState.allowStateChanges;
630
+ globalState.allowStateChanges = allowStateChanges;
631
+ return prev;
632
+ }
633
+ function allowStateChangesEnd(prev) {
634
+ globalState.allowStateChanges = prev;
635
+ }
636
+ function allowStateChangesInsideComputed(func) {
637
+ const prev = globalState.computationDepth;
638
+ globalState.computationDepth = 0;
639
+ let res;
640
+ try {
641
+ res = func();
642
+ }
643
+ finally {
644
+ globalState.computationDepth = prev;
645
+ }
646
+ return res;
647
+ }
648
+
649
+ class ObservableValue extends Atom {
650
+ constructor(value, enhancer, name = "ObservableValue@" + getNextId(), notifySpy = true, equals = comparer.default) {
651
+ super(name);
652
+ this.enhancer = enhancer;
653
+ this.name = name;
654
+ this.equals = equals;
655
+ this.hasUnreportedChange = false;
656
+ this.value = enhancer(value, undefined, name);
657
+ if (notifySpy && isSpyEnabled()) {
658
+ // only notify spy if this is a stand-alone observable
659
+ spyReport({ type: "create", name: this.name, newValue: "" + this.value });
660
+ }
661
+ }
662
+ dehanceValue(value) {
663
+ if (this.dehancer !== undefined)
664
+ return this.dehancer(value);
665
+ return value;
666
+ }
667
+ set(newValue) {
668
+ const oldValue = this.value;
669
+ newValue = this.prepareNewValue(newValue);
670
+ if (newValue !== globalState.UNCHANGED) {
671
+ const notifySpy = isSpyEnabled();
672
+ if (notifySpy) {
673
+ spyReportStart({
674
+ type: "update",
675
+ name: this.name,
676
+ newValue,
677
+ oldValue
678
+ });
679
+ }
680
+ this.setNewValue(newValue);
681
+ if (notifySpy)
682
+ spyReportEnd();
683
+ }
684
+ }
685
+ prepareNewValue(newValue) {
686
+ checkIfStateModificationsAreAllowed(this);
687
+ if (hasInterceptors(this)) {
688
+ const change = interceptChange(this, {
689
+ object: this,
690
+ type: "update",
691
+ newValue
692
+ });
693
+ if (!change)
694
+ return globalState.UNCHANGED;
695
+ newValue = change.newValue;
696
+ }
697
+ // apply modifier
698
+ newValue = this.enhancer(newValue, this.value, this.name);
699
+ return this.equals(this.value, newValue) ? globalState.UNCHANGED : newValue;
700
+ }
701
+ setNewValue(newValue) {
702
+ const oldValue = this.value;
703
+ this.value = newValue;
704
+ this.reportChanged();
705
+ if (hasListeners(this)) {
706
+ notifyListeners(this, {
707
+ type: "update",
708
+ object: this,
709
+ newValue,
710
+ oldValue
711
+ });
712
+ }
713
+ }
714
+ get() {
715
+ this.reportObserved();
716
+ return this.dehanceValue(this.value);
717
+ }
718
+ intercept(handler) {
719
+ return registerInterceptor(this, handler);
720
+ }
721
+ observe(listener, fireImmediately) {
722
+ if (fireImmediately)
723
+ listener({
724
+ object: this,
725
+ type: "update",
726
+ newValue: this.value,
727
+ oldValue: undefined
728
+ });
729
+ return registerListener(this, listener);
730
+ }
731
+ toJSON() {
732
+ return this.get();
733
+ }
734
+ toString() {
735
+ return `${this.name}[${this.value}]`;
736
+ }
737
+ valueOf() {
738
+ return toPrimitive(this.get());
739
+ }
740
+ }
741
+ ObservableValue.prototype[primitiveSymbol()] = ObservableValue.prototype.valueOf;
742
+ const isObservableValue = createInstanceofPredicate("ObservableValue", ObservableValue);
743
+
744
+ /**
745
+ * A node in the state dependency root that observes other nodes, and can be observed itself.
746
+ *
747
+ * ComputedValue will remember the result of the computation for the duration of the batch, or
748
+ * while being observed.
749
+ *
750
+ * During this time it will recompute only when one of its direct dependencies changed,
751
+ * but only when it is being accessed with `ComputedValue.get()`.
752
+ *
753
+ * Implementation description:
754
+ * 1. First time it's being accessed it will compute and remember result
755
+ * give back remembered result until 2. happens
756
+ * 2. First time any deep dependency change, propagate POSSIBLY_STALE to all observers, wait for 3.
757
+ * 3. When it's being accessed, recompute if any shallow dependency changed.
758
+ * if result changed: propagate STALE to all observers, that were POSSIBLY_STALE from the last step.
759
+ * go to step 2. either way
760
+ *
761
+ * If at any point it's outside batch and it isn't observed: reset everything and go to 1.
762
+ */
763
+ class ComputedValue {
764
+ /**
765
+ * Create a new computed value based on a function expression.
766
+ *
767
+ * The `name` property is for debug purposes only.
768
+ *
769
+ * The `equals` property specifies the comparer function to use to determine if a newly produced
770
+ * value differs from the previous value. Two comparers are provided in the library; `defaultComparer`
771
+ * compares based on identity comparison (===), and `structualComparer` deeply compares the structure.
772
+ * Structural comparison can be convenient if you always produce a new aggregated object and
773
+ * don't want to notify observers if it is structurally the same.
774
+ * This is useful for working with vectors, mouse coordinates etc.
775
+ */
776
+ constructor(options) {
777
+ this.dependenciesState = IDerivationState.NOT_TRACKING;
778
+ this.observing = []; // nodes we are looking at. Our value depends on these nodes
779
+ this.newObserving = null; // during tracking it's an array with new observed observers
780
+ this.isBeingObserved = false;
781
+ this.isPendingUnobservation = false;
782
+ this.observers = [];
783
+ this.observersIndexes = {};
784
+ this.diffValue = 0;
785
+ this.runId = 0;
786
+ this.lastAccessedBy = 0;
787
+ this.lowestObserverState = IDerivationState.UP_TO_DATE;
788
+ this.unboundDepsCount = 0;
789
+ this.__mapid = "#" + getNextId();
790
+ this.value = new CaughtException(null);
791
+ this.isComputing = false; // to check for cycles
792
+ this.isRunningSetter = false;
793
+ this.isTracing = TraceMode.NONE;
794
+ if (process.env.NODE_ENV !== "production" && !options.get)
795
+ return fail("missing option for computed: get");
796
+ this.derivation = options.get;
797
+ this.name = options.name || "ComputedValue@" + getNextId();
798
+ if (options.set)
799
+ this.setter = createAction(this.name + "-setter", options.set);
800
+ this.equals =
801
+ options.equals ||
802
+ (options.compareStructural || options.struct
803
+ ? comparer.structural
804
+ : comparer.default);
805
+ this.scope = options.context;
806
+ this.requiresReaction = !!options.requiresReaction;
807
+ this.keepAlive = !!options.keepAlive;
808
+ }
809
+ onBecomeStale() {
810
+ propagateMaybeChanged(this);
811
+ }
812
+ onBecomeUnobserved() { }
813
+ onBecomeObserved() { }
814
+ /**
815
+ * Returns the current value of this computed value.
816
+ * Will evaluate its computation first if needed.
817
+ */
818
+ get() {
819
+ if (this.isComputing)
820
+ fail(`Cycle detected in computation ${this.name}: ${this.derivation}`);
821
+ if (globalState.inBatch === 0 && this.observers.length === 0 && !this.keepAlive) {
822
+ if (shouldCompute(this)) {
823
+ this.warnAboutUntrackedRead();
824
+ startBatch(); // See perf test 'computed memoization'
825
+ this.value = this.computeValue(false);
826
+ endBatch();
827
+ }
828
+ }
829
+ else {
830
+ reportObserved(this);
831
+ if (shouldCompute(this))
832
+ if (this.trackAndCompute())
833
+ propagateChangeConfirmed(this);
834
+ }
835
+ const result = this.value;
836
+ if (isCaughtException(result))
837
+ throw result.cause;
838
+ return result;
839
+ }
840
+ peek() {
841
+ const res = this.computeValue(false);
842
+ if (isCaughtException(res))
843
+ throw res.cause;
844
+ return res;
845
+ }
846
+ set(value) {
847
+ if (this.setter) {
848
+ invariant(!this.isRunningSetter, `The setter of computed value '${this.name}' is trying to update itself. Did you intend to update an _observable_ value, instead of the computed property?`);
849
+ this.isRunningSetter = true;
850
+ try {
851
+ this.setter.call(this.scope, value);
852
+ }
853
+ finally {
854
+ this.isRunningSetter = false;
855
+ }
856
+ }
857
+ else
858
+ invariant(false, process.env.NODE_ENV !== "production" &&
859
+ `[ComputedValue '${this.name}'] It is not possible to assign a new value to a computed value.`);
860
+ }
861
+ trackAndCompute() {
862
+ if (isSpyEnabled()) {
863
+ spyReport({
864
+ object: this.scope,
865
+ type: "compute",
866
+ name: this.name
867
+ });
868
+ }
869
+ const oldValue = this.value;
870
+ const wasSuspended =
871
+ /* see #1208 */ this.dependenciesState === IDerivationState.NOT_TRACKING;
872
+ const newValue = this.computeValue(true);
873
+ const changed = wasSuspended ||
874
+ isCaughtException(oldValue) ||
875
+ isCaughtException(newValue) ||
876
+ !this.equals(oldValue, newValue);
877
+ if (changed) {
878
+ this.value = newValue;
879
+ }
880
+ return changed;
881
+ }
882
+ computeValue(track) {
883
+ this.isComputing = true;
884
+ globalState.computationDepth++;
885
+ let res;
886
+ if (track) {
887
+ res = trackDerivedFunction(this, this.derivation, this.scope);
888
+ }
889
+ else {
890
+ if (globalState.disableErrorBoundaries === true) {
891
+ res = this.derivation.call(this.scope);
892
+ }
893
+ else {
894
+ try {
895
+ res = this.derivation.call(this.scope);
896
+ }
897
+ catch (e) {
898
+ res = new CaughtException(e);
899
+ }
900
+ }
901
+ }
902
+ globalState.computationDepth--;
903
+ this.isComputing = false;
904
+ return res;
905
+ }
906
+ suspend() {
907
+ if (!this.keepAlive) {
908
+ clearObserving(this);
909
+ this.value = undefined; // don't hold on to computed value!
910
+ }
911
+ }
912
+ observe(listener, fireImmediately) {
913
+ let firstTime = true;
914
+ let prevValue = undefined;
915
+ return autorun(() => {
916
+ let newValue = this.get();
917
+ if (!firstTime || fireImmediately) {
918
+ const prevU = untrackedStart();
919
+ listener({
920
+ type: "update",
921
+ object: this,
922
+ newValue,
923
+ oldValue: prevValue
924
+ });
925
+ untrackedEnd(prevU);
926
+ }
927
+ firstTime = false;
928
+ prevValue = newValue;
929
+ });
930
+ }
931
+ warnAboutUntrackedRead() {
932
+ if (process.env.NODE_ENV === "production")
933
+ return;
934
+ if (this.requiresReaction === true) {
935
+ fail(`[mobx] Computed value ${this.name} is read outside a reactive context`);
936
+ }
937
+ if (this.isTracing !== TraceMode.NONE) {
938
+ console.log(`[mobx.trace] '${this.name}' is being read outside a reactive context. Doing a full recompute`);
939
+ }
940
+ if (globalState.computedRequiresReaction) {
941
+ console.warn(`[mobx] Computed value ${this.name} is being read outside a reactive context. Doing a full recompute`);
942
+ }
943
+ }
944
+ toJSON() {
945
+ return this.get();
946
+ }
947
+ toString() {
948
+ return `${this.name}[${this.derivation.toString()}]`;
949
+ }
950
+ valueOf() {
951
+ return toPrimitive(this.get());
952
+ }
953
+ }
954
+ ComputedValue.prototype[primitiveSymbol()] = ComputedValue.prototype.valueOf;
955
+ const isComputedValue = createInstanceofPredicate("ComputedValue", ComputedValue);
956
+
957
+ var IDerivationState;
958
+ (function (IDerivationState) {
959
+ // before being run or (outside batch and not being observed)
960
+ // at this point derivation is not holding any data about dependency tree
961
+ IDerivationState[IDerivationState["NOT_TRACKING"] = -1] = "NOT_TRACKING";
962
+ // no shallow dependency changed since last computation
963
+ // won't recalculate derivation
964
+ // this is what makes mobx fast
965
+ IDerivationState[IDerivationState["UP_TO_DATE"] = 0] = "UP_TO_DATE";
966
+ // some deep dependency changed, but don't know if shallow dependency changed
967
+ // will require to check first if UP_TO_DATE or POSSIBLY_STALE
968
+ // currently only ComputedValue will propagate POSSIBLY_STALE
969
+ //
970
+ // having this state is second big optimization:
971
+ // don't have to recompute on every dependency change, but only when it's needed
972
+ IDerivationState[IDerivationState["POSSIBLY_STALE"] = 1] = "POSSIBLY_STALE";
973
+ // A shallow dependency has changed since last computation and the derivation
974
+ // will need to recompute when it's needed next.
975
+ IDerivationState[IDerivationState["STALE"] = 2] = "STALE";
976
+ })(IDerivationState || (IDerivationState = {}));
977
+ var TraceMode;
978
+ (function (TraceMode) {
979
+ TraceMode[TraceMode["NONE"] = 0] = "NONE";
980
+ TraceMode[TraceMode["LOG"] = 1] = "LOG";
981
+ TraceMode[TraceMode["BREAK"] = 2] = "BREAK";
982
+ })(TraceMode || (TraceMode = {}));
983
+ class CaughtException {
984
+ constructor(cause) {
985
+ this.cause = cause;
986
+ // Empty
987
+ }
988
+ }
989
+ function isCaughtException(e) {
990
+ return e instanceof CaughtException;
991
+ }
992
+ /**
993
+ * Finds out whether any dependency of the derivation has actually changed.
994
+ * If dependenciesState is 1 then it will recalculate dependencies,
995
+ * if any dependency changed it will propagate it by changing dependenciesState to 2.
996
+ *
997
+ * By iterating over the dependencies in the same order that they were reported and
998
+ * stopping on the first change, all the recalculations are only called for ComputedValues
999
+ * that will be tracked by derivation. That is because we assume that if the first x
1000
+ * dependencies of the derivation doesn't change then the derivation should run the same way
1001
+ * up until accessing x-th dependency.
1002
+ */
1003
+ function shouldCompute(derivation) {
1004
+ switch (derivation.dependenciesState) {
1005
+ case IDerivationState.UP_TO_DATE:
1006
+ return false;
1007
+ case IDerivationState.NOT_TRACKING:
1008
+ case IDerivationState.STALE:
1009
+ return true;
1010
+ case IDerivationState.POSSIBLY_STALE: {
1011
+ const prevUntracked = untrackedStart(); // no need for those computeds to be reported, they will be picked up in trackDerivedFunction.
1012
+ const obs = derivation.observing, l = obs.length;
1013
+ for (let i = 0; i < l; i++) {
1014
+ const obj = obs[i];
1015
+ if (isComputedValue(obj)) {
1016
+ if (globalState.disableErrorBoundaries) {
1017
+ obj.get();
1018
+ }
1019
+ else {
1020
+ try {
1021
+ obj.get();
1022
+ }
1023
+ catch (e) {
1024
+ // we are not interested in the value *or* exception at this moment, but if there is one, notify all
1025
+ untrackedEnd(prevUntracked);
1026
+ return true;
1027
+ }
1028
+ }
1029
+ // if ComputedValue `obj` actually changed it will be computed and propagated to its observers.
1030
+ // and `derivation` is an observer of `obj`
1031
+ // invariantShouldCompute(derivation)
1032
+ if (derivation.dependenciesState === IDerivationState.STALE) {
1033
+ untrackedEnd(prevUntracked);
1034
+ return true;
1035
+ }
1036
+ }
1037
+ }
1038
+ changeDependenciesStateTo0(derivation);
1039
+ untrackedEnd(prevUntracked);
1040
+ return false;
1041
+ }
1042
+ }
1043
+ }
1044
+ // function invariantShouldCompute(derivation: IDerivation) {
1045
+ // const newDepState = (derivation as any).dependenciesState
1046
+ // if (
1047
+ // process.env.NODE_ENV === "production" &&
1048
+ // (newDepState === IDerivationState.POSSIBLY_STALE ||
1049
+ // newDepState === IDerivationState.NOT_TRACKING)
1050
+ // )
1051
+ // fail("Illegal dependency state")
1052
+ // }
1053
+ function isComputingDerivation() {
1054
+ return globalState.trackingDerivation !== null; // filter out actions inside computations
1055
+ }
1056
+ function checkIfStateModificationsAreAllowed(atom) {
1057
+ const hasObservers = atom.observers.length > 0;
1058
+ // Should never be possible to change an observed observable from inside computed, see #798
1059
+ if (globalState.computationDepth > 0 && hasObservers)
1060
+ fail(process.env.NODE_ENV !== "production" &&
1061
+ `Computed values are not allowed to cause side effects by changing observables that are already being observed. Tried to modify: ${atom.name}`);
1062
+ // Should not be possible to change observed state outside strict mode, except during initialization, see #563
1063
+ if (!globalState.allowStateChanges && (hasObservers || globalState.enforceActions === "strict"))
1064
+ fail(process.env.NODE_ENV !== "production" &&
1065
+ (globalState.enforceActions
1066
+ ? "Since strict-mode is enabled, changing observed observable values outside actions is not allowed. Please wrap the code in an `action` if this change is intended. Tried to modify: "
1067
+ : "Side effects like changing state are not allowed at this point. Are you trying to modify state from, for example, the render function of a React component? Tried to modify: ") +
1068
+ atom.name);
1069
+ }
1070
+ /**
1071
+ * Executes the provided function `f` and tracks which observables are being accessed.
1072
+ * The tracking information is stored on the `derivation` object and the derivation is registered
1073
+ * as observer of any of the accessed observables.
1074
+ */
1075
+ function trackDerivedFunction(derivation, f, context) {
1076
+ // pre allocate array allocation + room for variation in deps
1077
+ // array will be trimmed by bindDependencies
1078
+ changeDependenciesStateTo0(derivation);
1079
+ derivation.newObserving = new Array(derivation.observing.length + 100);
1080
+ derivation.unboundDepsCount = 0;
1081
+ derivation.runId = ++globalState.runId;
1082
+ const prevTracking = globalState.trackingDerivation;
1083
+ globalState.trackingDerivation = derivation;
1084
+ let result;
1085
+ if (globalState.disableErrorBoundaries === true) {
1086
+ result = f.call(context);
1087
+ }
1088
+ else {
1089
+ try {
1090
+ result = f.call(context);
1091
+ }
1092
+ catch (e) {
1093
+ result = new CaughtException(e);
1094
+ }
1095
+ }
1096
+ globalState.trackingDerivation = prevTracking;
1097
+ bindDependencies(derivation);
1098
+ return result;
1099
+ }
1100
+ /**
1101
+ * diffs newObserving with observing.
1102
+ * update observing to be newObserving with unique observables
1103
+ * notify observers that become observed/unobserved
1104
+ */
1105
+ function bindDependencies(derivation) {
1106
+ // invariant(derivation.dependenciesState !== IDerivationState.NOT_TRACKING, "INTERNAL ERROR bindDependencies expects derivation.dependenciesState !== -1");
1107
+ const prevObserving = derivation.observing;
1108
+ const observing = (derivation.observing = derivation.newObserving);
1109
+ let lowestNewObservingDerivationState = IDerivationState.UP_TO_DATE;
1110
+ // Go through all new observables and check diffValue: (this list can contain duplicates):
1111
+ // 0: first occurrence, change to 1 and keep it
1112
+ // 1: extra occurrence, drop it
1113
+ let i0 = 0, l = derivation.unboundDepsCount;
1114
+ for (let i = 0; i < l; i++) {
1115
+ const dep = observing[i];
1116
+ if (dep.diffValue === 0) {
1117
+ dep.diffValue = 1;
1118
+ if (i0 !== i)
1119
+ observing[i0] = dep;
1120
+ i0++;
1121
+ }
1122
+ // Upcast is 'safe' here, because if dep is IObservable, `dependenciesState` will be undefined,
1123
+ // not hitting the condition
1124
+ if (dep.dependenciesState > lowestNewObservingDerivationState) {
1125
+ lowestNewObservingDerivationState = dep.dependenciesState;
1126
+ }
1127
+ }
1128
+ observing.length = i0;
1129
+ derivation.newObserving = null; // newObserving shouldn't be needed outside tracking (statement moved down to work around FF bug, see #614)
1130
+ // Go through all old observables and check diffValue: (it is unique after last bindDependencies)
1131
+ // 0: it's not in new observables, unobserve it
1132
+ // 1: it keeps being observed, don't want to notify it. change to 0
1133
+ l = prevObserving.length;
1134
+ while (l--) {
1135
+ const dep = prevObserving[l];
1136
+ if (dep.diffValue === 0) {
1137
+ removeObserver(dep, derivation);
1138
+ }
1139
+ dep.diffValue = 0;
1140
+ }
1141
+ // Go through all new observables and check diffValue: (now it should be unique)
1142
+ // 0: it was set to 0 in last loop. don't need to do anything.
1143
+ // 1: it wasn't observed, let's observe it. set back to 0
1144
+ while (i0--) {
1145
+ const dep = observing[i0];
1146
+ if (dep.diffValue === 1) {
1147
+ dep.diffValue = 0;
1148
+ addObserver(dep, derivation);
1149
+ }
1150
+ }
1151
+ // Some new observed derivations may become stale during this derivation computation
1152
+ // so they have had no chance to propagate staleness (#916)
1153
+ if (lowestNewObservingDerivationState !== IDerivationState.UP_TO_DATE) {
1154
+ derivation.dependenciesState = lowestNewObservingDerivationState;
1155
+ derivation.onBecomeStale();
1156
+ }
1157
+ }
1158
+ function clearObserving(derivation) {
1159
+ // invariant(globalState.inBatch > 0, "INTERNAL ERROR clearObserving should be called only inside batch");
1160
+ const obs = derivation.observing;
1161
+ derivation.observing = [];
1162
+ let i = obs.length;
1163
+ while (i--)
1164
+ removeObserver(obs[i], derivation);
1165
+ derivation.dependenciesState = IDerivationState.NOT_TRACKING;
1166
+ }
1167
+ function untracked(action) {
1168
+ const prev = untrackedStart();
1169
+ const res = action();
1170
+ untrackedEnd(prev);
1171
+ return res;
1172
+ }
1173
+ function untrackedStart() {
1174
+ const prev = globalState.trackingDerivation;
1175
+ globalState.trackingDerivation = null;
1176
+ return prev;
1177
+ }
1178
+ function untrackedEnd(prev) {
1179
+ globalState.trackingDerivation = prev;
1180
+ }
1181
+ /**
1182
+ * needed to keep `lowestObserverState` correct. when changing from (2 or 1) to 0
1183
+ *
1184
+ */
1185
+ function changeDependenciesStateTo0(derivation) {
1186
+ if (derivation.dependenciesState === IDerivationState.UP_TO_DATE)
1187
+ return;
1188
+ derivation.dependenciesState = IDerivationState.UP_TO_DATE;
1189
+ const obs = derivation.observing;
1190
+ let i = obs.length;
1191
+ while (i--)
1192
+ obs[i].lowestObserverState = IDerivationState.UP_TO_DATE;
1193
+ }
1194
+
1195
+ /**
1196
+ * These values will persist if global state is reset
1197
+ */
1198
+ const persistentKeys = [
1199
+ "mobxGuid",
1200
+ "spyListeners",
1201
+ "enforceActions",
1202
+ "computedRequiresReaction",
1203
+ "disableErrorBoundaries",
1204
+ "runId",
1205
+ "UNCHANGED"
1206
+ ];
1207
+ class MobXGlobals {
1208
+ constructor() {
1209
+ /**
1210
+ * MobXGlobals version.
1211
+ * MobX compatiblity with other versions loaded in memory as long as this version matches.
1212
+ * It indicates that the global state still stores similar information
1213
+ *
1214
+ * N.B: this version is unrelated to the package version of MobX, and is only the version of the
1215
+ * internal state storage of MobX, and can be the same across many different package versions
1216
+ */
1217
+ this.version = 5;
1218
+ /**
1219
+ * globally unique token to signal unchanged
1220
+ */
1221
+ this.UNCHANGED = {};
1222
+ /**
1223
+ * Currently running derivation
1224
+ */
1225
+ this.trackingDerivation = null;
1226
+ /**
1227
+ * Are we running a computation currently? (not a reaction)
1228
+ */
1229
+ this.computationDepth = 0;
1230
+ /**
1231
+ * Each time a derivation is tracked, it is assigned a unique run-id
1232
+ */
1233
+ this.runId = 0;
1234
+ /**
1235
+ * 'guid' for general purpose. Will be persisted amongst resets.
1236
+ */
1237
+ this.mobxGuid = 0;
1238
+ /**
1239
+ * Are we in a batch block? (and how many of them)
1240
+ */
1241
+ this.inBatch = 0;
1242
+ /**
1243
+ * Observables that don't have observers anymore, and are about to be
1244
+ * suspended, unless somebody else accesses it in the same batch
1245
+ *
1246
+ * @type {IObservable[]}
1247
+ */
1248
+ this.pendingUnobservations = [];
1249
+ /**
1250
+ * List of scheduled, not yet executed, reactions.
1251
+ */
1252
+ this.pendingReactions = [];
1253
+ /**
1254
+ * Are we currently processing reactions?
1255
+ */
1256
+ this.isRunningReactions = false;
1257
+ /**
1258
+ * Is it allowed to change observables at this point?
1259
+ * In general, MobX doesn't allow that when running computations and React.render.
1260
+ * To ensure that those functions stay pure.
1261
+ */
1262
+ this.allowStateChanges = true;
1263
+ /**
1264
+ * If strict mode is enabled, state changes are by default not allowed
1265
+ */
1266
+ this.enforceActions = false;
1267
+ /**
1268
+ * Spy callbacks
1269
+ */
1270
+ this.spyListeners = [];
1271
+ /**
1272
+ * Globally attached error handlers that react specifically to errors in reactions
1273
+ */
1274
+ this.globalReactionErrorHandlers = [];
1275
+ /**
1276
+ * Warn if computed values are accessed outside a reactive context
1277
+ */
1278
+ this.computedRequiresReaction = false;
1279
+ /**
1280
+ * Allows overwriting of computed properties, useful in tests but not prod as it can cause
1281
+ * memory leaks. See https://github.com/mobxjs/mobx/issues/1867
1282
+ */
1283
+ this.computedConfigurable = false;
1284
+ /*
1285
+ * Don't catch and rethrow exceptions. This is useful for inspecting the state of
1286
+ * the stack when an exception occurs while debugging.
1287
+ */
1288
+ this.disableErrorBoundaries = false;
1289
+ /*
1290
+ * If true, we are already handling an exception in an action. Any errors in reactions should be supressed, as
1291
+ * they are not the cause, see: https://github.com/mobxjs/mobx/issues/1836
1292
+ */
1293
+ this.suppressReactionErrors = false;
1294
+ }
1295
+ }
1296
+ let canMergeGlobalState = true;
1297
+ let isolateCalled = false;
1298
+ let globalState = (function () {
1299
+ const global = getGlobal();
1300
+ if (global.__mobxInstanceCount > 0 && !global.__mobxGlobals)
1301
+ canMergeGlobalState = false;
1302
+ if (global.__mobxGlobals && global.__mobxGlobals.version !== new MobXGlobals().version)
1303
+ canMergeGlobalState = false;
1304
+ if (!canMergeGlobalState) {
1305
+ setTimeout(() => {
1306
+ if (!isolateCalled) {
1307
+ fail("There are multiple, different versions of MobX active. Make sure MobX is loaded only once or use `configure({ isolateGlobalState: true })`");
1308
+ }
1309
+ }, 1);
1310
+ return new MobXGlobals();
1311
+ }
1312
+ else if (global.__mobxGlobals) {
1313
+ global.__mobxInstanceCount += 1;
1314
+ if (!global.__mobxGlobals.UNCHANGED)
1315
+ global.__mobxGlobals.UNCHANGED = {}; // make merge backward compatible
1316
+ return global.__mobxGlobals;
1317
+ }
1318
+ else {
1319
+ global.__mobxInstanceCount = 1;
1320
+ return (global.__mobxGlobals = new MobXGlobals());
1321
+ }
1322
+ })();
1323
+ function isolateGlobalState() {
1324
+ if (globalState.pendingReactions.length ||
1325
+ globalState.inBatch ||
1326
+ globalState.isRunningReactions)
1327
+ fail("isolateGlobalState should be called before MobX is running any reactions");
1328
+ isolateCalled = true;
1329
+ if (canMergeGlobalState) {
1330
+ if (--getGlobal().__mobxInstanceCount === 0)
1331
+ getGlobal().__mobxGlobals = undefined;
1332
+ globalState = new MobXGlobals();
1333
+ }
1334
+ }
1335
+ function getGlobalState() {
1336
+ return globalState;
1337
+ }
1338
+ /**
1339
+ * For testing purposes only; this will break the internal state of existing observables,
1340
+ * but can be used to get back at a stable state after throwing errors
1341
+ */
1342
+ function resetGlobalState() {
1343
+ const defaultGlobals = new MobXGlobals();
1344
+ for (let key in defaultGlobals)
1345
+ if (persistentKeys.indexOf(key) === -1)
1346
+ globalState[key] = defaultGlobals[key];
1347
+ globalState.allowStateChanges = !globalState.enforceActions;
1348
+ }
1349
+
1350
+ function hasObservers(observable) {
1351
+ return observable.observers && observable.observers.length > 0;
1352
+ }
1353
+ function getObservers(observable) {
1354
+ return observable.observers;
1355
+ }
1356
+ // function invariantObservers(observable: IObservable) {
1357
+ // const list = observable.observers
1358
+ // const map = observable.observersIndexes
1359
+ // const l = list.length
1360
+ // for (let i = 0; i < l; i++) {
1361
+ // const id = list[i].__mapid
1362
+ // if (i) {
1363
+ // invariant(map[id] === i, "INTERNAL ERROR maps derivation.__mapid to index in list") // for performance
1364
+ // } else {
1365
+ // invariant(!(id in map), "INTERNAL ERROR observer on index 0 shouldn't be held in map.") // for performance
1366
+ // }
1367
+ // }
1368
+ // invariant(
1369
+ // list.length === 0 || Object.keys(map).length === list.length - 1,
1370
+ // "INTERNAL ERROR there is no junk in map"
1371
+ // )
1372
+ // }
1373
+ function addObserver(observable, node) {
1374
+ // invariant(node.dependenciesState !== -1, "INTERNAL ERROR, can add only dependenciesState !== -1");
1375
+ // invariant(observable._observers.indexOf(node) === -1, "INTERNAL ERROR add already added node");
1376
+ // invariantObservers(observable);
1377
+ const l = observable.observers.length;
1378
+ if (l) {
1379
+ // because object assignment is relatively expensive, let's not store data about index 0.
1380
+ observable.observersIndexes[node.__mapid] = l;
1381
+ }
1382
+ observable.observers[l] = node;
1383
+ if (observable.lowestObserverState > node.dependenciesState)
1384
+ observable.lowestObserverState = node.dependenciesState;
1385
+ // invariantObservers(observable);
1386
+ // invariant(observable._observers.indexOf(node) !== -1, "INTERNAL ERROR didn't add node");
1387
+ }
1388
+ function removeObserver(observable, node) {
1389
+ // invariant(globalState.inBatch > 0, "INTERNAL ERROR, remove should be called only inside batch");
1390
+ // invariant(observable._observers.indexOf(node) !== -1, "INTERNAL ERROR remove already removed node");
1391
+ // invariantObservers(observable);
1392
+ if (observable.observers.length === 1) {
1393
+ // deleting last observer
1394
+ observable.observers.length = 0;
1395
+ queueForUnobservation(observable);
1396
+ }
1397
+ else {
1398
+ // deleting from _observersIndexes is straight forward, to delete from _observers, let's swap `node` with last element
1399
+ const list = observable.observers;
1400
+ const map = observable.observersIndexes;
1401
+ const filler = list.pop(); // get last element, which should fill the place of `node`, so the array doesn't have holes
1402
+ if (filler !== node) {
1403
+ // otherwise node was the last element, which already got removed from array
1404
+ const index = map[node.__mapid] || 0; // getting index of `node`. this is the only place we actually use map.
1405
+ if (index) {
1406
+ // map store all indexes but 0, see comment in `addObserver`
1407
+ map[filler.__mapid] = index;
1408
+ }
1409
+ else {
1410
+ delete map[filler.__mapid];
1411
+ }
1412
+ list[index] = filler;
1413
+ }
1414
+ delete map[node.__mapid];
1415
+ }
1416
+ // invariantObservers(observable);
1417
+ // invariant(observable._observers.indexOf(node) === -1, "INTERNAL ERROR remove already removed node2");
1418
+ }
1419
+ function queueForUnobservation(observable) {
1420
+ if (observable.isPendingUnobservation === false) {
1421
+ // invariant(observable._observers.length === 0, "INTERNAL ERROR, should only queue for unobservation unobserved observables");
1422
+ observable.isPendingUnobservation = true;
1423
+ globalState.pendingUnobservations.push(observable);
1424
+ }
1425
+ }
1426
+ /**
1427
+ * Batch starts a transaction, at least for purposes of memoizing ComputedValues when nothing else does.
1428
+ * During a batch `onBecomeUnobserved` will be called at most once per observable.
1429
+ * Avoids unnecessary recalculations.
1430
+ */
1431
+ function startBatch() {
1432
+ globalState.inBatch++;
1433
+ }
1434
+ function endBatch() {
1435
+ if (--globalState.inBatch === 0) {
1436
+ runReactions();
1437
+ // the batch is actually about to finish, all unobserving should happen here.
1438
+ const list = globalState.pendingUnobservations;
1439
+ for (let i = 0; i < list.length; i++) {
1440
+ const observable = list[i];
1441
+ observable.isPendingUnobservation = false;
1442
+ if (observable.observers.length === 0) {
1443
+ if (observable.isBeingObserved) {
1444
+ // if this observable had reactive observers, trigger the hooks
1445
+ observable.isBeingObserved = false;
1446
+ observable.onBecomeUnobserved();
1447
+ }
1448
+ if (observable instanceof ComputedValue) {
1449
+ // computed values are automatically teared down when the last observer leaves
1450
+ // this process happens recursively, this computed might be the last observabe of another, etc..
1451
+ observable.suspend();
1452
+ }
1453
+ }
1454
+ }
1455
+ globalState.pendingUnobservations = [];
1456
+ }
1457
+ }
1458
+ function reportObserved(observable) {
1459
+ const derivation = globalState.trackingDerivation;
1460
+ if (derivation !== null) {
1461
+ /**
1462
+ * Simple optimization, give each derivation run an unique id (runId)
1463
+ * Check if last time this observable was accessed the same runId is used
1464
+ * if this is the case, the relation is already known
1465
+ */
1466
+ if (derivation.runId !== observable.lastAccessedBy) {
1467
+ observable.lastAccessedBy = derivation.runId;
1468
+ derivation.newObserving[derivation.unboundDepsCount++] = observable;
1469
+ if (!observable.isBeingObserved) {
1470
+ observable.isBeingObserved = true;
1471
+ observable.onBecomeObserved();
1472
+ }
1473
+ }
1474
+ return true;
1475
+ }
1476
+ else if (observable.observers.length === 0 && globalState.inBatch > 0) {
1477
+ queueForUnobservation(observable);
1478
+ }
1479
+ return false;
1480
+ }
1481
+ // function invariantLOS(observable: IObservable, msg: string) {
1482
+ // // it's expensive so better not run it in produciton. but temporarily helpful for testing
1483
+ // const min = getObservers(observable).reduce((a, b) => Math.min(a, b.dependenciesState), 2)
1484
+ // if (min >= observable.lowestObserverState) return // <- the only assumption about `lowestObserverState`
1485
+ // throw new Error(
1486
+ // "lowestObserverState is wrong for " +
1487
+ // msg +
1488
+ // " because " +
1489
+ // min +
1490
+ // " < " +
1491
+ // observable.lowestObserverState
1492
+ // )
1493
+ // }
1494
+ /**
1495
+ * NOTE: current propagation mechanism will in case of self reruning autoruns behave unexpectedly
1496
+ * It will propagate changes to observers from previous run
1497
+ * It's hard or maybe impossible (with reasonable perf) to get it right with current approach
1498
+ * Hopefully self reruning autoruns aren't a feature people should depend on
1499
+ * Also most basic use cases should be ok
1500
+ */
1501
+ // Called by Atom when its value changes
1502
+ function propagateChanged(observable) {
1503
+ // invariantLOS(observable, "changed start");
1504
+ if (observable.lowestObserverState === IDerivationState.STALE)
1505
+ return;
1506
+ observable.lowestObserverState = IDerivationState.STALE;
1507
+ const observers = observable.observers;
1508
+ let i = observers.length;
1509
+ while (i--) {
1510
+ const d = observers[i];
1511
+ if (d.dependenciesState === IDerivationState.UP_TO_DATE) {
1512
+ if (d.isTracing !== TraceMode.NONE) {
1513
+ logTraceInfo(d, observable);
1514
+ }
1515
+ d.onBecomeStale();
1516
+ }
1517
+ d.dependenciesState = IDerivationState.STALE;
1518
+ }
1519
+ // invariantLOS(observable, "changed end");
1520
+ }
1521
+ // Called by ComputedValue when it recalculate and its value changed
1522
+ function propagateChangeConfirmed(observable) {
1523
+ // invariantLOS(observable, "confirmed start");
1524
+ if (observable.lowestObserverState === IDerivationState.STALE)
1525
+ return;
1526
+ observable.lowestObserverState = IDerivationState.STALE;
1527
+ const observers = observable.observers;
1528
+ let i = observers.length;
1529
+ while (i--) {
1530
+ const d = observers[i];
1531
+ if (d.dependenciesState === IDerivationState.POSSIBLY_STALE)
1532
+ d.dependenciesState = IDerivationState.STALE;
1533
+ else if (d.dependenciesState === IDerivationState.UP_TO_DATE // this happens during computing of `d`, just keep lowestObserverState up to date.
1534
+ )
1535
+ observable.lowestObserverState = IDerivationState.UP_TO_DATE;
1536
+ }
1537
+ // invariantLOS(observable, "confirmed end");
1538
+ }
1539
+ // Used by computed when its dependency changed, but we don't wan't to immediately recompute.
1540
+ function propagateMaybeChanged(observable) {
1541
+ // invariantLOS(observable, "maybe start");
1542
+ if (observable.lowestObserverState !== IDerivationState.UP_TO_DATE)
1543
+ return;
1544
+ observable.lowestObserverState = IDerivationState.POSSIBLY_STALE;
1545
+ const observers = observable.observers;
1546
+ let i = observers.length;
1547
+ while (i--) {
1548
+ const d = observers[i];
1549
+ if (d.dependenciesState === IDerivationState.UP_TO_DATE) {
1550
+ d.dependenciesState = IDerivationState.POSSIBLY_STALE;
1551
+ if (d.isTracing !== TraceMode.NONE) {
1552
+ logTraceInfo(d, observable);
1553
+ }
1554
+ d.onBecomeStale();
1555
+ }
1556
+ }
1557
+ // invariantLOS(observable, "maybe end");
1558
+ }
1559
+ function logTraceInfo(derivation, observable) {
1560
+ console.log(`[mobx.trace] '${derivation.name}' is invalidated due to a change in: '${observable.name}'`);
1561
+ if (derivation.isTracing === TraceMode.BREAK) {
1562
+ const lines = [];
1563
+ printDepTree(getDependencyTree(derivation), lines, 1);
1564
+ // prettier-ignore
1565
+ new Function(`debugger;
1566
+ /*
1567
+ Tracing '${derivation.name}'
1568
+
1569
+ You are entering this break point because derivation '${derivation.name}' is being traced and '${observable.name}' is now forcing it to update.
1570
+ Just follow the stacktrace you should now see in the devtools to see precisely what piece of your code is causing this update
1571
+ The stackframe you are looking for is at least ~6-8 stack-frames up.
1572
+
1573
+ ${derivation instanceof ComputedValue ? derivation.derivation.toString().replace(/[*]\//g, "/") : ""}
1574
+
1575
+ The dependencies for this derivation are:
1576
+
1577
+ ${lines.join("\n")}
1578
+ */
1579
+ `)();
1580
+ }
1581
+ }
1582
+ function printDepTree(tree, lines, depth) {
1583
+ if (lines.length >= 1000) {
1584
+ lines.push("(and many more)");
1585
+ return;
1586
+ }
1587
+ lines.push(`${new Array(depth).join("\t")}${tree.name}`); // MWE: not the fastest, but the easiest way :)
1588
+ if (tree.dependencies)
1589
+ tree.dependencies.forEach(child => printDepTree(child, lines, depth + 1));
1590
+ }
1591
+
1592
+ class Reaction {
1593
+ constructor(name = "Reaction@" + getNextId(), onInvalidate, errorHandler) {
1594
+ this.name = name;
1595
+ this.onInvalidate = onInvalidate;
1596
+ this.errorHandler = errorHandler;
1597
+ this.observing = []; // nodes we are looking at. Our value depends on these nodes
1598
+ this.newObserving = [];
1599
+ this.dependenciesState = IDerivationState.NOT_TRACKING;
1600
+ this.diffValue = 0;
1601
+ this.runId = 0;
1602
+ this.unboundDepsCount = 0;
1603
+ this.__mapid = "#" + getNextId();
1604
+ this.isDisposed = false;
1605
+ this._isScheduled = false;
1606
+ this._isTrackPending = false;
1607
+ this._isRunning = false;
1608
+ this.isTracing = TraceMode.NONE;
1609
+ }
1610
+ onBecomeStale() {
1611
+ this.schedule();
1612
+ }
1613
+ schedule() {
1614
+ if (!this._isScheduled) {
1615
+ this._isScheduled = true;
1616
+ globalState.pendingReactions.push(this);
1617
+ runReactions();
1618
+ }
1619
+ }
1620
+ isScheduled() {
1621
+ return this._isScheduled;
1622
+ }
1623
+ /**
1624
+ * internal, use schedule() if you intend to kick off a reaction
1625
+ */
1626
+ runReaction() {
1627
+ if (!this.isDisposed) {
1628
+ startBatch();
1629
+ this._isScheduled = false;
1630
+ if (shouldCompute(this)) {
1631
+ this._isTrackPending = true;
1632
+ try {
1633
+ this.onInvalidate();
1634
+ if (this._isTrackPending && isSpyEnabled()) {
1635
+ // onInvalidate didn't trigger track right away..
1636
+ spyReport({
1637
+ name: this.name,
1638
+ type: "scheduled-reaction"
1639
+ });
1640
+ }
1641
+ }
1642
+ catch (e) {
1643
+ this.reportExceptionInDerivation(e);
1644
+ }
1645
+ }
1646
+ endBatch();
1647
+ }
1648
+ }
1649
+ track(fn) {
1650
+ startBatch();
1651
+ const notify = isSpyEnabled();
1652
+ let startTime;
1653
+ if (notify) {
1654
+ startTime = Date.now();
1655
+ spyReportStart({
1656
+ name: this.name,
1657
+ type: "reaction"
1658
+ });
1659
+ }
1660
+ this._isRunning = true;
1661
+ const result = trackDerivedFunction(this, fn, undefined);
1662
+ this._isRunning = false;
1663
+ this._isTrackPending = false;
1664
+ if (this.isDisposed) {
1665
+ // disposed during last run. Clean up everything that was bound after the dispose call.
1666
+ clearObserving(this);
1667
+ }
1668
+ if (isCaughtException(result))
1669
+ this.reportExceptionInDerivation(result.cause);
1670
+ if (notify) {
1671
+ spyReportEnd({
1672
+ time: Date.now() - startTime
1673
+ });
1674
+ }
1675
+ endBatch();
1676
+ }
1677
+ reportExceptionInDerivation(error) {
1678
+ if (this.errorHandler) {
1679
+ this.errorHandler(error, this);
1680
+ return;
1681
+ }
1682
+ if (globalState.disableErrorBoundaries)
1683
+ throw error;
1684
+ const message = `[mobx] Encountered an uncaught exception that was thrown by a reaction or observer component, in: '${this}'`;
1685
+ if (globalState.suppressReactionErrors) {
1686
+ console.warn(`[mobx] (error in reaction '${this.name}' suppressed, fix error of causing action below)`); // prettier-ignore
1687
+ }
1688
+ else {
1689
+ console.error(message, error);
1690
+ /** If debugging brought you here, please, read the above message :-). Tnx! */
1691
+ }
1692
+ if (isSpyEnabled()) {
1693
+ spyReport({
1694
+ type: "error",
1695
+ name: this.name,
1696
+ message,
1697
+ error: "" + error
1698
+ });
1699
+ }
1700
+ globalState.globalReactionErrorHandlers.forEach(f => f(error, this));
1701
+ }
1702
+ dispose() {
1703
+ if (!this.isDisposed) {
1704
+ this.isDisposed = true;
1705
+ if (!this._isRunning) {
1706
+ // if disposed while running, clean up later. Maybe not optimal, but rare case
1707
+ startBatch();
1708
+ clearObserving(this);
1709
+ endBatch();
1710
+ }
1711
+ }
1712
+ }
1713
+ getDisposer() {
1714
+ const r = this.dispose.bind(this);
1715
+ r.$mobx = this;
1716
+ return r;
1717
+ }
1718
+ toString() {
1719
+ return `Reaction[${this.name}]`;
1720
+ }
1721
+ trace(enterBreakPoint = false) {
1722
+ trace(this, enterBreakPoint);
1723
+ }
1724
+ }
1725
+ function onReactionError(handler) {
1726
+ globalState.globalReactionErrorHandlers.push(handler);
1727
+ return () => {
1728
+ const idx = globalState.globalReactionErrorHandlers.indexOf(handler);
1729
+ if (idx >= 0)
1730
+ globalState.globalReactionErrorHandlers.splice(idx, 1);
1731
+ };
1732
+ }
1733
+ /**
1734
+ * Magic number alert!
1735
+ * Defines within how many times a reaction is allowed to re-trigger itself
1736
+ * until it is assumed that this is gonna be a never ending loop...
1737
+ */
1738
+ const MAX_REACTION_ITERATIONS = 100;
1739
+ let reactionScheduler = f => f();
1740
+ function runReactions() {
1741
+ // Trampolining, if runReactions are already running, new reactions will be picked up
1742
+ if (globalState.inBatch > 0 || globalState.isRunningReactions)
1743
+ return;
1744
+ reactionScheduler(runReactionsHelper);
1745
+ }
1746
+ function runReactionsHelper() {
1747
+ globalState.isRunningReactions = true;
1748
+ const allReactions = globalState.pendingReactions;
1749
+ let iterations = 0;
1750
+ // While running reactions, new reactions might be triggered.
1751
+ // Hence we work with two variables and check whether
1752
+ // we converge to no remaining reactions after a while.
1753
+ while (allReactions.length > 0) {
1754
+ if (++iterations === MAX_REACTION_ITERATIONS) {
1755
+ console.error(`Reaction doesn't converge to a stable state after ${MAX_REACTION_ITERATIONS} iterations.` +
1756
+ ` Probably there is a cycle in the reactive function: ${allReactions[0]}`);
1757
+ allReactions.splice(0); // clear reactions
1758
+ }
1759
+ let remainingReactions = allReactions.splice(0);
1760
+ for (let i = 0, l = remainingReactions.length; i < l; i++)
1761
+ remainingReactions[i].runReaction();
1762
+ }
1763
+ globalState.isRunningReactions = false;
1764
+ }
1765
+ const isReaction = createInstanceofPredicate("Reaction", Reaction);
1766
+ function setReactionScheduler(fn) {
1767
+ const baseScheduler = reactionScheduler;
1768
+ reactionScheduler = f => fn(() => baseScheduler(f));
1769
+ }
1770
+
1771
+ function isSpyEnabled() {
1772
+ return !!globalState.spyListeners.length;
1773
+ }
1774
+ function spyReport(event) {
1775
+ if (!globalState.spyListeners.length)
1776
+ return;
1777
+ const listeners = globalState.spyListeners;
1778
+ for (let i = 0, l = listeners.length; i < l; i++)
1779
+ listeners[i](event);
1780
+ }
1781
+ function spyReportStart(event) {
1782
+ const change = Object.assign({}, event, { spyReportStart: true });
1783
+ spyReport(change);
1784
+ }
1785
+ const END_EVENT = { spyReportEnd: true };
1786
+ function spyReportEnd(change) {
1787
+ if (change)
1788
+ spyReport(Object.assign({}, change, { spyReportEnd: true }));
1789
+ else
1790
+ spyReport(END_EVENT);
1791
+ }
1792
+ function spy(listener) {
1793
+ globalState.spyListeners.push(listener);
1794
+ return once(() => {
1795
+ globalState.spyListeners = globalState.spyListeners.filter(l => l !== listener);
1796
+ });
1797
+ }
1798
+
1799
+ function dontReassignFields() {
1800
+ fail(process.env.NODE_ENV !== "production" && "@action fields are not reassignable");
1801
+ }
1802
+ function namedActionDecorator(name) {
1803
+ return function (target, prop, descriptor) {
1804
+ if (descriptor) {
1805
+ if (process.env.NODE_ENV !== "production" && descriptor.get !== undefined) {
1806
+ return fail("@action cannot be used with getters");
1807
+ }
1808
+ // babel / typescript
1809
+ // @action method() { }
1810
+ if (descriptor.value) {
1811
+ // typescript
1812
+ return {
1813
+ value: createAction(name, descriptor.value),
1814
+ enumerable: false,
1815
+ configurable: true,
1816
+ writable: true // for typescript, this must be writable, otherwise it cannot inherit :/ (see inheritable actions test)
1817
+ };
1818
+ }
1819
+ // babel only: @action method = () => {}
1820
+ const { initializer } = descriptor;
1821
+ return {
1822
+ enumerable: false,
1823
+ configurable: true,
1824
+ writable: true,
1825
+ initializer() {
1826
+ // N.B: we can't immediately invoke initializer; this would be wrong
1827
+ return createAction(name, initializer.call(this));
1828
+ }
1829
+ };
1830
+ }
1831
+ // bound instance methods
1832
+ return actionFieldDecorator(name).apply(this, arguments);
1833
+ };
1834
+ }
1835
+ function actionFieldDecorator(name) {
1836
+ // Simple property that writes on first invocation to the current instance
1837
+ return function (target, prop, descriptor) {
1838
+ Object.defineProperty(target, prop, {
1839
+ configurable: true,
1840
+ enumerable: false,
1841
+ get() {
1842
+ return undefined;
1843
+ },
1844
+ set(value) {
1845
+ addHiddenProp(this, prop, action(name, value));
1846
+ }
1847
+ });
1848
+ };
1849
+ }
1850
+ function boundActionDecorator(target, propertyName, descriptor, applyToInstance) {
1851
+ if (applyToInstance === true) {
1852
+ defineBoundAction(target, propertyName, descriptor.value);
1853
+ return null;
1854
+ }
1855
+ if (descriptor) {
1856
+ // if (descriptor.value)
1857
+ // Typescript / Babel: @action.bound method() { }
1858
+ // also: babel @action.bound method = () => {}
1859
+ return {
1860
+ configurable: true,
1861
+ enumerable: false,
1862
+ get() {
1863
+ defineBoundAction(this, propertyName, descriptor.value || descriptor.initializer.call(this));
1864
+ return this[propertyName];
1865
+ },
1866
+ set: dontReassignFields
1867
+ };
1868
+ }
1869
+ // field decorator Typescript @action.bound method = () => {}
1870
+ return {
1871
+ enumerable: false,
1872
+ configurable: true,
1873
+ set(v) {
1874
+ defineBoundAction(this, propertyName, v);
1875
+ },
1876
+ get() {
1877
+ return undefined;
1878
+ }
1879
+ };
1880
+ }
1881
+
1882
+ const action = function action(arg1, arg2, arg3, arg4) {
1883
+ // action(fn() {})
1884
+ if (arguments.length === 1 && typeof arg1 === "function")
1885
+ return createAction(arg1.name || "<unnamed action>", arg1);
1886
+ // action("name", fn() {})
1887
+ if (arguments.length === 2 && typeof arg2 === "function")
1888
+ return createAction(arg1, arg2);
1889
+ // @action("name") fn() {}
1890
+ if (arguments.length === 1 && typeof arg1 === "string")
1891
+ return namedActionDecorator(arg1);
1892
+ // @action fn() {}
1893
+ if (arg4 === true) {
1894
+ // apply to instance immediately
1895
+ arg1[arg2] = createAction(arg1.name || arg2, arg3.value);
1896
+ }
1897
+ else {
1898
+ return namedActionDecorator(arg2).apply(null, arguments);
1899
+ }
1900
+ };
1901
+ action.bound = boundActionDecorator;
1902
+ function runInAction(arg1, arg2) {
1903
+ // TODO: deprecate?
1904
+ const actionName = typeof arg1 === "string" ? arg1 : arg1.name || "<unnamed action>";
1905
+ const fn = typeof arg1 === "function" ? arg1 : arg2;
1906
+ if (process.env.NODE_ENV !== "production") {
1907
+ invariant(typeof fn === "function" && fn.length === 0, "`runInAction` expects a function without arguments");
1908
+ if (typeof actionName !== "string" || !actionName)
1909
+ fail(`actions should have valid names, got: '${actionName}'`);
1910
+ }
1911
+ return executeAction(actionName, fn, this, undefined);
1912
+ }
1913
+ function isAction(thing) {
1914
+ return typeof thing === "function" && thing.isMobxAction === true;
1915
+ }
1916
+ function defineBoundAction(target, propertyName, fn) {
1917
+ addHiddenProp(target, propertyName, createAction(propertyName, fn.bind(target)));
1918
+ }
1919
+
1920
+ /**
1921
+ * Creates a named reactive view and keeps it alive, so that the view is always
1922
+ * updated if one of the dependencies changes, even when the view is not further used by something else.
1923
+ * @param view The reactive view
1924
+ * @returns disposer function, which can be used to stop the view from being updated in the future.
1925
+ */
1926
+ function autorun(view, opts = EMPTY_OBJECT) {
1927
+ if (process.env.NODE_ENV !== "production") {
1928
+ invariant(typeof view === "function", "Autorun expects a function as first argument");
1929
+ invariant(isAction(view) === false, "Autorun does not accept actions since actions are untrackable");
1930
+ }
1931
+ const name = (opts && opts.name) || view.name || "Autorun@" + getNextId();
1932
+ const runSync = !opts.scheduler && !opts.delay;
1933
+ let reaction;
1934
+ if (runSync) {
1935
+ // normal autorun
1936
+ reaction = new Reaction(name, function () {
1937
+ this.track(reactionRunner);
1938
+ }, opts.onError);
1939
+ }
1940
+ else {
1941
+ const scheduler = createSchedulerFromOptions(opts);
1942
+ // debounced autorun
1943
+ let isScheduled = false;
1944
+ reaction = new Reaction(name, () => {
1945
+ if (!isScheduled) {
1946
+ isScheduled = true;
1947
+ scheduler(() => {
1948
+ isScheduled = false;
1949
+ if (!reaction.isDisposed)
1950
+ reaction.track(reactionRunner);
1951
+ });
1952
+ }
1953
+ }, opts.onError);
1954
+ }
1955
+ function reactionRunner() {
1956
+ view(reaction);
1957
+ }
1958
+ reaction.schedule();
1959
+ return reaction.getDisposer();
1960
+ }
1961
+ const run = (f) => f();
1962
+ function createSchedulerFromOptions(opts) {
1963
+ return opts.scheduler
1964
+ ? opts.scheduler
1965
+ : opts.delay
1966
+ ? (f) => setTimeout(f, opts.delay)
1967
+ : run;
1968
+ }
1969
+ function reaction(expression, effect, opts = EMPTY_OBJECT) {
1970
+ if (typeof opts === "boolean") {
1971
+ opts = { fireImmediately: opts };
1972
+ deprecated(`Using fireImmediately as argument is deprecated. Use '{ fireImmediately: true }' instead`);
1973
+ }
1974
+ if (process.env.NODE_ENV !== "production") {
1975
+ invariant(typeof expression === "function", "First argument to reaction should be a function");
1976
+ invariant(typeof opts === "object", "Third argument of reactions should be an object");
1977
+ }
1978
+ const name = opts.name || "Reaction@" + getNextId();
1979
+ const effectAction = action(name, opts.onError ? wrapErrorHandler(opts.onError, effect) : effect);
1980
+ const runSync = !opts.scheduler && !opts.delay;
1981
+ const scheduler = createSchedulerFromOptions(opts);
1982
+ let firstTime = true;
1983
+ let isScheduled = false;
1984
+ let value;
1985
+ const equals = opts.compareStructural
1986
+ ? comparer.structural
1987
+ : opts.equals || comparer.default;
1988
+ const r = new Reaction(name, () => {
1989
+ if (firstTime || runSync) {
1990
+ reactionRunner();
1991
+ }
1992
+ else if (!isScheduled) {
1993
+ isScheduled = true;
1994
+ scheduler(reactionRunner);
1995
+ }
1996
+ }, opts.onError);
1997
+ function reactionRunner() {
1998
+ isScheduled = false; // Q: move into reaction runner?
1999
+ if (r.isDisposed)
2000
+ return;
2001
+ let changed = false;
2002
+ r.track(() => {
2003
+ const nextValue = expression(r);
2004
+ changed = firstTime || !equals(value, nextValue);
2005
+ value = nextValue;
2006
+ });
2007
+ if (firstTime && opts.fireImmediately)
2008
+ effectAction(value, r);
2009
+ if (!firstTime && changed === true)
2010
+ effectAction(value, r);
2011
+ if (firstTime)
2012
+ firstTime = false;
2013
+ }
2014
+ r.schedule();
2015
+ return r.getDisposer();
2016
+ }
2017
+ function wrapErrorHandler(errorHandler, baseFn) {
2018
+ return function () {
2019
+ try {
2020
+ return baseFn.apply(this, arguments);
2021
+ }
2022
+ catch (e) {
2023
+ errorHandler.call(this, e);
2024
+ }
2025
+ };
2026
+ }
2027
+
2028
+ function onBecomeObserved(thing, arg2, arg3) {
2029
+ return interceptHook("onBecomeObserved", thing, arg2, arg3);
2030
+ }
2031
+ function onBecomeUnobserved(thing, arg2, arg3) {
2032
+ return interceptHook("onBecomeUnobserved", thing, arg2, arg3);
2033
+ }
2034
+ function interceptHook(hook, thing, arg2, arg3) {
2035
+ const atom = typeof arg2 === "string" ? getAtom(thing, arg2) : getAtom(thing);
2036
+ const cb = typeof arg2 === "string" ? arg3 : arg2;
2037
+ const orig = atom[hook];
2038
+ if (typeof orig !== "function")
2039
+ return fail(process.env.NODE_ENV !== "production" && "Not an atom that can be (un)observed");
2040
+ atom[hook] = function () {
2041
+ orig.call(this);
2042
+ cb.call(this);
2043
+ };
2044
+ return function () {
2045
+ atom[hook] = orig;
2046
+ };
2047
+ }
2048
+
2049
+ function configure(options) {
2050
+ const { enforceActions, computedRequiresReaction, computedConfigurable, disableErrorBoundaries, arrayBuffer, reactionScheduler } = options;
2051
+ if (options.isolateGlobalState === true) {
2052
+ isolateGlobalState();
2053
+ }
2054
+ if (enforceActions !== undefined) {
2055
+ if (typeof enforceActions === "boolean" || enforceActions === "strict")
2056
+ deprecated(`Deprecated value for 'enforceActions', use 'false' => '"never"', 'true' => '"observed"', '"strict"' => "'always'" instead`);
2057
+ let ea;
2058
+ switch (enforceActions) {
2059
+ case true:
2060
+ case "observed":
2061
+ ea = true;
2062
+ break;
2063
+ case false:
2064
+ case "never":
2065
+ ea = false;
2066
+ break;
2067
+ case "strict":
2068
+ case "always":
2069
+ ea = "strict";
2070
+ break;
2071
+ default:
2072
+ fail(`Invalid value for 'enforceActions': '${enforceActions}', expected 'never', 'always' or 'observed'`);
2073
+ }
2074
+ globalState.enforceActions = ea;
2075
+ globalState.allowStateChanges = ea === true || ea === "strict" ? false : true;
2076
+ }
2077
+ if (computedRequiresReaction !== undefined) {
2078
+ globalState.computedRequiresReaction = !!computedRequiresReaction;
2079
+ }
2080
+ if (computedConfigurable !== undefined) {
2081
+ globalState.computedConfigurable = !!computedConfigurable;
2082
+ }
2083
+ if (disableErrorBoundaries !== undefined) {
2084
+ if (disableErrorBoundaries === true)
2085
+ console.warn("WARNING: Debug feature only. MobX will NOT recover from errors if this is on.");
2086
+ globalState.disableErrorBoundaries = !!disableErrorBoundaries;
2087
+ }
2088
+ if (typeof arrayBuffer === "number") {
2089
+ reserveArrayBuffer(arrayBuffer);
2090
+ }
2091
+ if (reactionScheduler) {
2092
+ setReactionScheduler(reactionScheduler);
2093
+ }
2094
+ }
2095
+
2096
+ function decorate(thing, decorators) {
2097
+ if (process.env.NODE_ENV !== "production" && !isPlainObject(decorators))
2098
+ fail("Decorators should be a key value map");
2099
+ const target = typeof thing === "function" ? thing.prototype : thing;
2100
+ for (let prop in decorators) {
2101
+ let propertyDecorators = decorators[prop];
2102
+ if (!Array.isArray(propertyDecorators)) {
2103
+ propertyDecorators = [propertyDecorators];
2104
+ }
2105
+ // prettier-ignore
2106
+ if (process.env.NODE_ENV !== "production" && !propertyDecorators.every(decorator => typeof decorator === "function"))
2107
+ fail(`Decorate: expected a decorator function or array of decorator functions for '${prop}'`);
2108
+ const descriptor = Object.getOwnPropertyDescriptor(target, prop);
2109
+ const newDescriptor = propertyDecorators.reduce((accDescriptor, decorator) => decorator(target, prop, accDescriptor), descriptor);
2110
+ if (newDescriptor)
2111
+ Object.defineProperty(target, prop, newDescriptor);
2112
+ }
2113
+ return thing;
2114
+ }
2115
+
2116
+ function extendShallowObservable(target, properties, decorators) {
2117
+ deprecated("'extendShallowObservable' is deprecated, use 'extendObservable(target, props, { deep: false })' instead");
2118
+ return extendObservable(target, properties, decorators, shallowCreateObservableOptions);
2119
+ }
2120
+ function extendObservable(target, properties, decorators, options) {
2121
+ if (process.env.NODE_ENV !== "production") {
2122
+ invariant(arguments.length >= 2 && arguments.length <= 4, "'extendObservable' expected 2-4 arguments");
2123
+ invariant(typeof target === "object", "'extendObservable' expects an object as first argument");
2124
+ invariant(!isObservableMap(target), "'extendObservable' should not be used on maps, use map.merge instead");
2125
+ invariant(!isObservable(properties), "Extending an object with another observable (object) is not supported. Please construct an explicit propertymap, using `toJS` if need. See issue #540");
2126
+ if (decorators)
2127
+ for (let key in decorators)
2128
+ if (!(key in properties))
2129
+ fail(`Trying to declare a decorator for unspecified property '${key}'`);
2130
+ }
2131
+ options = asCreateObservableOptions(options);
2132
+ const defaultDecorator = options.defaultDecorator || (options.deep === false ? refDecorator : deepDecorator);
2133
+ initializeInstance(target);
2134
+ asObservableObject(target, options.name, defaultDecorator.enhancer); // make sure object is observable, even without initial props
2135
+ startBatch();
2136
+ try {
2137
+ for (let key in properties) {
2138
+ const descriptor = Object.getOwnPropertyDescriptor(properties, key);
2139
+ if (process.env.NODE_ENV !== "production") {
2140
+ if (Object.getOwnPropertyDescriptor(target, key))
2141
+ fail(`'extendObservable' can only be used to introduce new properties. Use 'set' or 'decorate' instead. The property '${key}' already exists on '${target}'`);
2142
+ if (isComputed(descriptor.value))
2143
+ fail(`Passing a 'computed' as initial property value is no longer supported by extendObservable. Use a getter or decorator instead`);
2144
+ }
2145
+ const decorator = decorators && key in decorators
2146
+ ? decorators[key]
2147
+ : descriptor.get
2148
+ ? computedDecorator
2149
+ : defaultDecorator;
2150
+ if (process.env.NODE_ENV !== "production" && typeof decorator !== "function")
2151
+ return fail(`Not a valid decorator for '${key}', got: ${decorator}`);
2152
+ const resultDescriptor = decorator(target, key, descriptor, true);
2153
+ if (resultDescriptor // otherwise, assume already applied, due to `applyToInstance`
2154
+ )
2155
+ Object.defineProperty(target, key, resultDescriptor);
2156
+ }
2157
+ }
2158
+ finally {
2159
+ endBatch();
2160
+ }
2161
+ return target;
2162
+ }
2163
+
2164
+ function getDependencyTree(thing, property) {
2165
+ return nodeToDependencyTree(getAtom(thing, property));
2166
+ }
2167
+ function nodeToDependencyTree(node) {
2168
+ const result = {
2169
+ name: node.name
2170
+ };
2171
+ if (node.observing && node.observing.length > 0)
2172
+ result.dependencies = unique(node.observing).map(nodeToDependencyTree);
2173
+ return result;
2174
+ }
2175
+ function getObserverTree(thing, property) {
2176
+ return nodeToObserverTree(getAtom(thing, property));
2177
+ }
2178
+ function nodeToObserverTree(node) {
2179
+ const result = {
2180
+ name: node.name
2181
+ };
2182
+ if (hasObservers(node))
2183
+ result.observers = getObservers(node).map(nodeToObserverTree);
2184
+ return result;
2185
+ }
2186
+
2187
+ let generatorId = 0;
2188
+ function flow(generator) {
2189
+ if (arguments.length !== 1)
2190
+ fail(!!process.env.NODE_ENV && `Flow expects one 1 argument and cannot be used as decorator`);
2191
+ const name = generator.name || "<unnamed flow>";
2192
+ // Implementation based on https://github.com/tj/co/blob/master/index.js
2193
+ return function () {
2194
+ const ctx = this;
2195
+ const args = arguments;
2196
+ const runId = ++generatorId;
2197
+ const gen = action(`${name} - runid: ${runId} - init`, generator).apply(ctx, args);
2198
+ let rejector;
2199
+ let pendingPromise = undefined;
2200
+ const res = new Promise(function (resolve, reject) {
2201
+ let stepId = 0;
2202
+ rejector = reject;
2203
+ function onFulfilled(res) {
2204
+ pendingPromise = undefined;
2205
+ let ret;
2206
+ try {
2207
+ ret = action(`${name} - runid: ${runId} - yield ${stepId++}`, gen.next).call(gen, res);
2208
+ }
2209
+ catch (e) {
2210
+ return reject(e);
2211
+ }
2212
+ next(ret);
2213
+ }
2214
+ function onRejected(err) {
2215
+ pendingPromise = undefined;
2216
+ let ret;
2217
+ try {
2218
+ ret = action(`${name} - runid: ${runId} - yield ${stepId++}`, gen.throw).call(gen, err);
2219
+ }
2220
+ catch (e) {
2221
+ return reject(e);
2222
+ }
2223
+ next(ret);
2224
+ }
2225
+ function next(ret) {
2226
+ if (ret && typeof ret.then === "function") {
2227
+ // an async iterator
2228
+ ret.then(next, reject);
2229
+ return;
2230
+ }
2231
+ if (ret.done)
2232
+ return resolve(ret.value);
2233
+ pendingPromise = Promise.resolve(ret.value);
2234
+ return pendingPromise.then(onFulfilled, onRejected);
2235
+ }
2236
+ onFulfilled(undefined); // kick off the process
2237
+ });
2238
+ res.cancel = action(`${name} - runid: ${runId} - cancel`, function () {
2239
+ try {
2240
+ if (pendingPromise)
2241
+ cancelPromise(pendingPromise);
2242
+ // Finally block can return (or yield) stuff..
2243
+ const res = gen.return();
2244
+ // eat anything that promise would do, it's cancelled!
2245
+ const yieldedPromise = Promise.resolve(res.value);
2246
+ yieldedPromise.then(noop, noop);
2247
+ cancelPromise(yieldedPromise); // maybe it can be cancelled :)
2248
+ // reject our original promise
2249
+ rejector(new Error("FLOW_CANCELLED"));
2250
+ }
2251
+ catch (e) {
2252
+ rejector(e); // there could be a throwing finally block
2253
+ }
2254
+ });
2255
+ return res;
2256
+ };
2257
+ }
2258
+ function cancelPromise(promise) {
2259
+ if (typeof promise.cancel === "function")
2260
+ promise.cancel();
2261
+ }
2262
+
2263
+ function interceptReads(thing, propOrHandler, handler) {
2264
+ let target;
2265
+ if (isObservableMap(thing) || isObservableArray(thing) || isObservableValue(thing)) {
2266
+ target = getAdministration(thing);
2267
+ }
2268
+ else if (isObservableObject(thing)) {
2269
+ if (typeof propOrHandler !== "string")
2270
+ return fail(process.env.NODE_ENV !== "production" &&
2271
+ `InterceptReads can only be used with a specific property, not with an object in general`);
2272
+ target = getAdministration(thing, propOrHandler);
2273
+ }
2274
+ else {
2275
+ return fail(process.env.NODE_ENV !== "production" &&
2276
+ `Expected observable map, object or array as first array`);
2277
+ }
2278
+ if (target.dehancer !== undefined)
2279
+ return fail(process.env.NODE_ENV !== "production" && `An intercept reader was already established`);
2280
+ target.dehancer = typeof propOrHandler === "function" ? propOrHandler : handler;
2281
+ return () => {
2282
+ target.dehancer = undefined;
2283
+ };
2284
+ }
2285
+
2286
+ function intercept(thing, propOrHandler, handler) {
2287
+ if (typeof handler === "function")
2288
+ return interceptProperty(thing, propOrHandler, handler);
2289
+ else
2290
+ return interceptInterceptable(thing, propOrHandler);
2291
+ }
2292
+ function interceptInterceptable(thing, handler) {
2293
+ return getAdministration(thing).intercept(handler);
2294
+ }
2295
+ function interceptProperty(thing, property, handler) {
2296
+ return getAdministration(thing, property).intercept(handler);
2297
+ }
2298
+
2299
+ function _isComputed(value, property) {
2300
+ if (value === null || value === undefined)
2301
+ return false;
2302
+ if (property !== undefined) {
2303
+ if (isObservableObject(value) === false)
2304
+ return false;
2305
+ if (!value.$mobx.values[property])
2306
+ return false;
2307
+ const atom = getAtom(value, property);
2308
+ return isComputedValue(atom);
2309
+ }
2310
+ return isComputedValue(value);
2311
+ }
2312
+ function isComputed(value) {
2313
+ if (arguments.length > 1)
2314
+ return fail(process.env.NODE_ENV !== "production" &&
2315
+ `isComputed expects only 1 argument. Use isObservableProp to inspect the observability of a property`);
2316
+ return _isComputed(value);
2317
+ }
2318
+ function isComputedProp(value, propName) {
2319
+ if (typeof propName !== "string")
2320
+ return fail(process.env.NODE_ENV !== "production" &&
2321
+ `isComputed expected a property name as second argument`);
2322
+ return _isComputed(value, propName);
2323
+ }
2324
+
2325
+ function _isObservable(value, property) {
2326
+ if (value === null || value === undefined)
2327
+ return false;
2328
+ if (property !== undefined) {
2329
+ if (process.env.NODE_ENV !== "production" &&
2330
+ (isObservableMap(value) || isObservableArray(value)))
2331
+ return fail("isObservable(object, propertyName) is not supported for arrays and maps. Use map.has or array.length instead.");
2332
+ if (isObservableObject(value)) {
2333
+ const o = value.$mobx;
2334
+ return o.values && !!o.values[property];
2335
+ }
2336
+ return false;
2337
+ }
2338
+ // For first check, see #701
2339
+ return (isObservableObject(value) ||
2340
+ !!value.$mobx ||
2341
+ isAtom(value) ||
2342
+ isReaction(value) ||
2343
+ isComputedValue(value));
2344
+ }
2345
+ function isObservable(value) {
2346
+ if (arguments.length !== 1)
2347
+ fail(process.env.NODE_ENV !== "production" &&
2348
+ `isObservable expects only 1 argument. Use isObservableProp to inspect the observability of a property`);
2349
+ return _isObservable(value);
2350
+ }
2351
+ function isObservableProp(value, propName) {
2352
+ if (typeof propName !== "string")
2353
+ return fail(process.env.NODE_ENV !== "production" && `expected a property name as second argument`);
2354
+ return _isObservable(value, propName);
2355
+ }
2356
+
2357
+ function keys(obj) {
2358
+ if (isObservableObject(obj)) {
2359
+ return obj.$mobx.getKeys();
2360
+ }
2361
+ if (isObservableMap(obj)) {
2362
+ return obj._keys.slice();
2363
+ }
2364
+ if (isObservableSet(obj)) {
2365
+ return iteratorToArray(obj.keys());
2366
+ }
2367
+ if (isObservableArray(obj)) {
2368
+ return obj.map((_, index) => index);
2369
+ }
2370
+ return fail(process.env.NODE_ENV !== "production" &&
2371
+ "'keys()' can only be used on observable objects, arrays, sets and maps");
2372
+ }
2373
+ function values(obj) {
2374
+ if (isObservableObject(obj)) {
2375
+ return keys(obj).map(key => obj[key]);
2376
+ }
2377
+ if (isObservableMap(obj)) {
2378
+ return keys(obj).map(key => obj.get(key));
2379
+ }
2380
+ if (isObservableSet(obj)) {
2381
+ return iteratorToArray(obj.values());
2382
+ }
2383
+ if (isObservableArray(obj)) {
2384
+ return obj.slice();
2385
+ }
2386
+ return fail(process.env.NODE_ENV !== "production" &&
2387
+ "'values()' can only be used on observable objects, arrays, sets and maps");
2388
+ }
2389
+ function entries(obj) {
2390
+ if (isObservableObject(obj)) {
2391
+ return keys(obj).map(key => [key, obj[key]]);
2392
+ }
2393
+ if (isObservableMap(obj)) {
2394
+ return keys(obj).map(key => [key, obj.get(key)]);
2395
+ }
2396
+ if (isObservableSet(obj)) {
2397
+ return iteratorToArray(obj.entries());
2398
+ }
2399
+ if (isObservableArray(obj)) {
2400
+ return obj.map((key, index) => [index, key]);
2401
+ }
2402
+ return fail(process.env.NODE_ENV !== "production" &&
2403
+ "'entries()' can only be used on observable objects, arrays and maps");
2404
+ }
2405
+ function set(obj, key, value) {
2406
+ if (arguments.length === 2 && !isObservableSet(obj)) {
2407
+ startBatch();
2408
+ const values = key;
2409
+ try {
2410
+ for (let key in values)
2411
+ set(obj, key, values[key]);
2412
+ }
2413
+ finally {
2414
+ endBatch();
2415
+ }
2416
+ return;
2417
+ }
2418
+ if (isObservableObject(obj)) {
2419
+ const adm = obj.$mobx;
2420
+ const existingObservable = adm.values[key];
2421
+ if (existingObservable) {
2422
+ adm.write(obj, key, value);
2423
+ }
2424
+ else {
2425
+ defineObservableProperty(obj, key, value, adm.defaultEnhancer);
2426
+ }
2427
+ }
2428
+ else if (isObservableMap(obj)) {
2429
+ obj.set(key, value);
2430
+ }
2431
+ else if (isObservableSet(obj)) {
2432
+ obj.add(key);
2433
+ }
2434
+ else if (isObservableArray(obj)) {
2435
+ if (typeof key !== "number")
2436
+ key = parseInt(key, 10);
2437
+ invariant(key >= 0, `Not a valid index: '${key}'`);
2438
+ startBatch();
2439
+ if (key >= obj.length)
2440
+ obj.length = key + 1;
2441
+ obj[key] = value;
2442
+ endBatch();
2443
+ }
2444
+ else {
2445
+ return fail(process.env.NODE_ENV !== "production" &&
2446
+ "'set()' can only be used on observable objects, arrays and maps");
2447
+ }
2448
+ }
2449
+ function remove(obj, key) {
2450
+ if (isObservableObject(obj)) {
2451
+ obj.$mobx.remove(key);
2452
+ }
2453
+ else if (isObservableMap(obj)) {
2454
+ obj.delete(key);
2455
+ }
2456
+ else if (isObservableSet(obj)) {
2457
+ obj.delete(key);
2458
+ }
2459
+ else if (isObservableArray(obj)) {
2460
+ if (typeof key !== "number")
2461
+ key = parseInt(key, 10);
2462
+ invariant(key >= 0, `Not a valid index: '${key}'`);
2463
+ obj.splice(key, 1);
2464
+ }
2465
+ else {
2466
+ return fail(process.env.NODE_ENV !== "production" &&
2467
+ "'remove()' can only be used on observable objects, arrays and maps");
2468
+ }
2469
+ }
2470
+ function has(obj, key) {
2471
+ if (isObservableObject(obj)) {
2472
+ // return keys(obj).indexOf(key) >= 0
2473
+ const adm = getAdministration(obj);
2474
+ adm.getKeys(); // make sure we get notified of key changes, but for performance, use the values map to look up existence
2475
+ return !!adm.values[key];
2476
+ }
2477
+ else if (isObservableMap(obj)) {
2478
+ return obj.has(key);
2479
+ }
2480
+ else if (isObservableSet(obj)) {
2481
+ return obj.has(key);
2482
+ }
2483
+ else if (isObservableArray(obj)) {
2484
+ return key >= 0 && key < obj.length;
2485
+ }
2486
+ else {
2487
+ return fail(process.env.NODE_ENV !== "production" &&
2488
+ "'has()' can only be used on observable objects, arrays and maps");
2489
+ }
2490
+ }
2491
+ function get(obj, key) {
2492
+ if (!has(obj, key))
2493
+ return undefined;
2494
+ if (isObservableObject(obj)) {
2495
+ return obj[key];
2496
+ }
2497
+ else if (isObservableMap(obj)) {
2498
+ return obj.get(key);
2499
+ }
2500
+ else if (isObservableArray(obj)) {
2501
+ return obj[key];
2502
+ }
2503
+ else {
2504
+ return fail(process.env.NODE_ENV !== "production" &&
2505
+ "'get()' can only be used on observable objects, arrays and maps");
2506
+ }
2507
+ }
2508
+
2509
+ function observe(thing, propOrCb, cbOrFire, fireImmediately) {
2510
+ if (typeof cbOrFire === "function")
2511
+ return observeObservableProperty(thing, propOrCb, cbOrFire, fireImmediately);
2512
+ else
2513
+ return observeObservable(thing, propOrCb, cbOrFire);
2514
+ }
2515
+ function observeObservable(thing, listener, fireImmediately) {
2516
+ return getAdministration(thing).observe(listener, fireImmediately);
2517
+ }
2518
+ function observeObservableProperty(thing, property, listener, fireImmediately) {
2519
+ return getAdministration(thing, property).observe(listener, fireImmediately);
2520
+ }
2521
+
2522
+ const defaultOptions = {
2523
+ detectCycles: true,
2524
+ exportMapsAsObjects: true,
2525
+ recurseEverything: false
2526
+ };
2527
+ function cache(map, key, value, options) {
2528
+ if (options.detectCycles)
2529
+ map.set(key, value);
2530
+ return value;
2531
+ }
2532
+ function toJSHelper(source, options, __alreadySeen) {
2533
+ if (!options.recurseEverything && !isObservable(source))
2534
+ return source;
2535
+ if (typeof source !== "object")
2536
+ return source;
2537
+ // Directly return null if source is null
2538
+ if (source === null)
2539
+ return null;
2540
+ // Directly return the Date object itself if contained in the observable
2541
+ if (source instanceof Date)
2542
+ return source;
2543
+ if (isObservableValue(source))
2544
+ return toJSHelper(source.get(), options, __alreadySeen);
2545
+ // make sure we track the keys of the object
2546
+ if (isObservable(source))
2547
+ keys(source);
2548
+ const detectCycles = options.detectCycles === true;
2549
+ if (detectCycles && source !== null && __alreadySeen.has(source)) {
2550
+ return __alreadySeen.get(source);
2551
+ }
2552
+ if (isObservableArray(source) || Array.isArray(source)) {
2553
+ const res = cache(__alreadySeen, source, [], options);
2554
+ const toAdd = source.map(value => toJSHelper(value, options, __alreadySeen));
2555
+ res.length = toAdd.length;
2556
+ for (let i = 0, l = toAdd.length; i < l; i++)
2557
+ res[i] = toAdd[i];
2558
+ return res;
2559
+ }
2560
+ if (isObservableSet(source) || Object.getPrototypeOf(source) === Set.prototype) {
2561
+ if (options.exportMapsAsObjects === false) {
2562
+ const res = cache(__alreadySeen, source, new Set(), options);
2563
+ source.forEach(value => {
2564
+ res.add(toJSHelper(value, options, __alreadySeen));
2565
+ });
2566
+ return res;
2567
+ }
2568
+ else {
2569
+ const res = cache(__alreadySeen, source, [], options);
2570
+ source.forEach(value => {
2571
+ res.push(toJSHelper(value, options, __alreadySeen));
2572
+ });
2573
+ return res;
2574
+ }
2575
+ }
2576
+ if (isObservableMap(source) || Object.getPrototypeOf(source) === Map.prototype) {
2577
+ if (options.exportMapsAsObjects === false) {
2578
+ const res = cache(__alreadySeen, source, new Map(), options);
2579
+ source.forEach((value, key) => {
2580
+ res.set(key, toJSHelper(value, options, __alreadySeen));
2581
+ });
2582
+ return res;
2583
+ }
2584
+ else {
2585
+ const res = cache(__alreadySeen, source, {}, options);
2586
+ source.forEach((value, key) => {
2587
+ res[key] = toJSHelper(value, options, __alreadySeen);
2588
+ });
2589
+ return res;
2590
+ }
2591
+ }
2592
+ // Fallback to the situation that source is an ObservableObject or a plain object
2593
+ const res = cache(__alreadySeen, source, {}, options);
2594
+ for (let key in source) {
2595
+ res[key] = toJSHelper(source[key], options, __alreadySeen);
2596
+ }
2597
+ return res;
2598
+ }
2599
+ function toJS(source, options) {
2600
+ // backward compatibility
2601
+ if (typeof options === "boolean")
2602
+ options = { detectCycles: options };
2603
+ if (!options)
2604
+ options = defaultOptions;
2605
+ options.detectCycles =
2606
+ options.detectCycles === undefined
2607
+ ? options.recurseEverything === true
2608
+ : options.detectCycles === true;
2609
+ let __alreadySeen;
2610
+ if (options.detectCycles)
2611
+ __alreadySeen = new Map();
2612
+ return toJSHelper(source, options, __alreadySeen);
2613
+ }
2614
+
2615
+ function trace(...args) {
2616
+ let enterBreakPoint = false;
2617
+ if (typeof args[args.length - 1] === "boolean")
2618
+ enterBreakPoint = args.pop();
2619
+ const derivation = getAtomFromArgs(args);
2620
+ if (!derivation) {
2621
+ return fail(process.env.NODE_ENV !== "production" &&
2622
+ `'trace(break?)' can only be used inside a tracked computed value or a Reaction. Consider passing in the computed value or reaction explicitly`);
2623
+ }
2624
+ if (derivation.isTracing === TraceMode.NONE) {
2625
+ console.log(`[mobx.trace] '${derivation.name}' tracing enabled`);
2626
+ }
2627
+ derivation.isTracing = enterBreakPoint ? TraceMode.BREAK : TraceMode.LOG;
2628
+ }
2629
+ function getAtomFromArgs(args) {
2630
+ switch (args.length) {
2631
+ case 0:
2632
+ return globalState.trackingDerivation;
2633
+ case 1:
2634
+ return getAtom(args[0]);
2635
+ case 2:
2636
+ return getAtom(args[0], args[1]);
2637
+ }
2638
+ }
2639
+
2640
+ /**
2641
+ * During a transaction no views are updated until the end of the transaction.
2642
+ * The transaction will be run synchronously nonetheless.
2643
+ *
2644
+ * @param action a function that updates some reactive state
2645
+ * @returns any value that was returned by the 'action' parameter.
2646
+ */
2647
+ function transaction(action, thisArg = undefined) {
2648
+ startBatch();
2649
+ try {
2650
+ return action.apply(thisArg);
2651
+ }
2652
+ finally {
2653
+ endBatch();
2654
+ }
2655
+ }
2656
+
2657
+ function when(predicate, arg1, arg2) {
2658
+ if (arguments.length === 1 || (arg1 && typeof arg1 === "object"))
2659
+ return whenPromise(predicate, arg1);
2660
+ return _when(predicate, arg1, arg2 || {});
2661
+ }
2662
+ function _when(predicate, effect, opts) {
2663
+ let timeoutHandle;
2664
+ if (typeof opts.timeout === "number") {
2665
+ timeoutHandle = setTimeout(() => {
2666
+ if (!disposer.$mobx.isDisposed) {
2667
+ disposer();
2668
+ const error = new Error("WHEN_TIMEOUT");
2669
+ if (opts.onError)
2670
+ opts.onError(error);
2671
+ else
2672
+ throw error;
2673
+ }
2674
+ }, opts.timeout);
2675
+ }
2676
+ opts.name = opts.name || "When@" + getNextId();
2677
+ const effectAction = createAction(opts.name + "-effect", effect);
2678
+ const disposer = autorun(r => {
2679
+ if (predicate()) {
2680
+ r.dispose();
2681
+ if (timeoutHandle)
2682
+ clearTimeout(timeoutHandle);
2683
+ effectAction();
2684
+ }
2685
+ }, opts);
2686
+ return disposer;
2687
+ }
2688
+ function whenPromise(predicate, opts) {
2689
+ if (process.env.NODE_ENV !== "production" && opts && opts.onError)
2690
+ return fail(`the options 'onError' and 'promise' cannot be combined`);
2691
+ let cancel;
2692
+ const res = new Promise((resolve, reject) => {
2693
+ let disposer = _when(predicate, resolve, Object.assign({}, opts, { onError: reject }));
2694
+ cancel = () => {
2695
+ disposer();
2696
+ reject("WHEN_CANCELLED");
2697
+ };
2698
+ });
2699
+ res.cancel = cancel;
2700
+ return res;
2701
+ }
2702
+
2703
+ function hasInterceptors(interceptable) {
2704
+ return interceptable.interceptors !== undefined && interceptable.interceptors.length > 0;
2705
+ }
2706
+ function registerInterceptor(interceptable, handler) {
2707
+ const interceptors = interceptable.interceptors || (interceptable.interceptors = []);
2708
+ interceptors.push(handler);
2709
+ return once(() => {
2710
+ const idx = interceptors.indexOf(handler);
2711
+ if (idx !== -1)
2712
+ interceptors.splice(idx, 1);
2713
+ });
2714
+ }
2715
+ function interceptChange(interceptable, change) {
2716
+ const prevU = untrackedStart();
2717
+ try {
2718
+ const interceptors = interceptable.interceptors;
2719
+ if (interceptors)
2720
+ for (let i = 0, l = interceptors.length; i < l; i++) {
2721
+ change = interceptors[i](change);
2722
+ invariant(!change || change.type, "Intercept handlers should return nothing or a change object");
2723
+ if (!change)
2724
+ break;
2725
+ }
2726
+ return change;
2727
+ }
2728
+ finally {
2729
+ untrackedEnd(prevU);
2730
+ }
2731
+ }
2732
+
2733
+ function hasListeners(listenable) {
2734
+ return listenable.changeListeners !== undefined && listenable.changeListeners.length > 0;
2735
+ }
2736
+ function registerListener(listenable, handler) {
2737
+ const listeners = listenable.changeListeners || (listenable.changeListeners = []);
2738
+ listeners.push(handler);
2739
+ return once(() => {
2740
+ const idx = listeners.indexOf(handler);
2741
+ if (idx !== -1)
2742
+ listeners.splice(idx, 1);
2743
+ });
2744
+ }
2745
+ function notifyListeners(listenable, change) {
2746
+ const prevU = untrackedStart();
2747
+ let listeners = listenable.changeListeners;
2748
+ if (!listeners)
2749
+ return;
2750
+ listeners = listeners.slice();
2751
+ for (let i = 0, l = listeners.length; i < l; i++) {
2752
+ listeners[i](change);
2753
+ }
2754
+ untrackedEnd(prevU);
2755
+ }
2756
+
2757
+ const MAX_SPLICE_SIZE = 10000; // See e.g. https://github.com/mobxjs/mobx/issues/859
2758
+ // Detects bug in safari 9.1.1 (or iOS 9 safari mobile). See #364
2759
+ const safariPrototypeSetterInheritanceBug = (() => {
2760
+ let v = false;
2761
+ const p = {};
2762
+ Object.defineProperty(p, "0", {
2763
+ set: () => {
2764
+ v = true;
2765
+ }
2766
+ });
2767
+ Object.create(p)["0"] = 1;
2768
+ return v === false;
2769
+ })();
2770
+ /**
2771
+ * This array buffer contains two lists of properties, so that all arrays
2772
+ * can recycle their property definitions, which significantly improves performance of creating
2773
+ * properties on the fly.
2774
+ */
2775
+ let OBSERVABLE_ARRAY_BUFFER_SIZE = 0;
2776
+ // Typescript workaround to make sure ObservableArray extends Array
2777
+ class StubArray {
2778
+ }
2779
+ function inherit(ctor, proto) {
2780
+ if (typeof Object["setPrototypeOf"] !== "undefined") {
2781
+ Object["setPrototypeOf"](ctor.prototype, proto);
2782
+ }
2783
+ else if (typeof ctor.prototype.__proto__ !== "undefined") {
2784
+ ctor.prototype.__proto__ = proto;
2785
+ }
2786
+ else {
2787
+ ctor["prototype"] = proto;
2788
+ }
2789
+ }
2790
+ inherit(StubArray, Array.prototype);
2791
+ // Weex freeze Array.prototype
2792
+ // Make them writeable and configurable in prototype chain
2793
+ // https://github.com/alibaba/weex/pull/1529
2794
+ if (Object.isFrozen(Array)) {
2795
+ [
2796
+ "constructor",
2797
+ "push",
2798
+ "shift",
2799
+ "concat",
2800
+ "pop",
2801
+ "unshift",
2802
+ "replace",
2803
+ "find",
2804
+ "findIndex",
2805
+ "splice",
2806
+ "reverse",
2807
+ "sort"
2808
+ ].forEach(function (key) {
2809
+ Object.defineProperty(StubArray.prototype, key, {
2810
+ configurable: true,
2811
+ writable: true,
2812
+ value: Array.prototype[key]
2813
+ });
2814
+ });
2815
+ }
2816
+ class ObservableArrayAdministration {
2817
+ constructor(name, enhancer, array, owned) {
2818
+ this.array = array;
2819
+ this.owned = owned;
2820
+ this.values = [];
2821
+ this.lastKnownLength = 0;
2822
+ this.atom = new Atom(name || "ObservableArray@" + getNextId());
2823
+ this.enhancer = (newV, oldV) => enhancer(newV, oldV, name + "[..]");
2824
+ }
2825
+ dehanceValue(value) {
2826
+ if (this.dehancer !== undefined)
2827
+ return this.dehancer(value);
2828
+ return value;
2829
+ }
2830
+ dehanceValues(values) {
2831
+ if (this.dehancer !== undefined && values.length > 0)
2832
+ return values.map(this.dehancer);
2833
+ return values;
2834
+ }
2835
+ intercept(handler) {
2836
+ return registerInterceptor(this, handler);
2837
+ }
2838
+ observe(listener, fireImmediately = false) {
2839
+ if (fireImmediately) {
2840
+ listener({
2841
+ object: this.array,
2842
+ type: "splice",
2843
+ index: 0,
2844
+ added: this.values.slice(),
2845
+ addedCount: this.values.length,
2846
+ removed: [],
2847
+ removedCount: 0
2848
+ });
2849
+ }
2850
+ return registerListener(this, listener);
2851
+ }
2852
+ getArrayLength() {
2853
+ this.atom.reportObserved();
2854
+ return this.values.length;
2855
+ }
2856
+ setArrayLength(newLength) {
2857
+ if (typeof newLength !== "number" || newLength < 0)
2858
+ throw new Error("[mobx.array] Out of range: " + newLength);
2859
+ let currentLength = this.values.length;
2860
+ if (newLength === currentLength)
2861
+ return;
2862
+ else if (newLength > currentLength) {
2863
+ const newItems = new Array(newLength - currentLength);
2864
+ for (let i = 0; i < newLength - currentLength; i++)
2865
+ newItems[i] = undefined; // No Array.fill everywhere...
2866
+ this.spliceWithArray(currentLength, 0, newItems);
2867
+ }
2868
+ else
2869
+ this.spliceWithArray(newLength, currentLength - newLength);
2870
+ }
2871
+ // adds / removes the necessary numeric properties to this object
2872
+ updateArrayLength(oldLength, delta) {
2873
+ if (oldLength !== this.lastKnownLength)
2874
+ throw new Error("[mobx] Modification exception: the internal structure of an observable array was changed. Did you use peek() to change it?");
2875
+ this.lastKnownLength += delta;
2876
+ if (delta > 0 && oldLength + delta + 1 > OBSERVABLE_ARRAY_BUFFER_SIZE)
2877
+ reserveArrayBuffer(oldLength + delta + 1);
2878
+ }
2879
+ spliceWithArray(index, deleteCount, newItems) {
2880
+ checkIfStateModificationsAreAllowed(this.atom);
2881
+ const length = this.values.length;
2882
+ if (index === undefined)
2883
+ index = 0;
2884
+ else if (index > length)
2885
+ index = length;
2886
+ else if (index < 0)
2887
+ index = Math.max(0, length + index);
2888
+ if (arguments.length === 1)
2889
+ deleteCount = length - index;
2890
+ else if (deleteCount === undefined || deleteCount === null)
2891
+ deleteCount = 0;
2892
+ else
2893
+ deleteCount = Math.max(0, Math.min(deleteCount, length - index));
2894
+ if (newItems === undefined)
2895
+ newItems = EMPTY_ARRAY;
2896
+ if (hasInterceptors(this)) {
2897
+ const change = interceptChange(this, {
2898
+ object: this.array,
2899
+ type: "splice",
2900
+ index,
2901
+ removedCount: deleteCount,
2902
+ added: newItems
2903
+ });
2904
+ if (!change)
2905
+ return EMPTY_ARRAY;
2906
+ deleteCount = change.removedCount;
2907
+ newItems = change.added;
2908
+ }
2909
+ newItems =
2910
+ newItems.length === 0 ? newItems : newItems.map(v => this.enhancer(v, undefined));
2911
+ const lengthDelta = newItems.length - deleteCount;
2912
+ this.updateArrayLength(length, lengthDelta); // create or remove new entries
2913
+ const res = this.spliceItemsIntoValues(index, deleteCount, newItems);
2914
+ if (deleteCount !== 0 || newItems.length !== 0)
2915
+ this.notifyArraySplice(index, newItems, res);
2916
+ return this.dehanceValues(res);
2917
+ }
2918
+ spliceItemsIntoValues(index, deleteCount, newItems) {
2919
+ if (newItems.length < MAX_SPLICE_SIZE) {
2920
+ return this.values.splice(index, deleteCount, ...newItems);
2921
+ }
2922
+ else {
2923
+ const res = this.values.slice(index, index + deleteCount);
2924
+ this.values = this.values
2925
+ .slice(0, index)
2926
+ .concat(newItems, this.values.slice(index + deleteCount));
2927
+ return res;
2928
+ }
2929
+ }
2930
+ notifyArrayChildUpdate(index, newValue, oldValue) {
2931
+ const notifySpy = !this.owned && isSpyEnabled();
2932
+ const notify = hasListeners(this);
2933
+ const change = notify || notifySpy
2934
+ ? {
2935
+ object: this.array,
2936
+ type: "update",
2937
+ index,
2938
+ newValue,
2939
+ oldValue
2940
+ }
2941
+ : null;
2942
+ if (notifySpy)
2943
+ spyReportStart(Object.assign({}, change, { name: this.atom.name }));
2944
+ this.atom.reportChanged();
2945
+ if (notify)
2946
+ notifyListeners(this, change);
2947
+ if (notifySpy)
2948
+ spyReportEnd();
2949
+ }
2950
+ notifyArraySplice(index, added, removed) {
2951
+ const notifySpy = !this.owned && isSpyEnabled();
2952
+ const notify = hasListeners(this);
2953
+ const change = notify || notifySpy
2954
+ ? {
2955
+ object: this.array,
2956
+ type: "splice",
2957
+ index,
2958
+ removed,
2959
+ added,
2960
+ removedCount: removed.length,
2961
+ addedCount: added.length
2962
+ }
2963
+ : null;
2964
+ if (notifySpy)
2965
+ spyReportStart(Object.assign({}, change, { name: this.atom.name }));
2966
+ this.atom.reportChanged();
2967
+ // conform: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/observe
2968
+ if (notify)
2969
+ notifyListeners(this, change);
2970
+ if (notifySpy)
2971
+ spyReportEnd();
2972
+ }
2973
+ }
2974
+ class ObservableArray extends StubArray {
2975
+ constructor(initialValues, enhancer, name = "ObservableArray@" + getNextId(), owned = false) {
2976
+ super();
2977
+ const adm = new ObservableArrayAdministration(name, enhancer, this, owned);
2978
+ addHiddenFinalProp(this, "$mobx", adm);
2979
+ if (initialValues && initialValues.length) {
2980
+ const prev = allowStateChangesStart(true);
2981
+ this.spliceWithArray(0, 0, initialValues);
2982
+ allowStateChangesEnd(prev);
2983
+ }
2984
+ if (safariPrototypeSetterInheritanceBug) {
2985
+ // Seems that Safari won't use numeric prototype setter untill any * numeric property is
2986
+ // defined on the instance. After that it works fine, even if this property is deleted.
2987
+ Object.defineProperty(adm.array, "0", ENTRY_0);
2988
+ }
2989
+ }
2990
+ intercept(handler) {
2991
+ return this.$mobx.intercept(handler);
2992
+ }
2993
+ observe(listener, fireImmediately = false) {
2994
+ return this.$mobx.observe(listener, fireImmediately);
2995
+ }
2996
+ clear() {
2997
+ return this.splice(0);
2998
+ }
2999
+ concat(...arrays) {
3000
+ this.$mobx.atom.reportObserved();
3001
+ return Array.prototype.concat.apply(this.peek(), arrays.map(a => (isObservableArray(a) ? a.peek() : a)));
3002
+ }
3003
+ replace(newItems) {
3004
+ return this.$mobx.spliceWithArray(0, this.$mobx.values.length, newItems);
3005
+ }
3006
+ /**
3007
+ * Converts this array back to a (shallow) javascript structure.
3008
+ * For a deep clone use mobx.toJS
3009
+ */
3010
+ toJS() {
3011
+ return this.slice();
3012
+ }
3013
+ toJSON() {
3014
+ // Used by JSON.stringify
3015
+ return this.toJS();
3016
+ }
3017
+ peek() {
3018
+ this.$mobx.atom.reportObserved();
3019
+ return this.$mobx.dehanceValues(this.$mobx.values);
3020
+ }
3021
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
3022
+ find(predicate, thisArg, fromIndex = 0) {
3023
+ if (arguments.length === 3)
3024
+ deprecated("The array.find fromIndex argument to find will not be supported anymore in the next major");
3025
+ const idx = this.findIndex.apply(this, arguments);
3026
+ return idx === -1 ? undefined : this.get(idx);
3027
+ }
3028
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex
3029
+ findIndex(predicate, thisArg, fromIndex = 0) {
3030
+ if (arguments.length === 3)
3031
+ deprecated("The array.findIndex fromIndex argument to find will not be supported anymore in the next major");
3032
+ const items = this.peek(), l = items.length;
3033
+ for (let i = fromIndex; i < l; i++)
3034
+ if (predicate.call(thisArg, items[i], i, this))
3035
+ return i;
3036
+ return -1;
3037
+ }
3038
+ /*
3039
+ * functions that do alter the internal structure of the array, (based on lib.es6.d.ts)
3040
+ * since these functions alter the inner structure of the array, the have side effects.
3041
+ * Because the have side effects, they should not be used in computed function,
3042
+ * and for that reason the do not call dependencyState.notifyObserved
3043
+ */
3044
+ splice(index, deleteCount, ...newItems) {
3045
+ switch (arguments.length) {
3046
+ case 0:
3047
+ return [];
3048
+ case 1:
3049
+ return this.$mobx.spliceWithArray(index);
3050
+ case 2:
3051
+ return this.$mobx.spliceWithArray(index, deleteCount);
3052
+ }
3053
+ return this.$mobx.spliceWithArray(index, deleteCount, newItems);
3054
+ }
3055
+ spliceWithArray(index, deleteCount, newItems) {
3056
+ return this.$mobx.spliceWithArray(index, deleteCount, newItems);
3057
+ }
3058
+ push(...items) {
3059
+ const adm = this.$mobx;
3060
+ adm.spliceWithArray(adm.values.length, 0, items);
3061
+ return adm.values.length;
3062
+ }
3063
+ pop() {
3064
+ return this.splice(Math.max(this.$mobx.values.length - 1, 0), 1)[0];
3065
+ }
3066
+ shift() {
3067
+ return this.splice(0, 1)[0];
3068
+ }
3069
+ unshift(...items) {
3070
+ const adm = this.$mobx;
3071
+ adm.spliceWithArray(0, 0, items);
3072
+ return adm.values.length;
3073
+ }
3074
+ reverse() {
3075
+ // reverse by default mutates in place before returning the result
3076
+ // which makes it both a 'derivation' and a 'mutation'.
3077
+ // so we deviate from the default and just make it an dervitation
3078
+ const clone = this.slice();
3079
+ return clone.reverse.apply(clone, arguments);
3080
+ }
3081
+ sort(compareFn) {
3082
+ // sort by default mutates in place before returning the result
3083
+ // which goes against all good practices. Let's not change the array in place!
3084
+ const clone = this.slice();
3085
+ return clone.sort.apply(clone, arguments);
3086
+ }
3087
+ remove(value) {
3088
+ const idx = this.$mobx.dehanceValues(this.$mobx.values).indexOf(value);
3089
+ if (idx > -1) {
3090
+ this.splice(idx, 1);
3091
+ return true;
3092
+ }
3093
+ return false;
3094
+ }
3095
+ move(fromIndex, toIndex) {
3096
+ deprecated("observableArray.move is deprecated, use .slice() & .replace() instead");
3097
+ function checkIndex(index) {
3098
+ if (index < 0) {
3099
+ throw new Error(`[mobx.array] Index out of bounds: ${index} is negative`);
3100
+ }
3101
+ const length = this.$mobx.values.length;
3102
+ if (index >= length) {
3103
+ throw new Error(`[mobx.array] Index out of bounds: ${index} is not smaller than ${length}`);
3104
+ }
3105
+ }
3106
+ checkIndex.call(this, fromIndex);
3107
+ checkIndex.call(this, toIndex);
3108
+ if (fromIndex === toIndex) {
3109
+ return;
3110
+ }
3111
+ const oldItems = this.$mobx.values;
3112
+ let newItems;
3113
+ if (fromIndex < toIndex) {
3114
+ newItems = [
3115
+ ...oldItems.slice(0, fromIndex),
3116
+ ...oldItems.slice(fromIndex + 1, toIndex + 1),
3117
+ oldItems[fromIndex],
3118
+ ...oldItems.slice(toIndex + 1)
3119
+ ];
3120
+ }
3121
+ else {
3122
+ // toIndex < fromIndex
3123
+ newItems = [
3124
+ ...oldItems.slice(0, toIndex),
3125
+ oldItems[fromIndex],
3126
+ ...oldItems.slice(toIndex, fromIndex),
3127
+ ...oldItems.slice(fromIndex + 1)
3128
+ ];
3129
+ }
3130
+ this.replace(newItems);
3131
+ }
3132
+ // See #734, in case property accessors are unreliable...
3133
+ get(index) {
3134
+ const impl = this.$mobx;
3135
+ if (impl) {
3136
+ if (index < impl.values.length) {
3137
+ impl.atom.reportObserved();
3138
+ return impl.dehanceValue(impl.values[index]);
3139
+ }
3140
+ console.warn(`[mobx.array] Attempt to read an array index (${index}) that is out of bounds (${impl.values.length}). Please check length first. Out of bound indices will not be tracked by MobX`);
3141
+ }
3142
+ return undefined;
3143
+ }
3144
+ // See #734, in case property accessors are unreliable...
3145
+ set(index, newValue) {
3146
+ const adm = this.$mobx;
3147
+ const values = adm.values;
3148
+ if (index < values.length) {
3149
+ // update at index in range
3150
+ checkIfStateModificationsAreAllowed(adm.atom);
3151
+ const oldValue = values[index];
3152
+ if (hasInterceptors(adm)) {
3153
+ const change = interceptChange(adm, {
3154
+ type: "update",
3155
+ object: this,
3156
+ index,
3157
+ newValue
3158
+ });
3159
+ if (!change)
3160
+ return;
3161
+ newValue = change.newValue;
3162
+ }
3163
+ newValue = adm.enhancer(newValue, oldValue);
3164
+ const changed = newValue !== oldValue;
3165
+ if (changed) {
3166
+ values[index] = newValue;
3167
+ adm.notifyArrayChildUpdate(index, newValue, oldValue);
3168
+ }
3169
+ }
3170
+ else if (index === values.length) {
3171
+ // add a new item
3172
+ adm.spliceWithArray(index, 0, [newValue]);
3173
+ }
3174
+ else {
3175
+ // out of bounds
3176
+ throw new Error(`[mobx.array] Index out of bounds, ${index} is larger than ${values.length}`);
3177
+ }
3178
+ }
3179
+ }
3180
+ declareIterator(ObservableArray.prototype, function () {
3181
+ this.$mobx.atom.reportObserved();
3182
+ const self = this;
3183
+ let nextIndex = 0;
3184
+ return makeIterable({
3185
+ next() {
3186
+ return nextIndex < self.length
3187
+ ? { value: self[nextIndex++], done: false }
3188
+ : { done: true, value: undefined };
3189
+ }
3190
+ });
3191
+ });
3192
+ Object.defineProperty(ObservableArray.prototype, "length", {
3193
+ enumerable: false,
3194
+ configurable: true,
3195
+ get: function () {
3196
+ return this.$mobx.getArrayLength();
3197
+ },
3198
+ set: function (newLength) {
3199
+ this.$mobx.setArrayLength(newLength);
3200
+ }
3201
+ });
3202
+ addHiddenProp(ObservableArray.prototype, toStringTagSymbol(), "Array");
3203
+ [
3204
+ "every",
3205
+ "filter",
3206
+ "forEach",
3207
+ "indexOf",
3208
+ "join",
3209
+ "lastIndexOf",
3210
+ "map",
3211
+ "reduce",
3212
+ "reduceRight",
3213
+ "slice",
3214
+ "some",
3215
+ "toString",
3216
+ "toLocaleString"
3217
+ ].forEach(funcName => {
3218
+ const baseFunc = Array.prototype[funcName];
3219
+ invariant(typeof baseFunc === "function", `Base function not defined on Array prototype: '${funcName}'`);
3220
+ addHiddenProp(ObservableArray.prototype, funcName, function () {
3221
+ return baseFunc.apply(this.peek(), arguments);
3222
+ });
3223
+ });
3224
+ /**
3225
+ * We don't want those to show up in `for (const key in ar)` ...
3226
+ */
3227
+ makeNonEnumerable(ObservableArray.prototype, [
3228
+ "constructor",
3229
+ "intercept",
3230
+ "observe",
3231
+ "clear",
3232
+ "concat",
3233
+ "get",
3234
+ "replace",
3235
+ "toJS",
3236
+ "toJSON",
3237
+ "peek",
3238
+ "find",
3239
+ "findIndex",
3240
+ "splice",
3241
+ "spliceWithArray",
3242
+ "push",
3243
+ "pop",
3244
+ "set",
3245
+ "shift",
3246
+ "unshift",
3247
+ "reverse",
3248
+ "sort",
3249
+ "remove",
3250
+ "move",
3251
+ "toString",
3252
+ "toLocaleString"
3253
+ ]);
3254
+ // See #364
3255
+ const ENTRY_0 = createArrayEntryDescriptor(0);
3256
+ function createArrayEntryDescriptor(index) {
3257
+ return {
3258
+ enumerable: false,
3259
+ configurable: false,
3260
+ get: function () {
3261
+ return this.get(index);
3262
+ },
3263
+ set: function (value) {
3264
+ this.set(index, value);
3265
+ }
3266
+ };
3267
+ }
3268
+ function createArrayBufferItem(index) {
3269
+ Object.defineProperty(ObservableArray.prototype, "" + index, createArrayEntryDescriptor(index));
3270
+ }
3271
+ function reserveArrayBuffer(max) {
3272
+ for (let index = OBSERVABLE_ARRAY_BUFFER_SIZE; index < max; index++)
3273
+ createArrayBufferItem(index);
3274
+ OBSERVABLE_ARRAY_BUFFER_SIZE = max;
3275
+ }
3276
+ reserveArrayBuffer(1000);
3277
+ const isObservableArrayAdministration = createInstanceofPredicate("ObservableArrayAdministration", ObservableArrayAdministration);
3278
+ function isObservableArray(thing) {
3279
+ return isObject(thing) && isObservableArrayAdministration(thing.$mobx);
3280
+ }
3281
+
3282
+ const ObservableMapMarker = {};
3283
+ class ObservableMap {
3284
+ constructor(initialData, enhancer = deepEnhancer, name = "ObservableMap@" + getNextId()) {
3285
+ this.enhancer = enhancer;
3286
+ this.name = name;
3287
+ this.$mobx = ObservableMapMarker;
3288
+ this._keys = (new ObservableArray(undefined, referenceEnhancer, `${this.name}.keys()`, true));
3289
+ if (typeof Map !== "function") {
3290
+ throw new Error("mobx.map requires Map polyfill for the current browser. Check babel-polyfill or core-js/es6/map.js");
3291
+ }
3292
+ this._data = new Map();
3293
+ this._hasMap = new Map();
3294
+ this.merge(initialData);
3295
+ }
3296
+ _has(key) {
3297
+ return this._data.has(key);
3298
+ }
3299
+ has(key) {
3300
+ if (!globalState.trackingDerivation)
3301
+ return this._has(key);
3302
+ let entry = this._hasMap.get(key);
3303
+ if (!entry) {
3304
+ // todo: replace with atom (breaking change)
3305
+ const newEntry = (entry = new ObservableValue(this._has(key), referenceEnhancer, `${this.name}.${stringifyKey(key)}?`, false));
3306
+ this._hasMap.set(key, newEntry);
3307
+ onBecomeUnobserved(newEntry, () => this._hasMap.delete(key));
3308
+ }
3309
+ return entry.get();
3310
+ }
3311
+ set(key, value) {
3312
+ const hasKey = this._has(key);
3313
+ if (hasInterceptors(this)) {
3314
+ const change = interceptChange(this, {
3315
+ type: hasKey ? "update" : "add",
3316
+ object: this,
3317
+ newValue: value,
3318
+ name: key
3319
+ });
3320
+ if (!change)
3321
+ return this;
3322
+ value = change.newValue;
3323
+ }
3324
+ if (hasKey) {
3325
+ this._updateValue(key, value);
3326
+ }
3327
+ else {
3328
+ this._addValue(key, value);
3329
+ }
3330
+ return this;
3331
+ }
3332
+ delete(key) {
3333
+ if (hasInterceptors(this)) {
3334
+ const change = interceptChange(this, {
3335
+ type: "delete",
3336
+ object: this,
3337
+ name: key
3338
+ });
3339
+ if (!change)
3340
+ return false;
3341
+ }
3342
+ if (this._has(key)) {
3343
+ const notifySpy = isSpyEnabled();
3344
+ const notify = hasListeners(this);
3345
+ const change = notify || notifySpy
3346
+ ? {
3347
+ type: "delete",
3348
+ object: this,
3349
+ oldValue: this._data.get(key).value,
3350
+ name: key
3351
+ }
3352
+ : null;
3353
+ if (notifySpy)
3354
+ spyReportStart(Object.assign({}, change, { name: this.name, key }));
3355
+ transaction(() => {
3356
+ this._keys.remove(key);
3357
+ this._updateHasMapEntry(key, false);
3358
+ const observable = this._data.get(key);
3359
+ observable.setNewValue(undefined);
3360
+ this._data.delete(key);
3361
+ });
3362
+ if (notify)
3363
+ notifyListeners(this, change);
3364
+ if (notifySpy)
3365
+ spyReportEnd();
3366
+ return true;
3367
+ }
3368
+ return false;
3369
+ }
3370
+ _updateHasMapEntry(key, value) {
3371
+ let entry = this._hasMap.get(key);
3372
+ if (entry) {
3373
+ entry.setNewValue(value);
3374
+ }
3375
+ }
3376
+ _updateValue(key, newValue) {
3377
+ const observable = this._data.get(key);
3378
+ newValue = observable.prepareNewValue(newValue);
3379
+ if (newValue !== globalState.UNCHANGED) {
3380
+ const notifySpy = isSpyEnabled();
3381
+ const notify = hasListeners(this);
3382
+ const change = notify || notifySpy
3383
+ ? {
3384
+ type: "update",
3385
+ object: this,
3386
+ oldValue: observable.value,
3387
+ name: key,
3388
+ newValue
3389
+ }
3390
+ : null;
3391
+ if (notifySpy)
3392
+ spyReportStart(Object.assign({}, change, { name: this.name, key }));
3393
+ observable.setNewValue(newValue);
3394
+ if (notify)
3395
+ notifyListeners(this, change);
3396
+ if (notifySpy)
3397
+ spyReportEnd();
3398
+ }
3399
+ }
3400
+ _addValue(key, newValue) {
3401
+ transaction(() => {
3402
+ const observable = new ObservableValue(newValue, this.enhancer, `${this.name}.${stringifyKey(key)}`, false);
3403
+ this._data.set(key, observable);
3404
+ newValue = observable.value; // value might have been changed
3405
+ this._updateHasMapEntry(key, true);
3406
+ this._keys.push(key);
3407
+ });
3408
+ const notifySpy = isSpyEnabled();
3409
+ const notify = hasListeners(this);
3410
+ const change = notify || notifySpy
3411
+ ? {
3412
+ type: "add",
3413
+ object: this,
3414
+ name: key,
3415
+ newValue
3416
+ }
3417
+ : null;
3418
+ if (notifySpy)
3419
+ spyReportStart(Object.assign({}, change, { name: this.name, key }));
3420
+ if (notify)
3421
+ notifyListeners(this, change);
3422
+ if (notifySpy)
3423
+ spyReportEnd();
3424
+ }
3425
+ get(key) {
3426
+ if (this.has(key))
3427
+ return this.dehanceValue(this._data.get(key).get());
3428
+ return this.dehanceValue(undefined);
3429
+ }
3430
+ dehanceValue(value) {
3431
+ if (this.dehancer !== undefined) {
3432
+ return this.dehancer(value);
3433
+ }
3434
+ return value;
3435
+ }
3436
+ keys() {
3437
+ return this._keys[iteratorSymbol()]();
3438
+ }
3439
+ values() {
3440
+ const self = this;
3441
+ let nextIndex = 0;
3442
+ return makeIterable({
3443
+ next() {
3444
+ return nextIndex < self._keys.length
3445
+ ? { value: self.get(self._keys[nextIndex++]), done: false }
3446
+ : { value: undefined, done: true };
3447
+ }
3448
+ });
3449
+ }
3450
+ entries() {
3451
+ const self = this;
3452
+ let nextIndex = 0;
3453
+ return makeIterable({
3454
+ next: function () {
3455
+ if (nextIndex < self._keys.length) {
3456
+ const key = self._keys[nextIndex++];
3457
+ return {
3458
+ value: [key, self.get(key)],
3459
+ done: false
3460
+ };
3461
+ }
3462
+ return { done: true };
3463
+ }
3464
+ });
3465
+ }
3466
+ forEach(callback, thisArg) {
3467
+ this._keys.forEach(key => callback.call(thisArg, this.get(key), key, this));
3468
+ }
3469
+ /** Merge another object into this object, returns this. */
3470
+ merge(other) {
3471
+ if (isObservableMap(other)) {
3472
+ other = other.toJS();
3473
+ }
3474
+ transaction(() => {
3475
+ if (isPlainObject(other))
3476
+ Object.keys(other).forEach(key => this.set(key, other[key]));
3477
+ else if (Array.isArray(other))
3478
+ other.forEach(([key, value]) => this.set(key, value));
3479
+ else if (isES6Map(other)) {
3480
+ if (other.constructor !== Map)
3481
+ fail("Cannot initialize from classes that inherit from Map: " + other.constructor.name); // prettier-ignore
3482
+ else
3483
+ other.forEach((value, key) => this.set(key, value));
3484
+ }
3485
+ else if (other !== null && other !== undefined)
3486
+ fail("Cannot initialize map from " + other);
3487
+ });
3488
+ return this;
3489
+ }
3490
+ clear() {
3491
+ transaction(() => {
3492
+ untracked(() => {
3493
+ this._keys.slice().forEach(key => this.delete(key));
3494
+ });
3495
+ });
3496
+ }
3497
+ replace(values) {
3498
+ transaction(() => {
3499
+ // grab all the keys that are present in the new map but not present in the current map
3500
+ // and delete them from the map, then merge the new map
3501
+ // this will cause reactions only on changed values
3502
+ const newKeys = getMapLikeKeys(values);
3503
+ const oldKeys = this._keys;
3504
+ const missingKeys = oldKeys.filter(k => newKeys.indexOf(k) === -1);
3505
+ missingKeys.forEach(k => this.delete(k));
3506
+ this.merge(values);
3507
+ });
3508
+ return this;
3509
+ }
3510
+ get size() {
3511
+ return this._keys.length;
3512
+ }
3513
+ /**
3514
+ * Returns a plain object that represents this map.
3515
+ * Note that all the keys being stringified.
3516
+ * If there are duplicating keys after converting them to strings, behaviour is undetermined.
3517
+ */
3518
+ toPOJO() {
3519
+ const res = {};
3520
+ this._keys.forEach(key => (res[typeof key === "symbol" ? key : stringifyKey(key)] = this.get(key)));
3521
+ return res;
3522
+ }
3523
+ /**
3524
+ * Returns a shallow non observable object clone of this map.
3525
+ * Note that the values migth still be observable. For a deep clone use mobx.toJS.
3526
+ */
3527
+ toJS() {
3528
+ const res = new Map();
3529
+ this._keys.forEach(key => res.set(key, this.get(key)));
3530
+ return res;
3531
+ }
3532
+ toJSON() {
3533
+ // Used by JSON.stringify
3534
+ return this.toPOJO();
3535
+ }
3536
+ toString() {
3537
+ return (this.name +
3538
+ "[{ " +
3539
+ this._keys.map(key => `${stringifyKey(key)}: ${"" + this.get(key)}`).join(", ") +
3540
+ " }]");
3541
+ }
3542
+ /**
3543
+ * Observes this object. Triggers for the events 'add', 'update' and 'delete'.
3544
+ * See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/observe
3545
+ * for callback details
3546
+ */
3547
+ observe(listener, fireImmediately) {
3548
+ process.env.NODE_ENV !== "production" &&
3549
+ invariant(fireImmediately !== true, "`observe` doesn't support fireImmediately=true in combination with maps.");
3550
+ return registerListener(this, listener);
3551
+ }
3552
+ intercept(handler) {
3553
+ return registerInterceptor(this, handler);
3554
+ }
3555
+ }
3556
+ function stringifyKey(key) {
3557
+ if (key && key.toString)
3558
+ return key.toString();
3559
+ else
3560
+ return new String(key).toString();
3561
+ }
3562
+ declareIterator(ObservableMap.prototype, function () {
3563
+ return this.entries();
3564
+ });
3565
+ addHiddenFinalProp(ObservableMap.prototype, toStringTagSymbol(), "Map");
3566
+ /* 'var' fixes small-build issue */
3567
+ const isObservableMap = createInstanceofPredicate("ObservableMap", ObservableMap);
3568
+
3569
+ const ObservableSetMarker = {};
3570
+ class ObservableSet {
3571
+ constructor(initialData, enhancer = deepEnhancer, name = "ObservableSet@" + getNextId()) {
3572
+ this.name = name;
3573
+ this.$mobx = ObservableSetMarker;
3574
+ this._data = new Set();
3575
+ this._atom = createAtom(this.name);
3576
+ if (typeof Set !== "function") {
3577
+ throw new Error("mobx.set requires Set polyfill for the current browser. Check babel-polyfill or core-js/es6/set.js");
3578
+ }
3579
+ this.enhancer = (newV, oldV) => enhancer(newV, oldV, name);
3580
+ if (initialData) {
3581
+ this.replace(initialData);
3582
+ }
3583
+ }
3584
+ dehanceValue(value) {
3585
+ if (this.dehancer !== undefined) {
3586
+ return this.dehancer(value);
3587
+ }
3588
+ return value;
3589
+ }
3590
+ clear() {
3591
+ transaction(() => {
3592
+ untracked(() => {
3593
+ this._data.forEach(value => {
3594
+ this.delete(value);
3595
+ });
3596
+ });
3597
+ });
3598
+ }
3599
+ forEach(callbackFn, thisArg) {
3600
+ this._data.forEach(value => {
3601
+ callbackFn.call(thisArg, value, value, this);
3602
+ });
3603
+ }
3604
+ get size() {
3605
+ this._atom.reportObserved();
3606
+ return this._data.size;
3607
+ }
3608
+ add(value) {
3609
+ checkIfStateModificationsAreAllowed(this._atom);
3610
+ if (hasInterceptors(this)) {
3611
+ const change = interceptChange(this, {
3612
+ type: "add",
3613
+ object: this,
3614
+ newValue: value
3615
+ });
3616
+ if (!change)
3617
+ return this;
3618
+ // TODO: ideally, value = change.value would be done here, so that values can be
3619
+ // changed by interceptor. Same applies for other Set and Map api's.
3620
+ }
3621
+ if (!this.has(value)) {
3622
+ transaction(() => {
3623
+ this._data.add(this.enhancer(value, undefined));
3624
+ this._atom.reportChanged();
3625
+ });
3626
+ const notifySpy = isSpyEnabled();
3627
+ const notify = hasListeners(this);
3628
+ const change = notify || notifySpy
3629
+ ? {
3630
+ type: "add",
3631
+ object: this,
3632
+ newValue: value
3633
+ }
3634
+ : null;
3635
+ if (notifySpy && process.env.NODE_ENV !== "production")
3636
+ spyReportStart(change);
3637
+ if (notify)
3638
+ notifyListeners(this, change);
3639
+ if (notifySpy && process.env.NODE_ENV !== "production")
3640
+ spyReportEnd();
3641
+ }
3642
+ return this;
3643
+ }
3644
+ delete(value) {
3645
+ if (hasInterceptors(this)) {
3646
+ const change = interceptChange(this, {
3647
+ type: "delete",
3648
+ object: this,
3649
+ oldValue: value
3650
+ });
3651
+ if (!change)
3652
+ return false;
3653
+ }
3654
+ if (this.has(value)) {
3655
+ const notifySpy = isSpyEnabled();
3656
+ const notify = hasListeners(this);
3657
+ const change = notify || notifySpy
3658
+ ? {
3659
+ type: "delete",
3660
+ object: this,
3661
+ oldValue: value
3662
+ }
3663
+ : null;
3664
+ if (notifySpy && process.env.NODE_ENV !== "production")
3665
+ spyReportStart(Object.assign({}, change, { name: this.name }));
3666
+ transaction(() => {
3667
+ this._atom.reportChanged();
3668
+ this._data.delete(value);
3669
+ });
3670
+ if (notify)
3671
+ notifyListeners(this, change);
3672
+ if (notifySpy && process.env.NODE_ENV !== "production")
3673
+ spyReportEnd();
3674
+ return true;
3675
+ }
3676
+ return false;
3677
+ }
3678
+ has(value) {
3679
+ this._atom.reportObserved();
3680
+ return this._data.has(this.dehanceValue(value));
3681
+ }
3682
+ entries() {
3683
+ let nextIndex = 0;
3684
+ const keys = iteratorToArray(this.keys());
3685
+ const values = iteratorToArray(this.values());
3686
+ return makeIterable({
3687
+ next() {
3688
+ const index = nextIndex;
3689
+ nextIndex += 1;
3690
+ return index < values.length
3691
+ ? { value: [keys[index], values[index]], done: false }
3692
+ : { done: true };
3693
+ }
3694
+ });
3695
+ }
3696
+ keys() {
3697
+ return this.values();
3698
+ }
3699
+ values() {
3700
+ this._atom.reportObserved();
3701
+ const self = this;
3702
+ let nextIndex = 0;
3703
+ let observableValues;
3704
+ if (this._data.values !== undefined) {
3705
+ observableValues = iteratorToArray(this._data.values());
3706
+ }
3707
+ else {
3708
+ // There is no values function in IE11
3709
+ observableValues = [];
3710
+ this._data.forEach(e => observableValues.push(e));
3711
+ }
3712
+ return makeIterable({
3713
+ next() {
3714
+ return nextIndex < observableValues.length
3715
+ ? { value: self.dehanceValue(observableValues[nextIndex++]), done: false }
3716
+ : { done: true };
3717
+ }
3718
+ });
3719
+ }
3720
+ replace(other) {
3721
+ if (isObservableSet(other)) {
3722
+ other = other.toJS();
3723
+ }
3724
+ transaction(() => {
3725
+ if (Array.isArray(other)) {
3726
+ this.clear();
3727
+ other.forEach(value => this.add(value));
3728
+ }
3729
+ else if (isES6Set(other)) {
3730
+ this.clear();
3731
+ other.forEach(value => this.add(value));
3732
+ }
3733
+ else if (other !== null && other !== undefined) {
3734
+ fail("Cannot initialize set from " + other);
3735
+ }
3736
+ });
3737
+ return this;
3738
+ }
3739
+ observe(listener, fireImmediately) {
3740
+ // TODO 'fireImmediately' can be true?
3741
+ process.env.NODE_ENV !== "production" &&
3742
+ invariant(fireImmediately !== true, "`observe` doesn't support fireImmediately=true in combination with sets.");
3743
+ return registerListener(this, listener);
3744
+ }
3745
+ intercept(handler) {
3746
+ return registerInterceptor(this, handler);
3747
+ }
3748
+ toJS() {
3749
+ return new Set(this);
3750
+ }
3751
+ toString() {
3752
+ return this.name + "[ " + iteratorToArray(this.keys()).join(", ") + " ]";
3753
+ }
3754
+ }
3755
+ declareIterator(ObservableSet.prototype, function () {
3756
+ return this.values();
3757
+ });
3758
+ addHiddenFinalProp(ObservableSet.prototype, toStringTagSymbol(), "Set");
3759
+ const isObservableSet = createInstanceofPredicate("ObservableSet", ObservableSet);
3760
+
3761
+ class ObservableObjectAdministration {
3762
+ constructor(target, name, defaultEnhancer) {
3763
+ this.target = target;
3764
+ this.name = name;
3765
+ this.defaultEnhancer = defaultEnhancer;
3766
+ this.values = {};
3767
+ }
3768
+ read(owner, key) {
3769
+ if (process.env.NODE_ENV === "production" && this.target !== owner) {
3770
+ this.illegalAccess(owner, key);
3771
+ if (!this.values[key])
3772
+ return undefined;
3773
+ }
3774
+ return this.values[key].get();
3775
+ }
3776
+ write(owner, key, newValue) {
3777
+ const instance = this.target;
3778
+ if (process.env.NODE_ENV === "production" && instance !== owner) {
3779
+ this.illegalAccess(owner, key);
3780
+ }
3781
+ const observable = this.values[key];
3782
+ if (observable instanceof ComputedValue) {
3783
+ observable.set(newValue);
3784
+ return;
3785
+ }
3786
+ // intercept
3787
+ if (hasInterceptors(this)) {
3788
+ const change = interceptChange(this, {
3789
+ type: "update",
3790
+ object: instance,
3791
+ name: key,
3792
+ newValue
3793
+ });
3794
+ if (!change)
3795
+ return;
3796
+ newValue = change.newValue;
3797
+ }
3798
+ newValue = observable.prepareNewValue(newValue);
3799
+ // notify spy & observers
3800
+ if (newValue !== globalState.UNCHANGED) {
3801
+ const notify = hasListeners(this);
3802
+ const notifySpy = isSpyEnabled();
3803
+ const change = notify || notifySpy
3804
+ ? {
3805
+ type: "update",
3806
+ object: instance,
3807
+ oldValue: observable.value,
3808
+ name: key,
3809
+ newValue
3810
+ }
3811
+ : null;
3812
+ if (notifySpy)
3813
+ spyReportStart(Object.assign({}, change, { name: this.name, key }));
3814
+ observable.setNewValue(newValue);
3815
+ if (notify)
3816
+ notifyListeners(this, change);
3817
+ if (notifySpy)
3818
+ spyReportEnd();
3819
+ }
3820
+ }
3821
+ remove(key) {
3822
+ if (!this.values[key])
3823
+ return;
3824
+ const { target } = this;
3825
+ if (hasInterceptors(this)) {
3826
+ const change = interceptChange(this, {
3827
+ object: target,
3828
+ name: key,
3829
+ type: "remove"
3830
+ });
3831
+ if (!change)
3832
+ return;
3833
+ }
3834
+ try {
3835
+ startBatch();
3836
+ const notify = hasListeners(this);
3837
+ const notifySpy = isSpyEnabled();
3838
+ const oldValue = this.values[key].get();
3839
+ if (this.keys)
3840
+ this.keys.remove(key);
3841
+ delete this.values[key];
3842
+ delete this.target[key];
3843
+ const change = notify || notifySpy
3844
+ ? {
3845
+ type: "remove",
3846
+ object: target,
3847
+ oldValue: oldValue,
3848
+ name: key
3849
+ }
3850
+ : null;
3851
+ if (notifySpy)
3852
+ spyReportStart(Object.assign({}, change, { name: this.name, key }));
3853
+ if (notify)
3854
+ notifyListeners(this, change);
3855
+ if (notifySpy)
3856
+ spyReportEnd();
3857
+ }
3858
+ finally {
3859
+ endBatch();
3860
+ }
3861
+ }
3862
+ illegalAccess(owner, propName) {
3863
+ /**
3864
+ * This happens if a property is accessed through the prototype chain, but the property was
3865
+ * declared directly as own property on the prototype.
3866
+ *
3867
+ * E.g.:
3868
+ * class A {
3869
+ * }
3870
+ * extendObservable(A.prototype, { x: 1 })
3871
+ *
3872
+ * classB extens A {
3873
+ * }
3874
+ * console.log(new B().x)
3875
+ *
3876
+ * It is unclear whether the property should be considered 'static' or inherited.
3877
+ * Either use `console.log(A.x)`
3878
+ * or: decorate(A, { x: observable })
3879
+ *
3880
+ * When using decorate, the property will always be redeclared as own property on the actual instance
3881
+ */
3882
+ console.warn(`Property '${propName}' of '${owner}' was accessed through the prototype chain. Use 'decorate' instead to declare the prop or access it statically through it's owner`);
3883
+ }
3884
+ /**
3885
+ * Observes this object. Triggers for the events 'add', 'update' and 'delete'.
3886
+ * See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/observe
3887
+ * for callback details
3888
+ */
3889
+ observe(callback, fireImmediately) {
3890
+ process.env.NODE_ENV !== "production" &&
3891
+ invariant(fireImmediately !== true, "`observe` doesn't support the fire immediately property for observable objects.");
3892
+ return registerListener(this, callback);
3893
+ }
3894
+ intercept(handler) {
3895
+ return registerInterceptor(this, handler);
3896
+ }
3897
+ getKeys() {
3898
+ if (this.keys === undefined) {
3899
+ this.keys = (new ObservableArray(Object.keys(this.values).filter(key => this.values[key] instanceof ObservableValue), referenceEnhancer, `keys(${this.name})`, true));
3900
+ }
3901
+ return this.keys.slice();
3902
+ }
3903
+ }
3904
+ function asObservableObject(target, name = "", defaultEnhancer = deepEnhancer) {
3905
+ let adm = target.$mobx;
3906
+ if (adm)
3907
+ return adm;
3908
+ process.env.NODE_ENV !== "production" &&
3909
+ invariant(Object.isExtensible(target), "Cannot make the designated object observable; it is not extensible");
3910
+ if (!isPlainObject(target))
3911
+ name = (target.constructor.name || "ObservableObject") + "@" + getNextId();
3912
+ if (!name)
3913
+ name = "ObservableObject@" + getNextId();
3914
+ adm = new ObservableObjectAdministration(target, name, defaultEnhancer);
3915
+ addHiddenFinalProp(target, "$mobx", adm);
3916
+ return adm;
3917
+ }
3918
+ function defineObservableProperty(target, propName, newValue, enhancer) {
3919
+ const adm = asObservableObject(target);
3920
+ assertPropertyConfigurable(target, propName);
3921
+ if (hasInterceptors(adm)) {
3922
+ const change = interceptChange(adm, {
3923
+ object: target,
3924
+ name: propName,
3925
+ type: "add",
3926
+ newValue
3927
+ });
3928
+ if (!change)
3929
+ return;
3930
+ newValue = change.newValue;
3931
+ }
3932
+ const observable = (adm.values[propName] = new ObservableValue(newValue, enhancer, `${adm.name}.${propName}`, false));
3933
+ newValue = observable.value; // observableValue might have changed it
3934
+ Object.defineProperty(target, propName, generateObservablePropConfig(propName));
3935
+ if (adm.keys)
3936
+ adm.keys.push(propName);
3937
+ notifyPropertyAddition(adm, target, propName, newValue);
3938
+ }
3939
+ function defineComputedProperty(target, // which objects holds the observable and provides `this` context?
3940
+ propName, options) {
3941
+ const adm = asObservableObject(target);
3942
+ options.name = `${adm.name}.${propName}`;
3943
+ options.context = target;
3944
+ adm.values[propName] = new ComputedValue(options);
3945
+ Object.defineProperty(target, propName, generateComputedPropConfig(propName));
3946
+ }
3947
+ const observablePropertyConfigs = Object.create(null);
3948
+ const computedPropertyConfigs = Object.create(null);
3949
+ function generateObservablePropConfig(propName) {
3950
+ return (observablePropertyConfigs[propName] ||
3951
+ (observablePropertyConfigs[propName] = {
3952
+ configurable: true,
3953
+ enumerable: true,
3954
+ get() {
3955
+ return this.$mobx.read(this, propName);
3956
+ },
3957
+ set(v) {
3958
+ this.$mobx.write(this, propName, v);
3959
+ }
3960
+ }));
3961
+ }
3962
+ function getAdministrationForComputedPropOwner(owner) {
3963
+ const adm = owner.$mobx;
3964
+ if (!adm) {
3965
+ // because computed props are declared on proty,
3966
+ // the current instance might not have been initialized yet
3967
+ initializeInstance(owner);
3968
+ return owner.$mobx;
3969
+ }
3970
+ return adm;
3971
+ }
3972
+ function generateComputedPropConfig(propName) {
3973
+ return (computedPropertyConfigs[propName] ||
3974
+ (computedPropertyConfigs[propName] = {
3975
+ configurable: globalState.computedConfigurable,
3976
+ enumerable: false,
3977
+ get() {
3978
+ return getAdministrationForComputedPropOwner(this).read(this, propName);
3979
+ },
3980
+ set(v) {
3981
+ getAdministrationForComputedPropOwner(this).write(this, propName, v);
3982
+ }
3983
+ }));
3984
+ }
3985
+ function notifyPropertyAddition(adm, object, key, newValue) {
3986
+ const notify = hasListeners(adm);
3987
+ const notifySpy = isSpyEnabled();
3988
+ const change = notify || notifySpy
3989
+ ? {
3990
+ type: "add",
3991
+ object,
3992
+ name: key,
3993
+ newValue
3994
+ }
3995
+ : null;
3996
+ if (notifySpy)
3997
+ spyReportStart(Object.assign({}, change, { name: adm.name, key }));
3998
+ if (notify)
3999
+ notifyListeners(adm, change);
4000
+ if (notifySpy)
4001
+ spyReportEnd();
4002
+ }
4003
+ const isObservableObjectAdministration = createInstanceofPredicate("ObservableObjectAdministration", ObservableObjectAdministration);
4004
+ function isObservableObject(thing) {
4005
+ if (isObject(thing)) {
4006
+ // Initializers run lazily when transpiling to babel, so make sure they are run...
4007
+ initializeInstance(thing);
4008
+ return isObservableObjectAdministration(thing.$mobx);
4009
+ }
4010
+ return false;
4011
+ }
4012
+
4013
+ function getAtom(thing, property) {
4014
+ if (typeof thing === "object" && thing !== null) {
4015
+ if (isObservableArray(thing)) {
4016
+ if (property !== undefined)
4017
+ fail(process.env.NODE_ENV !== "production" &&
4018
+ "It is not possible to get index atoms from arrays");
4019
+ return thing.$mobx.atom;
4020
+ }
4021
+ if (isObservableSet(thing)) {
4022
+ return thing.$mobx;
4023
+ }
4024
+ if (isObservableMap(thing)) {
4025
+ const anyThing = thing;
4026
+ if (property === undefined)
4027
+ return getAtom(anyThing._keys);
4028
+ const observable = anyThing._data.get(property) || anyThing._hasMap.get(property);
4029
+ if (!observable)
4030
+ fail(process.env.NODE_ENV !== "production" &&
4031
+ `the entry '${property}' does not exist in the observable map '${getDebugName(thing)}'`);
4032
+ return observable;
4033
+ }
4034
+ // Initializers run lazily when transpiling to babel, so make sure they are run...
4035
+ initializeInstance(thing);
4036
+ if (property && !thing.$mobx)
4037
+ thing[property]; // See #1072
4038
+ if (isObservableObject(thing)) {
4039
+ if (!property)
4040
+ return fail(process.env.NODE_ENV !== "production" && `please specify a property`);
4041
+ const observable = thing.$mobx.values[property];
4042
+ if (!observable)
4043
+ fail(process.env.NODE_ENV !== "production" &&
4044
+ `no observable property '${property}' found on the observable object '${getDebugName(thing)}'`);
4045
+ return observable;
4046
+ }
4047
+ if (isAtom(thing) || isComputedValue(thing) || isReaction(thing)) {
4048
+ return thing;
4049
+ }
4050
+ }
4051
+ else if (typeof thing === "function") {
4052
+ if (isReaction(thing.$mobx)) {
4053
+ // disposer function
4054
+ return thing.$mobx;
4055
+ }
4056
+ }
4057
+ return fail(process.env.NODE_ENV !== "production" && "Cannot obtain atom from " + thing);
4058
+ }
4059
+ function getAdministration(thing, property) {
4060
+ if (!thing)
4061
+ fail("Expecting some object");
4062
+ if (property !== undefined)
4063
+ return getAdministration(getAtom(thing, property));
4064
+ if (isAtom(thing) || isComputedValue(thing) || isReaction(thing))
4065
+ return thing;
4066
+ if (isObservableMap(thing) || isObservableSet(thing))
4067
+ return thing;
4068
+ // Initializers run lazily when transpiling to babel, so make sure they are run...
4069
+ initializeInstance(thing);
4070
+ if (thing.$mobx)
4071
+ return thing.$mobx;
4072
+ fail(process.env.NODE_ENV !== "production" && "Cannot obtain administration from " + thing);
4073
+ }
4074
+ function getDebugName(thing, property) {
4075
+ let named;
4076
+ if (property !== undefined)
4077
+ named = getAtom(thing, property);
4078
+ else if (isObservableObject(thing) || isObservableMap(thing) || isObservableSet(thing))
4079
+ named = getAdministration(thing);
4080
+ else
4081
+ named = getAtom(thing); // valid for arrays as well
4082
+ return named.name;
4083
+ }
4084
+
4085
+ const toString = Object.prototype.toString;
4086
+ function deepEqual(a, b) {
4087
+ return eq(a, b);
4088
+ }
4089
+ // Copied from https://github.com/jashkenas/underscore/blob/5c237a7c682fb68fd5378203f0bf22dce1624854/underscore.js#L1186-L1289
4090
+ // Internal recursive comparison function for `isEqual`.
4091
+ function eq(a, b, aStack, bStack) {
4092
+ // Identical objects are equal. `0 === -0`, but they aren't identical.
4093
+ // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
4094
+ if (a === b)
4095
+ return a !== 0 || 1 / a === 1 / b;
4096
+ // `null` or `undefined` only equal to itself (strict comparison).
4097
+ if (a == null || b == null)
4098
+ return false;
4099
+ // `NaN`s are equivalent, but non-reflexive.
4100
+ if (a !== a)
4101
+ return b !== b;
4102
+ // Exhaust primitive checks
4103
+ const type = typeof a;
4104
+ if (type !== "function" && type !== "object" && typeof b != "object")
4105
+ return false;
4106
+ return deepEq(a, b, aStack, bStack);
4107
+ }
4108
+ // Internal recursive comparison function for `isEqual`.
4109
+ function deepEq(a, b, aStack, bStack) {
4110
+ // Unwrap any wrapped objects.
4111
+ a = unwrap(a);
4112
+ b = unwrap(b);
4113
+ // Compare `[[Class]]` names.
4114
+ const className = toString.call(a);
4115
+ if (className !== toString.call(b))
4116
+ return false;
4117
+ switch (className) {
4118
+ // Strings, numbers, regular expressions, dates, and booleans are compared by value.
4119
+ case "[object RegExp]":
4120
+ // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
4121
+ case "[object String]":
4122
+ // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
4123
+ // equivalent to `new String("5")`.
4124
+ return "" + a === "" + b;
4125
+ case "[object Number]":
4126
+ // `NaN`s are equivalent, but non-reflexive.
4127
+ // Object(NaN) is equivalent to NaN.
4128
+ if (+a !== +a)
4129
+ return +b !== +b;
4130
+ // An `egal` comparison is performed for other numeric values.
4131
+ return +a === 0 ? 1 / +a === 1 / b : +a === +b;
4132
+ case "[object Date]":
4133
+ case "[object Boolean]":
4134
+ // Coerce dates and booleans to numeric primitive values. Dates are compared by their
4135
+ // millisecond representations. Note that invalid dates with millisecond representations
4136
+ // of `NaN` are not equivalent.
4137
+ return +a === +b;
4138
+ case "[object Symbol]":
4139
+ return (
4140
+ // eslint-disable-next-line
4141
+ typeof Symbol !== "undefined" && Symbol.valueOf.call(a) === Symbol.valueOf.call(b));
4142
+ }
4143
+ const areArrays = className === "[object Array]";
4144
+ if (!areArrays) {
4145
+ if (typeof a != "object" || typeof b != "object")
4146
+ return false;
4147
+ // Objects with different constructors are not equivalent, but `Object`s or `Array`s
4148
+ // from different frames are.
4149
+ const aCtor = a.constructor, bCtor = b.constructor;
4150
+ if (aCtor !== bCtor &&
4151
+ !(typeof aCtor === "function" &&
4152
+ aCtor instanceof aCtor &&
4153
+ typeof bCtor === "function" &&
4154
+ bCtor instanceof bCtor) &&
4155
+ ("constructor" in a && "constructor" in b)) {
4156
+ return false;
4157
+ }
4158
+ }
4159
+ // Assume equality for cyclic structures. The algorithm for detecting cyclic
4160
+ // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
4161
+ // Initializing stack of traversed objects.
4162
+ // It's done here since we only need them for objects and arrays comparison.
4163
+ aStack = aStack || [];
4164
+ bStack = bStack || [];
4165
+ let length = aStack.length;
4166
+ while (length--) {
4167
+ // Linear search. Performance is inversely proportional to the number of
4168
+ // unique nested structures.
4169
+ if (aStack[length] === a)
4170
+ return bStack[length] === b;
4171
+ }
4172
+ // Add the first object to the stack of traversed objects.
4173
+ aStack.push(a);
4174
+ bStack.push(b);
4175
+ // Recursively compare objects and arrays.
4176
+ if (areArrays) {
4177
+ // Compare array lengths to determine if a deep comparison is necessary.
4178
+ length = a.length;
4179
+ if (length !== b.length)
4180
+ return false;
4181
+ // Deep compare the contents, ignoring non-numeric properties.
4182
+ while (length--) {
4183
+ if (!eq(a[length], b[length], aStack, bStack))
4184
+ return false;
4185
+ }
4186
+ }
4187
+ else {
4188
+ // Deep compare objects.
4189
+ const keys = Object.keys(a);
4190
+ let key;
4191
+ length = keys.length;
4192
+ // Ensure that both objects contain the same number of properties before comparing deep equality.
4193
+ if (Object.keys(b).length !== length)
4194
+ return false;
4195
+ while (length--) {
4196
+ // Deep compare each member
4197
+ key = keys[length];
4198
+ if (!(has$1(b, key) && eq(a[key], b[key], aStack, bStack)))
4199
+ return false;
4200
+ }
4201
+ }
4202
+ // Remove the first object from the stack of traversed objects.
4203
+ aStack.pop();
4204
+ bStack.pop();
4205
+ return true;
4206
+ }
4207
+ function unwrap(a) {
4208
+ if (isObservableArray(a))
4209
+ return a.peek();
4210
+ if (isES6Map(a) || isObservableMap(a))
4211
+ return iteratorToArray(a.entries());
4212
+ if (isES6Set(a) || isObservableSet(a))
4213
+ return iteratorToArray(a.entries());
4214
+ return a;
4215
+ }
4216
+ function has$1(a, key) {
4217
+ return Object.prototype.hasOwnProperty.call(a, key);
4218
+ }
4219
+
4220
+ /*
4221
+ The only reason for this file to exist is pure horror:
4222
+ Without it rollup can make the bundling fail at any point in time; when it rolls up the files in the wrong order
4223
+ it will cause undefined errors (for example because super classes or local variables not being hosted).
4224
+ With this file that will still happen,
4225
+ but at least in this file we can magically reorder the imports with trial and error until the build succeeds again.
4226
+ */
4227
+
4228
+ /**
4229
+ * (c) Michel Weststrate 2015 - 2019
4230
+ * MIT Licensed
4231
+ *
4232
+ * Welcome to the mobx sources! To get an global overview of how MobX internally works,
4233
+ * this is a good place to start:
4234
+ * https://medium.com/@mweststrate/becoming-fully-reactive-an-in-depth-explanation-of-mobservable-55995262a254#.xvbh6qd74
4235
+ *
4236
+ * Source folders:
4237
+ * ===============
4238
+ *
4239
+ * - api/ Most of the public static methods exposed by the module can be found here.
4240
+ * - core/ Implementation of the MobX algorithm; atoms, derivations, reactions, dependency trees, optimizations. Cool stuff can be found here.
4241
+ * - types/ All the magic that is need to have observable objects, arrays and values is in this folder. Including the modifiers like `asFlat`.
4242
+ * - utils/ Utility stuff.
4243
+ *
4244
+ */
4245
+ try {
4246
+ // define process.env if needed
4247
+ // if this is not a production build in the first place
4248
+ // (in which case the expression below would be substituted with 'production')
4249
+ // tslint:disable-next-line
4250
+ process.env.NODE_ENV;
4251
+ }
4252
+ catch (e) {
4253
+ const g = typeof window !== "undefined" ? window : global;
4254
+ if (typeof process === "undefined")
4255
+ g.process = {};
4256
+ g.process.env = {};
4257
+ }
4258
+ (() => {
4259
+ function testCodeMinification() { }
4260
+ if (testCodeMinification.name !== "testCodeMinification" &&
4261
+ process.env.NODE_ENV !== "production" &&
4262
+ process.env.IGNORE_MOBX_MINIFY_WARNING !== "true") {
4263
+ // trick so it doesn't get replaced
4264
+ const varName = ["process", "env", "NODE_ENV"].join(".");
4265
+ console.warn(`[mobx] you are running a minified build, but '${varName}' was not set to 'production' in your bundler. This results in an unnecessarily large and slow bundle`);
4266
+ }
4267
+ })();
4268
+ // forward compatibility with mobx, so that packages can easily support mobx 4 & 5
4269
+ const $mobx = "$mobx";
4270
+ if (typeof __MOBX_DEVTOOLS_GLOBAL_HOOK__ === "object") {
4271
+ // See: https://github.com/andykog/mobx-devtools/
4272
+ __MOBX_DEVTOOLS_GLOBAL_HOOK__.injectMobx({
4273
+ spy,
4274
+ extras: {
4275
+ getDebugName
4276
+ },
4277
+ $mobx
4278
+ });
4279
+ }
4280
+ // TODO: remove in some future build
4281
+ if (process.env.NODE_ENV !== "production" &&
4282
+ typeof module !== "undefined" &&
4283
+ typeof module.exports !== "undefined") {
4284
+ let warnedAboutDefaultExport = false;
4285
+ Object.defineProperty(module.exports, "default", {
4286
+ enumerable: false,
4287
+ get() {
4288
+ if (!warnedAboutDefaultExport) {
4289
+ warnedAboutDefaultExport = true;
4290
+ console.warn(`The MobX package does not have a default export. Use 'import { thing } from "mobx"' (recommended) or 'import * as mobx from "mobx"' instead."`);
4291
+ }
4292
+ return undefined;
4293
+ }
4294
+ });
4295
+ [
4296
+ "extras",
4297
+ "Atom",
4298
+ "BaseAtom",
4299
+ "asFlat",
4300
+ "asMap",
4301
+ "asReference",
4302
+ "asStructure",
4303
+ "autorunAsync",
4304
+ "createTranformer",
4305
+ "expr",
4306
+ "isModifierDescriptor",
4307
+ "isStrictModeEnabled",
4308
+ "map",
4309
+ "useStrict",
4310
+ "whyRun"
4311
+ ].forEach(prop => {
4312
+ Object.defineProperty(module.exports, prop, {
4313
+ enumerable: false,
4314
+ get() {
4315
+ fail(`'${prop}' is no longer part of the public MobX api. Please consult the changelog to find out where this functionality went`);
4316
+ },
4317
+ set() { }
4318
+ });
4319
+ });
4320
+ }
4321
+
4322
+ export { $mobx, IDerivationState, ObservableMap, ObservableSet, Reaction, allowStateChanges as _allowStateChanges, allowStateChangesInsideComputed as _allowStateChangesInsideComputed, getAdministration as _getAdministration, getGlobalState as _getGlobalState, interceptReads as _interceptReads, isComputingDerivation as _isComputingDerivation, resetGlobalState as _resetGlobalState, action, autorun, comparer, computed, configure, createAtom, decorate, entries, extendObservable, extendShallowObservable, flow, get, getAtom, getDebugName, getDependencyTree, getObserverTree, has, intercept, isAction, isArrayLike, isObservableValue as isBoxedObservable, isComputed, isComputedProp, isObservable, isObservableArray, isObservableMap, isObservableObject, isObservableProp, isObservableSet, keys, observable, observe, onBecomeObserved, onBecomeUnobserved, onReactionError, reaction, remove, runInAction, set, spy, toJS, trace, transaction, untracked, values, when };