UNPKG

@politie/sherlock-utils

Version:

Utility functions that are designed to work with Sherlock. His toolbelt.

281 lines (268 loc) 9.43 kB
import { isDerivable, lens, _internal, isSettableDerivable, atom, PullDataSource, ErrorWrapper, unresolved, derive, unwrap, utils } from '@politie/sherlock'; import { __extends } from 'tslib'; function defaultMapFactory() { return new Map; } var CACHED_PROXY = '__cachedProxy'; function derivableCache(opts) { var cache = (opts.mapFactory || defaultMapFactory)(); var delayedEviction = opts.delayedEviction, derivableFactory = opts.derivableFactory; var descriptor = { get: function (key) { var cachedDerivable = cache.get(key); // If the cache has a hit for the current key, we know it is already connected (through another proxy). if (cachedDerivable) { return cachedDerivable.getState(); } // A cache miss means no other proxy is currently connected. var newDerivable = _internal.independentTracking(function () { return derivableFactory(key); }); // We don't want final-value-optimalization, because that defeats the purpose of the cache. A final value // is not registered as an observed value, which means we cannot track the usage of our newly created derivable. // Therefore introduce a non-final atom (`atom(0)`) in the derivation: var derivable = isSettableDerivable(newDerivable) ? lens({ get: function () { return newDerivable.get(); }, set: function (v) { return newDerivable.set(v); } }, atom(0)) : atom(0).derive(function () { return newDerivable.get(); }); if (delayedEviction) { derivable.autoCache(); } // Get the state of our derivable early so it connects when needed. var state = derivable.getState(); if (derivable.connected) { derivable[CACHED_PROXY] = this; cache.set(key, derivable); derivable.connected$.react(function () { return cache.delete(key); }, { skipFirst: true, once: true }); } return state; }, set: function (newValue, key) { var derivable = cache.get(key) || derivableFactory(key); if (!isSettableDerivable(derivable)) { throw _internal.augmentStack(new Error('Cached derivable is not settable'), derivable); } derivable.set(newValue); }, }; return function (key) { if (!isDerivable(key)) { var cacheItem = cache.get(key); if (cacheItem) { return cacheItem[CACHED_PROXY]; } } return lens(descriptor, key); }; } /** * Lazy PullDataSource that is based on a plain javascript function that has to supply the value when someone subscribes to this * datasource. */ var FunctionDataSource = /** @class */ (function (_super) { __extends(FunctionDataSource, _super); /* istanbul ignore next: transpiled code for constructor cannot be fully covered */ /* More info: https://github.com/Microsoft/TypeScript/issues/13029 */ function FunctionDataSource(fn) { var _this = _super.call(this) || this; _this.fn = fn; return _this; } /** * Required function that calculates the current value for this datasource. Will be called once everytime * `get()` is called when not connected. When connected, it will be called once and then only whenever `checkForChanges()` * was called. */ FunctionDataSource.prototype.calculateCurrentValue = function () { return this.fn(); }; /** * Update the currently cached value of this datasource (only when connected) and notify observers when neccessary. */ FunctionDataSource.prototype.changed = function () { _super.prototype.checkForChanges.call(this); }; return FunctionDataSource; }(PullDataSource)); function fromPromise(prom) { var atom$ = atom.unresolved(); prom.then(function (v) { return atom$.setFinal(v); }, function (e) { return atom$.setFinal(new ErrorWrapper(e)); }); return atom$; } function lift(f) { return function () { var ps = []; for (var _i = 0; _i < arguments.length; _i++) { ps[_i] = arguments[_i]; } return new _internal.Derivation(f, ps); }; } function pairwise(f, init) { var oldValue = init; return function wrapped(newValue) { var result = f.call(this, newValue, oldValue); oldValue = newValue; return result; }; } /** * Returns the current state of the provided Derivable without registering any dependencies while in a derivation. Comparable to #getState(). */ function peekState(d) { return _internal.independentTracking(function () { return d.getState(); }); } /** * Returns the current value of the provided Derivable without registering any dependencies while in a derivation. Comparable to #get(). */ function peek(d) { return _internal.independentTracking(function () { return d.get(); }); } /** * Returns the current value of the provided Derivable without registering any dependencies while in a derivation. Comparable to #value. */ function peekValue(d) { return _internal.independentTracking(function () { return d.value; }); } function scan(f, seed) { var acc = seed; return function wrapped(value) { return acc = f.call(this, acc, value); }; } function getStateObject(from) { return toStateObject(from.getState()); } function toStateObject(state) { if (state === unresolved) { return { errored: false, resolved: false }; } if (state instanceof ErrorWrapper) { var error = state.error; return { error: error, errored: true, resolved: true }; } return { value: state, errored: false, resolved: true }; } function fromStateObject(state) { if (state.errored) { return new ErrorWrapper(state.error); } if (state.resolved) { return state.value; } return unresolved; } function materialize(derivable) { return derivable.mapState(toStateObject); } function dematerialize(derivable) { return derivable.map(fromStateObject); } function setStateObject(to, state) { if (!state.resolved) { to.unset(); } else if (state.errored) { to.setError(state.error); } else { to.set(state.value); } } function syncState(from, to, opts) { return materialize(from).react(function (state) { return setStateObject(to, state); }, opts); } function copyState(from, to) { setStateObject(to, getStateObject(from)); } /** * Performs JavaScript `&&` operation on the provided arguments after unwrapping. * * @method */ var and = andOrImpl(function (v) { return !v; }); /** * Performs JavaScript `||` operation on the provided arguments after unwrapping. * * @method */ var or = andOrImpl(function (v) { return !!v; }); /** * Returns the first operand that is not `null` or `undefined` after unwrapping. * * @method */ var firstNotNull = andOrImpl(function (v) { return v != null; }); function andOrImpl(breakOn) { return function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return derive(function () { var value; for (var _i = 0, args_1 = args; _i < args_1.length; _i++) { var arg = args_1[_i]; value = unwrap(arg); if (breakOn(value)) { break; } } return value; }); }; } function struct(obj) { if (isDerivable(obj)) { return obj; } if (!Array.isArray(obj) && !utils.isPlainObject(obj)) { throw new Error('"struct" only accepts Derivables, plain Objects and Arrays'); } return derive(deepUnwrap, obj); } function deepUnwrap(obj) { if (isDerivable(obj)) { return obj.get(); } if (Array.isArray(obj)) { return obj.map(deepUnwrap); } if (utils.isPlainObject(obj)) { var result = {}; for (var _i = 0, _a = Object.keys(obj); _i < _a.length; _i++) { var key = _a[_i]; result[key] = deepUnwrap(obj[key]); } return result; } return obj; } /** * A template literal tag to create a string derivation using a template literal. * * For example: * * ``` * const name$ = atom('Pete'); * const age$ = atom(24); * const nameAndAge$ = template`${name$} is ${age$} years old`; * nameAndAge$.get(); // -> Pete is 24 years old * ``` * * @param parts the string parts * @param args the results of the expressions inside the template literal */ function template(parts) { var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } return derive(function () { var s = ''; for (var i = 0; i < parts.length; i++) { s += parts[i]; if (i < args.length) { s += unwrap(args[i]); } } return s; }); } export { FunctionDataSource, and, copyState, dematerialize, derivableCache, firstNotNull, fromPromise, fromStateObject, getStateObject, lift, materialize, or, pairwise, peek, peekState, peekValue, scan, setStateObject, struct, syncState, template, toStateObject }; //# sourceMappingURL=sherlock-utils.esm.js.map