Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
it('should compare the lensed values of DerivableProxies', () => {
const pd = new ProxyDescriptor();
// We force the target to be differing numbers, while the lensed value is the correct boolean.
let idx = 1;
pd.$lens = () => ({
get: v => v > 0,
set: v => v ? idx++ : -idx++,
});
const lhs = pd.$create(atom(0));
lhs.$value = identityValue;
const rhs = pd.$create(atom(0));
rhs.$value = false;
const result = lhs[method](rhs) as Derivable;
expect(result.get()).to.equal(false);
rhs.$value = true;
expect(result.get()).to.equal(true);
});
it('should support for ... of (ES5 style)', () => {
const obj = new LetterCount().$create(constant('also pointless')) as any;
const result = [];
// tslint:disable-next-line:prefer-for-of
for (let i = 0; i < obj.length; i++) {
result.push(obj[i].$value);
}
expect(result).to.deep.equal('also pointless'.split(''));
});
it('should reuse proxies as much as possible', () => {
const cache = derivableCache({ derivableFactory: constant });
const proxy1 = cache('abc');
const proxy2 = cache('abc');
// Cannot remember proxies without connection, because we don't know when to evict them.
expect(proxy2).to.not.equal(proxy1);
proxy1.autoCache().get();
// But when connected we can automatically reuse proxies when using simple keys.
expect(cache('abc')).to.equal(proxy1);
// Not possible when using derivables as input of course
expect(cache(constant('abc'))).to.not.equal(proxy1);
});
get(key) {
const 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.
const newDerivable = _internal.independentTracking(() => 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:
const derivable = isSettableDerivable(newDerivable)
? lens({ get: () => newDerivable.get(), set: v => newDerivable.set(v) }, atom(0))
: atom(0).derive(() => newDerivable.get());
if (delayedEviction) {
derivable.autoCache();
}
// Get the state of our derivable early so it connects when needed.
const state = derivable.getState();
if (derivable.connected) {
derivable[CACHED_PROXY] = this;
cache.set(key, derivable);
derivable.connected$.react(() => cache.delete(key), { skipFirst: true, once: true });
}
return state;
},
set(newValue, key) {
export function fromObservable(observable: Subscribable): Derivable {
const atom$ = atom.unresolved();
let subscription: Unsubscribable | undefined;
atom$.connected$.react(() => {
if (atom$.connected && !subscription) {
subscription = observable.subscribe(
value => atom$.set(value),
err => atom$.setFinal(new ErrorWrapper(err)),
() => atom$.setFinal(atom$.getState()),
);
}
// This is not chained with the previous as an `else` branch, because this can be true immediately after
// the subscription occurs. Observables can complete synchronously on subscription.
if (!atom$.connected && subscription) {
subscription.unsubscribe();
subscription = undefined;
}
derivableFactory = spy((key: Request) => {
const result = atom.unresolved();
// Do some hard work (an HTTP call for example).
fetchItLater();
return result;
async function fetchItLater() {
await Promise.resolve();
result.set({ code: 200, body: `Result from ${key.method} to ${key.url}.` });
}
});
performCall = derivableCache({ derivableFactory, mapFactory: ImmutableMap.factory });
get(key) {
const 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.
const newDerivable = _internal.independentTracking(() => 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:
const derivable = isSettableDerivable(newDerivable)
? lens({ get: () => newDerivable.get(), set: v => newDerivable.set(v) }, atom(0))
: atom(0).derive(() => newDerivable.get());
if (delayedEviction) {
derivable.autoCache();
}
// Get the state of our derivable early so it connects when needed.
const state = derivable.getState();
if (derivable.connected) {
derivable[CACHED_PROXY] = this;
cache.set(key, derivable);
get(key) {
const 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.
const newDerivable = _internal.independentTracking(() => 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:
const derivable = isSettableDerivable(newDerivable)
? lens({ get: () => newDerivable.get(), set: v => newDerivable.set(v) }, atom(0))
: atom(0).derive(() => newDerivable.get());
if (delayedEviction) {
derivable.autoCache();
}
// Get the state of our derivable early so it connects when needed.
const state = derivable.getState();
if (derivable.connected) {
derivable[CACHED_PROXY] = this;
cache.set(key, derivable);
derivable.connected$.react(() => cache.delete(key), { skipFirst: true, once: true });
}
return state;
},
get(key) {
const 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.
const newDerivable = _internal.independentTracking(() => 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:
const derivable = isSettableDerivable(newDerivable)
? lens({ get: () => newDerivable.get(), set: v => newDerivable.set(v) }, atom(0))
: atom(0).derive(() => newDerivable.get());
if (delayedEviction) {
derivable.autoCache();
}
// Get the state of our derivable early so it connects when needed.
const state = derivable.getState();
if (derivable.connected) {
derivable[CACHED_PROXY] = this;
cache.set(key, derivable);
derivable.connected$.react(() => cache.delete(key), { skipFirst: true, once: true });
}
return state;
},
set(newValue, key) {
/**
* When `true` the derivable will not update the first time it receives an update from the parent derivable. After that it has no effect.
*/
skipFirst?: boolean;
/*
* Indicates whether an update to unresolved state is considered an update. Default: false.
*/
includeUnresolved?: boolean;
}
// tslint:disable-next-line:ban-types
type PreparedOptions = { [P in keyof ControlFlowOptions]?: Exclude[P], Function> };
class ControlFlow extends _internal.BaseDerivable implements Derivable {
private readonly opts: PreparedOptions;
constructor(
private readonly base: Derivable,
opts?: ControlFlowOptions,
) {
super();
this.opts = prepareOptions(base, opts);
}
/**
* The last state that was calculated for this derivable. Is only used when connected.
* @internal
*/
private _currentState: State = unresolved;