mobx-utils
Advanced tools
Comparing version 5.0.3 to 5.0.4
@@ -0,1 +1,5 @@ | ||
# 5.0.4 | ||
* Fixed [#158](https://github.com/mobxjs/mobx-utils/issues/158), `deepObserve` not being published | ||
# 5.0.3 | ||
@@ -2,0 +6,0 @@ |
@@ -23,3 +23,3 @@ import { ObservableMap } from "mobx"; | ||
* `createViewModel` takes an object with observable properties (model) | ||
* and wraps a viewmodel around it. The viewmodel proxies all enumerable property of the original model with the following behavior: | ||
* and wraps a viewmodel around it. The viewmodel proxies all enumerable properties of the original model with the following behavior: | ||
* - as long as no new value has been assigned to the viewmodel property, the original property will be returned. | ||
@@ -26,0 +26,0 @@ * - any future change in the model will be visible in the viewmodel as well unless the viewmodel property was dirty at the time of the attempted change. |
@@ -97,3 +97,3 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
* `createViewModel` takes an object with observable properties (model) | ||
* and wraps a viewmodel around it. The viewmodel proxies all enumerable property of the original model with the following behavior: | ||
* and wraps a viewmodel around it. The viewmodel proxies all enumerable properties of the original model with the following behavior: | ||
* - as long as no new value has been assigned to the viewmodel property, the original property will be returned. | ||
@@ -100,0 +100,0 @@ * - any future change in the model will be visible in the viewmodel as well unless the viewmodel property was dirty at the time of the attempted change. |
@@ -53,3 +53,3 @@ export declare type PromiseState = "pending" | "fulfilled" | "rejected"; | ||
* when( | ||
* () => fetchResult.state !== "pending" | ||
* () => fetchResult.state !== "pending", | ||
* () => { | ||
@@ -56,0 +56,0 @@ * console.log("Got ", fetchResult.value) |
@@ -71,3 +71,3 @@ import { action, extendObservable } from "mobx"; | ||
* when( | ||
* () => fetchResult.state !== "pending" | ||
* () => fetchResult.state !== "pending", | ||
* () => { | ||
@@ -74,0 +74,0 @@ * console.log("Got ", fetchResult.value) |
@@ -94,3 +94,3 @@ import { createAtom, _allowStateChanges } from "mobx"; | ||
if (!isBeingTracked && !isActive) | ||
console.warn("Called `get` of an subscribingObservable outside a reaction. Current value will be returned but no new subscription has started"); | ||
console.warn("Called `get` of a subscribingObservable outside a reaction. Current value will be returned but no new subscription has started"); | ||
return value; | ||
@@ -97,0 +97,0 @@ }, |
@@ -17,1 +17,2 @@ export * from "./from-promise"; | ||
export * from "./create-transformer"; | ||
export * from "./deepObserve"; |
@@ -17,1 +17,2 @@ export * from "./from-promise"; | ||
export * from "./create-transformer"; | ||
export * from "./deepObserve"; |
@@ -39,3 +39,3 @@ export interface IStreamObserver<T> { | ||
* | ||
* Converts an subscribable, observable stream (TC 39 observable / RxJS stream) | ||
* Converts a subscribable, observable stream (TC 39 observable / RxJS stream) | ||
* into an object which stores the current value (as `current`). The subscription can be cancelled through the `dispose` method. | ||
@@ -42,0 +42,0 @@ * Takes an initial value as second optional argument |
@@ -99,3 +99,3 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
* | ||
* Converts an subscribable, observable stream (TC 39 observable / RxJS stream) | ||
* Converts a subscribable, observable stream (TC 39 observable / RxJS stream) | ||
* into an object which stores the current value (as `current`). The subscription can be cancelled through the `dispose` method. | ||
@@ -102,0 +102,0 @@ * Takes an initial value as second optional argument |
/** | ||
* _deprecated_ whenAsync is deprecated, use mobx.when without effect instead. | ||
* | ||
* Like normal `when`, except that this `when` will return a promise that resolves when the expression becomes truthy | ||
@@ -3,0 +5,0 @@ * |
import { when } from "mobx"; | ||
import { deprecated } from "./utils"; | ||
/** | ||
* _deprecated_ whenAsync is deprecated, use mobx.when without effect instead. | ||
* | ||
* Like normal `when`, except that this `when` will return a promise that resolves when the expression becomes truthy | ||
@@ -5,0 +7,0 @@ * |
@@ -1,2 +0,2 @@ | ||
import { $mobx, _allowStateChanges, _getAdministration, _isComputingDerivation, action, autorun, computed, createAtom, extendObservable, flow, getAtom, isAction, isComputed, isComputedProp, isObservableArray, isObservableMap, isObservableObject, keys, observable, onBecomeUnobserved, runInAction, when } from 'mobx'; | ||
import { $mobx, _allowStateChanges, _getAdministration, _isComputingDerivation, action, autorun, computed, createAtom, entries, extendObservable, flow, getAtom, isAction, isComputed, isComputedProp, isObservableArray, isObservableMap, isObservableObject, keys, observable, observe, onBecomeUnobserved, runInAction, values, when } from 'mobx'; | ||
@@ -94,3 +94,3 @@ var NOOP = function () { }; | ||
* when( | ||
* () => fetchResult.state !== "pending" | ||
* () => fetchResult.state !== "pending", | ||
* () => { | ||
@@ -367,3 +367,3 @@ * console.log("Got ", fetchResult.value) | ||
if (!isBeingTracked && !isActive) | ||
console.warn("Called `get` of an subscribingObservable outside a reaction. Current value will be returned but no new subscription has started"); | ||
console.warn("Called `get` of a subscribingObservable outside a reaction. Current value will be returned but no new subscription has started"); | ||
return value; | ||
@@ -476,3 +476,3 @@ }, | ||
* | ||
* Converts an subscribable, observable stream (TC 39 observable / RxJS stream) | ||
* Converts a subscribable, observable stream (TC 39 observable / RxJS stream) | ||
* into an object which stores the current value (as `current`). The subscription can be cancelled through the `dispose` method. | ||
@@ -598,3 +598,3 @@ * Takes an initial value as second optional argument | ||
* `createViewModel` takes an object with observable properties (model) | ||
* and wraps a viewmodel around it. The viewmodel proxies all enumerable property of the original model with the following behavior: | ||
* and wraps a viewmodel around it. The viewmodel proxies all enumerable properties of the original model with the following behavior: | ||
* - as long as no new value has been assigned to the viewmodel property, the original property will be returned. | ||
@@ -976,2 +976,4 @@ * - any future change in the model will be visible in the viewmodel as well unless the viewmodel property was dirty at the time of the attempted change. | ||
/** | ||
* _deprecated_ whenAsync is deprecated, use mobx.when without effect instead. | ||
* | ||
* Like normal `when`, except that this `when` will return a promise that resolves when the expression becomes truthy | ||
@@ -1068,2 +1070,100 @@ * | ||
export { PENDING, FULFILLED, REJECTED, fromPromise, isPromiseBasedObservable, moveItem, lazyObservable, fromResource, toStream, fromStream, ViewModel, createViewModel, whenWithTimeout, keepAlive, queueProcessor, chunkProcessor, now, NOOP, IDENTITY, invariant, deprecated, addHiddenProp, asyncAction, whenAsync, expr, createTransformer }; | ||
function buildPath(entry) { | ||
var res = []; | ||
while (entry.parent) { | ||
res.push(entry.path); | ||
entry = entry.parent; | ||
} | ||
return res.reverse().join("/"); | ||
} | ||
/** | ||
* Given an object, deeply observes the given object. | ||
* It is like `observe` from mobx, but applied recursively, including all future children | ||
* | ||
* Note that the given object cannot ever contain cycles and should be a tree. | ||
* | ||
* As benefit: path and root will be provided in the callback, so the signature of the listener is | ||
* (change, path, root) => void | ||
* | ||
* The returned disposer can be invoked to clean up the listner | ||
* | ||
* @example | ||
* const disposer = deepObserve(target, (change, path) => { | ||
* console.dir(change) | ||
* }) | ||
*/ | ||
function deepObserve(target, listener) { | ||
var entrySet = new WeakMap(); | ||
function genericListener(change) { | ||
var entry = entrySet.get(change.object); | ||
processChange(change, entry); | ||
listener(change, buildPath(entry), target); | ||
} | ||
function processChange(change, parent) { | ||
switch (change.type) { | ||
// Object changes | ||
case "add": // also for map | ||
observeRecursively(change.newValue, parent, change.name); | ||
break; | ||
case "update": // also for array and map | ||
unobserveRecursively(change.oldValue); | ||
observeRecursively(change.newValue, parent, change.name || "" + change.index); | ||
break; | ||
case "remove": // object | ||
case "delete": // map | ||
unobserveRecursively(change.oldValue); | ||
break; | ||
// Array changes | ||
case "splice": | ||
change.removed.map(unobserveRecursively); | ||
change.added.forEach(function (value, idx) { | ||
return observeRecursively(value, parent, "" + (change.index + idx)); | ||
}); | ||
// update paths | ||
for (var i = change.index + change.addedCount; i < change.object.length; i++) { | ||
var entry = entrySet.get(change.object[i]); | ||
if (entry) | ||
entry.path = "" + i; | ||
} | ||
break; | ||
} | ||
} | ||
function observeRecursively(thing, parent, path) { | ||
if (isObservableObject(thing) || isObservableArray(thing) || isObservableMap(thing)) { | ||
if (entrySet.has(thing)) { | ||
var entry = entrySet.get(thing); | ||
if (entry.parent !== parent || entry.path !== path) | ||
// MWE: this constraint is artificial, and this tool could be made to work with cycles, | ||
// but it increases administration complexity, has tricky edge cases and the meaning of 'path' | ||
// would become less clear. So doesn't seem to be needed for now | ||
throw new Error("The same observable object cannot appear twice in the same tree, trying to assign it to '" + buildPath(parent) + "/" + path + "', but it already exists at '" + buildPath(entry.parent) + "/" + entry.path + "'"); | ||
} | ||
else { | ||
var entry_1 = { | ||
parent: parent, | ||
path: path, | ||
dispose: observe(thing, genericListener) | ||
}; | ||
entrySet.set(thing, entry_1); | ||
entries(thing).forEach(function (_a) { | ||
var key = _a[0], value = _a[1]; | ||
return observeRecursively(value, entry_1, key); | ||
}); | ||
} | ||
} | ||
} | ||
function unobserveRecursively(thing) { | ||
var entry = entrySet.get(thing); | ||
if (!entry) | ||
return; | ||
entrySet.delete(thing); | ||
entry.dispose(); | ||
values(thing).forEach(unobserveRecursively); | ||
} | ||
observeRecursively(target, undefined, ""); | ||
return function () { | ||
unobserveRecursively(target); | ||
}; | ||
} | ||
export { PENDING, FULFILLED, REJECTED, fromPromise, isPromiseBasedObservable, moveItem, lazyObservable, fromResource, toStream, fromStream, ViewModel, createViewModel, whenWithTimeout, keepAlive, queueProcessor, chunkProcessor, now, NOOP, IDENTITY, invariant, deprecated, addHiddenProp, asyncAction, whenAsync, expr, createTransformer, deepObserve }; |
@@ -98,3 +98,3 @@ (function (global, factory) { | ||
* when( | ||
* () => fetchResult.state !== "pending" | ||
* () => fetchResult.state !== "pending", | ||
* () => { | ||
@@ -371,3 +371,3 @@ * console.log("Got ", fetchResult.value) | ||
if (!isBeingTracked && !isActive) | ||
console.warn("Called `get` of an subscribingObservable outside a reaction. Current value will be returned but no new subscription has started"); | ||
console.warn("Called `get` of a subscribingObservable outside a reaction. Current value will be returned but no new subscription has started"); | ||
return value; | ||
@@ -480,3 +480,3 @@ }, | ||
* | ||
* Converts an subscribable, observable stream (TC 39 observable / RxJS stream) | ||
* Converts a subscribable, observable stream (TC 39 observable / RxJS stream) | ||
* into an object which stores the current value (as `current`). The subscription can be cancelled through the `dispose` method. | ||
@@ -602,3 +602,3 @@ * Takes an initial value as second optional argument | ||
* `createViewModel` takes an object with observable properties (model) | ||
* and wraps a viewmodel around it. The viewmodel proxies all enumerable property of the original model with the following behavior: | ||
* and wraps a viewmodel around it. The viewmodel proxies all enumerable properties of the original model with the following behavior: | ||
* - as long as no new value has been assigned to the viewmodel property, the original property will be returned. | ||
@@ -980,2 +980,4 @@ * - any future change in the model will be visible in the viewmodel as well unless the viewmodel property was dirty at the time of the attempted change. | ||
/** | ||
* _deprecated_ whenAsync is deprecated, use mobx.when without effect instead. | ||
* | ||
* Like normal `when`, except that this `when` will return a promise that resolves when the expression becomes truthy | ||
@@ -1072,2 +1074,100 @@ * | ||
function buildPath(entry) { | ||
var res = []; | ||
while (entry.parent) { | ||
res.push(entry.path); | ||
entry = entry.parent; | ||
} | ||
return res.reverse().join("/"); | ||
} | ||
/** | ||
* Given an object, deeply observes the given object. | ||
* It is like `observe` from mobx, but applied recursively, including all future children | ||
* | ||
* Note that the given object cannot ever contain cycles and should be a tree. | ||
* | ||
* As benefit: path and root will be provided in the callback, so the signature of the listener is | ||
* (change, path, root) => void | ||
* | ||
* The returned disposer can be invoked to clean up the listner | ||
* | ||
* @example | ||
* const disposer = deepObserve(target, (change, path) => { | ||
* console.dir(change) | ||
* }) | ||
*/ | ||
function deepObserve(target, listener) { | ||
var entrySet = new WeakMap(); | ||
function genericListener(change) { | ||
var entry = entrySet.get(change.object); | ||
processChange(change, entry); | ||
listener(change, buildPath(entry), target); | ||
} | ||
function processChange(change, parent) { | ||
switch (change.type) { | ||
// Object changes | ||
case "add": // also for map | ||
observeRecursively(change.newValue, parent, change.name); | ||
break; | ||
case "update": // also for array and map | ||
unobserveRecursively(change.oldValue); | ||
observeRecursively(change.newValue, parent, change.name || "" + change.index); | ||
break; | ||
case "remove": // object | ||
case "delete": // map | ||
unobserveRecursively(change.oldValue); | ||
break; | ||
// Array changes | ||
case "splice": | ||
change.removed.map(unobserveRecursively); | ||
change.added.forEach(function (value, idx) { | ||
return observeRecursively(value, parent, "" + (change.index + idx)); | ||
}); | ||
// update paths | ||
for (var i = change.index + change.addedCount; i < change.object.length; i++) { | ||
var entry = entrySet.get(change.object[i]); | ||
if (entry) | ||
entry.path = "" + i; | ||
} | ||
break; | ||
} | ||
} | ||
function observeRecursively(thing, parent, path) { | ||
if (mobx.isObservableObject(thing) || mobx.isObservableArray(thing) || mobx.isObservableMap(thing)) { | ||
if (entrySet.has(thing)) { | ||
var entry = entrySet.get(thing); | ||
if (entry.parent !== parent || entry.path !== path) | ||
// MWE: this constraint is artificial, and this tool could be made to work with cycles, | ||
// but it increases administration complexity, has tricky edge cases and the meaning of 'path' | ||
// would become less clear. So doesn't seem to be needed for now | ||
throw new Error("The same observable object cannot appear twice in the same tree, trying to assign it to '" + buildPath(parent) + "/" + path + "', but it already exists at '" + buildPath(entry.parent) + "/" + entry.path + "'"); | ||
} | ||
else { | ||
var entry_1 = { | ||
parent: parent, | ||
path: path, | ||
dispose: mobx.observe(thing, genericListener) | ||
}; | ||
entrySet.set(thing, entry_1); | ||
mobx.entries(thing).forEach(function (_a) { | ||
var key = _a[0], value = _a[1]; | ||
return observeRecursively(value, entry_1, key); | ||
}); | ||
} | ||
} | ||
} | ||
function unobserveRecursively(thing) { | ||
var entry = entrySet.get(thing); | ||
if (!entry) | ||
return; | ||
entrySet.delete(thing); | ||
entry.dispose(); | ||
mobx.values(thing).forEach(unobserveRecursively); | ||
} | ||
observeRecursively(target, undefined, ""); | ||
return function () { | ||
unobserveRecursively(target); | ||
}; | ||
} | ||
exports.PENDING = PENDING; | ||
@@ -1099,2 +1199,3 @@ exports.FULFILLED = FULFILLED; | ||
exports.createTransformer = createTransformer; | ||
exports.deepObserve = deepObserve; | ||
@@ -1101,0 +1202,0 @@ Object.defineProperty(exports, '__esModule', { value: true }); |
{ | ||
"name": "mobx-utils", | ||
"version": "5.0.3", | ||
"version": "5.0.4", | ||
"description": "Utility functions and common patterns for MobX", | ||
@@ -5,0 +5,0 @@ "main": "mobx-utils.umd.js", |
@@ -61,3 +61,3 @@ # MobX-utils | ||
when( | ||
() => fetchResult.state !== "pending" | ||
() => fetchResult.state !== "pending", | ||
() => { | ||
@@ -132,4 +132,4 @@ console.log("Got ", fetchResult.value) | ||
until the observable is needed the first time. | ||
The fetch method receives a `sync` callback which can be used to replace the | ||
current value of the lazyObservable. It is allowed to call `sync` multiple times | ||
The fetch method receives a `sink` callback which can be used to replace the | ||
current value of the lazyObservable. It is allowed to call `sink` multiple times | ||
to keep the lazyObservable up to date with some external resource. | ||
@@ -143,3 +143,3 @@ | ||
- `fetch` | ||
- `initialValue` **T** optional initialValue that will be returned from `current` as long as the `sync` has not been called at least once (optional, default `undefined`) | ||
- `initialValue` **T** optional initialValue that will be returned from `current` as long as the `sink` has not been called at least once (optional, default `undefined`) | ||
@@ -150,3 +150,3 @@ **Examples** | ||
const userProfile = lazyObservable( | ||
sync => fetch("/myprofile").then(profile => sync(profile)) | ||
sink => fetch("/myprofile").then(profile => sink(profile)) | ||
) | ||
@@ -172,6 +172,6 @@ | ||
(un)subscribing when needed. To enable `fromResource` to do that two callbacks need to be provided, | ||
one to subscribe, and one to unsubscribe. The subscribe callback itself will receive a `sync` callback, which can be used | ||
one to subscribe, and one to unsubscribe. The subscribe callback itself will receive a `sink` callback, which can be used | ||
to update the current state of the observable, allowing observes to react. | ||
Whatever is passed to `sync` will be returned by `current()`. The values passed to the sync will not be converted to | ||
Whatever is passed to `sink` will be returned by `current()`. The values passed to the sink will not be converted to | ||
observables automatically, but feel free to do so. | ||
@@ -191,3 +191,3 @@ It is the `current()` call itself which is being tracked, | ||
- `unsubscriber` **IDisposer** (optional, default `NOOP`) | ||
- `initialValue` **T** the data that will be returned by `get()` until the `sync` has emitted its first data (optional, default `undefined`) | ||
- `initialValue` **T** the data that will be returned by `get()` until the `sink` has emitted its first data (optional, default `undefined`) | ||
@@ -200,8 +200,8 @@ **Examples** | ||
return fromResource( | ||
(sync) => { | ||
// sync the current state | ||
sync(dbUserRecord.fields) | ||
// subscribe to the record, invoke the sync callback whenever new data arrives | ||
(sink) => { | ||
// sink the current state | ||
sink(dbUserRecord.fields) | ||
// subscribe to the record, invoke the sink callback whenever new data arrives | ||
currentSubscription = dbUserRecord.onUpdated(() => { | ||
sync(dbUserRecord.fields) | ||
sink(dbUserRecord.fields) | ||
}) | ||
@@ -251,3 +251,3 @@ }, | ||
Rx.Observable | ||
.from(mobxUtils.toStream(() => user.firstName + user.lastName)) | ||
.from(mobxUtils.toStream(() => user.firstname + user.lastName)) | ||
.scan(nameChanges => nameChanges + 1, 0) | ||
@@ -373,6 +373,2 @@ .subscribe(nameChanges => console.log("Changed name ", nameChanges, "times")) | ||
MobX normally suspends any computed value that is not in use by any reaction, | ||
and lazily re-evaluates the expression if needed outside a reaction while not in use. | ||
`keepAlive` marks a computed value as always in use, meaning that it will always fresh, but never disposed automatically. | ||
**Parameters** | ||
@@ -382,4 +378,3 @@ | ||
- `_2` | ||
- `target` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** an object that has a computed property, created by `@computed` or `extendObservable` | ||
- `property` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** the name of the property to keep alive | ||
- `computedValue` **IComputedValue<any>** created using the `computed` function | ||
@@ -389,7 +384,8 @@ **Examples** | ||
```javascript | ||
const obj = observable({ | ||
number: 3, | ||
doubler: function() { return this.number * 2 } | ||
}) | ||
const stop = keepAlive(obj, "doubler") | ||
const number = observable(3) | ||
const doubler = computed(() => number.get() * 2) | ||
const stop = keepAlive(doubler) | ||
// doubler will now stay in sync reactively even when there are no further observers | ||
stop() | ||
// normal behavior, doubler results will be recomputed if not observed but needed, but lazily | ||
``` | ||
@@ -401,2 +397,6 @@ | ||
MobX normally suspends any computed value that is not in use by any reaction, | ||
and lazily re-evaluates the expression if needed outside a reaction while not in use. | ||
`keepAlive` marks a computed value as always in use, meaning that it will always fresh, but never disposed automatically. | ||
**Parameters** | ||
@@ -406,3 +406,4 @@ | ||
- `_2` | ||
- `computedValue` **IComputedValue<any>** created using the `computed` function | ||
- `target` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** an object that has a computed property, created by `@computed` or `extendObservable` | ||
- `property` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** the name of the property to keep alive | ||
@@ -412,8 +413,7 @@ **Examples** | ||
```javascript | ||
const number = observable(3) | ||
const doubler = computed(() => number.get() * 2) | ||
const stop = keepAlive(doubler) | ||
// doubler will now stay in sync reactively even when there are no further observers | ||
stop() | ||
// normal behavior, doubler results will be recomputed if not observed but needed, but lazily | ||
const obj = observable({ | ||
number: 3, | ||
doubler: function() { return this.number * 2 } | ||
}) | ||
const stop = keepAlive(obj, "doubler") | ||
``` | ||
@@ -637,1 +637,26 @@ | ||
- `onCleanup` | ||
## deepObserve | ||
Given an object, deeply observes the given object. | ||
It is like `observe` from mobx, but applied recursively, including all future children | ||
Note that the given object cannot ever contain cycles and should be a tree. | ||
As benefit: path and root will be provided in the callback, so the signature of the listener is | ||
(change, path, root) => void | ||
The returned disposer can be invoked to clean up the listner | ||
**Parameters** | ||
- `target` | ||
- `listener` | ||
**Examples** | ||
```javascript | ||
const disposer = deepObserve(target, (change, path) => { | ||
console.dir(change) | ||
}) | ||
``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
253414
70
5369
648