Socket
Socket
Sign inDemoInstall

mobx-utils

Package Overview
Dependencies
Maintainers
1
Versions
58
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mobx-utils - npm Package Compare versions

Comparing version 5.3.0 to 5.4.0

lib/computedFn.d.ts

4

CHANGELOG.md

@@ -0,1 +1,5 @@

# 5.4.0
Introduced `computedFn`, to support using arbitrary functions as computed!
# 5.3.0

@@ -2,0 +6,0 @@

@@ -18,1 +18,2 @@ export * from "./from-promise";

export * from "./deepObserve";
export { computedFn } from "./computedFn";

@@ -18,1 +18,2 @@ export * from "./from-promise";

export * from "./deepObserve";
export { computedFn } from "./computedFn";

@@ -1255,2 +1255,170 @@ 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';

export { PENDING, FULFILLED, REJECTED, fromPromise, isPromiseBasedObservable, moveItem, lazyObservable, fromResource, toStream, fromStream, ViewModel, createViewModel, whenWithTimeout, keepAlive, queueProcessor, chunkProcessor, now, NOOP, IDENTITY, invariant, deprecated, addHiddenProp, getAllMethodsAndProperties, asyncAction, whenAsync, expr, createTransformer, deepObserve };
/**
* @private
*/
var DeepMapEntry = /** @class */ (function () {
function DeepMapEntry(base, args) {
this.base = base;
this.args = args;
this.closestIdx = 0;
this.isDisposed = false;
var current = this.closest = this.root = base;
var i = 0;
for (; i < this.args.length - 1; i++) {
current = current.get(args[i]);
if (current)
this.closest = current;
else
break;
}
this.closestIdx = i;
}
DeepMapEntry.prototype.exists = function () {
this.assertNotDisposed();
var l = this.args.length;
return this.closestIdx >= l - 1 && this.closest.has(this.args[l - 1]);
};
DeepMapEntry.prototype.get = function () {
this.assertNotDisposed();
if (!this.exists())
throw new Error("Entry doesn't exist");
return this.closest.get(this.args[this.args.length - 1]);
};
DeepMapEntry.prototype.set = function (value) {
this.assertNotDisposed();
var l = this.args.length;
var current = this.closest;
// create remaining maps
for (var i = this.closestIdx; i < l - 1; i++) {
var m = new Map();
current.set(this.args[i], m);
current = m;
}
this.closestIdx = l - 1;
this.closest = current;
current.set(this.args[l - 1], value);
};
DeepMapEntry.prototype.delete = function () {
this.assertNotDisposed();
if (!this.exists())
throw new Error("Entry doesn't exist");
var l = this.args.length;
this.closest.delete(this.args[l - 1]);
// clean up remaining maps if needed (reconstruct stack first)
var c = this.root;
var maps = [c];
for (var i = 0; i < l - 1; i++) {
c = c.get(this.args[i]);
maps.push(c);
}
for (var i = maps.length - 1; i > 0; i--) {
if (maps[i].size === 0)
maps[i - 1].delete(this.args[i - 1]);
}
this.isDisposed = true;
};
DeepMapEntry.prototype.assertNotDisposed = function () {
// TODO: once this becomes annoying, we should introduce a reset method to re-run the constructor logic
if (this.isDisposed)
throw new Error("Concurrent modification exception");
};
return DeepMapEntry;
}());
/**
* @private
*/
var DeepMap = /** @class */ (function () {
function DeepMap() {
this.store = new Map();
this.argsLength = -1;
}
DeepMap.prototype.entry = function (args) {
if (this.argsLength === -1)
this.argsLength = args.length;
else if (this.argsLength !== args.length)
throw new Error("DeepMap should be used with functions with a consistent length, expected: " + this.argsLength + ", got: " + args.length);
if (this.last)
this.last.isDisposed = true;
return this.last = new DeepMapEntry(this.store, args);
};
return DeepMap;
}());
/**
* computedFn takes a function with an arbitrarily amount of arguments,
* and memoized the output of the function based on the arguments passed in.
*
* computedFn(fn) returns a function with the very same signature. There is no limit on the amount of arguments
* that is accepted. However, the amount of arguments must be consistent and default arguments are not supported.
*
* By default the output of a function call will only be memoized as long as the
* output is being observed.
*
* The function passes into `computedFn` should be pure, not be an action and only be relying on
* observables.
*
* Setting `keepAlive` to `true` will cause the output to be forcefully cached forever.
* Note that this might introduce memory leaks!
*
* @example
* const store = observable({
a: 1,
b: 2,
c: 3,
m: computedFn(function(x) {
return this.a * this.b * x
})
})
const d = autorun(() => {
// store.m(3) will be cached as long as this autorun is running
console.log((store.m(3) * store.c))
})
*
* @param fn
* @param keepAlive
*/
function computedFn(fn, keepAlive) {
if (keepAlive === void 0) { keepAlive = false; }
if (isAction(fn))
throw new Error("computedFn shouldn't be used on actions");
var memoWarned = false;
var i = 0;
var d = new DeepMap();
return function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var self = this;
var entry = d.entry(args);
// cache hit, return
if (entry.exists())
return entry.get().get();
// if function is invoked, and its a cache miss without reactive, there is no point in caching...
if (!keepAlive && !_isComputingDerivation()) {
if (!memoWarned) {
console.warn("invoking a computedFn from outside an reactive context won't be memoized, unless keepAlive is set");
memoWarned = true;
}
return fn.apply(self, args);
}
// create new entry
var c = computed(function () {
return fn.apply(self, args);
}, {
name: "computedFn(" + fn.name + "#" + (++i) + ")",
keepAlive: keepAlive
});
entry.set(c);
// clean up if no longer observed
if (!keepAlive)
onBecomeUnobserved(c, function () {
d.entry(args).delete();
});
// return current val
return c.get();
};
}
export { computedFn, PENDING, FULFILLED, REJECTED, fromPromise, isPromiseBasedObservable, moveItem, lazyObservable, fromResource, toStream, fromStream, ViewModel, createViewModel, whenWithTimeout, keepAlive, queueProcessor, chunkProcessor, now, NOOP, IDENTITY, invariant, deprecated, addHiddenProp, getAllMethodsAndProperties, asyncAction, whenAsync, expr, createTransformer, deepObserve };

