Skip to content

Commit

Permalink
Merge branch 'master' into computed-comparator
Browse files Browse the repository at this point in the history
  • Loading branch information
mweststrate authored Jul 11, 2017
2 parents 7ef703f + f409b5c commit ab38024
Show file tree
Hide file tree
Showing 24 changed files with 121 additions and 43 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@ dist/
.build*/
yarn.lock
.idea
.wp-build*/
.wp-build*/
*.iml
*.ipr
*.iws
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 3.2.0

* MobX will warn again when there are multiple instances of MobX loaded, as this lead to often to confusing bugs if the project setup was not properly. The signal mobx that multiple instances are loaded on purpose, use `mobx.extras.runInSandbox`. See [#1082](https://github.com/mobxjs/mobx/issues/1082) for details.

# 3.1.17

* Improved typings of `IObservableArray.intercept`: use more restrictive types for `change` parameter of `handler`, by @bvanreeven
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mobx",
"version": "3.1.17",
"version": "3.2.0",
"description": "Simple, scalable state management.",
"main": "lib/mobx.js",
"umd:main": "lib/mobx.umd.js",
Expand Down
2 changes: 1 addition & 1 deletion src/api/autorun.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {Lambda, getNextId, invariant, fail} from "../utils/utils";
import {isModifierDescriptor} from "../types/modifiers";
import {Reaction, IReactionPublic, IReactionDisposer} from "../core/reaction";
import {untrackedStart, untrackedEnd} from "../core/derivation";
import {action, isAction} from "../api/action";
import {action, isAction} from "./action";
import {IEqualsComparer, comparer} from "../types/comparer";
import {getMessage} from "../utils/messages";

Expand Down
2 changes: 1 addition & 1 deletion src/api/expr.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {computed} from "../api/computed";
import {computed} from "./computed";
import {isComputingDerivation} from "../core/derivation";
import {getMessage} from "../utils/messages";

Expand Down
2 changes: 1 addition & 1 deletion src/api/extendobservable.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {isObservableMap} from "../types/observablemap";
import {asObservableObject, defineObservablePropertyFromDescriptor} from "../types/observableobject";
import {isObservable} from "../api/isobservable";
import {isObservable} from "./isobservable";
import {invariant, isPropertyConfigurable, hasOwnProperty} from "../utils/utils";
import {deepEnhancer, referenceEnhancer, IEnhancer} from "../types/modifiers";
import {getMessage} from "../utils/messages";
Expand Down
2 changes: 1 addition & 1 deletion src/api/isobservable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {getMessage} from "../utils/messages";
/**
* Returns true if the provided value is reactive.
* @param value object, function or array
* @param propertyName if propertyName is specified, checkes whether value.propertyName is reactive.
* @param property if property is specified, checks whether value.property is reactive.
*/
export function isObservable(value, property?: string): boolean {
if (value === null || value === undefined)
Expand Down
4 changes: 2 additions & 2 deletions src/api/observable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {IObservableArray, ObservableArray} from "../types/observablearray";
import {createDecoratorForEnhancer} from "./observabledecorator";
import {isObservable} from "./isobservable";
import {IObservableObject, asObservableObject} from "../types/observableobject";
import {extendObservable, extendShallowObservable} from "../api/extendobservable";
import {extendObservable, extendShallowObservable} from "./extendobservable";
import {IObservableMapInitialValues, ObservableMap, IMap} from "../types/observablemap";
import {getMessage} from "../utils/messages";

Expand All @@ -18,7 +18,7 @@ const refStructDecorator = createDecoratorForEnhancer(refStructEnhancer);

/**
* Turns an object, array or function into a reactive structure.
* @param value the value which should become observable.
* @param v the value which should become observable.
*/
function createObservable(v: any = undefined) {
// @observable someProp;
Expand Down
3 changes: 1 addition & 2 deletions src/api/tojs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import {isObservableArray} from "../types/observablearray";
import {isObservableObject} from "../types/observableobject";
import {isObservableMap} from "../types/observablemap";
import {isObservableValue} from "../types/observablevalue";
import {isObservable} from "../api/isobservable";
import {deprecated, isArrayLike} from "../utils/utils";
import {isObservable} from "./isobservable";

/**
* Basically, a deep clone, so that no reactive property will exist anymore.
Expand Down
2 changes: 1 addition & 1 deletion src/api/whyrun.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {globalState} from "../core/globalstate";
import {isComputedValue} from "../core/computedvalue";
import {isReaction} from "../core/reaction";
import {getAtom} from "../types/type-utils";
import {fail, deprecated} from "../utils/utils";
import {fail} from "../utils/utils";
import {getMessage} from "../utils/messages";

function log(msg: string): string {
Expand Down
10 changes: 5 additions & 5 deletions src/core/action.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {IDerivation} from "../core/derivation";
import {IDerivation} from "./derivation";
import {invariant} from "../utils/utils";
import {untrackedStart, untrackedEnd} from "../core/derivation";
import {startBatch, endBatch} from "../core/observable";
import {isSpyEnabled, spyReportStart, spyReportEnd} from "../core/spy";
import {globalState} from "../core/globalstate";
import {untrackedStart, untrackedEnd} from "./derivation";
import {startBatch, endBatch} from "./observable";
import {isSpyEnabled, spyReportStart, spyReportEnd} from "./spy";
import {globalState} from "./globalstate";
import {getMessage} from "../utils/messages";

export interface IAction{
Expand Down
10 changes: 5 additions & 5 deletions src/core/computedvalue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import {IObservable, reportObserved, propagateMaybeChanged, propagateChangeConfi
import {IDerivation, IDerivationState, trackDerivedFunction, clearObserving, untrackedStart, untrackedEnd, shouldCompute, CaughtException, isCaughtException} from "./derivation";
import {globalState} from "./globalstate";
import {createAction} from "./action";
import {createInstanceofPredicate, getNextId, invariant, Lambda, unique, joinStrings, primitiveSymbol, toPrimitive} from "../utils/utils";
import {isSpyEnabled, spyReport} from "../core/spy";
import {createInstanceofPredicate, getNextId, valueDidChange, invariant, Lambda, unique, joinStrings, primitiveSymbol, toPrimitive} from "../utils/utils";
import {isSpyEnabled, spyReport} from "./spy";
import {autorun} from "../api/autorun";
import {IEqualsComparer} from "../types/comparer";
import {IValueDidChange} from "../types/observablevalue";
Expand Down Expand Up @@ -87,9 +87,9 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
public get(): T {
invariant(!this.isComputing, `Cycle detected in computation ${this.name}`, this.derivation);
if (globalState.inBatch === 0) {
// just for small optimization, can be droped for simplicity
// computed called outside of any mobx stuff. batch observing shuold be enough, don't need tracking
// because it will never be called again inside this batch
// This is an minor optimization which could be omitted to simplify the code
// The computedValue is accessed outside of any mobx stuff. Batch observing should be enough and don't need
// tracking as it will never be called again inside this batch.
startBatch();
if (shouldCompute(this))
this.value = this.computeValue(false);
Expand Down
17 changes: 9 additions & 8 deletions src/core/derivation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,15 @@ export function isCaughtException(e): e is CaughtException {
}

/**
* Finds out wether any dependency of derivation actually changed
* If dependenciesState is 1 it will recalculate dependencies,
* Finds out whether any dependency of the derivation has actually changed.
* If dependenciesState is 1 then it will recalculate dependencies,
* if any dependency changed it will propagate it by changing dependenciesState to 2.
*
* By iterating over dependencies in the same order they were reported and stoping on first change
* all recalculations are called only for ComputedValues that will be tracked anyway by derivation.
* That is because we assume that if first x dependencies of derivation doesn't change
* than derivation shuold run the same way up until accessing x-th dependency.
* By iterating over the dependencies in the same order that they were reported and
* stopping on the first change, all the recalculations are only called for ComputedValues
* that will be tracked by derivation. That is because we assume that if the first x
* dependencies of the derivation doesn't change then the derivation should run the same way
* up until accessing x-th dependency.
*/
export function shouldCompute(derivation: IDerivation): boolean {
switch (derivation.dependenciesState) {
Expand Down Expand Up @@ -153,8 +154,8 @@ function bindDependencies(derivation: IDerivation) {
derivation.newObserving = null; // newObserving shouldn't be needed outside tracking

// Go through all new observables and check diffValue: (this list can contain duplicates):
// 0: first occurence, change to 1 and keep it
// 1: extra occurence, drop it
// 0: first occurrence, change to 1 and keep it
// 1: extra occurrence, drop it
let i0 = 0, l = derivation.unboundDepsCount;
for (let i = 0; i < l; i++) {
const dep = observing[i];
Expand Down
31 changes: 29 additions & 2 deletions src/core/globalstate.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {getGlobal} from "../utils/utils";
import {IDerivation, CaughtException} from "./derivation";
import {getGlobal, deprecated} from "../utils/utils";
import {IDerivation} from "./derivation";
import {Reaction} from "./reaction";
import {IObservable} from "./observable";

Expand Down Expand Up @@ -88,7 +88,34 @@ export class MobXGlobals {

export let globalState: MobXGlobals = new MobXGlobals();

let shareGlobalStateCalled = false;
let runInIsolationCalled = false;
let warnedAboutMultipleInstances = false;

{
const global = getGlobal();
if (!global.__mobxInstanceCount) {
global.__mobxInstanceCount = 1;
} else {
global.__mobxInstanceCount++;
setTimeout(() => {
if (!shareGlobalStateCalled && !runInIsolationCalled && !warnedAboutMultipleInstances ) {
warnedAboutMultipleInstances = true;
console.warn("[mobx] Warning: there are multiple mobx instances active. This might lead to unexpected results. See https://github.com/mobxjs/mobx/issues/1082 for details.")
}
})
}
}

export function isolateGlobalState() {
runInIsolationCalled = true;
getGlobal().__mobxInstanceCount--;
}

export function shareGlobalState() {
// TODO: remove in 4.0; just use peer dependencies instead.
deprecated("Using `shareGlobalState` is not recommended, use peer dependencies instead. See https://github.com/mobxjs/mobx/issues/1082 for details.")
shareGlobalStateCalled = true;
const global = getGlobal();
const ownState = globalState;

Expand Down
2 changes: 1 addition & 1 deletion src/core/observable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export interface IDepTreeNode {
export interface IObservable extends IDepTreeNode {
diffValue: number;
/**
* Id of the derivation *run* that last accesed this observable.
* Id of the derivation *run* that last accessed this observable.
* If this id equals the *run* id of the current derivation,
* the dependency is already established
*/
Expand Down
2 changes: 1 addition & 1 deletion src/core/reaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export class Reaction implements IDerivation, IReactionPublic {
const messageToUser = getMessage("m037");

console.error(message || messageToUser /* latter will not be true, make sure uglify doesn't remove */, error);
/** If debugging brough you here, please, read the above message :-). Tnx! */
/** If debugging brought you here, please, read the above message :-). Tnx! */

if (isSpyEnabled()) {
spyReport({
Expand Down
3 changes: 2 additions & 1 deletion src/mobx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export { Lambda, isArrayLike } from "./utils/ut
export { Iterator } from "./utils/iterable";
export { IObserverTree, IDependencyTree } from "./api/extras";

import { resetGlobalState, shareGlobalState, getGlobalState } from "./core/globalstate";
import { resetGlobalState, shareGlobalState, getGlobalState, isolateGlobalState } from "./core/globalstate";
import { IDerivation } from "./core/derivation";
import { IDepTreeNode } from "./core/observable";
import { IObserverTree, IDependencyTree, getDependencyTree, getObserverTree } from "./api/extras";
Expand Down Expand Up @@ -98,6 +98,7 @@ export const extras = {
onReactionError,
reserveArrayBuffer, // See #734
resetGlobalState,
isolateGlobalState,
shareGlobalState,
spyReport,
spyReportEnd,
Expand Down
2 changes: 1 addition & 1 deletion src/types/modifiers-old.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {observable} from "../api/observable";
import {ObservableMap, IMapEntries, IKeyValueMap} from "../types/observablemap";
import {ObservableMap, IMapEntries, IKeyValueMap} from "./observablemap";
import {deprecated} from "../utils/utils";

export function asReference<T>(value: T): T {
Expand Down
2 changes: 1 addition & 1 deletion src/types/observablearray.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {IInterceptable, IInterceptor, hasInterceptors, registerInterceptor, inte
import {IListenable, registerListener, hasListeners, notifyListeners} from "./listen-utils";
import {isSpyEnabled, spyReportStart, spyReportEnd} from "../core/spy";
import {arrayAsIterator, declareIterator} from "../utils/iterable";
import {IEnhancer} from "../types/modifiers";
import {IEnhancer} from "./modifiers";

const MAX_SPLICE_SIZE = 10000; // See e.g. https://github.com/mobxjs/mobx/issues/859

Expand Down
4 changes: 2 additions & 2 deletions src/types/observableobject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {runLazyInitializers} from "../utils/decorators";
import {hasInterceptors, IInterceptable, registerInterceptor, interceptChange} from "./intercept-utils";
import {IListenable, registerListener, hasListeners, notifyListeners} from "./listen-utils";
import {isSpyEnabled, spyReportStart, spyReportEnd} from "../core/spy";
import {IEqualsComparer, comparer} from "../types/comparer";
import {IEnhancer, isModifierDescriptor, IModifierDescriptor} from "../types/modifiers";
import {IEqualsComparer, comparer} from "./comparer";
import {IEnhancer, isModifierDescriptor, IModifierDescriptor} from "./modifiers";
import {isAction, defineBoundAction} from "../api/action";
import {getMessage} from "../utils/messages";

Expand Down
2 changes: 1 addition & 1 deletion src/types/observablevalue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {Lambda, getNextId, createInstanceofPredicate, primitiveSymbol, toPrimiti
import {hasInterceptors, IInterceptable, IInterceptor, registerInterceptor, interceptChange} from "./intercept-utils";
import {IListenable, registerListener, hasListeners, notifyListeners} from "./listen-utils";
import {isSpyEnabled, spyReportStart, spyReportEnd, spyReport} from "../core/spy";
import {IEnhancer} from "../types/modifiers";
import {IEnhancer} from "./modifiers";

export interface IValueWillChange<T> {
object: any;
Expand Down
6 changes: 3 additions & 3 deletions src/types/type-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import {runLazyInitializers} from "../utils/decorators";
import {isAtom} from "../core/atom";
import {isComputedValue} from "../core/computedvalue";
import {isReaction} from "../core/reaction";
import {isObservableArray} from "../types/observablearray";
import {isObservableMap} from "../types/observablemap";
import {isObservableObject} from "../types/observableobject";
import {isObservableArray} from "./observablearray";
import {isObservableMap} from "./observablemap";
import {isObservableObject} from "./observableobject";
import {getMessage} from "../utils/messages";


Expand Down
3 changes: 2 additions & 1 deletion test/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ test('correct api should be exposed', function(t) {
'interceptReads',
'isComputingDerivation',
'isSpyEnabled',
'isolateGlobalState',
'onReactionError',
'reserveArrayBuffer',
'resetGlobalState',
Expand All @@ -72,7 +73,7 @@ test('correct api should be exposed', function(t) {
'spyReport',
'spyReportEnd',
'spyReportStart'
]);
].sort());
t.equals(Object.keys(mobx.extras).filter(function(key) {
return mobx.extras[key] == undefined;
}).length, 0);
Expand Down
42 changes: 42 additions & 0 deletions test/state-sharing.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"use strict"
const test = require('tape');
const child_process = require("child_process")

function testOutput(t, cmd, expected) {
test("Global state sharing: " + cmd, t => {
const output = child_process.exec(
'node -e \'' + cmd + '\'',
{ cwd: __dirname },
(e, stdout, stderr) => {
if (e)
t.fail(e)
else {
t.equal(stdout.toString(), '')
t.equal(stderr.toString(), expected)
t.end()
}
}
);
})
}

test("it should handle multiple instances with the correct warnings", t => {
testOutput(t,
'require("..");require("../lib/mobx.umd.js")',
'[mobx] Warning: there are multiple mobx instances active. This might lead to unexpected results. See https://github.com/mobxjs/mobx/issues/1082 for details.\n'
);
testOutput(t,
'require("..").extras.shareGlobalState();require("../lib/mobx.umd.js")',
'[mobx] Deprecated: Using `shareGlobalState` is not recommended, use peer dependencies instead. See https://github.com/mobxjs/mobx/issues/1082 for details.' +
'\n[mobx] Warning: there are multiple mobx instances active. This might lead to unexpected results. See https://github.com/mobxjs/mobx/issues/1082 for details.\n'
);
testOutput(t,
'require("..").extras.shareGlobalState();require("../lib/mobx.umd.js").extras.shareGlobalState()',
'[mobx] Deprecated: Using `shareGlobalState` is not recommended, use peer dependencies instead. See https://github.com/mobxjs/mobx/issues/1082 for details.'+
'\n[mobx] Deprecated: Using `shareGlobalState` is not recommended, use peer dependencies instead. See https://github.com/mobxjs/mobx/issues/1082 for details.\n'
);
testOutput(t, 'require("..").extras.isolateGlobalState();require("../lib/mobx.umd.js").extras.isolateGlobalState()', '');
testOutput(t, 'require("..");require("../lib/mobx.umd.js").extras.isolateGlobalState()', '');
testOutput(t, 'require("..").extras.isolateGlobalState();require("../lib/mobx.umd.js")', '');
t.end();
})

0 comments on commit ab38024

Please sign in to comment.