@@ -1259,2 +1259,171 @@ (function (global, factory) {

/**
* @private
*/
var DeepMapEntry = /** @class */ (function () {
function DeepMapEntry(base, args) {
this.base = base;
this.args = args;
this.closestIdx = 0;
this.isDisposed = false;
var current = this.closest = this.root = base;
var i = 0;
for (; i < this.args.length - 1; i++) {
current = current.get(args[i]);
if (current)
this.closest = current;
else
break;
}
this.closestIdx = i;
}
DeepMapEntry.prototype.exists = function () {
this.assertNotDisposed();
var l = this.args.length;
return this.closestIdx >= l - 1 && this.closest.has(this.args[l - 1]);
};
DeepMapEntry.prototype.get = function () {
this.assertNotDisposed();
if (!this.exists())
throw new Error("Entry doesn't exist");
return this.closest.get(this.args[this.args.length - 1]);
};
DeepMapEntry.prototype.set = function (value) {
this.assertNotDisposed();
var l = this.args.length;
var current = this.closest;
// create remaining maps
for (var i = this.closestIdx; i < l - 1; i++) {
var m = new Map();
current.set(this.args[i], m);
current = m;
}
this.closestIdx = l - 1;
this.closest = current;
current.set(this.args[l - 1], value);
};
DeepMapEntry.prototype.delete = function () {
this.assertNotDisposed();
if (!this.exists())
throw new Error("Entry doesn't exist");
var l = this.args.length;
this.closest.delete(this.args[l - 1]);
// clean up remaining maps if needed (reconstruct stack first)
var c = this.root;
var maps = [c];
for (var i = 0; i < l - 1; i++) {
c = c.get(this.args[i]);
maps.push(c);
}
for (var i = maps.length - 1; i > 0; i--) {
if (maps[i].size === 0)
maps[i - 1].delete(this.args[i - 1]);
}
this.isDisposed = true;
};
DeepMapEntry.prototype.assertNotDisposed = function () {
// TODO: once this becomes annoying, we should introduce a reset method to re-run the constructor logic
if (this.isDisposed)
throw new Error("Concurrent modification exception");
};
return DeepMapEntry;
}());
/**
* @private
*/
var DeepMap = /** @class */ (function () {
function DeepMap() {
this.store = new Map();
this.argsLength = -1;
}
DeepMap.prototype.entry = function (args) {
if (this.argsLength === -1)
this.argsLength = args.length;
else if (this.argsLength !== args.length)
throw new Error("DeepMap should be used with functions with a consistent length, expected: " + this.argsLength + ", got: " + args.length);
if (this.last)
this.last.isDisposed = true;
return this.last = new DeepMapEntry(this.store, args);
};
return DeepMap;
}());
/**
* computedFn takes a function with an arbitrarily amount of arguments,
* and memoized the output of the function based on the arguments passed in.
*
* computedFn(fn) returns a function with the very same signature. There is no limit on the amount of arguments
* that is accepted. However, the amount of arguments must be consistent and default arguments are not supported.
*
* By default the output of a function call will only be memoized as long as the
* output is being observed.
*
* The function passes into `computedFn` should be pure, not be an action and only be relying on
* observables.
*
* Setting `keepAlive` to `true` will cause the output to be forcefully cached forever.
* Note that this might introduce memory leaks!
*
* @example
* const store = observable({
a: 1,
b: 2,
c: 3,
m: computedFn(function(x) {
return this.a * this.b * x
})
})
const d = autorun(() => {
// store.m(3) will be cached as long as this autorun is running
console.log((store.m(3) * store.c))
})
*
* @param fn
* @param keepAlive
*/
function computedFn(fn, keepAlive) {
if (keepAlive === void 0) { keepAlive = false; }
if (mobx.isAction(fn))
throw new Error("computedFn shouldn't be used on actions");
var memoWarned = false;
var i = 0;
var d = new DeepMap();
return function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var self = this;
var entry = d.entry(args);
// cache hit, return
if (entry.exists())
return entry.get().get();
// if function is invoked, and its a cache miss without reactive, there is no point in caching...
if (!keepAlive && !mobx._isComputingDerivation()) {
if (!memoWarned) {
console.warn("invoking a computedFn from outside an reactive context won't be memoized, unless keepAlive is set");
memoWarned = true;
}
return fn.apply(self, args);
}
// create new entry
var c = mobx.computed(function () {
return fn.apply(self, args);
}, {
name: "computedFn(" + fn.name + "#" + (++i) + ")",
keepAlive: keepAlive
});
entry.set(c);
// clean up if no longer observed
if (!keepAlive)
mobx.onBecomeUnobserved(c, function () {
d.entry(args).delete();
});
// return current val
return c.get();
};
}
exports.computedFn = computedFn;
exports.PENDING = PENDING;

@@ -1261,0 +1430,0 @@ exports.FULFILLED = FULFILLED;

2

package.json
{
"name": "mobx-utils",
"version": "5.3.0",
"version": "5.4.0",
"description": "Utility functions and common patterns for MobX",

@@ -5,0 +5,0 @@ "main": "mobx-utils.umd.js",

@@ -82,2 +82,7 @@ # MobX-utils

- [Examples](#examples-16)
- [computedFn](#computedfn)
- [Parameters](#parameters-18)
- [Examples](#examples-17)
- [DeepMapEntry](#deepmapentry)
- [DeepMap](#deepmap)

@@ -700,1 +705,45 @@ ## fromPromise

```
## computedFn
computedFn takes a function with an arbitrarily amount of arguments,
and memoized the output of the function based on the arguments passed in.
computedFn(fn) returns a function with the very same signature. There is no limit on the amount of arguments
that is accepted. However, the amount of arguments must be consistent and default arguments are not supported.
By default the output of a function call will only be memoized as long as the
output is being observed.
The function passes into `computedFn` should be pure, not be an action and only be relying on
observables.
Setting `keepAlive` to `true` will cause the output to be forcefully cached forever.
Note that this might introduce memory leaks!
### Parameters
- `fn`
- `keepAlive`
### Examples
```javascript
const store = observable({
a: 1,
b: 2,
c: 3,
m: computedFn(function(x) {
return this.a * this.b * x
})
})
const d = autorun(() => {
// store.m(3) will be cached as long as this autorun is running
console.log((store.m(3) * store.c))
})
```
## DeepMapEntry
## DeepMap
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc