Comparing version 2.0.0-beta.1 to 2.0.0-beta.2
@@ -10,19 +10,10 @@ /** | ||
derive<E>(f: (value: T) => E): Derivable<E>; | ||
derive(prop: (string | Derivable<string>)): Derivable<any>; | ||
derive(index: (number | Derivable<number>)): Derivable<any>; | ||
derive(re: (RegExp | Derivable<RegExp>)): Derivable<string[]>; | ||
derive<E>(f: Derivable<(value: T) => E>): Derivable<E>; | ||
derive(args: any[]): Derivable<any>[]; | ||
derive<A, E>(f: (value: T, a: A) => E, a: (A | Derivable<A>)): Derivable<E>; | ||
derive<A, B, E>(f: (value: T, a: A, b: B) => E, a: (A | Derivable<A>), b: (B | Derivable<B>)): Derivable<E>; | ||
derive<E>(f: (value: T, ...args: any[]) => E, ...args: any[]): Derivable<E>; | ||
mDerive<E>(f: (value: T) => E): Derivable<E>; | ||
mDerive<A, E>(f: (value: T, a: A) => E, a: (A | Derivable<A>)): Derivable<E>; | ||
mDerive<A, B, E>(f: (value: T, a: A, b: B) => E, a: (A | Derivable<A>), b: (B | Derivable<B>)): Derivable<E>; | ||
mDerive<E>(f: (value: T, ...args: any[]) => E, ...args: any[]): Derivable<E>; | ||
maybeDerive<E>(f: (value: T) => E): Derivable<E>; | ||
orDefault<E>(E): Derivable<T | E> | ||
react(f: (value: T) => void, options?: Lifecycle<T>): void; | ||
mReact(f: (value: T) => void, options?: Lifecycle<T>): void; | ||
maybeReact(f: (value: T) => void, options?: Lifecycle<T>): void; | ||
@@ -33,18 +24,2 @@ get(): T; | ||
and(other: any): Derivable<any>; | ||
mAnd(other: any): Derivable<any>; | ||
or(other: any): Derivable<any>; | ||
mOr(other: any): Derivable<any>; | ||
then(thenD: any, elseD: any): Derivable<any>; | ||
mThen(thenD: any, elseD: any): Derivable<any>; | ||
not(): Derivable<boolean>; | ||
switch(...args: any[]): Derivable<any>; | ||
withEquality(equals: (a: any, b: any) => boolean): this; | ||
@@ -93,17 +68,2 @@ } | ||
function derive<T, A>(f: (a: A) => T, a: A | Derivable<A>): Derivable<T>; | ||
function derive<T, A, B>(f: (a: A, b: B) => T, a: A | Derivable<A>, b: B | Derivable<B>): Derivable<T>; | ||
function derive<T, A, B, C>(f: (a: A, b: B, c: C) => T, a: A | Derivable<A>, | ||
b: B | Derivable<B>, c: C | Derivable<C>): Derivable<T>; | ||
function derive<T, A, B, C, D>(f: (a: A, b: B, c: C, d: D) => T, a: A | Derivable<A>, | ||
b: B | Derivable<B>, c: C | Derivable<C>, d: D | Derivable<D>): Derivable<T>; | ||
function derive<T>(f: (...args: any[])=> T, ...args: any[]): Derivable<T> | ||
function derive(sections: string[], ...values: any[]): Derivable<string> | ||
function proxy<T>(proxy: CompositeProxy<T>): Atom<T>; | ||
@@ -131,14 +91,2 @@ | ||
function derive(strings: string[], ...things: any[]): Derivable<string>; | ||
function or(...conditions: any[]): Derivable<any>; | ||
function mOr(...conditions: any[]): Derivable<any>; | ||
function and(...conditions: any[]): Derivable<any>; | ||
function mAnd(...conditions: any[]): Derivable<any>; | ||
function wrapPreviousState<A, B>(fn: (currentState: A, previousState: A) => B, init?: A): (currentState: A) => B; | ||
function captureDereferences(fn: () => void): Derivable<any>[]; | ||
@@ -145,0 +93,0 @@ |
@@ -1,12 +0,6 @@ | ||
var keys = Object.keys; | ||
var assign = Object.assign; | ||
function equals (a, b) { | ||
return Object.is(a, b) || (a && typeof a.equals === 'function' && a.equals(b)); | ||
} | ||
function addToArray (a, b) { | ||
function addToArray(a, b) { | ||
var i = a.indexOf(b); | ||
if (i < 0) { | ||
if (i === -1) { | ||
a.push(b); | ||
@@ -16,5 +10,5 @@ } | ||
function removeFromArray (a, b) { | ||
function removeFromArray(a, b) { | ||
var i = a.indexOf(b); | ||
if (i >= 0) { | ||
if (i !== -1) { | ||
a.splice(i, 1); | ||
@@ -25,26 +19,37 @@ } | ||
var _nextId = 0; | ||
function nextId () { | ||
function nextId() { | ||
return _nextId++; | ||
} | ||
function slice (a, i) { | ||
return Array.prototype.slice.call(a, i); | ||
} | ||
var unique = Object.freeze({ equals: function () { return false; } }); | ||
var unique = Object.freeze({equals: function () { return false; }}); | ||
function some (x) { | ||
return (x !== null) && (x !== void 0); | ||
function some(x) { | ||
return x !== null && x !== void 0; | ||
} | ||
var DEBUG_MODE = false; | ||
function setDebugMode$1 (val) { | ||
function setDebugMode(val) { | ||
DEBUG_MODE = !!val; | ||
} | ||
function setEquals (derivable, equals) { | ||
derivable._equals = equals; | ||
function isDebug() { | ||
return DEBUG_MODE; | ||
} | ||
function defaultEquals(a, b) { | ||
return ( | ||
Object.is(a, b) || (a && typeof a.equals === "function" && a.equals(b)) | ||
); | ||
} | ||
function setEquals(derivable, eq) { | ||
derivable._equals = eq; | ||
return derivable; | ||
} | ||
function equals(ctx, a, b) { | ||
return (ctx._equals || defaultEquals)(a, b); | ||
} | ||
var ATOM = "ATOM"; | ||
@@ -55,18 +60,15 @@ var DERIVATION = "DERIVATION"; | ||
function isDerivable$1(x) { | ||
return x && | ||
(x._type === DERIVATION || | ||
x._type === ATOM || | ||
x._type === PROXY); | ||
function isDerivable(x) { | ||
return x && (x._type === DERIVATION || x._type === ATOM || x._type === PROXY); | ||
} | ||
function isAtom$1 (x) { | ||
function isAtom(x) { | ||
return x && (x._type === ATOM || x._type === PROXY); | ||
} | ||
function isDerivation$1 (x) { | ||
function isDerivation(x) { | ||
return x && (x._type === DERIVATION || x._type === PROXY); | ||
} | ||
function isProxy$1 (x) { | ||
function isProxy(x) { | ||
return x && x._type === PROXY; | ||
@@ -83,17 +85,18 @@ } | ||
function startCapturingParents (_child, parents) { | ||
parentsStack.push({parents: parents, offset: 0, child: _child}); | ||
function startCapturingParents(_child, parents) { | ||
parentsStack.push({ parents: parents, offset: 0, child: _child }); | ||
child = _child; | ||
} | ||
function retrieveParentsFrame () { | ||
function retrieveParentsFrame() { | ||
return parentsStack[parentsStack.length - 1]; | ||
} | ||
function stopCapturingParents () { | ||
function stopCapturingParents() { | ||
parentsStack.pop(); | ||
child = parentsStack.length === 0 | ||
? null | ||
: parentsStack[parentsStack.length - 1].child; | ||
child = | ||
parentsStack.length === 0 | ||
? null | ||
: parentsStack[parentsStack.length - 1].child; | ||
} | ||
function maybeCaptureParent (p) { | ||
function maybeCaptureParent(p) { | ||
if (child !== null) { | ||
@@ -137,201 +140,14 @@ var frame = parentsStack[parentsStack.length - 1]; | ||
function mark (node, reactors) { | ||
for (var i = 0, len = node._activeChildren.length; i < len; i++) { | ||
var child = node._activeChildren[i]; | ||
switch (child._type) { | ||
case DERIVATION: | ||
case PROXY: | ||
if (child._state !== UNKNOWN) { | ||
child._state = UNKNOWN; | ||
mark(child, reactors); | ||
} | ||
break; | ||
case REACTOR: | ||
reactors.push(child); | ||
break; | ||
} | ||
} | ||
} | ||
function processReactors (reactors) { | ||
for (var i = 0, len = reactors.length; i < len; i++) { | ||
var r = reactors[i]; | ||
if (r._reacting) { | ||
throw new Error("Synchronous cyclical reactions disallowed. " + | ||
"Use setImmediate."); | ||
} | ||
r._maybeReact(); | ||
} | ||
} | ||
var TransactionAbortion = {}; | ||
function initiateAbortion() { | ||
throw TransactionAbortion; | ||
} | ||
function TransactionContext(parent) { | ||
this.parent = parent; | ||
this.id2originalValue = {}; | ||
this.modifiedAtoms = []; | ||
} | ||
function maybeTrack (atom) { | ||
if (currentCtx !== null) { | ||
if (!(atom._id in currentCtx.id2originalValue)) { | ||
currentCtx.modifiedAtoms.push(atom); | ||
currentCtx.id2originalValue[atom._id] = atom._value; | ||
} | ||
} | ||
} | ||
var currentCtx = null; | ||
function inTransaction () { | ||
return currentCtx !== null; | ||
} | ||
function transact$1 (f) { | ||
beginTransaction(); | ||
function captureDereferences(f) { | ||
var captured = []; | ||
startCapturingParents(void 0, captured); | ||
try { | ||
f.call(null, initiateAbortion); | ||
} | ||
catch (e) { | ||
abortTransaction(); | ||
if (e !== TransactionAbortion) { | ||
throw e; | ||
} | ||
return; | ||
} | ||
commitTransaction(); | ||
} | ||
function atomically$1 (f) { | ||
if (!inTransaction()) { | ||
transact$1(f); | ||
} else { | ||
f(); | ||
} finally { | ||
stopCapturingParents(); | ||
} | ||
return captured; | ||
} | ||
function transaction$1 (f) { | ||
return function () { | ||
var args = slice(arguments, 0); | ||
var that = this; | ||
var result; | ||
transact$1(function () { | ||
result = f.apply(that, args); | ||
}); | ||
return result; | ||
}; | ||
} | ||
function atomic$1 (f) { | ||
return function () { | ||
var args = slice(arguments, 0); | ||
var that = this; | ||
var result; | ||
atomically$1(function () { | ||
result = f.apply(that, args); | ||
}); | ||
return result; | ||
}; | ||
} | ||
function beginTransaction() { | ||
currentCtx = new TransactionContext(currentCtx); | ||
} | ||
function commitTransaction() { | ||
var ctx = currentCtx; | ||
currentCtx = ctx.parent; | ||
if (currentCtx === null) { | ||
var reactors = []; | ||
ctx.modifiedAtoms.forEach(function (a) { | ||
if (a.__equals(a._value, ctx.id2originalValue[a._id])) { | ||
a._state = UNCHANGED; | ||
} else { | ||
a._state = CHANGED; | ||
mark(a, reactors); | ||
} | ||
}); | ||
processReactors(reactors); | ||
ctx.modifiedAtoms.forEach(function (a) { | ||
a._state = UNCHANGED; | ||
}); | ||
} | ||
} | ||
function abortTransaction() { | ||
var ctx = currentCtx; | ||
currentCtx = ctx.parent; | ||
ctx.modifiedAtoms.forEach(function (atom) { | ||
atom._value = ctx.id2originalValue[atom._id]; | ||
atom._state = UNCHANGED; | ||
mark(atom, []); | ||
}); | ||
} | ||
var _tickerRefCount = 0; | ||
function ticker$1 () { | ||
if (_tickerRefCount === 0) { | ||
beginTransaction(); | ||
} | ||
_tickerRefCount++; | ||
var done = false; | ||
return { | ||
tick: function () { | ||
if (done) throw new Error('trying to use ticker after release'); | ||
commitTransaction(); | ||
beginTransaction(); | ||
}, | ||
reset: function () { | ||
if (done) throw new Error('trying to use ticker after release'); | ||
abortTransaction(); | ||
beginTransaction(); | ||
}, | ||
release: function () { | ||
if (done) throw new Error('ticker already released'); | ||
_tickerRefCount--; | ||
done = true; | ||
if (_tickerRefCount === 0) { | ||
commitTransaction(); | ||
} | ||
}, | ||
}; | ||
} | ||
/** | ||
* dereferences a thing if it is dereferencable, otherwise just returns it. | ||
*/ | ||
function unpack$1 (thing) { | ||
if (isDerivable$1(thing)) { | ||
return thing.get(); | ||
} else { | ||
return thing; | ||
} | ||
} | ||
function deepUnpack (thing) { | ||
if (isDerivable$1(thing)) { | ||
return thing.get(); | ||
} else if (thing instanceof Array) { | ||
return thing.map(deepUnpack); | ||
} else if (thing.constructor === Object) { | ||
var result = {}; | ||
var keys$$1 = keys(thing); | ||
for (var i = keys$$1.length; i--;) { | ||
var prop = keys$$1[i]; | ||
result[prop] = deepUnpack(thing[prop]); | ||
} | ||
return result; | ||
} else { | ||
return thing; | ||
} | ||
} | ||
function Derivation (deriver) { | ||
function Derivation(deriver) { | ||
this._deriver = deriver; | ||
@@ -345,3 +161,3 @@ this._parents = null; | ||
if (DEBUG_MODE) { | ||
if (isDebug()) { | ||
this.stack = Error().stack; | ||
@@ -352,8 +168,9 @@ } | ||
assign(Derivation.prototype, { | ||
_clone: function () { | ||
return setEquals(derive$1(this._deriver), this._equals); | ||
_clone: function _clone() { | ||
return setEquals(derive(this._deriver), this._equals); | ||
}, | ||
_forceEval: function () { | ||
var that = this; | ||
_forceEval: function _forceEval() { | ||
var this$1 = this; | ||
var newVal = null; | ||
@@ -367,9 +184,9 @@ var newNumParents; | ||
startCapturingParents(this, this._parents); | ||
if (!DEBUG_MODE) { | ||
newVal = that._deriver(); | ||
if (!isDebug()) { | ||
newVal = this._deriver(); | ||
} else { | ||
try { | ||
newVal = that._deriver(); | ||
newVal = this._deriver(); | ||
} catch (e) { | ||
console.error(that.stack); | ||
console.error(this.stack); | ||
throw e; | ||
@@ -383,3 +200,3 @@ } | ||
if (!this.__equals(newVal, this._value)) { | ||
if (!equals(this, newVal, this._value)) { | ||
this._state = CHANGED; | ||
@@ -391,5 +208,5 @@ } else { | ||
for (var i = newNumParents, len = this._parents.length; i < len; i++) { | ||
var oldParent = this._parents[i]; | ||
detach(oldParent, this); | ||
this._parents[i] = null; | ||
var oldParent = this$1._parents[i]; | ||
detach(oldParent, this$1); | ||
this$1._parents[i] = null; | ||
} | ||
@@ -402,3 +219,5 @@ | ||
_update: function () { | ||
_update: function _update() { | ||
var this$1 = this; | ||
if (this._parents === null) { | ||
@@ -411,3 +230,3 @@ // this._state === DISCONNECTED | ||
for (var i = 0; i < len; i++) { | ||
var parent = this._parents[i]; | ||
var parent = this$1._parents[i]; | ||
@@ -419,3 +238,3 @@ if (parent._state === UNKNOWN) { | ||
if (parent._state === CHANGED) { | ||
this._forceEval(); | ||
this$1._forceEval(); | ||
break; | ||
@@ -430,3 +249,3 @@ } | ||
get: function () { | ||
get: function get() { | ||
maybeCaptureParent(this); | ||
@@ -444,6 +263,6 @@ if (this._activeChildren.length > 0) { | ||
return this._value; | ||
}, | ||
} | ||
}); | ||
function detach (parent, child) { | ||
function detach(parent, child) { | ||
removeFromArray(parent._activeChildren, child); | ||
@@ -460,55 +279,13 @@ if (parent._activeChildren.length === 0 && parent._parents != null) { | ||
function derive$1 (f, a, b, c, d) { | ||
if (f instanceof Array) { | ||
// Template string tag for derivable strings | ||
var args = slice(arguments, 1); | ||
return derive$1(function () { | ||
var s = ""; | ||
for (var i=0; i < f.length; i++) { | ||
s += f[i]; | ||
if (i < args.length) { | ||
s += unpack$1(args[i]); | ||
} | ||
} | ||
return s; | ||
}); | ||
} else { | ||
switch (arguments.length) { | ||
case 0: | ||
throw new Error('derive takes at least one argument'); | ||
case 1: | ||
return new Derivation(f); | ||
case 2: | ||
return new Derivation(function () { | ||
return f(unpack$1(a)); | ||
}); | ||
case 3: | ||
return new Derivation(function () { | ||
return f(unpack$1(a), unpack$1(b)); | ||
}); | ||
case 4: | ||
return new Derivation(function () { | ||
return f(unpack$1(a), unpack$1(b), unpack$1(c)); | ||
}); | ||
case 5: | ||
return new Derivation(function () { | ||
return f(unpack$1(a), | ||
unpack$1(b), | ||
unpack$1(c), | ||
unpack$1(d)); | ||
}); | ||
default: | ||
var args = slice(arguments, 1); | ||
return new Derivation(function () { | ||
return f.apply(null, args.map(unpack$1)); | ||
}); | ||
} | ||
function derive(f) { | ||
if (typeof f !== "function") { | ||
throw Error("derive requires function"); | ||
} | ||
return new Derivation(f); | ||
} | ||
function Reactor(parent, react, governor) { | ||
function Reactor(parent, react) { | ||
this._parent = parent; | ||
this.react = react; | ||
this._governor = governor || null; | ||
this._governor = null; | ||
this._active = false; | ||
@@ -518,3 +295,3 @@ this._reacting = false; | ||
if (DEBUG_MODE) { | ||
if (isDebug()) { | ||
this.stack = Error().stack; | ||
@@ -525,3 +302,3 @@ } | ||
assign(Reactor.prototype, { | ||
start: function () { | ||
start: function start() { | ||
this._active = true; | ||
@@ -532,6 +309,5 @@ | ||
this._parent.get(); | ||
return this; | ||
}, | ||
_force: function (nextValue) { | ||
_force: function _force(nextValue) { | ||
try { | ||
@@ -541,3 +317,3 @@ this._reacting = true; | ||
} catch (e) { | ||
if (DEBUG_MODE) { | ||
if (isDebug()) { | ||
console.error(this.stack); | ||
@@ -551,9 +327,12 @@ } | ||
force: function () { | ||
force: function force() { | ||
this._force(this._parent.get()); | ||
}, | ||
return this; | ||
stop: function stop() { | ||
detach(this._parent, this); | ||
this._active = false; | ||
}, | ||
_maybeReact: function () { | ||
_maybeReact: function _maybeReact() { | ||
if (!this._reacting && this._active) { | ||
@@ -571,39 +350,20 @@ if (this._governor !== null) { | ||
} | ||
}, | ||
stop: function () { | ||
detach(this._parent, this); | ||
this._active = false; | ||
return this; | ||
}, | ||
} | ||
}); | ||
function makeReactor (derivable, f, opts) { | ||
if (typeof f !== 'function') { | ||
throw Error('the first argument to .react must be a function'); | ||
function makeReactor(derivable, f, opts) { | ||
if (typeof f !== "function") { | ||
throw Error("the first argument to .react must be a function"); | ||
} | ||
opts = assign({ | ||
once: false, | ||
from: true, | ||
until: false, | ||
when: true, | ||
skipFirst: false, | ||
}, opts); | ||
opts = assign( | ||
{ | ||
once: false, | ||
skipFirst: false | ||
}, | ||
opts | ||
); | ||
var skipFirst = opts.skipFirst; | ||
// coerce fn or bool to derivable<bool> | ||
function condDerivable(fOrD, name) { | ||
if (!isDerivable$1(fOrD)) { | ||
if (typeof fOrD === 'function') { | ||
return derive$1(function () { return fOrD(derivable); }); | ||
} else if (typeof fOrD === 'boolean') { | ||
return derive$1(function () { return fOrD; }); | ||
} else { | ||
throw Error('react ' + name + ' condition must be derivable, got: ' + JSON.stringify(fOrD)); | ||
} | ||
} | ||
return fOrD; | ||
} | ||
// wrap reactor so f doesn't get a .this context, and to allow | ||
@@ -617,3 +377,3 @@ // stopping after one reaction if desired. | ||
if (opts.once) { | ||
this.stop(); | ||
reactor.stop(); | ||
controller.stop(); | ||
@@ -624,178 +384,278 @@ } | ||
var assertCondition = function (condition, name) { | ||
if (isDerivable(condition)) { | ||
return condition; | ||
} | ||
if (typeof condition === "function") { | ||
return condition; | ||
} | ||
if (typeof condition === "undefined") { | ||
return condition; | ||
} | ||
throw Error( | ||
"react " + name + " condition must be derivable or function, got: " + | ||
JSON.stringify(condition) | ||
); | ||
}; | ||
var getCondition = function (condition, def) { return condition | ||
? typeof condition === "function" ? condition(derivable) : condition.get() | ||
: def; }; | ||
// listen to from condition, starting the reactor controller | ||
// when appropriate | ||
var $from = assertCondition(opts.from, "from"); | ||
// listen to when and until conditions, starting and stopping the | ||
// reactor as appropriate, and stopping this controller when until | ||
// condition becomes true | ||
var $until = condDerivable(opts.until, 'until'); | ||
var $when = condDerivable(opts.when, 'when'); | ||
var $until = assertCondition(opts.until, "until"); | ||
var $when = assertCondition(opts.when, "when"); | ||
var $whenUntil = derive$1(function () { | ||
var $conds = derive(function () { | ||
return { | ||
until: $until.get(), | ||
when: $when.get(), | ||
from: getCondition($from, true), | ||
until: getCondition($until, false), | ||
when: getCondition($when, true) | ||
}; | ||
}); | ||
var controller = new Reactor($whenUntil, function (conds) { | ||
if (conds.until) { | ||
reactor.stop(); | ||
this.stop(); | ||
} else if (conds.when) { | ||
if (!reactor._active) { | ||
reactor.start().force(); | ||
var started = false; | ||
var controller = new Reactor($conds, function (conds) { | ||
if (conds.from) { | ||
started = true; | ||
} | ||
if (started) { | ||
if (conds.until) { | ||
reactor.stop(); | ||
controller.stop(); | ||
} else if (conds.when) { | ||
if (!reactor._active) { | ||
reactor.start(); | ||
reactor.force(); | ||
} | ||
} else if (reactor._active) { | ||
reactor.stop(); | ||
} | ||
} else if (reactor._active) { | ||
reactor.stop(); | ||
} | ||
}); | ||
controller.start(); | ||
controller.force(); | ||
reactor._governor = controller; | ||
} | ||
// listen to from condition, starting the reactor controller | ||
// when appropriate | ||
var $from = condDerivable(opts.from, 'from'); | ||
var initiator = new Reactor($from, function (from) { | ||
if (from) { | ||
controller.start().force(); | ||
this.stop(); | ||
} | ||
}); | ||
/** | ||
* dereferences a thing if it is dereferencable, otherwise just returns it. | ||
*/ | ||
initiator.start().force(); | ||
function unpack(thing) { | ||
if (isDerivable(thing)) { | ||
return thing.get(); | ||
} else { | ||
return thing; | ||
} | ||
} | ||
var global$1 = typeof window === 'object' ? window : typeof global=== 'object' ? global : {}; | ||
function deepUnpack(thing) { | ||
if (isDerivable(thing)) { | ||
return thing.get(); | ||
} else if (Array.isArray(thing)) { | ||
return thing.map(deepUnpack); | ||
} else if (thing.constructor === Object) { | ||
var result = {}; | ||
var keys = Object.keys(thing); | ||
for (var i = keys.length; i--; ) { | ||
var prop = keys[i]; | ||
result[prop] = deepUnpack(thing[prop]); | ||
} | ||
return result; | ||
} else { | ||
return thing; | ||
} | ||
} | ||
var devtoolsHook = global$1.__DERIVABLE_DEVTOOLS_HOOK__; | ||
function Atom (value) { | ||
this._id = nextId(); | ||
this._activeChildren = []; | ||
this._value = value; | ||
this._state = UNCHANGED; | ||
this._type = ATOM; | ||
this._equals = null; | ||
return this; | ||
function struct(arg) { | ||
if (arg.constructor === Object || Array.isArray(arg)) { | ||
return derive(function () { return deepUnpack(arg); }); | ||
} else { | ||
throw new Error("`struct` expects plain Object or Array"); | ||
} | ||
} | ||
assign(Atom.prototype, { | ||
_clone: function () { | ||
return setEquals(atom$2(this._value), this._equals); | ||
var derivablePrototype = { | ||
derive: function derive$1(f) { | ||
var this$1 = this; | ||
if (typeof f !== "function") { | ||
throw Error("derive requires function"); | ||
} | ||
return derive(function () { return f(this$1.get()); }); | ||
}, | ||
set: function (value) { | ||
maybeTrack(this); | ||
maybeDerive: function maybeDerive(f) { | ||
var this$1 = this; | ||
var oldValue = this._value; | ||
this._value = value; | ||
if (!inTransaction()) { | ||
if (!this.__equals(value, oldValue)) { | ||
try { | ||
this._state = CHANGED; | ||
var reactors = []; | ||
mark(this, reactors); | ||
processReactors(reactors); | ||
} finally { | ||
this._state = UNCHANGED; | ||
} | ||
} | ||
if (typeof f !== "function") { | ||
throw Error("maybeDerive requires function"); | ||
} | ||
return derive(function () { | ||
var arg = this$1.get(); | ||
return some(arg) ? f(arg) : null; | ||
}); | ||
}, | ||
get: function () { | ||
if (typeof devtoolsHook === 'function') { | ||
devtoolsHook('captureAtom', this); | ||
orDefault: function orDefault(def) { | ||
if (!some(def)) { | ||
throw Error("orDefault requires non-null value"); | ||
} | ||
maybeCaptureParent(this); | ||
return this._value; | ||
return this.derive(function (value) { return (some(value) ? value : def); }); | ||
}, | ||
}); | ||
function atom$2 (value) { | ||
return new Atom(value); | ||
} | ||
react: function react(f, opts) { | ||
makeReactor(this, f, opts); | ||
}, | ||
function Proxy (descriptor) { | ||
Derivation.call(this, descriptor.get); | ||
this._proxyMapping = descriptor; | ||
this._type = PROXY; | ||
} | ||
assign(Proxy.prototype, Derivation.prototype, { | ||
_clone: function () { | ||
return setEquals(new Proxy(this._proxyMapping), this._equals); | ||
maybeReact: function maybeReact(f, opts) { | ||
var maybeWhen = this.derive(Boolean); | ||
if (opts && "when" in opts && opts.when !== true) { | ||
var when = opts.when; | ||
if (typeof when === "function" || when === false) { | ||
when = derive(when); | ||
} else if (!isDerivable(when)) { | ||
throw new Error("when condition must be bool, function, or derivable"); | ||
} | ||
maybeWhen = maybeWhen.derive(function (d) { return d && when.get(); }); | ||
} | ||
makeReactor(this, f, assign({}, opts, { when: maybeWhen })); | ||
}, | ||
set: function (value) { | ||
var that = this; | ||
atomically$1(function () { | ||
that._proxyMapping.set(value); | ||
}); | ||
return this; | ||
is: function is(other) { | ||
var this$1 = this; | ||
return derive(function () { return equals(this$1, this$1.get(), unpack(other)); }); | ||
}, | ||
}); | ||
function proxy$2 (descriptor) { | ||
return new Proxy(descriptor); | ||
} | ||
withEquality: function withEquality(equals$$1) { | ||
if (equals$$1) { | ||
if (typeof equals$$1 !== "function") { | ||
throw new Error("equals must be function"); | ||
} | ||
} else { | ||
equals$$1 = null; | ||
} | ||
function andOrFn (breakOn) { | ||
return function () { | ||
var args = arguments; | ||
return derive$1(function () { | ||
var val; | ||
for (var i = 0; i < args.length; i++) { | ||
val = unpack$1(args[i]); | ||
if (breakOn(val)) { | ||
break; | ||
return setEquals(this._clone(), equals$$1); | ||
} | ||
}; | ||
var mutablePrototype = { | ||
update: function update(f, a, b, c, d) { | ||
switch (arguments.length) { | ||
case 0: | ||
throw Error("update method accepts at least 1 argument"); | ||
case 1: | ||
return this.set(f(this.get())); | ||
case 2: | ||
return this.set(f(this.get(), a)); | ||
case 3: | ||
return this.set(f(this.get(), a, b)); | ||
case 4: | ||
return this.set(f(this.get(), a, b, c)); | ||
case 5: | ||
return this.set(f(this.get(), a, b, c, d)); | ||
default: | ||
throw Error("update method accepts only 5 arguments"); | ||
} | ||
} | ||
}; | ||
function mark(node, reactors) { | ||
for (var i = 0, len = node._activeChildren.length; i < len; i++) { | ||
var child = node._activeChildren[i]; | ||
switch (child._type) { | ||
case DERIVATION: | ||
case PROXY: | ||
if (child._state !== UNKNOWN) { | ||
child._state = UNKNOWN; | ||
mark(child, reactors); | ||
} | ||
} | ||
return val; | ||
}); | ||
}; | ||
break; | ||
case REACTOR: | ||
reactors.push(child); | ||
break; | ||
} | ||
} | ||
} | ||
function identity (x) { return x; } | ||
function processReactors(reactors) { | ||
for (var i = 0, len = reactors.length; i < len; i++) { | ||
var r = reactors[i]; | ||
if (r._reacting) { | ||
throw Error( | ||
"Synchronous cyclical reactions disallowed. " + "Use setImmediate." | ||
); | ||
} | ||
r._maybeReact(); | ||
} | ||
} | ||
function complement (f) { return function (x) { return !f(x); }; } | ||
var TransactionAbortion = {}; | ||
var or$1 = andOrFn(identity); | ||
function initiateAbortion() { | ||
throw TransactionAbortion; | ||
} | ||
var mOr$1 = andOrFn(some); | ||
function TransactionContext(parent) { | ||
this.parent = parent; | ||
this.id2originalValue = {}; | ||
this.modifiedAtoms = []; | ||
} | ||
var and$1 = andOrFn(complement(identity)); | ||
function maybeTrack(atom) { | ||
if (currentCtx !== null) { | ||
if (!(atom._id in currentCtx.id2originalValue)) { | ||
currentCtx.modifiedAtoms.push(atom); | ||
currentCtx.id2originalValue[atom._id] = atom._value; | ||
} | ||
} | ||
} | ||
var mAnd$1 = andOrFn(complement(some)); | ||
var currentCtx = null; | ||
var __Reactor$1 = Reactor; | ||
var transact$2 = transact$1; | ||
var setDebugMode$2 = setDebugMode$1; | ||
var transaction$2 = transaction$1; | ||
var ticker$2 = ticker$1; | ||
var isDerivable$2 = isDerivable$1; | ||
var isAtom$2 = isAtom$1; | ||
var isProxy$2 = isProxy$1; | ||
var isDerivation$2 = isDerivation$1; | ||
var derive$2 = derive$1; | ||
var atom$1 = atom$2; | ||
var atomic$2 = atomic$1; | ||
var atomically$2 = atomically$1; | ||
var proxy$1 = proxy$2; | ||
var unpack$2 = unpack$1; | ||
function inTransaction() { | ||
return currentCtx !== null; | ||
} | ||
function struct$1 (arg) { | ||
if (arg.constructor === Object || arg instanceof Array) { | ||
return derive$2(function () { | ||
return deepUnpack(arg); | ||
}); | ||
function transact(f) { | ||
beginTransaction(); | ||
try { | ||
f(initiateAbortion); | ||
} catch (e) { | ||
abortTransaction(); | ||
if (e !== TransactionAbortion) { | ||
throw e; | ||
} | ||
return; | ||
} | ||
commitTransaction(); | ||
} | ||
function atomically(f) { | ||
if (!inTransaction()) { | ||
transact(f); | ||
} else { | ||
throw new Error("`struct` expects plain Object or Array"); | ||
f(); | ||
} | ||
} | ||
function wrapPreviousState$1 (f, init) { | ||
var lastState = init; | ||
return function (newState) { | ||
var result = f.call(this, newState, lastState); | ||
lastState = newState; | ||
function transaction(f) { | ||
return function () { | ||
var args = [], len = arguments.length; | ||
while ( len-- ) args[ len ] = arguments[ len ]; | ||
var result; | ||
transact(function () { | ||
result = f.apply(void 0, args); | ||
}); | ||
return result; | ||
@@ -805,224 +665,157 @@ }; | ||
function captureDereferences$1 (f) { | ||
var captured = []; | ||
startCapturingParents(void 0, captured); | ||
try { | ||
f(); | ||
} finally { | ||
stopCapturingParents(); | ||
} | ||
return captured; | ||
function atomic(f) { | ||
return function () { | ||
var args = [], len = arguments.length; | ||
while ( len-- ) args[ len ] = arguments[ len ]; | ||
var result; | ||
atomically(function () { | ||
result = f.apply(void 0, args); | ||
}); | ||
return result; | ||
}; | ||
} | ||
function beginTransaction() { | ||
currentCtx = new TransactionContext(currentCtx); | ||
} | ||
var derivable$1 = Object.freeze({ | ||
__Reactor: __Reactor$1, | ||
transact: transact$2, | ||
setDebugMode: setDebugMode$2, | ||
transaction: transaction$2, | ||
ticker: ticker$2, | ||
isDerivable: isDerivable$2, | ||
isAtom: isAtom$2, | ||
isProxy: isProxy$2, | ||
isDerivation: isDerivation$2, | ||
derive: derive$2, | ||
atom: atom$1, | ||
atomic: atomic$2, | ||
atomically: atomically$2, | ||
proxy: proxy$1, | ||
unpack: unpack$2, | ||
struct: struct$1, | ||
wrapPreviousState: wrapPreviousState$1, | ||
captureDereferences: captureDereferences$1, | ||
or: or$1, | ||
mOr: mOr$1, | ||
and: and$1, | ||
mAnd: mAnd$1 | ||
}); | ||
function commitTransaction() { | ||
var ctx = currentCtx; | ||
currentCtx = ctx.parent; | ||
var derivablePrototype = { | ||
/** | ||
* Creates a derived value whose state will always be f applied to this | ||
* value | ||
*/ | ||
derive: function (f, a, b, c, d) { | ||
var that = this; | ||
switch (arguments.length) { | ||
case 0: | ||
throw new Error('.derive takes at least one argument'); | ||
case 1: | ||
switch (typeof f) { | ||
case 'function': | ||
return derive$2(f, that); | ||
case 'string': | ||
case 'number': | ||
return derive$2(function () { | ||
return that.get()[f]; | ||
}); | ||
default: | ||
if (f instanceof Array) { | ||
return f.map(function (x) { | ||
return that.derive(x); | ||
}); | ||
} else if (f instanceof RegExp) { | ||
return derive$2(function () { | ||
return that.get().match(f); | ||
}); | ||
} else if (isDerivable$1(f)) { | ||
return derive$2(function () { | ||
var deriver = f.get(); | ||
var thing = that.get(); | ||
switch (typeof deriver) { | ||
case 'function': | ||
return deriver(thing); | ||
case 'string': | ||
case 'number': | ||
return thing[deriver]; | ||
default: | ||
if (deriver instanceof RegExp) { | ||
return thing.match(deriver); | ||
} else { | ||
throw Error('type error'); | ||
} | ||
} | ||
}); | ||
} else { | ||
throw Error('type error'); | ||
} | ||
} | ||
case 2: | ||
return derive$2(f, that, a); | ||
case 3: | ||
return derive$2(f, that, a, b); | ||
case 4: | ||
return derive$2(f, that, a, b, c); | ||
case 5: | ||
return derive$2(f, that, a, b, c, d); | ||
default: | ||
var args = ([f, that]).concat(slice(arguments, 1)); | ||
return derive$2.apply(null, args); | ||
} | ||
}, | ||
if (currentCtx === null) { | ||
var reactors = []; | ||
ctx.modifiedAtoms.forEach(function (a) { | ||
if (equals(a, a._value, ctx.id2originalValue[a._id])) { | ||
a._state = UNCHANGED; | ||
} else { | ||
a._state = CHANGED; | ||
mark(a, reactors); | ||
} | ||
}); | ||
processReactors(reactors); | ||
ctx.modifiedAtoms.forEach(function (a) { | ||
a._state = UNCHANGED; | ||
}); | ||
} | ||
} | ||
react: function (f, opts) { | ||
makeReactor(this, f, opts); | ||
}, | ||
function abortTransaction() { | ||
var ctx = currentCtx; | ||
currentCtx = ctx.parent; | ||
ctx.modifiedAtoms.forEach(function (atom) { | ||
atom._value = ctx.id2originalValue[atom._id]; | ||
atom._state = UNCHANGED; | ||
mark(atom, []); | ||
}); | ||
} | ||
mReact: function (f, opts) { | ||
var mWhen = this.mThen(true, false); | ||
if (opts && 'when' in opts && opts.when !== true) { | ||
var when = opts.when; | ||
if (typeof when === 'function' || when === false) { | ||
when = derive$2(when); | ||
} else if (!isDerivable$1(when)) { | ||
throw new Error('when condition must be bool, function, or derivable'); | ||
var _tickerRefCount = 0; | ||
function ticker() { | ||
if (_tickerRefCount === 0) { | ||
beginTransaction(); | ||
} | ||
_tickerRefCount++; | ||
var done = false; | ||
return { | ||
tick: function tick() { | ||
if (done) { throw new Error("trying to use ticker after release"); } | ||
commitTransaction(); | ||
beginTransaction(); | ||
}, | ||
reset: function reset() { | ||
if (done) { throw new Error("trying to use ticker after release"); } | ||
abortTransaction(); | ||
beginTransaction(); | ||
}, | ||
release: function release() { | ||
if (done) { throw new Error("ticker already released"); } | ||
_tickerRefCount--; | ||
done = true; | ||
if (_tickerRefCount === 0) { | ||
commitTransaction(); | ||
} | ||
mWhen = when.and(mWhen); | ||
} | ||
return this.react(f, assign({}, opts, {when: mWhen})); | ||
}, | ||
}; | ||
} | ||
is: function (other) { | ||
var x = this; | ||
return derive$2(function () { | ||
return x.__equals(x.get(), unpack$1(other)); | ||
}); | ||
}, | ||
var global$1 = (typeof window === "object" | ||
? window | ||
: typeof global === "object" ? global : {}); | ||
then: function (thenClause, elseClause) { | ||
var x = this; | ||
return derive$2(function () { | ||
return unpack$1(x.get() ? thenClause : elseClause); | ||
}); | ||
}, | ||
var devtoolsHook = global$1.__DERIVABLE_DEVTOOLS_HOOK__; | ||
mThen: function (thenClause, elseClause) { | ||
var x = this; | ||
return derive$2(function () { | ||
return unpack$1(some(x.get()) ? thenClause : elseClause); | ||
}); | ||
}, | ||
function Atom(value) { | ||
this._id = nextId(); | ||
this._activeChildren = []; | ||
this._value = value; | ||
this._state = UNCHANGED; | ||
this._type = ATOM; | ||
this._equals = null; | ||
} | ||
or: function (other) { | ||
return or$1(this, other); | ||
assign(Atom.prototype, { | ||
_clone: function _clone() { | ||
return setEquals(atom(this._value), this._equals); | ||
}, | ||
mOr: function (other) { | ||
return mOr$1(this, other); | ||
}, | ||
set: function set(value) { | ||
maybeTrack(this); | ||
and: function (other) { | ||
return and$1(this, other); | ||
}, | ||
var oldValue = this._value; | ||
this._value = value; | ||
mAnd: function (other) { | ||
return mAnd$1(this, other); | ||
if (!inTransaction()) { | ||
if (!equals(this, value, oldValue)) { | ||
try { | ||
this._state = CHANGED; | ||
var reactors = []; | ||
mark(this, reactors); | ||
processReactors(reactors); | ||
} finally { | ||
this._state = UNCHANGED; | ||
} | ||
} | ||
} | ||
}, | ||
mDerive: function (arg) { | ||
if (arguments.length === 1 && arg instanceof Array) { | ||
var that = this; | ||
return arg.map(function (a) { return that.mDerive(a); }); | ||
} else { | ||
return this.mThen(this.derive.apply(this, arguments)); | ||
get: function get() { | ||
if (typeof devtoolsHook === "function") { | ||
devtoolsHook("captureAtom", this); | ||
} | ||
}, | ||
maybeCaptureParent(this); | ||
return this._value; | ||
} | ||
}); | ||
not: function () { | ||
var x = this; | ||
return derive$2(function () { return !x.get(); }); | ||
}, | ||
function atom(value) { | ||
return new Atom(value); | ||
} | ||
withEquality: function (equals$$1) { | ||
if (equals$$1) { | ||
if (typeof equals$$1 !== 'function') { | ||
throw new Error('equals must be function'); | ||
} | ||
} else { | ||
equals$$1 = null; | ||
} | ||
function Proxy(descriptor) { | ||
Derivation.call(this, descriptor.get); | ||
this._proxyMapping = descriptor; | ||
this._type = PROXY; | ||
} | ||
return setEquals(this._clone(), equals$$1); | ||
assign(Proxy.prototype, Derivation.prototype, { | ||
_clone: function _clone() { | ||
return setEquals(new Proxy(this._proxyMapping), this._equals); | ||
}, | ||
__equals: function (a, b) { | ||
return (this._equals || equals)(a, b); | ||
}, | ||
}; | ||
set: function set(value) { | ||
var this$1 = this; | ||
derivablePrototype.switch = function () { | ||
var args = arguments; | ||
var that = this; | ||
return this.derive(function (x) { | ||
var i; | ||
for (i = 0; i < args.length-1; i+=2) { | ||
if (that.__equals(x, unpack$1(args[i]))) { | ||
return unpack$1(args[i+1]); | ||
} | ||
} | ||
if (i === args.length - 1) { | ||
return unpack$1(args[i]); | ||
} | ||
}); | ||
}; | ||
var mutablePrototype = { | ||
update: function (f) { | ||
var args = slice(arguments, 0); | ||
args[0] = this.get(); | ||
return this.set(f.apply(null, args)); | ||
}, | ||
proxy: function (monoProxyMapping) { | ||
var that = this; | ||
return new Proxy({ | ||
get: function () { | ||
return monoProxyMapping.get(that.get()); | ||
}, | ||
set: function (val) { | ||
that.set(monoProxyMapping.set(that.get(), val)); | ||
} | ||
atomically(function () { | ||
this$1._proxyMapping.set(value); | ||
}); | ||
}, | ||
}; | ||
} | ||
}); | ||
function proxy(descriptor) { | ||
return new Proxy(descriptor); | ||
} | ||
assign(Derivation.prototype, derivablePrototype); | ||
@@ -1033,31 +826,9 @@ assign(Proxy.prototype, derivablePrototype, mutablePrototype); | ||
if (global$1.__DERIVABLE_INIT_FLAG__) { | ||
console.warn('Multiple instances of derivable have been initialized on the same page'); | ||
console.warn( | ||
"Multiple instances of derivable have been initialized on the same page" | ||
); | ||
} | ||
global$1.__DERIVABLE_INIT_FLAG__ = true; | ||
var __Reactor = __Reactor$1; | ||
var transact = transact$2; | ||
var setDebugMode = setDebugMode$2; | ||
var transaction = transaction$2; | ||
var ticker = ticker$2; | ||
var isDerivable = isDerivable$2; | ||
var isAtom = isAtom$2; | ||
var isProxy = isProxy$2; | ||
var isDerivation = isDerivation$2; | ||
var derive = derive$2; | ||
var atom = atom$1; | ||
var atomic = atomic$2; | ||
var atomically = atomically$2; | ||
var proxy = proxy$1; | ||
var unpack = unpack$2; | ||
var struct = struct$1; | ||
var wrapPreviousState = wrapPreviousState$1; | ||
var captureDereferences = captureDereferences$1; | ||
var or = or$1; | ||
var mOr = mOr$1; | ||
var and = and$1; | ||
var mAnd = mAnd$1; | ||
export { __Reactor, transact, setDebugMode, transaction, ticker, isDerivable, isAtom, isProxy, isDerivation, derive, atom, atomic, atomically, proxy, unpack, struct, wrapPreviousState, captureDereferences, or, mOr, and, mAnd }; | ||
export default derivable$1; | ||
export { atom, proxy, derive, setDebugMode, isDerivable, isAtom, isProxy, isDerivation, unpack, struct, transact, transaction, ticker, atomic, atomically, Reactor as __Reactor, captureDereferences as __captureDereferences }; | ||
//# sourceMappingURL=derivable.es.js.map |
@@ -5,13 +5,7 @@ 'use strict'; | ||
var keys = Object.keys; | ||
var assign = Object.assign; | ||
function equals (a, b) { | ||
return Object.is(a, b) || (a && typeof a.equals === 'function' && a.equals(b)); | ||
} | ||
function addToArray (a, b) { | ||
function addToArray(a, b) { | ||
var i = a.indexOf(b); | ||
if (i < 0) { | ||
if (i === -1) { | ||
a.push(b); | ||
@@ -21,5 +15,5 @@ } | ||
function removeFromArray (a, b) { | ||
function removeFromArray(a, b) { | ||
var i = a.indexOf(b); | ||
if (i >= 0) { | ||
if (i !== -1) { | ||
a.splice(i, 1); | ||
@@ -30,26 +24,37 @@ } | ||
var _nextId = 0; | ||
function nextId () { | ||
function nextId() { | ||
return _nextId++; | ||
} | ||
function slice (a, i) { | ||
return Array.prototype.slice.call(a, i); | ||
} | ||
var unique = Object.freeze({ equals: function () { return false; } }); | ||
var unique = Object.freeze({equals: function () { return false; }}); | ||
function some (x) { | ||
return (x !== null) && (x !== void 0); | ||
function some(x) { | ||
return x !== null && x !== void 0; | ||
} | ||
var DEBUG_MODE = false; | ||
function setDebugMode$1 (val) { | ||
function setDebugMode(val) { | ||
DEBUG_MODE = !!val; | ||
} | ||
function setEquals (derivable, equals) { | ||
derivable._equals = equals; | ||
function isDebug() { | ||
return DEBUG_MODE; | ||
} | ||
function defaultEquals(a, b) { | ||
return ( | ||
Object.is(a, b) || (a && typeof a.equals === "function" && a.equals(b)) | ||
); | ||
} | ||
function setEquals(derivable, eq) { | ||
derivable._equals = eq; | ||
return derivable; | ||
} | ||
function equals(ctx, a, b) { | ||
return (ctx._equals || defaultEquals)(a, b); | ||
} | ||
var ATOM = "ATOM"; | ||
@@ -60,18 +65,15 @@ var DERIVATION = "DERIVATION"; | ||
function isDerivable$1(x) { | ||
return x && | ||
(x._type === DERIVATION || | ||
x._type === ATOM || | ||
x._type === PROXY); | ||
function isDerivable(x) { | ||
return x && (x._type === DERIVATION || x._type === ATOM || x._type === PROXY); | ||
} | ||
function isAtom$1 (x) { | ||
function isAtom(x) { | ||
return x && (x._type === ATOM || x._type === PROXY); | ||
} | ||
function isDerivation$1 (x) { | ||
function isDerivation(x) { | ||
return x && (x._type === DERIVATION || x._type === PROXY); | ||
} | ||
function isProxy$1 (x) { | ||
function isProxy(x) { | ||
return x && x._type === PROXY; | ||
@@ -88,17 +90,18 @@ } | ||
function startCapturingParents (_child, parents) { | ||
parentsStack.push({parents: parents, offset: 0, child: _child}); | ||
function startCapturingParents(_child, parents) { | ||
parentsStack.push({ parents: parents, offset: 0, child: _child }); | ||
child = _child; | ||
} | ||
function retrieveParentsFrame () { | ||
function retrieveParentsFrame() { | ||
return parentsStack[parentsStack.length - 1]; | ||
} | ||
function stopCapturingParents () { | ||
function stopCapturingParents() { | ||
parentsStack.pop(); | ||
child = parentsStack.length === 0 | ||
? null | ||
: parentsStack[parentsStack.length - 1].child; | ||
child = | ||
parentsStack.length === 0 | ||
? null | ||
: parentsStack[parentsStack.length - 1].child; | ||
} | ||
function maybeCaptureParent (p) { | ||
function maybeCaptureParent(p) { | ||
if (child !== null) { | ||
@@ -142,201 +145,14 @@ var frame = parentsStack[parentsStack.length - 1]; | ||
function mark (node, reactors) { | ||
for (var i = 0, len = node._activeChildren.length; i < len; i++) { | ||
var child = node._activeChildren[i]; | ||
switch (child._type) { | ||
case DERIVATION: | ||
case PROXY: | ||
if (child._state !== UNKNOWN) { | ||
child._state = UNKNOWN; | ||
mark(child, reactors); | ||
} | ||
break; | ||
case REACTOR: | ||
reactors.push(child); | ||
break; | ||
} | ||
} | ||
} | ||
function processReactors (reactors) { | ||
for (var i = 0, len = reactors.length; i < len; i++) { | ||
var r = reactors[i]; | ||
if (r._reacting) { | ||
throw new Error("Synchronous cyclical reactions disallowed. " + | ||
"Use setImmediate."); | ||
} | ||
r._maybeReact(); | ||
} | ||
} | ||
var TransactionAbortion = {}; | ||
function initiateAbortion() { | ||
throw TransactionAbortion; | ||
} | ||
function TransactionContext(parent) { | ||
this.parent = parent; | ||
this.id2originalValue = {}; | ||
this.modifiedAtoms = []; | ||
} | ||
function maybeTrack (atom) { | ||
if (currentCtx !== null) { | ||
if (!(atom._id in currentCtx.id2originalValue)) { | ||
currentCtx.modifiedAtoms.push(atom); | ||
currentCtx.id2originalValue[atom._id] = atom._value; | ||
} | ||
} | ||
} | ||
var currentCtx = null; | ||
function inTransaction () { | ||
return currentCtx !== null; | ||
} | ||
function transact$1 (f) { | ||
beginTransaction(); | ||
function captureDereferences(f) { | ||
var captured = []; | ||
startCapturingParents(void 0, captured); | ||
try { | ||
f.call(null, initiateAbortion); | ||
} | ||
catch (e) { | ||
abortTransaction(); | ||
if (e !== TransactionAbortion) { | ||
throw e; | ||
} | ||
return; | ||
} | ||
commitTransaction(); | ||
} | ||
function atomically$1 (f) { | ||
if (!inTransaction()) { | ||
transact$1(f); | ||
} else { | ||
f(); | ||
} finally { | ||
stopCapturingParents(); | ||
} | ||
return captured; | ||
} | ||
function transaction$1 (f) { | ||
return function () { | ||
var args = slice(arguments, 0); | ||
var that = this; | ||
var result; | ||
transact$1(function () { | ||
result = f.apply(that, args); | ||
}); | ||
return result; | ||
}; | ||
} | ||
function atomic$1 (f) { | ||
return function () { | ||
var args = slice(arguments, 0); | ||
var that = this; | ||
var result; | ||
atomically$1(function () { | ||
result = f.apply(that, args); | ||
}); | ||
return result; | ||
}; | ||
} | ||
function beginTransaction() { | ||
currentCtx = new TransactionContext(currentCtx); | ||
} | ||
function commitTransaction() { | ||
var ctx = currentCtx; | ||
currentCtx = ctx.parent; | ||
if (currentCtx === null) { | ||
var reactors = []; | ||
ctx.modifiedAtoms.forEach(function (a) { | ||
if (a.__equals(a._value, ctx.id2originalValue[a._id])) { | ||
a._state = UNCHANGED; | ||
} else { | ||
a._state = CHANGED; | ||
mark(a, reactors); | ||
} | ||
}); | ||
processReactors(reactors); | ||
ctx.modifiedAtoms.forEach(function (a) { | ||
a._state = UNCHANGED; | ||
}); | ||
} | ||
} | ||
function abortTransaction() { | ||
var ctx = currentCtx; | ||
currentCtx = ctx.parent; | ||
ctx.modifiedAtoms.forEach(function (atom) { | ||
atom._value = ctx.id2originalValue[atom._id]; | ||
atom._state = UNCHANGED; | ||
mark(atom, []); | ||
}); | ||
} | ||
var _tickerRefCount = 0; | ||
function ticker$1 () { | ||
if (_tickerRefCount === 0) { | ||
beginTransaction(); | ||
} | ||
_tickerRefCount++; | ||
var done = false; | ||
return { | ||
tick: function () { | ||
if (done) throw new Error('trying to use ticker after release'); | ||
commitTransaction(); | ||
beginTransaction(); | ||
}, | ||
reset: function () { | ||
if (done) throw new Error('trying to use ticker after release'); | ||
abortTransaction(); | ||
beginTransaction(); | ||
}, | ||
release: function () { | ||
if (done) throw new Error('ticker already released'); | ||
_tickerRefCount--; | ||
done = true; | ||
if (_tickerRefCount === 0) { | ||
commitTransaction(); | ||
} | ||
}, | ||
}; | ||
} | ||
/** | ||
* dereferences a thing if it is dereferencable, otherwise just returns it. | ||
*/ | ||
function unpack$1 (thing) { | ||
if (isDerivable$1(thing)) { | ||
return thing.get(); | ||
} else { | ||
return thing; | ||
} | ||
} | ||
function deepUnpack (thing) { | ||
if (isDerivable$1(thing)) { | ||
return thing.get(); | ||
} else if (thing instanceof Array) { | ||
return thing.map(deepUnpack); | ||
} else if (thing.constructor === Object) { | ||
var result = {}; | ||
var keys$$1 = keys(thing); | ||
for (var i = keys$$1.length; i--;) { | ||
var prop = keys$$1[i]; | ||
result[prop] = deepUnpack(thing[prop]); | ||
} | ||
return result; | ||
} else { | ||
return thing; | ||
} | ||
} | ||
function Derivation (deriver) { | ||
function Derivation(deriver) { | ||
this._deriver = deriver; | ||
@@ -350,3 +166,3 @@ this._parents = null; | ||
if (DEBUG_MODE) { | ||
if (isDebug()) { | ||
this.stack = Error().stack; | ||
@@ -357,8 +173,9 @@ } | ||
assign(Derivation.prototype, { | ||
_clone: function () { | ||
return setEquals(derive$1(this._deriver), this._equals); | ||
_clone: function _clone() { | ||
return setEquals(derive(this._deriver), this._equals); | ||
}, | ||
_forceEval: function () { | ||
var that = this; | ||
_forceEval: function _forceEval() { | ||
var this$1 = this; | ||
var newVal = null; | ||
@@ -372,9 +189,9 @@ var newNumParents; | ||
startCapturingParents(this, this._parents); | ||
if (!DEBUG_MODE) { | ||
newVal = that._deriver(); | ||
if (!isDebug()) { | ||
newVal = this._deriver(); | ||
} else { | ||
try { | ||
newVal = that._deriver(); | ||
newVal = this._deriver(); | ||
} catch (e) { | ||
console.error(that.stack); | ||
console.error(this.stack); | ||
throw e; | ||
@@ -388,3 +205,3 @@ } | ||
if (!this.__equals(newVal, this._value)) { | ||
if (!equals(this, newVal, this._value)) { | ||
this._state = CHANGED; | ||
@@ -396,5 +213,5 @@ } else { | ||
for (var i = newNumParents, len = this._parents.length; i < len; i++) { | ||
var oldParent = this._parents[i]; | ||
detach(oldParent, this); | ||
this._parents[i] = null; | ||
var oldParent = this$1._parents[i]; | ||
detach(oldParent, this$1); | ||
this$1._parents[i] = null; | ||
} | ||
@@ -407,3 +224,5 @@ | ||
_update: function () { | ||
_update: function _update() { | ||
var this$1 = this; | ||
if (this._parents === null) { | ||
@@ -416,3 +235,3 @@ // this._state === DISCONNECTED | ||
for (var i = 0; i < len; i++) { | ||
var parent = this._parents[i]; | ||
var parent = this$1._parents[i]; | ||
@@ -424,3 +243,3 @@ if (parent._state === UNKNOWN) { | ||
if (parent._state === CHANGED) { | ||
this._forceEval(); | ||
this$1._forceEval(); | ||
break; | ||
@@ -435,3 +254,3 @@ } | ||
get: function () { | ||
get: function get() { | ||
maybeCaptureParent(this); | ||
@@ -449,6 +268,6 @@ if (this._activeChildren.length > 0) { | ||
return this._value; | ||
}, | ||
} | ||
}); | ||
function detach (parent, child) { | ||
function detach(parent, child) { | ||
removeFromArray(parent._activeChildren, child); | ||
@@ -465,55 +284,13 @@ if (parent._activeChildren.length === 0 && parent._parents != null) { | ||
function derive$1 (f, a, b, c, d) { | ||
if (f instanceof Array) { | ||
// Template string tag for derivable strings | ||
var args = slice(arguments, 1); | ||
return derive$1(function () { | ||
var s = ""; | ||
for (var i=0; i < f.length; i++) { | ||
s += f[i]; | ||
if (i < args.length) { | ||
s += unpack$1(args[i]); | ||
} | ||
} | ||
return s; | ||
}); | ||
} else { | ||
switch (arguments.length) { | ||
case 0: | ||
throw new Error('derive takes at least one argument'); | ||
case 1: | ||
return new Derivation(f); | ||
case 2: | ||
return new Derivation(function () { | ||
return f(unpack$1(a)); | ||
}); | ||
case 3: | ||
return new Derivation(function () { | ||
return f(unpack$1(a), unpack$1(b)); | ||
}); | ||
case 4: | ||
return new Derivation(function () { | ||
return f(unpack$1(a), unpack$1(b), unpack$1(c)); | ||
}); | ||
case 5: | ||
return new Derivation(function () { | ||
return f(unpack$1(a), | ||
unpack$1(b), | ||
unpack$1(c), | ||
unpack$1(d)); | ||
}); | ||
default: | ||
var args = slice(arguments, 1); | ||
return new Derivation(function () { | ||
return f.apply(null, args.map(unpack$1)); | ||
}); | ||
} | ||
function derive(f) { | ||
if (typeof f !== "function") { | ||
throw Error("derive requires function"); | ||
} | ||
return new Derivation(f); | ||
} | ||
function Reactor(parent, react, governor) { | ||
function Reactor(parent, react) { | ||
this._parent = parent; | ||
this.react = react; | ||
this._governor = governor || null; | ||
this._governor = null; | ||
this._active = false; | ||
@@ -523,3 +300,3 @@ this._reacting = false; | ||
if (DEBUG_MODE) { | ||
if (isDebug()) { | ||
this.stack = Error().stack; | ||
@@ -530,3 +307,3 @@ } | ||
assign(Reactor.prototype, { | ||
start: function () { | ||
start: function start() { | ||
this._active = true; | ||
@@ -537,6 +314,5 @@ | ||
this._parent.get(); | ||
return this; | ||
}, | ||
_force: function (nextValue) { | ||
_force: function _force(nextValue) { | ||
try { | ||
@@ -546,3 +322,3 @@ this._reacting = true; | ||
} catch (e) { | ||
if (DEBUG_MODE) { | ||
if (isDebug()) { | ||
console.error(this.stack); | ||
@@ -556,9 +332,12 @@ } | ||
force: function () { | ||
force: function force() { | ||
this._force(this._parent.get()); | ||
}, | ||
return this; | ||
stop: function stop() { | ||
detach(this._parent, this); | ||
this._active = false; | ||
}, | ||
_maybeReact: function () { | ||
_maybeReact: function _maybeReact() { | ||
if (!this._reacting && this._active) { | ||
@@ -576,39 +355,20 @@ if (this._governor !== null) { | ||
} | ||
}, | ||
stop: function () { | ||
detach(this._parent, this); | ||
this._active = false; | ||
return this; | ||
}, | ||
} | ||
}); | ||
function makeReactor (derivable, f, opts) { | ||
if (typeof f !== 'function') { | ||
throw Error('the first argument to .react must be a function'); | ||
function makeReactor(derivable, f, opts) { | ||
if (typeof f !== "function") { | ||
throw Error("the first argument to .react must be a function"); | ||
} | ||
opts = assign({ | ||
once: false, | ||
from: true, | ||
until: false, | ||
when: true, | ||
skipFirst: false, | ||
}, opts); | ||
opts = assign( | ||
{ | ||
once: false, | ||
skipFirst: false | ||
}, | ||
opts | ||
); | ||
var skipFirst = opts.skipFirst; | ||
// coerce fn or bool to derivable<bool> | ||
function condDerivable(fOrD, name) { | ||
if (!isDerivable$1(fOrD)) { | ||
if (typeof fOrD === 'function') { | ||
return derive$1(function () { return fOrD(derivable); }); | ||
} else if (typeof fOrD === 'boolean') { | ||
return derive$1(function () { return fOrD; }); | ||
} else { | ||
throw Error('react ' + name + ' condition must be derivable, got: ' + JSON.stringify(fOrD)); | ||
} | ||
} | ||
return fOrD; | ||
} | ||
// wrap reactor so f doesn't get a .this context, and to allow | ||
@@ -622,3 +382,3 @@ // stopping after one reaction if desired. | ||
if (opts.once) { | ||
this.stop(); | ||
reactor.stop(); | ||
controller.stop(); | ||
@@ -629,178 +389,278 @@ } | ||
var assertCondition = function (condition, name) { | ||
if (isDerivable(condition)) { | ||
return condition; | ||
} | ||
if (typeof condition === "function") { | ||
return condition; | ||
} | ||
if (typeof condition === "undefined") { | ||
return condition; | ||
} | ||
throw Error( | ||
"react " + name + " condition must be derivable or function, got: " + | ||
JSON.stringify(condition) | ||
); | ||
}; | ||
var getCondition = function (condition, def) { return condition | ||
? typeof condition === "function" ? condition(derivable) : condition.get() | ||
: def; }; | ||
// listen to from condition, starting the reactor controller | ||
// when appropriate | ||
var $from = assertCondition(opts.from, "from"); | ||
// listen to when and until conditions, starting and stopping the | ||
// reactor as appropriate, and stopping this controller when until | ||
// condition becomes true | ||
var $until = condDerivable(opts.until, 'until'); | ||
var $when = condDerivable(opts.when, 'when'); | ||
var $until = assertCondition(opts.until, "until"); | ||
var $when = assertCondition(opts.when, "when"); | ||
var $whenUntil = derive$1(function () { | ||
var $conds = derive(function () { | ||
return { | ||
until: $until.get(), | ||
when: $when.get(), | ||
from: getCondition($from, true), | ||
until: getCondition($until, false), | ||
when: getCondition($when, true) | ||
}; | ||
}); | ||
var controller = new Reactor($whenUntil, function (conds) { | ||
if (conds.until) { | ||
reactor.stop(); | ||
this.stop(); | ||
} else if (conds.when) { | ||
if (!reactor._active) { | ||
reactor.start().force(); | ||
var started = false; | ||
var controller = new Reactor($conds, function (conds) { | ||
if (conds.from) { | ||
started = true; | ||
} | ||
if (started) { | ||
if (conds.until) { | ||
reactor.stop(); | ||
controller.stop(); | ||
} else if (conds.when) { | ||
if (!reactor._active) { | ||
reactor.start(); | ||
reactor.force(); | ||
} | ||
} else if (reactor._active) { | ||
reactor.stop(); | ||
} | ||
} else if (reactor._active) { | ||
reactor.stop(); | ||
} | ||
}); | ||
controller.start(); | ||
controller.force(); | ||
reactor._governor = controller; | ||
} | ||
// listen to from condition, starting the reactor controller | ||
// when appropriate | ||
var $from = condDerivable(opts.from, 'from'); | ||
var initiator = new Reactor($from, function (from) { | ||
if (from) { | ||
controller.start().force(); | ||
this.stop(); | ||
} | ||
}); | ||
/** | ||
* dereferences a thing if it is dereferencable, otherwise just returns it. | ||
*/ | ||
initiator.start().force(); | ||
function unpack(thing) { | ||
if (isDerivable(thing)) { | ||
return thing.get(); | ||
} else { | ||
return thing; | ||
} | ||
} | ||
var global$1 = typeof window === 'object' ? window : typeof global=== 'object' ? global : {}; | ||
function deepUnpack(thing) { | ||
if (isDerivable(thing)) { | ||
return thing.get(); | ||
} else if (Array.isArray(thing)) { | ||
return thing.map(deepUnpack); | ||
} else if (thing.constructor === Object) { | ||
var result = {}; | ||
var keys = Object.keys(thing); | ||
for (var i = keys.length; i--; ) { | ||
var prop = keys[i]; | ||
result[prop] = deepUnpack(thing[prop]); | ||
} | ||
return result; | ||
} else { | ||
return thing; | ||
} | ||
} | ||
var devtoolsHook = global$1.__DERIVABLE_DEVTOOLS_HOOK__; | ||
function Atom (value) { | ||
this._id = nextId(); | ||
this._activeChildren = []; | ||
this._value = value; | ||
this._state = UNCHANGED; | ||
this._type = ATOM; | ||
this._equals = null; | ||
return this; | ||
function struct(arg) { | ||
if (arg.constructor === Object || Array.isArray(arg)) { | ||
return derive(function () { return deepUnpack(arg); }); | ||
} else { | ||
throw new Error("`struct` expects plain Object or Array"); | ||
} | ||
} | ||
assign(Atom.prototype, { | ||
_clone: function () { | ||
return setEquals(atom$2(this._value), this._equals); | ||
var derivablePrototype = { | ||
derive: function derive$1(f) { | ||
var this$1 = this; | ||
if (typeof f !== "function") { | ||
throw Error("derive requires function"); | ||
} | ||
return derive(function () { return f(this$1.get()); }); | ||
}, | ||
set: function (value) { | ||
maybeTrack(this); | ||
maybeDerive: function maybeDerive(f) { | ||
var this$1 = this; | ||
var oldValue = this._value; | ||
this._value = value; | ||
if (!inTransaction()) { | ||
if (!this.__equals(value, oldValue)) { | ||
try { | ||
this._state = CHANGED; | ||
var reactors = []; | ||
mark(this, reactors); | ||
processReactors(reactors); | ||
} finally { | ||
this._state = UNCHANGED; | ||
} | ||
} | ||
if (typeof f !== "function") { | ||
throw Error("maybeDerive requires function"); | ||
} | ||
return derive(function () { | ||
var arg = this$1.get(); | ||
return some(arg) ? f(arg) : null; | ||
}); | ||
}, | ||
get: function () { | ||
if (typeof devtoolsHook === 'function') { | ||
devtoolsHook('captureAtom', this); | ||
orDefault: function orDefault(def) { | ||
if (!some(def)) { | ||
throw Error("orDefault requires non-null value"); | ||
} | ||
maybeCaptureParent(this); | ||
return this._value; | ||
return this.derive(function (value) { return (some(value) ? value : def); }); | ||
}, | ||
}); | ||
function atom$2 (value) { | ||
return new Atom(value); | ||
} | ||
react: function react(f, opts) { | ||
makeReactor(this, f, opts); | ||
}, | ||
function Proxy (descriptor) { | ||
Derivation.call(this, descriptor.get); | ||
this._proxyMapping = descriptor; | ||
this._type = PROXY; | ||
} | ||
assign(Proxy.prototype, Derivation.prototype, { | ||
_clone: function () { | ||
return setEquals(new Proxy(this._proxyMapping), this._equals); | ||
maybeReact: function maybeReact(f, opts) { | ||
var maybeWhen = this.derive(Boolean); | ||
if (opts && "when" in opts && opts.when !== true) { | ||
var when = opts.when; | ||
if (typeof when === "function" || when === false) { | ||
when = derive(when); | ||
} else if (!isDerivable(when)) { | ||
throw new Error("when condition must be bool, function, or derivable"); | ||
} | ||
maybeWhen = maybeWhen.derive(function (d) { return d && when.get(); }); | ||
} | ||
makeReactor(this, f, assign({}, opts, { when: maybeWhen })); | ||
}, | ||
set: function (value) { | ||
var that = this; | ||
atomically$1(function () { | ||
that._proxyMapping.set(value); | ||
}); | ||
return this; | ||
is: function is(other) { | ||
var this$1 = this; | ||
return derive(function () { return equals(this$1, this$1.get(), unpack(other)); }); | ||
}, | ||
}); | ||
function proxy$2 (descriptor) { | ||
return new Proxy(descriptor); | ||
} | ||
withEquality: function withEquality(equals$$1) { | ||
if (equals$$1) { | ||
if (typeof equals$$1 !== "function") { | ||
throw new Error("equals must be function"); | ||
} | ||
} else { | ||
equals$$1 = null; | ||
} | ||
function andOrFn (breakOn) { | ||
return function () { | ||
var args = arguments; | ||
return derive$1(function () { | ||
var val; | ||
for (var i = 0; i < args.length; i++) { | ||
val = unpack$1(args[i]); | ||
if (breakOn(val)) { | ||
break; | ||
return setEquals(this._clone(), equals$$1); | ||
} | ||
}; | ||
var mutablePrototype = { | ||
update: function update(f, a, b, c, d) { | ||
switch (arguments.length) { | ||
case 0: | ||
throw Error("update method accepts at least 1 argument"); | ||
case 1: | ||
return this.set(f(this.get())); | ||
case 2: | ||
return this.set(f(this.get(), a)); | ||
case 3: | ||
return this.set(f(this.get(), a, b)); | ||
case 4: | ||
return this.set(f(this.get(), a, b, c)); | ||
case 5: | ||
return this.set(f(this.get(), a, b, c, d)); | ||
default: | ||
throw Error("update method accepts only 5 arguments"); | ||
} | ||
} | ||
}; | ||
function mark(node, reactors) { | ||
for (var i = 0, len = node._activeChildren.length; i < len; i++) { | ||
var child = node._activeChildren[i]; | ||
switch (child._type) { | ||
case DERIVATION: | ||
case PROXY: | ||
if (child._state !== UNKNOWN) { | ||
child._state = UNKNOWN; | ||
mark(child, reactors); | ||
} | ||
} | ||
return val; | ||
}); | ||
}; | ||
break; | ||
case REACTOR: | ||
reactors.push(child); | ||
break; | ||
} | ||
} | ||
} | ||
function identity (x) { return x; } | ||
function processReactors(reactors) { | ||
for (var i = 0, len = reactors.length; i < len; i++) { | ||
var r = reactors[i]; | ||
if (r._reacting) { | ||
throw Error( | ||
"Synchronous cyclical reactions disallowed. " + "Use setImmediate." | ||
); | ||
} | ||
r._maybeReact(); | ||
} | ||
} | ||
function complement (f) { return function (x) { return !f(x); }; } | ||
var TransactionAbortion = {}; | ||
var or$1 = andOrFn(identity); | ||
function initiateAbortion() { | ||
throw TransactionAbortion; | ||
} | ||
var mOr$1 = andOrFn(some); | ||
function TransactionContext(parent) { | ||
this.parent = parent; | ||
this.id2originalValue = {}; | ||
this.modifiedAtoms = []; | ||
} | ||
var and$1 = andOrFn(complement(identity)); | ||
function maybeTrack(atom) { | ||
if (currentCtx !== null) { | ||
if (!(atom._id in currentCtx.id2originalValue)) { | ||
currentCtx.modifiedAtoms.push(atom); | ||
currentCtx.id2originalValue[atom._id] = atom._value; | ||
} | ||
} | ||
} | ||
var mAnd$1 = andOrFn(complement(some)); | ||
var currentCtx = null; | ||
var __Reactor$1 = Reactor; | ||
var transact$2 = transact$1; | ||
var setDebugMode$2 = setDebugMode$1; | ||
var transaction$2 = transaction$1; | ||
var ticker$2 = ticker$1; | ||
var isDerivable$2 = isDerivable$1; | ||
var isAtom$2 = isAtom$1; | ||
var isProxy$2 = isProxy$1; | ||
var isDerivation$2 = isDerivation$1; | ||
var derive$2 = derive$1; | ||
var atom$1 = atom$2; | ||
var atomic$2 = atomic$1; | ||
var atomically$2 = atomically$1; | ||
var proxy$1 = proxy$2; | ||
var unpack$2 = unpack$1; | ||
function inTransaction() { | ||
return currentCtx !== null; | ||
} | ||
function struct$1 (arg) { | ||
if (arg.constructor === Object || arg instanceof Array) { | ||
return derive$2(function () { | ||
return deepUnpack(arg); | ||
}); | ||
function transact(f) { | ||
beginTransaction(); | ||
try { | ||
f(initiateAbortion); | ||
} catch (e) { | ||
abortTransaction(); | ||
if (e !== TransactionAbortion) { | ||
throw e; | ||
} | ||
return; | ||
} | ||
commitTransaction(); | ||
} | ||
function atomically(f) { | ||
if (!inTransaction()) { | ||
transact(f); | ||
} else { | ||
throw new Error("`struct` expects plain Object or Array"); | ||
f(); | ||
} | ||
} | ||
function wrapPreviousState$1 (f, init) { | ||
var lastState = init; | ||
return function (newState) { | ||
var result = f.call(this, newState, lastState); | ||
lastState = newState; | ||
function transaction(f) { | ||
return function () { | ||
var args = [], len = arguments.length; | ||
while ( len-- ) args[ len ] = arguments[ len ]; | ||
var result; | ||
transact(function () { | ||
result = f.apply(void 0, args); | ||
}); | ||
return result; | ||
@@ -810,224 +670,157 @@ }; | ||
function captureDereferences$1 (f) { | ||
var captured = []; | ||
startCapturingParents(void 0, captured); | ||
try { | ||
f(); | ||
} finally { | ||
stopCapturingParents(); | ||
} | ||
return captured; | ||
function atomic(f) { | ||
return function () { | ||
var args = [], len = arguments.length; | ||
while ( len-- ) args[ len ] = arguments[ len ]; | ||
var result; | ||
atomically(function () { | ||
result = f.apply(void 0, args); | ||
}); | ||
return result; | ||
}; | ||
} | ||
function beginTransaction() { | ||
currentCtx = new TransactionContext(currentCtx); | ||
} | ||
var derivable$1 = Object.freeze({ | ||
__Reactor: __Reactor$1, | ||
transact: transact$2, | ||
setDebugMode: setDebugMode$2, | ||
transaction: transaction$2, | ||
ticker: ticker$2, | ||
isDerivable: isDerivable$2, | ||
isAtom: isAtom$2, | ||
isProxy: isProxy$2, | ||
isDerivation: isDerivation$2, | ||
derive: derive$2, | ||
atom: atom$1, | ||
atomic: atomic$2, | ||
atomically: atomically$2, | ||
proxy: proxy$1, | ||
unpack: unpack$2, | ||
struct: struct$1, | ||
wrapPreviousState: wrapPreviousState$1, | ||
captureDereferences: captureDereferences$1, | ||
or: or$1, | ||
mOr: mOr$1, | ||
and: and$1, | ||
mAnd: mAnd$1 | ||
}); | ||
function commitTransaction() { | ||
var ctx = currentCtx; | ||
currentCtx = ctx.parent; | ||
var derivablePrototype = { | ||
/** | ||
* Creates a derived value whose state will always be f applied to this | ||
* value | ||
*/ | ||
derive: function (f, a, b, c, d) { | ||
var that = this; | ||
switch (arguments.length) { | ||
case 0: | ||
throw new Error('.derive takes at least one argument'); | ||
case 1: | ||
switch (typeof f) { | ||
case 'function': | ||
return derive$2(f, that); | ||
case 'string': | ||
case 'number': | ||
return derive$2(function () { | ||
return that.get()[f]; | ||
}); | ||
default: | ||
if (f instanceof Array) { | ||
return f.map(function (x) { | ||
return that.derive(x); | ||
}); | ||
} else if (f instanceof RegExp) { | ||
return derive$2(function () { | ||
return that.get().match(f); | ||
}); | ||
} else if (isDerivable$1(f)) { | ||
return derive$2(function () { | ||
var deriver = f.get(); | ||
var thing = that.get(); | ||
switch (typeof deriver) { | ||
case 'function': | ||
return deriver(thing); | ||
case 'string': | ||
case 'number': | ||
return thing[deriver]; | ||
default: | ||
if (deriver instanceof RegExp) { | ||
return thing.match(deriver); | ||
} else { | ||
throw Error('type error'); | ||
} | ||
} | ||
}); | ||
} else { | ||
throw Error('type error'); | ||
} | ||
} | ||
case 2: | ||
return derive$2(f, that, a); | ||
case 3: | ||
return derive$2(f, that, a, b); | ||
case 4: | ||
return derive$2(f, that, a, b, c); | ||
case 5: | ||
return derive$2(f, that, a, b, c, d); | ||
default: | ||
var args = ([f, that]).concat(slice(arguments, 1)); | ||
return derive$2.apply(null, args); | ||
} | ||
}, | ||
if (currentCtx === null) { | ||
var reactors = []; | ||
ctx.modifiedAtoms.forEach(function (a) { | ||
if (equals(a, a._value, ctx.id2originalValue[a._id])) { | ||
a._state = UNCHANGED; | ||
} else { | ||
a._state = CHANGED; | ||
mark(a, reactors); | ||
} | ||
}); | ||
processReactors(reactors); | ||
ctx.modifiedAtoms.forEach(function (a) { | ||
a._state = UNCHANGED; | ||
}); | ||
} | ||
} | ||
react: function (f, opts) { | ||
makeReactor(this, f, opts); | ||
}, | ||
function abortTransaction() { | ||
var ctx = currentCtx; | ||
currentCtx = ctx.parent; | ||
ctx.modifiedAtoms.forEach(function (atom) { | ||
atom._value = ctx.id2originalValue[atom._id]; | ||
atom._state = UNCHANGED; | ||
mark(atom, []); | ||
}); | ||
} | ||
mReact: function (f, opts) { | ||
var mWhen = this.mThen(true, false); | ||
if (opts && 'when' in opts && opts.when !== true) { | ||
var when = opts.when; | ||
if (typeof when === 'function' || when === false) { | ||
when = derive$2(when); | ||
} else if (!isDerivable$1(when)) { | ||
throw new Error('when condition must be bool, function, or derivable'); | ||
var _tickerRefCount = 0; | ||
function ticker() { | ||
if (_tickerRefCount === 0) { | ||
beginTransaction(); | ||
} | ||
_tickerRefCount++; | ||
var done = false; | ||
return { | ||
tick: function tick() { | ||
if (done) { throw new Error("trying to use ticker after release"); } | ||
commitTransaction(); | ||
beginTransaction(); | ||
}, | ||
reset: function reset() { | ||
if (done) { throw new Error("trying to use ticker after release"); } | ||
abortTransaction(); | ||
beginTransaction(); | ||
}, | ||
release: function release() { | ||
if (done) { throw new Error("ticker already released"); } | ||
_tickerRefCount--; | ||
done = true; | ||
if (_tickerRefCount === 0) { | ||
commitTransaction(); | ||
} | ||
mWhen = when.and(mWhen); | ||
} | ||
return this.react(f, assign({}, opts, {when: mWhen})); | ||
}, | ||
}; | ||
} | ||
is: function (other) { | ||
var x = this; | ||
return derive$2(function () { | ||
return x.__equals(x.get(), unpack$1(other)); | ||
}); | ||
}, | ||
var global$1 = (typeof window === "object" | ||
? window | ||
: typeof global === "object" ? global : {}); | ||
then: function (thenClause, elseClause) { | ||
var x = this; | ||
return derive$2(function () { | ||
return unpack$1(x.get() ? thenClause : elseClause); | ||
}); | ||
}, | ||
var devtoolsHook = global$1.__DERIVABLE_DEVTOOLS_HOOK__; | ||
mThen: function (thenClause, elseClause) { | ||
var x = this; | ||
return derive$2(function () { | ||
return unpack$1(some(x.get()) ? thenClause : elseClause); | ||
}); | ||
}, | ||
function Atom(value) { | ||
this._id = nextId(); | ||
this._activeChildren = []; | ||
this._value = value; | ||
this._state = UNCHANGED; | ||
this._type = ATOM; | ||
this._equals = null; | ||
} | ||
or: function (other) { | ||
return or$1(this, other); | ||
assign(Atom.prototype, { | ||
_clone: function _clone() { | ||
return setEquals(atom(this._value), this._equals); | ||
}, | ||
mOr: function (other) { | ||
return mOr$1(this, other); | ||
}, | ||
set: function set(value) { | ||
maybeTrack(this); | ||
and: function (other) { | ||
return and$1(this, other); | ||
}, | ||
var oldValue = this._value; | ||
this._value = value; | ||
mAnd: function (other) { | ||
return mAnd$1(this, other); | ||
if (!inTransaction()) { | ||
if (!equals(this, value, oldValue)) { | ||
try { | ||
this._state = CHANGED; | ||
var reactors = []; | ||
mark(this, reactors); | ||
processReactors(reactors); | ||
} finally { | ||
this._state = UNCHANGED; | ||
} | ||
} | ||
} | ||
}, | ||
mDerive: function (arg) { | ||
if (arguments.length === 1 && arg instanceof Array) { | ||
var that = this; | ||
return arg.map(function (a) { return that.mDerive(a); }); | ||
} else { | ||
return this.mThen(this.derive.apply(this, arguments)); | ||
get: function get() { | ||
if (typeof devtoolsHook === "function") { | ||
devtoolsHook("captureAtom", this); | ||
} | ||
}, | ||
maybeCaptureParent(this); | ||
return this._value; | ||
} | ||
}); | ||
not: function () { | ||
var x = this; | ||
return derive$2(function () { return !x.get(); }); | ||
}, | ||
function atom(value) { | ||
return new Atom(value); | ||
} | ||
withEquality: function (equals$$1) { | ||
if (equals$$1) { | ||
if (typeof equals$$1 !== 'function') { | ||
throw new Error('equals must be function'); | ||
} | ||
} else { | ||
equals$$1 = null; | ||
} | ||
function Proxy(descriptor) { | ||
Derivation.call(this, descriptor.get); | ||
this._proxyMapping = descriptor; | ||
this._type = PROXY; | ||
} | ||
return setEquals(this._clone(), equals$$1); | ||
assign(Proxy.prototype, Derivation.prototype, { | ||
_clone: function _clone() { | ||
return setEquals(new Proxy(this._proxyMapping), this._equals); | ||
}, | ||
__equals: function (a, b) { | ||
return (this._equals || equals)(a, b); | ||
}, | ||
}; | ||
set: function set(value) { | ||
var this$1 = this; | ||
derivablePrototype.switch = function () { | ||
var args = arguments; | ||
var that = this; | ||
return this.derive(function (x) { | ||
var i; | ||
for (i = 0; i < args.length-1; i+=2) { | ||
if (that.__equals(x, unpack$1(args[i]))) { | ||
return unpack$1(args[i+1]); | ||
} | ||
} | ||
if (i === args.length - 1) { | ||
return unpack$1(args[i]); | ||
} | ||
}); | ||
}; | ||
var mutablePrototype = { | ||
update: function (f) { | ||
var args = slice(arguments, 0); | ||
args[0] = this.get(); | ||
return this.set(f.apply(null, args)); | ||
}, | ||
proxy: function (monoProxyMapping) { | ||
var that = this; | ||
return new Proxy({ | ||
get: function () { | ||
return monoProxyMapping.get(that.get()); | ||
}, | ||
set: function (val) { | ||
that.set(monoProxyMapping.set(that.get(), val)); | ||
} | ||
atomically(function () { | ||
this$1._proxyMapping.set(value); | ||
}); | ||
}, | ||
}; | ||
} | ||
}); | ||
function proxy(descriptor) { | ||
return new Proxy(descriptor); | ||
} | ||
assign(Derivation.prototype, derivablePrototype); | ||
@@ -1038,34 +831,12 @@ assign(Proxy.prototype, derivablePrototype, mutablePrototype); | ||
if (global$1.__DERIVABLE_INIT_FLAG__) { | ||
console.warn('Multiple instances of derivable have been initialized on the same page'); | ||
console.warn( | ||
"Multiple instances of derivable have been initialized on the same page" | ||
); | ||
} | ||
global$1.__DERIVABLE_INIT_FLAG__ = true; | ||
var __Reactor = __Reactor$1; | ||
var transact = transact$2; | ||
var setDebugMode = setDebugMode$2; | ||
var transaction = transaction$2; | ||
var ticker = ticker$2; | ||
var isDerivable = isDerivable$2; | ||
var isAtom = isAtom$2; | ||
var isProxy = isProxy$2; | ||
var isDerivation = isDerivation$2; | ||
var derive = derive$2; | ||
var atom = atom$1; | ||
var atomic = atomic$2; | ||
var atomically = atomically$2; | ||
var proxy = proxy$1; | ||
var unpack = unpack$2; | ||
var struct = struct$1; | ||
var wrapPreviousState = wrapPreviousState$1; | ||
var captureDereferences = captureDereferences$1; | ||
var or = or$1; | ||
var mOr = mOr$1; | ||
var and = and$1; | ||
var mAnd = mAnd$1; | ||
exports.__Reactor = __Reactor; | ||
exports.transact = transact; | ||
exports.atom = atom; | ||
exports.proxy = proxy; | ||
exports.derive = derive; | ||
exports.setDebugMode = setDebugMode; | ||
exports.transaction = transaction; | ||
exports.ticker = ticker; | ||
exports.isDerivable = isDerivable; | ||
@@ -1075,16 +846,11 @@ exports.isAtom = isAtom; | ||
exports.isDerivation = isDerivation; | ||
exports.derive = derive; | ||
exports.atom = atom; | ||
exports.unpack = unpack; | ||
exports.struct = struct; | ||
exports.transact = transact; | ||
exports.transaction = transaction; | ||
exports.ticker = ticker; | ||
exports.atomic = atomic; | ||
exports.atomically = atomically; | ||
exports.proxy = proxy; | ||
exports.unpack = unpack; | ||
exports.struct = struct; | ||
exports.wrapPreviousState = wrapPreviousState; | ||
exports.captureDereferences = captureDereferences; | ||
exports.or = or; | ||
exports.mOr = mOr; | ||
exports.and = and; | ||
exports.mAnd = mAnd; | ||
exports['default'] = derivable$1; | ||
exports.__Reactor = Reactor; | ||
exports.__captureDereferences = captureDereferences; | ||
//# sourceMappingURL=derivable.js.map |
@@ -7,13 +7,7 @@ (function (global, factory) { | ||
var keys = Object.keys; | ||
var assign = Object.assign; | ||
function equals (a, b) { | ||
return Object.is(a, b) || (a && typeof a.equals === 'function' && a.equals(b)); | ||
} | ||
function addToArray (a, b) { | ||
function addToArray(a, b) { | ||
var i = a.indexOf(b); | ||
if (i < 0) { | ||
if (i === -1) { | ||
a.push(b); | ||
@@ -23,5 +17,5 @@ } | ||
function removeFromArray (a, b) { | ||
function removeFromArray(a, b) { | ||
var i = a.indexOf(b); | ||
if (i >= 0) { | ||
if (i !== -1) { | ||
a.splice(i, 1); | ||
@@ -32,26 +26,37 @@ } | ||
var _nextId = 0; | ||
function nextId () { | ||
function nextId() { | ||
return _nextId++; | ||
} | ||
function slice (a, i) { | ||
return Array.prototype.slice.call(a, i); | ||
} | ||
var unique = Object.freeze({ equals: function () { return false; } }); | ||
var unique = Object.freeze({equals: function () { return false; }}); | ||
function some (x) { | ||
return (x !== null) && (x !== void 0); | ||
function some(x) { | ||
return x !== null && x !== void 0; | ||
} | ||
var DEBUG_MODE = false; | ||
function setDebugMode$1 (val) { | ||
function setDebugMode(val) { | ||
DEBUG_MODE = !!val; | ||
} | ||
function setEquals (derivable, equals) { | ||
derivable._equals = equals; | ||
function isDebug() { | ||
return DEBUG_MODE; | ||
} | ||
function defaultEquals(a, b) { | ||
return ( | ||
Object.is(a, b) || (a && typeof a.equals === "function" && a.equals(b)) | ||
); | ||
} | ||
function setEquals(derivable, eq) { | ||
derivable._equals = eq; | ||
return derivable; | ||
} | ||
function equals(ctx, a, b) { | ||
return (ctx._equals || defaultEquals)(a, b); | ||
} | ||
var ATOM = "ATOM"; | ||
@@ -62,18 +67,15 @@ var DERIVATION = "DERIVATION"; | ||
function isDerivable$1(x) { | ||
return x && | ||
(x._type === DERIVATION || | ||
x._type === ATOM || | ||
x._type === PROXY); | ||
function isDerivable(x) { | ||
return x && (x._type === DERIVATION || x._type === ATOM || x._type === PROXY); | ||
} | ||
function isAtom$1 (x) { | ||
function isAtom(x) { | ||
return x && (x._type === ATOM || x._type === PROXY); | ||
} | ||
function isDerivation$1 (x) { | ||
function isDerivation(x) { | ||
return x && (x._type === DERIVATION || x._type === PROXY); | ||
} | ||
function isProxy$1 (x) { | ||
function isProxy(x) { | ||
return x && x._type === PROXY; | ||
@@ -90,17 +92,18 @@ } | ||
function startCapturingParents (_child, parents) { | ||
parentsStack.push({parents: parents, offset: 0, child: _child}); | ||
function startCapturingParents(_child, parents) { | ||
parentsStack.push({ parents: parents, offset: 0, child: _child }); | ||
child = _child; | ||
} | ||
function retrieveParentsFrame () { | ||
function retrieveParentsFrame() { | ||
return parentsStack[parentsStack.length - 1]; | ||
} | ||
function stopCapturingParents () { | ||
function stopCapturingParents() { | ||
parentsStack.pop(); | ||
child = parentsStack.length === 0 | ||
? null | ||
: parentsStack[parentsStack.length - 1].child; | ||
child = | ||
parentsStack.length === 0 | ||
? null | ||
: parentsStack[parentsStack.length - 1].child; | ||
} | ||
function maybeCaptureParent (p) { | ||
function maybeCaptureParent(p) { | ||
if (child !== null) { | ||
@@ -144,201 +147,14 @@ var frame = parentsStack[parentsStack.length - 1]; | ||
function mark (node, reactors) { | ||
for (var i = 0, len = node._activeChildren.length; i < len; i++) { | ||
var child = node._activeChildren[i]; | ||
switch (child._type) { | ||
case DERIVATION: | ||
case PROXY: | ||
if (child._state !== UNKNOWN) { | ||
child._state = UNKNOWN; | ||
mark(child, reactors); | ||
} | ||
break; | ||
case REACTOR: | ||
reactors.push(child); | ||
break; | ||
} | ||
} | ||
} | ||
function processReactors (reactors) { | ||
for (var i = 0, len = reactors.length; i < len; i++) { | ||
var r = reactors[i]; | ||
if (r._reacting) { | ||
throw new Error("Synchronous cyclical reactions disallowed. " + | ||
"Use setImmediate."); | ||
} | ||
r._maybeReact(); | ||
} | ||
} | ||
var TransactionAbortion = {}; | ||
function initiateAbortion() { | ||
throw TransactionAbortion; | ||
} | ||
function TransactionContext(parent) { | ||
this.parent = parent; | ||
this.id2originalValue = {}; | ||
this.modifiedAtoms = []; | ||
} | ||
function maybeTrack (atom) { | ||
if (currentCtx !== null) { | ||
if (!(atom._id in currentCtx.id2originalValue)) { | ||
currentCtx.modifiedAtoms.push(atom); | ||
currentCtx.id2originalValue[atom._id] = atom._value; | ||
} | ||
} | ||
} | ||
var currentCtx = null; | ||
function inTransaction () { | ||
return currentCtx !== null; | ||
} | ||
function transact$1 (f) { | ||
beginTransaction(); | ||
function captureDereferences(f) { | ||
var captured = []; | ||
startCapturingParents(void 0, captured); | ||
try { | ||
f.call(null, initiateAbortion); | ||
} | ||
catch (e) { | ||
abortTransaction(); | ||
if (e !== TransactionAbortion) { | ||
throw e; | ||
} | ||
return; | ||
} | ||
commitTransaction(); | ||
} | ||
function atomically$1 (f) { | ||
if (!inTransaction()) { | ||
transact$1(f); | ||
} else { | ||
f(); | ||
} finally { | ||
stopCapturingParents(); | ||
} | ||
return captured; | ||
} | ||
function transaction$1 (f) { | ||
return function () { | ||
var args = slice(arguments, 0); | ||
var that = this; | ||
var result; | ||
transact$1(function () { | ||
result = f.apply(that, args); | ||
}); | ||
return result; | ||
}; | ||
} | ||
function atomic$1 (f) { | ||
return function () { | ||
var args = slice(arguments, 0); | ||
var that = this; | ||
var result; | ||
atomically$1(function () { | ||
result = f.apply(that, args); | ||
}); | ||
return result; | ||
}; | ||
} | ||
function beginTransaction() { | ||
currentCtx = new TransactionContext(currentCtx); | ||
} | ||
function commitTransaction() { | ||
var ctx = currentCtx; | ||
currentCtx = ctx.parent; | ||
if (currentCtx === null) { | ||
var reactors = []; | ||
ctx.modifiedAtoms.forEach(function (a) { | ||
if (a.__equals(a._value, ctx.id2originalValue[a._id])) { | ||
a._state = UNCHANGED; | ||
} else { | ||
a._state = CHANGED; | ||
mark(a, reactors); | ||
} | ||
}); | ||
processReactors(reactors); | ||
ctx.modifiedAtoms.forEach(function (a) { | ||
a._state = UNCHANGED; | ||
}); | ||
} | ||
} | ||
function abortTransaction() { | ||
var ctx = currentCtx; | ||
currentCtx = ctx.parent; | ||
ctx.modifiedAtoms.forEach(function (atom) { | ||
atom._value = ctx.id2originalValue[atom._id]; | ||
atom._state = UNCHANGED; | ||
mark(atom, []); | ||
}); | ||
} | ||
var _tickerRefCount = 0; | ||
function ticker$1 () { | ||
if (_tickerRefCount === 0) { | ||
beginTransaction(); | ||
} | ||
_tickerRefCount++; | ||
var done = false; | ||
return { | ||
tick: function () { | ||
if (done) throw new Error('trying to use ticker after release'); | ||
commitTransaction(); | ||
beginTransaction(); | ||
}, | ||
reset: function () { | ||
if (done) throw new Error('trying to use ticker after release'); | ||
abortTransaction(); | ||
beginTransaction(); | ||
}, | ||
release: function () { | ||
if (done) throw new Error('ticker already released'); | ||
_tickerRefCount--; | ||
done = true; | ||
if (_tickerRefCount === 0) { | ||
commitTransaction(); | ||
} | ||
}, | ||
}; | ||
} | ||
/** | ||
* dereferences a thing if it is dereferencable, otherwise just returns it. | ||
*/ | ||
function unpack$1 (thing) { | ||
if (isDerivable$1(thing)) { | ||
return thing.get(); | ||
} else { | ||
return thing; | ||
} | ||
} | ||
function deepUnpack (thing) { | ||
if (isDerivable$1(thing)) { | ||
return thing.get(); | ||
} else if (thing instanceof Array) { | ||
return thing.map(deepUnpack); | ||
} else if (thing.constructor === Object) { | ||
var result = {}; | ||
var keys$$1 = keys(thing); | ||
for (var i = keys$$1.length; i--;) { | ||
var prop = keys$$1[i]; | ||
result[prop] = deepUnpack(thing[prop]); | ||
} | ||
return result; | ||
} else { | ||
return thing; | ||
} | ||
} | ||
function Derivation (deriver) { | ||
function Derivation(deriver) { | ||
this._deriver = deriver; | ||
@@ -352,3 +168,3 @@ this._parents = null; | ||
if (DEBUG_MODE) { | ||
if (isDebug()) { | ||
this.stack = Error().stack; | ||
@@ -359,8 +175,9 @@ } | ||
assign(Derivation.prototype, { | ||
_clone: function () { | ||
return setEquals(derive$1(this._deriver), this._equals); | ||
_clone: function _clone() { | ||
return setEquals(derive(this._deriver), this._equals); | ||
}, | ||
_forceEval: function () { | ||
var that = this; | ||
_forceEval: function _forceEval() { | ||
var this$1 = this; | ||
var newVal = null; | ||
@@ -374,9 +191,9 @@ var newNumParents; | ||
startCapturingParents(this, this._parents); | ||
if (!DEBUG_MODE) { | ||
newVal = that._deriver(); | ||
if (!isDebug()) { | ||
newVal = this._deriver(); | ||
} else { | ||
try { | ||
newVal = that._deriver(); | ||
newVal = this._deriver(); | ||
} catch (e) { | ||
console.error(that.stack); | ||
console.error(this.stack); | ||
throw e; | ||
@@ -390,3 +207,3 @@ } | ||
if (!this.__equals(newVal, this._value)) { | ||
if (!equals(this, newVal, this._value)) { | ||
this._state = CHANGED; | ||
@@ -398,5 +215,5 @@ } else { | ||
for (var i = newNumParents, len = this._parents.length; i < len; i++) { | ||
var oldParent = this._parents[i]; | ||
detach(oldParent, this); | ||
this._parents[i] = null; | ||
var oldParent = this$1._parents[i]; | ||
detach(oldParent, this$1); | ||
this$1._parents[i] = null; | ||
} | ||
@@ -409,3 +226,5 @@ | ||
_update: function () { | ||
_update: function _update() { | ||
var this$1 = this; | ||
if (this._parents === null) { | ||
@@ -418,3 +237,3 @@ // this._state === DISCONNECTED | ||
for (var i = 0; i < len; i++) { | ||
var parent = this._parents[i]; | ||
var parent = this$1._parents[i]; | ||
@@ -426,3 +245,3 @@ if (parent._state === UNKNOWN) { | ||
if (parent._state === CHANGED) { | ||
this._forceEval(); | ||
this$1._forceEval(); | ||
break; | ||
@@ -437,3 +256,3 @@ } | ||
get: function () { | ||
get: function get() { | ||
maybeCaptureParent(this); | ||
@@ -451,6 +270,6 @@ if (this._activeChildren.length > 0) { | ||
return this._value; | ||
}, | ||
} | ||
}); | ||
function detach (parent, child) { | ||
function detach(parent, child) { | ||
removeFromArray(parent._activeChildren, child); | ||
@@ -467,55 +286,13 @@ if (parent._activeChildren.length === 0 && parent._parents != null) { | ||
function derive$1 (f, a, b, c, d) { | ||
if (f instanceof Array) { | ||
// Template string tag for derivable strings | ||
var args = slice(arguments, 1); | ||
return derive$1(function () { | ||
var s = ""; | ||
for (var i=0; i < f.length; i++) { | ||
s += f[i]; | ||
if (i < args.length) { | ||
s += unpack$1(args[i]); | ||
} | ||
} | ||
return s; | ||
}); | ||
} else { | ||
switch (arguments.length) { | ||
case 0: | ||
throw new Error('derive takes at least one argument'); | ||
case 1: | ||
return new Derivation(f); | ||
case 2: | ||
return new Derivation(function () { | ||
return f(unpack$1(a)); | ||
}); | ||
case 3: | ||
return new Derivation(function () { | ||
return f(unpack$1(a), unpack$1(b)); | ||
}); | ||
case 4: | ||
return new Derivation(function () { | ||
return f(unpack$1(a), unpack$1(b), unpack$1(c)); | ||
}); | ||
case 5: | ||
return new Derivation(function () { | ||
return f(unpack$1(a), | ||
unpack$1(b), | ||
unpack$1(c), | ||
unpack$1(d)); | ||
}); | ||
default: | ||
var args = slice(arguments, 1); | ||
return new Derivation(function () { | ||
return f.apply(null, args.map(unpack$1)); | ||
}); | ||
} | ||
function derive(f) { | ||
if (typeof f !== "function") { | ||
throw Error("derive requires function"); | ||
} | ||
return new Derivation(f); | ||
} | ||
function Reactor(parent, react, governor) { | ||
function Reactor(parent, react) { | ||
this._parent = parent; | ||
this.react = react; | ||
this._governor = governor || null; | ||
this._governor = null; | ||
this._active = false; | ||
@@ -525,3 +302,3 @@ this._reacting = false; | ||
if (DEBUG_MODE) { | ||
if (isDebug()) { | ||
this.stack = Error().stack; | ||
@@ -532,3 +309,3 @@ } | ||
assign(Reactor.prototype, { | ||
start: function () { | ||
start: function start() { | ||
this._active = true; | ||
@@ -539,6 +316,5 @@ | ||
this._parent.get(); | ||
return this; | ||
}, | ||
_force: function (nextValue) { | ||
_force: function _force(nextValue) { | ||
try { | ||
@@ -548,3 +324,3 @@ this._reacting = true; | ||
} catch (e) { | ||
if (DEBUG_MODE) { | ||
if (isDebug()) { | ||
console.error(this.stack); | ||
@@ -558,9 +334,12 @@ } | ||
force: function () { | ||
force: function force() { | ||
this._force(this._parent.get()); | ||
}, | ||
return this; | ||
stop: function stop() { | ||
detach(this._parent, this); | ||
this._active = false; | ||
}, | ||
_maybeReact: function () { | ||
_maybeReact: function _maybeReact() { | ||
if (!this._reacting && this._active) { | ||
@@ -578,39 +357,20 @@ if (this._governor !== null) { | ||
} | ||
}, | ||
stop: function () { | ||
detach(this._parent, this); | ||
this._active = false; | ||
return this; | ||
}, | ||
} | ||
}); | ||
function makeReactor (derivable, f, opts) { | ||
if (typeof f !== 'function') { | ||
throw Error('the first argument to .react must be a function'); | ||
function makeReactor(derivable, f, opts) { | ||
if (typeof f !== "function") { | ||
throw Error("the first argument to .react must be a function"); | ||
} | ||
opts = assign({ | ||
once: false, | ||
from: true, | ||
until: false, | ||
when: true, | ||
skipFirst: false, | ||
}, opts); | ||
opts = assign( | ||
{ | ||
once: false, | ||
skipFirst: false | ||
}, | ||
opts | ||
); | ||
var skipFirst = opts.skipFirst; | ||
// coerce fn or bool to derivable<bool> | ||
function condDerivable(fOrD, name) { | ||
if (!isDerivable$1(fOrD)) { | ||
if (typeof fOrD === 'function') { | ||
return derive$1(function () { return fOrD(derivable); }); | ||
} else if (typeof fOrD === 'boolean') { | ||
return derive$1(function () { return fOrD; }); | ||
} else { | ||
throw Error('react ' + name + ' condition must be derivable, got: ' + JSON.stringify(fOrD)); | ||
} | ||
} | ||
return fOrD; | ||
} | ||
// wrap reactor so f doesn't get a .this context, and to allow | ||
@@ -624,3 +384,3 @@ // stopping after one reaction if desired. | ||
if (opts.once) { | ||
this.stop(); | ||
reactor.stop(); | ||
controller.stop(); | ||
@@ -631,178 +391,278 @@ } | ||
var assertCondition = function (condition, name) { | ||
if (isDerivable(condition)) { | ||
return condition; | ||
} | ||
if (typeof condition === "function") { | ||
return condition; | ||
} | ||
if (typeof condition === "undefined") { | ||
return condition; | ||
} | ||
throw Error( | ||
"react " + name + " condition must be derivable or function, got: " + | ||
JSON.stringify(condition) | ||
); | ||
}; | ||
var getCondition = function (condition, def) { return condition | ||
? typeof condition === "function" ? condition(derivable) : condition.get() | ||
: def; }; | ||
// listen to from condition, starting the reactor controller | ||
// when appropriate | ||
var $from = assertCondition(opts.from, "from"); | ||
// listen to when and until conditions, starting and stopping the | ||
// reactor as appropriate, and stopping this controller when until | ||
// condition becomes true | ||
var $until = condDerivable(opts.until, 'until'); | ||
var $when = condDerivable(opts.when, 'when'); | ||
var $until = assertCondition(opts.until, "until"); | ||
var $when = assertCondition(opts.when, "when"); | ||
var $whenUntil = derive$1(function () { | ||
var $conds = derive(function () { | ||
return { | ||
until: $until.get(), | ||
when: $when.get(), | ||
from: getCondition($from, true), | ||
until: getCondition($until, false), | ||
when: getCondition($when, true) | ||
}; | ||
}); | ||
var controller = new Reactor($whenUntil, function (conds) { | ||
if (conds.until) { | ||
reactor.stop(); | ||
this.stop(); | ||
} else if (conds.when) { | ||
if (!reactor._active) { | ||
reactor.start().force(); | ||
var started = false; | ||
var controller = new Reactor($conds, function (conds) { | ||
if (conds.from) { | ||
started = true; | ||
} | ||
if (started) { | ||
if (conds.until) { | ||
reactor.stop(); | ||
controller.stop(); | ||
} else if (conds.when) { | ||
if (!reactor._active) { | ||
reactor.start(); | ||
reactor.force(); | ||
} | ||
} else if (reactor._active) { | ||
reactor.stop(); | ||
} | ||
} else if (reactor._active) { | ||
reactor.stop(); | ||
} | ||
}); | ||
controller.start(); | ||
controller.force(); | ||
reactor._governor = controller; | ||
} | ||
// listen to from condition, starting the reactor controller | ||
// when appropriate | ||
var $from = condDerivable(opts.from, 'from'); | ||
var initiator = new Reactor($from, function (from) { | ||
if (from) { | ||
controller.start().force(); | ||
this.stop(); | ||
} | ||
}); | ||
/** | ||
* dereferences a thing if it is dereferencable, otherwise just returns it. | ||
*/ | ||
initiator.start().force(); | ||
function unpack(thing) { | ||
if (isDerivable(thing)) { | ||
return thing.get(); | ||
} else { | ||
return thing; | ||
} | ||
} | ||
var global$1 = typeof window === 'object' ? window : typeof global=== 'object' ? global : {}; | ||
function deepUnpack(thing) { | ||
if (isDerivable(thing)) { | ||
return thing.get(); | ||
} else if (Array.isArray(thing)) { | ||
return thing.map(deepUnpack); | ||
} else if (thing.constructor === Object) { | ||
var result = {}; | ||
var keys = Object.keys(thing); | ||
for (var i = keys.length; i--; ) { | ||
var prop = keys[i]; | ||
result[prop] = deepUnpack(thing[prop]); | ||
} | ||
return result; | ||
} else { | ||
return thing; | ||
} | ||
} | ||
var devtoolsHook = global$1.__DERIVABLE_DEVTOOLS_HOOK__; | ||
function Atom (value) { | ||
this._id = nextId(); | ||
this._activeChildren = []; | ||
this._value = value; | ||
this._state = UNCHANGED; | ||
this._type = ATOM; | ||
this._equals = null; | ||
return this; | ||
function struct(arg) { | ||
if (arg.constructor === Object || Array.isArray(arg)) { | ||
return derive(function () { return deepUnpack(arg); }); | ||
} else { | ||
throw new Error("`struct` expects plain Object or Array"); | ||
} | ||
} | ||
assign(Atom.prototype, { | ||
_clone: function () { | ||
return setEquals(atom$2(this._value), this._equals); | ||
var derivablePrototype = { | ||
derive: function derive$1(f) { | ||
var this$1 = this; | ||
if (typeof f !== "function") { | ||
throw Error("derive requires function"); | ||
} | ||
return derive(function () { return f(this$1.get()); }); | ||
}, | ||
set: function (value) { | ||
maybeTrack(this); | ||
maybeDerive: function maybeDerive(f) { | ||
var this$1 = this; | ||
var oldValue = this._value; | ||
this._value = value; | ||
if (!inTransaction()) { | ||
if (!this.__equals(value, oldValue)) { | ||
try { | ||
this._state = CHANGED; | ||
var reactors = []; | ||
mark(this, reactors); | ||
processReactors(reactors); | ||
} finally { | ||
this._state = UNCHANGED; | ||
} | ||
} | ||
if (typeof f !== "function") { | ||
throw Error("maybeDerive requires function"); | ||
} | ||
return derive(function () { | ||
var arg = this$1.get(); | ||
return some(arg) ? f(arg) : null; | ||
}); | ||
}, | ||
get: function () { | ||
if (typeof devtoolsHook === 'function') { | ||
devtoolsHook('captureAtom', this); | ||
orDefault: function orDefault(def) { | ||
if (!some(def)) { | ||
throw Error("orDefault requires non-null value"); | ||
} | ||
maybeCaptureParent(this); | ||
return this._value; | ||
return this.derive(function (value) { return (some(value) ? value : def); }); | ||
}, | ||
}); | ||
function atom$2 (value) { | ||
return new Atom(value); | ||
} | ||
react: function react(f, opts) { | ||
makeReactor(this, f, opts); | ||
}, | ||
function Proxy (descriptor) { | ||
Derivation.call(this, descriptor.get); | ||
this._proxyMapping = descriptor; | ||
this._type = PROXY; | ||
} | ||
assign(Proxy.prototype, Derivation.prototype, { | ||
_clone: function () { | ||
return setEquals(new Proxy(this._proxyMapping), this._equals); | ||
maybeReact: function maybeReact(f, opts) { | ||
var maybeWhen = this.derive(Boolean); | ||
if (opts && "when" in opts && opts.when !== true) { | ||
var when = opts.when; | ||
if (typeof when === "function" || when === false) { | ||
when = derive(when); | ||
} else if (!isDerivable(when)) { | ||
throw new Error("when condition must be bool, function, or derivable"); | ||
} | ||
maybeWhen = maybeWhen.derive(function (d) { return d && when.get(); }); | ||
} | ||
makeReactor(this, f, assign({}, opts, { when: maybeWhen })); | ||
}, | ||
set: function (value) { | ||
var that = this; | ||
atomically$1(function () { | ||
that._proxyMapping.set(value); | ||
}); | ||
return this; | ||
is: function is(other) { | ||
var this$1 = this; | ||
return derive(function () { return equals(this$1, this$1.get(), unpack(other)); }); | ||
}, | ||
}); | ||
function proxy$2 (descriptor) { | ||
return new Proxy(descriptor); | ||
} | ||
withEquality: function withEquality(equals$$1) { | ||
if (equals$$1) { | ||
if (typeof equals$$1 !== "function") { | ||
throw new Error("equals must be function"); | ||
} | ||
} else { | ||
equals$$1 = null; | ||
} | ||
function andOrFn (breakOn) { | ||
return function () { | ||
var args = arguments; | ||
return derive$1(function () { | ||
var val; | ||
for (var i = 0; i < args.length; i++) { | ||
val = unpack$1(args[i]); | ||
if (breakOn(val)) { | ||
break; | ||
return setEquals(this._clone(), equals$$1); | ||
} | ||
}; | ||
var mutablePrototype = { | ||
update: function update(f, a, b, c, d) { | ||
switch (arguments.length) { | ||
case 0: | ||
throw Error("update method accepts at least 1 argument"); | ||
case 1: | ||
return this.set(f(this.get())); | ||
case 2: | ||
return this.set(f(this.get(), a)); | ||
case 3: | ||
return this.set(f(this.get(), a, b)); | ||
case 4: | ||
return this.set(f(this.get(), a, b, c)); | ||
case 5: | ||
return this.set(f(this.get(), a, b, c, d)); | ||
default: | ||
throw Error("update method accepts only 5 arguments"); | ||
} | ||
} | ||
}; | ||
function mark(node, reactors) { | ||
for (var i = 0, len = node._activeChildren.length; i < len; i++) { | ||
var child = node._activeChildren[i]; | ||
switch (child._type) { | ||
case DERIVATION: | ||
case PROXY: | ||
if (child._state !== UNKNOWN) { | ||
child._state = UNKNOWN; | ||
mark(child, reactors); | ||
} | ||
} | ||
return val; | ||
}); | ||
}; | ||
break; | ||
case REACTOR: | ||
reactors.push(child); | ||
break; | ||
} | ||
} | ||
} | ||
function identity (x) { return x; } | ||
function processReactors(reactors) { | ||
for (var i = 0, len = reactors.length; i < len; i++) { | ||
var r = reactors[i]; | ||
if (r._reacting) { | ||
throw Error( | ||
"Synchronous cyclical reactions disallowed. " + "Use setImmediate." | ||
); | ||
} | ||
r._maybeReact(); | ||
} | ||
} | ||
function complement (f) { return function (x) { return !f(x); }; } | ||
var TransactionAbortion = {}; | ||
var or$1 = andOrFn(identity); | ||
function initiateAbortion() { | ||
throw TransactionAbortion; | ||
} | ||
var mOr$1 = andOrFn(some); | ||
function TransactionContext(parent) { | ||
this.parent = parent; | ||
this.id2originalValue = {}; | ||
this.modifiedAtoms = []; | ||
} | ||
var and$1 = andOrFn(complement(identity)); | ||
function maybeTrack(atom) { | ||
if (currentCtx !== null) { | ||
if (!(atom._id in currentCtx.id2originalValue)) { | ||
currentCtx.modifiedAtoms.push(atom); | ||
currentCtx.id2originalValue[atom._id] = atom._value; | ||
} | ||
} | ||
} | ||
var mAnd$1 = andOrFn(complement(some)); | ||
var currentCtx = null; | ||
var __Reactor$1 = Reactor; | ||
var transact$2 = transact$1; | ||
var setDebugMode$2 = setDebugMode$1; | ||
var transaction$2 = transaction$1; | ||
var ticker$2 = ticker$1; | ||
var isDerivable$2 = isDerivable$1; | ||
var isAtom$2 = isAtom$1; | ||
var isProxy$2 = isProxy$1; | ||
var isDerivation$2 = isDerivation$1; | ||
var derive$2 = derive$1; | ||
var atom$1 = atom$2; | ||
var atomic$2 = atomic$1; | ||
var atomically$2 = atomically$1; | ||
var proxy$1 = proxy$2; | ||
var unpack$2 = unpack$1; | ||
function inTransaction() { | ||
return currentCtx !== null; | ||
} | ||
function struct$1 (arg) { | ||
if (arg.constructor === Object || arg instanceof Array) { | ||
return derive$2(function () { | ||
return deepUnpack(arg); | ||
}); | ||
function transact(f) { | ||
beginTransaction(); | ||
try { | ||
f(initiateAbortion); | ||
} catch (e) { | ||
abortTransaction(); | ||
if (e !== TransactionAbortion) { | ||
throw e; | ||
} | ||
return; | ||
} | ||
commitTransaction(); | ||
} | ||
function atomically(f) { | ||
if (!inTransaction()) { | ||
transact(f); | ||
} else { | ||
throw new Error("`struct` expects plain Object or Array"); | ||
f(); | ||
} | ||
} | ||
function wrapPreviousState$1 (f, init) { | ||
var lastState = init; | ||
return function (newState) { | ||
var result = f.call(this, newState, lastState); | ||
lastState = newState; | ||
function transaction(f) { | ||
return function () { | ||
var args = [], len = arguments.length; | ||
while ( len-- ) args[ len ] = arguments[ len ]; | ||
var result; | ||
transact(function () { | ||
result = f.apply(void 0, args); | ||
}); | ||
return result; | ||
@@ -812,224 +672,157 @@ }; | ||
function captureDereferences$1 (f) { | ||
var captured = []; | ||
startCapturingParents(void 0, captured); | ||
try { | ||
f(); | ||
} finally { | ||
stopCapturingParents(); | ||
} | ||
return captured; | ||
function atomic(f) { | ||
return function () { | ||
var args = [], len = arguments.length; | ||
while ( len-- ) args[ len ] = arguments[ len ]; | ||
var result; | ||
atomically(function () { | ||
result = f.apply(void 0, args); | ||
}); | ||
return result; | ||
}; | ||
} | ||
function beginTransaction() { | ||
currentCtx = new TransactionContext(currentCtx); | ||
} | ||
var derivable$1 = Object.freeze({ | ||
__Reactor: __Reactor$1, | ||
transact: transact$2, | ||
setDebugMode: setDebugMode$2, | ||
transaction: transaction$2, | ||
ticker: ticker$2, | ||
isDerivable: isDerivable$2, | ||
isAtom: isAtom$2, | ||
isProxy: isProxy$2, | ||
isDerivation: isDerivation$2, | ||
derive: derive$2, | ||
atom: atom$1, | ||
atomic: atomic$2, | ||
atomically: atomically$2, | ||
proxy: proxy$1, | ||
unpack: unpack$2, | ||
struct: struct$1, | ||
wrapPreviousState: wrapPreviousState$1, | ||
captureDereferences: captureDereferences$1, | ||
or: or$1, | ||
mOr: mOr$1, | ||
and: and$1, | ||
mAnd: mAnd$1 | ||
}); | ||
function commitTransaction() { | ||
var ctx = currentCtx; | ||
currentCtx = ctx.parent; | ||
var derivablePrototype = { | ||
/** | ||
* Creates a derived value whose state will always be f applied to this | ||
* value | ||
*/ | ||
derive: function (f, a, b, c, d) { | ||
var that = this; | ||
switch (arguments.length) { | ||
case 0: | ||
throw new Error('.derive takes at least one argument'); | ||
case 1: | ||
switch (typeof f) { | ||
case 'function': | ||
return derive$2(f, that); | ||
case 'string': | ||
case 'number': | ||
return derive$2(function () { | ||
return that.get()[f]; | ||
}); | ||
default: | ||
if (f instanceof Array) { | ||
return f.map(function (x) { | ||
return that.derive(x); | ||
}); | ||
} else if (f instanceof RegExp) { | ||
return derive$2(function () { | ||
return that.get().match(f); | ||
}); | ||
} else if (isDerivable$1(f)) { | ||
return derive$2(function () { | ||
var deriver = f.get(); | ||
var thing = that.get(); | ||
switch (typeof deriver) { | ||
case 'function': | ||
return deriver(thing); | ||
case 'string': | ||
case 'number': | ||
return thing[deriver]; | ||
default: | ||
if (deriver instanceof RegExp) { | ||
return thing.match(deriver); | ||
} else { | ||
throw Error('type error'); | ||
} | ||
} | ||
}); | ||
} else { | ||
throw Error('type error'); | ||
} | ||
} | ||
case 2: | ||
return derive$2(f, that, a); | ||
case 3: | ||
return derive$2(f, that, a, b); | ||
case 4: | ||
return derive$2(f, that, a, b, c); | ||
case 5: | ||
return derive$2(f, that, a, b, c, d); | ||
default: | ||
var args = ([f, that]).concat(slice(arguments, 1)); | ||
return derive$2.apply(null, args); | ||
} | ||
}, | ||
if (currentCtx === null) { | ||
var reactors = []; | ||
ctx.modifiedAtoms.forEach(function (a) { | ||
if (equals(a, a._value, ctx.id2originalValue[a._id])) { | ||
a._state = UNCHANGED; | ||
} else { | ||
a._state = CHANGED; | ||
mark(a, reactors); | ||
} | ||
}); | ||
processReactors(reactors); | ||
ctx.modifiedAtoms.forEach(function (a) { | ||
a._state = UNCHANGED; | ||
}); | ||
} | ||
} | ||
react: function (f, opts) { | ||
makeReactor(this, f, opts); | ||
}, | ||
function abortTransaction() { | ||
var ctx = currentCtx; | ||
currentCtx = ctx.parent; | ||
ctx.modifiedAtoms.forEach(function (atom) { | ||
atom._value = ctx.id2originalValue[atom._id]; | ||
atom._state = UNCHANGED; | ||
mark(atom, []); | ||
}); | ||
} | ||
mReact: function (f, opts) { | ||
var mWhen = this.mThen(true, false); | ||
if (opts && 'when' in opts && opts.when !== true) { | ||
var when = opts.when; | ||
if (typeof when === 'function' || when === false) { | ||
when = derive$2(when); | ||
} else if (!isDerivable$1(when)) { | ||
throw new Error('when condition must be bool, function, or derivable'); | ||
var _tickerRefCount = 0; | ||
function ticker() { | ||
if (_tickerRefCount === 0) { | ||
beginTransaction(); | ||
} | ||
_tickerRefCount++; | ||
var done = false; | ||
return { | ||
tick: function tick() { | ||
if (done) { throw new Error("trying to use ticker after release"); } | ||
commitTransaction(); | ||
beginTransaction(); | ||
}, | ||
reset: function reset() { | ||
if (done) { throw new Error("trying to use ticker after release"); } | ||
abortTransaction(); | ||
beginTransaction(); | ||
}, | ||
release: function release() { | ||
if (done) { throw new Error("ticker already released"); } | ||
_tickerRefCount--; | ||
done = true; | ||
if (_tickerRefCount === 0) { | ||
commitTransaction(); | ||
} | ||
mWhen = when.and(mWhen); | ||
} | ||
return this.react(f, assign({}, opts, {when: mWhen})); | ||
}, | ||
}; | ||
} | ||
is: function (other) { | ||
var x = this; | ||
return derive$2(function () { | ||
return x.__equals(x.get(), unpack$1(other)); | ||
}); | ||
}, | ||
var global$1 = (typeof window === "object" | ||
? window | ||
: typeof global === "object" ? global : {}); | ||
then: function (thenClause, elseClause) { | ||
var x = this; | ||
return derive$2(function () { | ||
return unpack$1(x.get() ? thenClause : elseClause); | ||
}); | ||
}, | ||
var devtoolsHook = global$1.__DERIVABLE_DEVTOOLS_HOOK__; | ||
mThen: function (thenClause, elseClause) { | ||
var x = this; | ||
return derive$2(function () { | ||
return unpack$1(some(x.get()) ? thenClause : elseClause); | ||
}); | ||
}, | ||
function Atom(value) { | ||
this._id = nextId(); | ||
this._activeChildren = []; | ||
this._value = value; | ||
this._state = UNCHANGED; | ||
this._type = ATOM; | ||
this._equals = null; | ||
} | ||
or: function (other) { | ||
return or$1(this, other); | ||
assign(Atom.prototype, { | ||
_clone: function _clone() { | ||
return setEquals(atom(this._value), this._equals); | ||
}, | ||
mOr: function (other) { | ||
return mOr$1(this, other); | ||
}, | ||
set: function set(value) { | ||
maybeTrack(this); | ||
and: function (other) { | ||
return and$1(this, other); | ||
}, | ||
var oldValue = this._value; | ||
this._value = value; | ||
mAnd: function (other) { | ||
return mAnd$1(this, other); | ||
if (!inTransaction()) { | ||
if (!equals(this, value, oldValue)) { | ||
try { | ||
this._state = CHANGED; | ||
var reactors = []; | ||
mark(this, reactors); | ||
processReactors(reactors); | ||
} finally { | ||
this._state = UNCHANGED; | ||
} | ||
} | ||
} | ||
}, | ||
mDerive: function (arg) { | ||
if (arguments.length === 1 && arg instanceof Array) { | ||
var that = this; | ||
return arg.map(function (a) { return that.mDerive(a); }); | ||
} else { | ||
return this.mThen(this.derive.apply(this, arguments)); | ||
get: function get() { | ||
if (typeof devtoolsHook === "function") { | ||
devtoolsHook("captureAtom", this); | ||
} | ||
}, | ||
maybeCaptureParent(this); | ||
return this._value; | ||
} | ||
}); | ||
not: function () { | ||
var x = this; | ||
return derive$2(function () { return !x.get(); }); | ||
}, | ||
function atom(value) { | ||
return new Atom(value); | ||
} | ||
withEquality: function (equals$$1) { | ||
if (equals$$1) { | ||
if (typeof equals$$1 !== 'function') { | ||
throw new Error('equals must be function'); | ||
} | ||
} else { | ||
equals$$1 = null; | ||
} | ||
function Proxy(descriptor) { | ||
Derivation.call(this, descriptor.get); | ||
this._proxyMapping = descriptor; | ||
this._type = PROXY; | ||
} | ||
return setEquals(this._clone(), equals$$1); | ||
assign(Proxy.prototype, Derivation.prototype, { | ||
_clone: function _clone() { | ||
return setEquals(new Proxy(this._proxyMapping), this._equals); | ||
}, | ||
__equals: function (a, b) { | ||
return (this._equals || equals)(a, b); | ||
}, | ||
}; | ||
set: function set(value) { | ||
var this$1 = this; | ||
derivablePrototype.switch = function () { | ||
var args = arguments; | ||
var that = this; | ||
return this.derive(function (x) { | ||
var i; | ||
for (i = 0; i < args.length-1; i+=2) { | ||
if (that.__equals(x, unpack$1(args[i]))) { | ||
return unpack$1(args[i+1]); | ||
} | ||
} | ||
if (i === args.length - 1) { | ||
return unpack$1(args[i]); | ||
} | ||
}); | ||
}; | ||
var mutablePrototype = { | ||
update: function (f) { | ||
var args = slice(arguments, 0); | ||
args[0] = this.get(); | ||
return this.set(f.apply(null, args)); | ||
}, | ||
proxy: function (monoProxyMapping) { | ||
var that = this; | ||
return new Proxy({ | ||
get: function () { | ||
return monoProxyMapping.get(that.get()); | ||
}, | ||
set: function (val) { | ||
that.set(monoProxyMapping.set(that.get(), val)); | ||
} | ||
atomically(function () { | ||
this$1._proxyMapping.set(value); | ||
}); | ||
}, | ||
}; | ||
} | ||
}); | ||
function proxy(descriptor) { | ||
return new Proxy(descriptor); | ||
} | ||
assign(Derivation.prototype, derivablePrototype); | ||
@@ -1040,34 +833,12 @@ assign(Proxy.prototype, derivablePrototype, mutablePrototype); | ||
if (global$1.__DERIVABLE_INIT_FLAG__) { | ||
console.warn('Multiple instances of derivable have been initialized on the same page'); | ||
console.warn( | ||
"Multiple instances of derivable have been initialized on the same page" | ||
); | ||
} | ||
global$1.__DERIVABLE_INIT_FLAG__ = true; | ||
var __Reactor = __Reactor$1; | ||
var transact = transact$2; | ||
var setDebugMode = setDebugMode$2; | ||
var transaction = transaction$2; | ||
var ticker = ticker$2; | ||
var isDerivable = isDerivable$2; | ||
var isAtom = isAtom$2; | ||
var isProxy = isProxy$2; | ||
var isDerivation = isDerivation$2; | ||
var derive = derive$2; | ||
var atom = atom$1; | ||
var atomic = atomic$2; | ||
var atomically = atomically$2; | ||
var proxy = proxy$1; | ||
var unpack = unpack$2; | ||
var struct = struct$1; | ||
var wrapPreviousState = wrapPreviousState$1; | ||
var captureDereferences = captureDereferences$1; | ||
var or = or$1; | ||
var mOr = mOr$1; | ||
var and = and$1; | ||
var mAnd = mAnd$1; | ||
exports.__Reactor = __Reactor; | ||
exports.transact = transact; | ||
exports.atom = atom; | ||
exports.proxy = proxy; | ||
exports.derive = derive; | ||
exports.setDebugMode = setDebugMode; | ||
exports.transaction = transaction; | ||
exports.ticker = ticker; | ||
exports.isDerivable = isDerivable; | ||
@@ -1077,16 +848,11 @@ exports.isAtom = isAtom; | ||
exports.isDerivation = isDerivation; | ||
exports.derive = derive; | ||
exports.atom = atom; | ||
exports.unpack = unpack; | ||
exports.struct = struct; | ||
exports.transact = transact; | ||
exports.transaction = transaction; | ||
exports.ticker = ticker; | ||
exports.atomic = atomic; | ||
exports.atomically = atomically; | ||
exports.proxy = proxy; | ||
exports.unpack = unpack; | ||
exports.struct = struct; | ||
exports.wrapPreviousState = wrapPreviousState; | ||
exports.captureDereferences = captureDereferences; | ||
exports.or = or; | ||
exports.mOr = mOr; | ||
exports.and = and; | ||
exports.mAnd = mAnd; | ||
exports['default'] = derivable$1; | ||
exports.__Reactor = Reactor; | ||
exports.__captureDereferences = captureDereferences; | ||
@@ -1093,0 +859,0 @@ Object.defineProperty(exports, '__esModule', { value: true }); |
@@ -1,7 +0,6 @@ | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e(t.Derivable={})}(this,function(t){"use strict";function e(t,e){t.indexOf(e)<0&&t.push(e)}function n(t,e){return Array.prototype.slice.call(t,e)}function r(t){return null!==t&&void 0!==t}function i(t,e){return t._equals=e,t}function o(t){return t&&(t._type===S||t._type===P||t._type===F)}function s(t,e){J.push({parents:e,offset:0,child:t}),K=t}function u(){J.pop(),K=0===J.length?null:J[J.length-1].child}function a(t){if(null!==K){var n=J[J.length-1];if(n.parents[n.offset]===t)n.offset++;else{var r=n.parents.indexOf(t);if(-1===r)void 0!==K&&e(t._activeChildren,K),n.offset===n.parents.length?n.parents.push(t):(n.parents.push(n.parents[n.offset]),n.parents[n.offset]=t),n.offset++;else if(r>n.offset){var i=n.parents[r];n.parents[r]=n.parents[n.offset],n.parents[n.offset]=i,n.offset++}}}}function c(t,e){for(var n=0,r=t._activeChildren.length;n<r;n++){var i=t._activeChildren[n];switch(i._type){case S:case F:i._state!==z&&(i._state=z,c(i,e));break;case N:e.push(i)}}}function f(t){for(var e=0,n=t.length;e<n;e++){var r=t[e];if(r._reacting)throw new Error("Synchronous cyclical reactions disallowed. Use setImmediate.");r._maybeReact()}}function h(){return null!==X}function l(t){p();try{t.call(null,function(){throw U})}catch(t){if(d(),t!==U)throw t;return}v()}function _(t){h()?t():l(t)}function p(){X=new function(t){this.parent=t,this.id2originalValue={},this.modifiedAtoms=[]}(X)}function v(){var t=X;if(null===(X=t.parent)){var e=[];t.modifiedAtoms.forEach(function(n){n.__equals(n._value,t.id2originalValue[n._id])?n._state=G:(n._state=B,c(n,e))}),f(e),t.modifiedAtoms.forEach(function(t){t._state=G})}}function d(){var t=X;X=t.parent,t.modifiedAtoms.forEach(function(e){e._value=t.id2originalValue[e._id],e._state=G,c(e,[])})}function y(t){return o(t)?t.get():t}function g(t){if(o(t))return t.get();if(t instanceof Array)return t.map(g);if(t.constructor===Object){ | ||
for(var e={},n=I(t),r=n.length;r--;){var i=n[r];e[i]=g(t[i])}return e}return t}function w(t){this._deriver=t,this._parents=null,this._type=S,this._value=M,this._equals=null,this._activeChildren=[],this._state=H,L&&(this.stack=Error().stack)}function m(t,e){if(function(t,e){var n=t.indexOf(e);n>=0&&t.splice(n,1)}(t._activeChildren,e),0===t._activeChildren.length&&null!=t._parents){for(var n=t._parents.length,r=0;r<n;r++)m(t._parents[r],t);t._parents=null,t._state=H}}function b(t,e,r,i,o){if(t instanceof Array){s=n(arguments,1);return b(function(){for(var e="",n=0;n<t.length;n++)e+=t[n],n<s.length&&(e+=y(s[n]));return e})}switch(arguments.length){case 0:throw new Error("derive takes at least one argument");case 1:return new w(t);case 2:return new w(function(){return t(y(e))});case 3:return new w(function(){return t(y(e),y(r))});case 4:return new w(function(){return t(y(e),y(r),y(i))});case 5:return new w(function(){return t(y(e),y(r),y(i),y(o))});default:var s=n(arguments,1);return new w(function(){return t.apply(null,s.map(y))})}}function E(t,e,n){this._parent=t,this.react=e,this._governor=n||null,this._active=!1,this._reacting=!1,this._type=N,L&&(this.stack=Error().stack)}function A(t){return this._id=T++,this._activeChildren=[],this._value=t,this._state=G,this._type=P,this._equals=null,this}function O(t){return new A(t)}function k(t){w.call(this,t.get),this._proxyMapping=t,this._type=F}function q(t){return function(){var e=arguments;return b(function(){for(var n,r=0;r<e.length&&(n=y(e[r]),!t(n));r++);return n})}}function x(t){return t}function D(t){return function(e){return!t(e)}}function R(t){if(t.constructor===Object||t instanceof Array)return ht(function(){return g(t)});throw new Error("`struct` expects plain Object or Array")}function j(t,e){var n=e;return function(e){var r=t.call(this,e,n);return n=e,r}}function C(t){var e=[];s(void 0,e);try{t()}finally{u()}return e}var I=Object.keys,V=Object.assign,T=0,M=Object.freeze({equals:function(){return!1} | ||
}),L=!1,P="ATOM",S="DERIVATION",F="PROXY",N="REACTOR",z=0,B=1,G=2,H=3,J=[],K=null,U={},X=null,Y=0;V(w.prototype,{_clone:function(){return i(b(this._deriver),this._equals)},_forceEval:function(){var t,e=this,n=null;try{if(null===this._parents&&(this._parents=[]),s(this,this._parents),L)try{n=e._deriver()}catch(t){throw console.error(e.stack),t}else n=e._deriver();t=J[J.length-1].offset}finally{u()}this._state=this.__equals(n,this._value)?G:B;for(var r=t,i=this._parents.length;r<i;r++){m(this._parents[r],this),this._parents[r]=null}this._parents.length=t,this._value=n},_update:function(){if(null===this._parents)this._forceEval();else if(this._state===z){for(var t=this._parents.length,e=0;e<t;e++){var n=this._parents[e];if(n._state===z&&n._update(),n._state===B){this._forceEval();break}}this._state===z&&(this._state=G)}},get:function(){if(a(this),this._activeChildren.length>0)this._update();else{s(void 0,[]);try{this._value=this._deriver()}finally{u()}}return this._value}}),V(E.prototype,{start:function(){return this._active=!0,e(this._parent._activeChildren,this),this._parent.get(),this},_force:function(t){try{this._reacting=!0,this.react(t)}catch(t){throw L&&console.error(this.stack),t}finally{this._reacting=!1}},force:function(){return this._force(this._parent.get()),this},_maybeReact:function(){if(!this._reacting&&this._active&&(null!==this._governor&&this._governor._maybeReact(),this._active)){var t=this._parent.get();this._parent._state===B&&this._force(t)}},stop:function(){return m(this._parent,this),this._active=!1,this}});var Q="object"==typeof window?window:"object"==typeof global?global:{},W=Q.__DERIVABLE_DEVTOOLS_HOOK__;V(A.prototype,{_clone:function(){return i(O(this._value),this._equals)},set:function(t){!function(t){null!==X&&(t._id in X.id2originalValue||(X.modifiedAtoms.push(t),X.id2originalValue[t._id]=t._value))}(this);var e=this._value;if(this._value=t,!h()&&!this.__equals(t,e))try{this._state=B;var n=[];c(this,n),f(n)}finally{this._state=G}},get:function(){ | ||
return"function"==typeof W&&W("captureAtom",this),a(this),this._value}}),V(k.prototype,w.prototype,{_clone:function(){return i(new k(this._proxyMapping),this._equals)},set:function(t){var e=this;return _(function(){e._proxyMapping.set(t)}),this}});var Z=q(x),$=q(r),tt=q(D(x)),et=q(D(r)),nt=E,rt=l,it=function(t){L=!!t},ot=function(t){return function(){var e,r=n(arguments,0),i=this;return l(function(){e=t.apply(i,r)}),e}},st=function(){0===Y&&p(),Y++;var t=!1;return{tick:function(){if(t)throw new Error("trying to use ticker after release");v(),p()},reset:function(){if(t)throw new Error("trying to use ticker after release");d(),p()},release:function(){if(t)throw new Error("ticker already released");t=!0,0==--Y&&v()}}},ut=o,at=function(t){return t&&(t._type===P||t._type===F)},ct=function(t){return t&&t._type===F},ft=function(t){return t&&(t._type===S||t._type===F)},ht=b,lt=O,_t=function(t){return function(){var e,r=n(arguments,0),i=this;return _(function(){e=t.apply(i,r)}),e}},pt=_,vt=function(t){return new k(t)},dt=y,yt=Object.freeze({__Reactor:nt,transact:rt,setDebugMode:it,transaction:ot,ticker:st,isDerivable:ut,isAtom:at,isProxy:ct,isDerivation:ft,derive:ht,atom:lt,atomic:_t,atomically:pt,proxy:vt,unpack:dt,struct:R,wrapPreviousState:j,captureDereferences:C,or:Z,mOr:$,and:tt,mAnd:et}),gt={derive:function(t,e,r,i,s){var u=this;switch(arguments.length){case 0:throw new Error(".derive takes at least one argument");case 1:switch(typeof t){case"function":return ht(t,u);case"string":case"number":return ht(function(){return u.get()[t]});default:if(t instanceof Array)return t.map(function(t){return u.derive(t)});if(t instanceof RegExp)return ht(function(){return u.get().match(t)});if(o(t))return ht(function(){var e=t.get(),n=u.get();switch(typeof e){case"function":return e(n);case"string":case"number":return n[e];default:if(e instanceof RegExp)return n.match(e);throw Error("type error")}});throw Error("type error")}case 2:return ht(t,u,e);case 3:return ht(t,u,e,r);case 4:return ht(t,u,e,r,i);case 5:return ht(t,u,e,r,i,s) | ||
;default:var a=[t,u].concat(n(arguments,1));return ht.apply(null,a)}},react:function(t,e){!function(t,e,n){function r(e,n){if(!o(e)){if("function"==typeof e)return b(function(){return e(t)});if("boolean"==typeof e)return b(function(){return e});throw Error("react "+n+" condition must be derivable, got: "+JSON.stringify(e))}return e}if("function"!=typeof e)throw Error("the first argument to .react must be a function");var i=(n=V({once:!1,from:!0,until:!1,when:!0,skipFirst:!1},n)).skipFirst,s=new E(t,function(t){i?i=!1:(e(t),n.once&&(this.stop(),c.stop()))}),u=r(n.until,"until"),a=r(n.when,"when"),c=new E(b(function(){return{until:u.get(),when:a.get()}}),function(t){t.until?(s.stop(),this.stop()):t.when?s._active||s.start().force():s._active&&s.stop()});s._governor=c,new E(r(n.from,"from"),function(t){t&&(c.start().force(),this.stop())}).start().force()}(this,t,e)},mReact:function(t,e){var n=this.mThen(!0,!1);if(e&&"when"in e&&!0!==e.when){var r=e.when;if("function"==typeof r||!1===r)r=ht(r);else if(!o(r))throw new Error("when condition must be bool, function, or derivable");n=r.and(n)}return this.react(t,V({},e,{when:n}))},is:function(t){var e=this;return ht(function(){return e.__equals(e.get(),y(t))})},then:function(t,e){var n=this;return ht(function(){return y(n.get()?t:e)})},mThen:function(t,e){var n=this;return ht(function(){return y(r(n.get())?t:e)})},or:function(t){return Z(this,t)},mOr:function(t){return $(this,t)},and:function(t){return tt(this,t)},mAnd:function(t){return et(this,t)},mDerive:function(t){if(1===arguments.length&&t instanceof Array){var e=this;return t.map(function(t){return e.mDerive(t)})}return this.mThen(this.derive.apply(this,arguments))},not:function(){var t=this;return ht(function(){return!t.get()})},withEquality:function(t){if(t){if("function"!=typeof t)throw new Error("equals must be function")}else t=null;return i(this._clone(),t)},__equals:function(t,e){return(this._equals||function(t,e){return Object.is(t,e)||t&&"function"==typeof t.equals&&t.equals(e)})(t,e)}} | ||
;gt.switch=function(){var t=arguments,e=this;return this.derive(function(n){var r;for(r=0;r<t.length-1;r+=2)if(e.__equals(n,y(t[r])))return y(t[r+1]);if(r===t.length-1)return y(t[r])})};var wt={update:function(t){var e=n(arguments,0);return e[0]=this.get(),this.set(t.apply(null,e))},proxy:function(t){var e=this;return new k({get:function(){return t.get(e.get())},set:function(n){e.set(t.set(e.get(),n))}})}};V(w.prototype,gt),V(k.prototype,gt,wt),V(A.prototype,gt,wt),Q.__DERIVABLE_INIT_FLAG__&&console.warn("Multiple instances of derivable have been initialized on the same page"),Q.__DERIVABLE_INIT_FLAG__=!0;var mt=rt,bt=it,Et=ot,At=st,Ot=ut,kt=at,qt=ct,xt=ft,Dt=ht,Rt=lt,jt=_t,Ct=pt,It=vt,Vt=dt,Tt=R,Mt=j,Lt=C,Pt=Z,St=$,Ft=tt,Nt=et;t.__Reactor=nt,t.transact=mt,t.setDebugMode=bt,t.transaction=Et,t.ticker=At,t.isDerivable=Ot,t.isAtom=kt,t.isProxy=qt,t.isDerivation=xt,t.derive=Dt,t.atom=Rt,t.atomic=jt,t.atomically=Ct,t.proxy=It,t.unpack=Vt,t.struct=Tt,t.wrapPreviousState=Mt,t.captureDereferences=Lt,t.or=Pt,t.mOr=St,t.and=Ft,t.mAnd=Nt,t.default=yt,Object.defineProperty(t,"__esModule",{value:!0})}); | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e(t.Derivable={})}(this,function(t){"use strict";function e(t,e){-1===t.indexOf(e)&&t.push(e)}function n(t){return null!==t&&void 0!==t}function r(){return C}function i(t,e){return t._equals=e,t}function o(t,e,n){return(t._equals||function(t,e){return Object.is(t,e)||t&&"function"==typeof t.equals&&t.equals(e)})(e,n)}function s(t){return t&&(t._type===V||t._type===I||t._type===M)}function a(t,e){P.push({parents:e,offset:0,child:t}),S=t}function u(){P.pop(),S=0===P.length?null:P[P.length-1].child}function f(t){if(null!==S){var n=P[P.length-1];if(n.parents[n.offset]===t)n.offset++;else{var r=n.parents.indexOf(t);if(-1===r)void 0!==S&&e(t._activeChildren,S),n.offset===n.parents.length?n.parents.push(t):(n.parents.push(n.parents[n.offset]),n.parents[n.offset]=t),n.offset++;else if(r>n.offset){var i=n.parents[r];n.parents[r]=n.parents[n.offset],n.parents[n.offset]=i,n.offset++}}}}function c(t){this._deriver=t,this._parents=null,this._type=V,this._value=j,this._equals=null,this._activeChildren=[],this._state=N,r()&&(this.stack=Error().stack)}function h(t,e){if(function(t,e){var n=t.indexOf(e);-1!==n&&t.splice(n,1)}(t._activeChildren,e),0===t._activeChildren.length&&null!=t._parents){for(var n=t._parents.length,r=0;r<n;r++)h(t._parents[r],t);t._parents=null,t._state=N}}function l(t){if("function"!=typeof t)throw Error("derive requires function");return new c(t)}function _(t,e){this._parent=t,this.react=e,this._governor=null,this._active=!1,this._reacting=!1,this._type=L,r()&&(this.stack=Error().stack)}function p(t,e,n){if("function"!=typeof e)throw Error("the first argument to .react must be a function");var r=(n=x({once:!1,skipFirst:!1},n)).skipFirst,i=new _(t,function(t){r?r=!1:(e(t),n.once&&(i.stop(),p.stop()))}),o=function(t,e){if(s(t))return t;if("function"==typeof t)return t;if(void 0===t)return t | ||
;throw Error("react "+e+" condition must be derivable or function, got: "+JSON.stringify(t))},a=function(e,n){return e?"function"==typeof e?e(t):e.get():n},u=o(n.from,"from"),f=o(n.until,"until"),c=o(n.when,"when"),h=!1,p=new _(l(function(){return{from:a(u,!0),until:a(f,!1),when:a(c,!0)}}),function(t){t.from&&(h=!0),h&&(t.until?(i.stop(),p.stop()):t.when?i._active||(i.start(),i.force()):i._active&&i.stop())});p.start(),p.force(),i._governor=p}function v(t){return s(t)?t.get():t}function d(t){if(s(t))return t.get();if(Array.isArray(t))return t.map(d);if(t.constructor===Object){for(var e={},n=Object.keys(t),r=n.length;r--;){var i=n[r];e[i]=d(t[i])}return e}return t}function y(t,e){for(var n=0,r=t._activeChildren.length;n<r;n++){var i=t._activeChildren[n];switch(i._type){case V:case M:i._state!==T&&(i._state=T,y(i,e));break;case L:e.push(i)}}}function g(t){for(var e=0,n=t.length;e<n;e++){var r=t[e];if(r._reacting)throw Error("Synchronous cyclical reactions disallowed. Use setImmediate.");r._maybeReact()}}function w(){return null!==J}function m(t){E();try{t(function(){throw H})}catch(t){if(O(),t!==H)throw t;return}A()}function b(t){w()?t():m(t)}function E(){J=new function(t){this.parent=t,this.id2originalValue={},this.modifiedAtoms=[]}(J)}function A(){var t=J;if(null===(J=t.parent)){var e=[];t.modifiedAtoms.forEach(function(n){o(n,n._value,t.id2originalValue[n._id])?n._state=F:(n._state=B,y(n,e))}),g(e),t.modifiedAtoms.forEach(function(t){t._state=F})}}function O(){var t=J;J=t.parent,t.modifiedAtoms.forEach(function(e){e._value=t.id2originalValue[e._id],e._state=F,y(e,[])})}function k(t){this._id=R++,this._activeChildren=[],this._value=t,this._state=F,this._type=I,this._equals=null}function q(t){return new k(t)}function D(t){c.call(this,t.get),this._proxyMapping=t,this._type=M}var x=Object.assign,R=0,j=Object.freeze({equals:function(){return!1}}),C=!1,I="ATOM",V="DERIVATION",M="PROXY",L="REACTOR",T=0,B=1,F=2,N=3,P=[],S=null;x(c.prototype,{_clone:function(){return i(l(this._deriver),this._equals)}, | ||
_forceEval:function(){var t,e=null;try{if(null===this._parents&&(this._parents=[]),a(this,this._parents),r())try{e=this._deriver()}catch(t){throw console.error(this.stack),t}else e=this._deriver();t=P[P.length-1].offset}finally{u()}this._state=o(this,e,this._value)?F:B;for(var n=t,i=this._parents.length;n<i;n++){h(this._parents[n],this),this._parents[n]=null}this._parents.length=t,this._value=e},_update:function(){if(null===this._parents)this._forceEval();else if(this._state===T){for(var t=this._parents.length,e=0;e<t;e++){var n=this._parents[e];if(n._state===T&&n._update(),n._state===B){this._forceEval();break}}this._state===T&&(this._state=F)}},get:function(){if(f(this),this._activeChildren.length>0)this._update();else{a(void 0,[]);try{this._value=this._deriver()}finally{u()}}return this._value}}),x(_.prototype,{start:function(){this._active=!0,e(this._parent._activeChildren,this),this._parent.get()},_force:function(t){try{this._reacting=!0,this.react(t)}catch(t){throw r()&&console.error(this.stack),t}finally{this._reacting=!1}},force:function(){this._force(this._parent.get())},stop:function(){h(this._parent,this),this._active=!1},_maybeReact:function(){if(!this._reacting&&this._active&&(null!==this._governor&&this._governor._maybeReact(),this._active)){var t=this._parent.get();this._parent._state===B&&this._force(t)}}});var z={derive:function(t){var e=this;if("function"!=typeof t)throw Error("derive requires function");return l(function(){return t(e.get())})},maybeDerive:function(t){var e=this;if("function"!=typeof t)throw Error("maybeDerive requires function");return l(function(){var r=e.get();return n(r)?t(r):null})},orDefault:function(t){if(!n(t))throw Error("orDefault requires non-null value");return this.derive(function(e){return n(e)?e:t})},react:function(t,e){p(this,t,e)},maybeReact:function(t,e){var n=this.derive(Boolean);if(e&&"when"in e&&!0!==e.when){var r=e.when;if("function"==typeof r||!1===r)r=l(r);else if(!s(r))throw new Error("when condition must be bool, function, or derivable") | ||
;n=n.derive(function(t){return t&&r.get()})}p(this,t,x({},e,{when:n}))},is:function(t){var e=this;return l(function(){return o(e,e.get(),v(t))})},withEquality:function(t){if(t){if("function"!=typeof t)throw new Error("equals must be function")}else t=null;return i(this._clone(),t)}},G={update:function(t,e,n,r,i){switch(arguments.length){case 0:throw Error("update method accepts at least 1 argument");case 1:return this.set(t(this.get()));case 2:return this.set(t(this.get(),e));case 3:return this.set(t(this.get(),e,n));case 4:return this.set(t(this.get(),e,n,r));case 5:return this.set(t(this.get(),e,n,r,i));default:throw Error("update method accepts only 5 arguments")}}},H={},J=null,K=0,U="object"==typeof window?window:"object"==typeof global?global:{},X=U.__DERIVABLE_DEVTOOLS_HOOK__;x(k.prototype,{_clone:function(){return i(q(this._value),this._equals)},set:function(t){!function(t){null!==J&&(t._id in J.id2originalValue||(J.modifiedAtoms.push(t),J.id2originalValue[t._id]=t._value))}(this);var e=this._value;if(this._value=t,!w()&&!o(this,t,e))try{this._state=B;var n=[];y(this,n),g(n)}finally{this._state=F}},get:function(){return"function"==typeof X&&X("captureAtom",this),f(this),this._value}}),x(D.prototype,c.prototype,{_clone:function(){return i(new D(this._proxyMapping),this._equals)},set:function(t){var e=this;b(function(){e._proxyMapping.set(t)})}}),x(c.prototype,z),x(D.prototype,z,G),x(k.prototype,z,G),U.__DERIVABLE_INIT_FLAG__&&console.warn("Multiple instances of derivable have been initialized on the same page"),U.__DERIVABLE_INIT_FLAG__=!0,t.atom=q,t.proxy=function(t){return new D(t)},t.derive=l,t.setDebugMode=function(t){C=!!t},t.isDerivable=s,t.isAtom=function(t){return t&&(t._type===I||t._type===M)},t.isProxy=function(t){return t&&t._type===M},t.isDerivation=function(t){return t&&(t._type===V||t._type===M)},t.unpack=v,t.struct=function(t){if(t.constructor===Object||Array.isArray(t))return l(function(){return d(t)});throw new Error("`struct` expects plain Object or Array")},t.transact=m, | ||
t.transaction=function(t){return function(){for(var e=[],n=arguments.length;n--;)e[n]=arguments[n];var r;return m(function(){r=t.apply(void 0,e)}),r}},t.ticker=function(){0===K&&E(),K++;var t=!1;return{tick:function(){if(t)throw new Error("trying to use ticker after release");A(),E()},reset:function(){if(t)throw new Error("trying to use ticker after release");O(),E()},release:function(){if(t)throw new Error("ticker already released");t=!0,0==--K&&A()}}},t.atomic=function(t){return function(){for(var e=[],n=arguments.length;n--;)e[n]=arguments[n];var r;return b(function(){r=t.apply(void 0,e)}),r}},t.atomically=b,t.__Reactor=_,t.__captureDereferences=function(t){var e=[];a(void 0,e);try{t()}finally{u()}return e},Object.defineProperty(t,"__esModule",{value:!0})}); | ||
//# sourceMappingURL=derivable.umd.min.js.map |
{ | ||
"name": "derivable", | ||
"version": "2.0.0-beta.1", | ||
"version": "2.0.0-beta.2", | ||
"description": "Functional Reactive State for JavaScript & TypeScript", | ||
"author": "David Sheldrick", | ||
"main": "dist/derivable.js", | ||
"module": "dist/derivable.es.js", | ||
"typings": "dist/derivable.d.ts", | ||
"typescript": { | ||
"definition": "dist/derivable.d.ts" | ||
}, | ||
"files": [ | ||
@@ -11,8 +17,7 @@ "dist" | ||
"prepublish": "npm run build", | ||
"build": "rollup -c && cross-env MINIFY=true rollup -c && cp derivable.d.ts derivable.js.flow dist/", | ||
"test": "npm run build && jest && npm run lint", | ||
"lint": "eslint src", | ||
"ci:test": "npm run test && (cd test_flow && npm install && npm test)", | ||
"build": "rollup -c && cp derivable.d.ts derivable.js.flow dist/", | ||
"lint": "eslint src test", | ||
"test": "npm run build && jest --coverage && npm run lint", | ||
"test-types": "cd test_flow && yarn && yarn test", | ||
"bench": "node scripts/bench.js", | ||
"coverage": "jest --coverage", | ||
"report-coverage": "jest --coverage && cat ./coverage/lcov.info | coveralls", | ||
@@ -22,10 +27,12 @@ "stats": "node scripts/stats.js", | ||
"clean": "rm -rf dist", | ||
"all": "npm run clean && npm run build && npm run test && npm run coverage && npm run stats && npm run bench && npm run toc" | ||
"all": "npm run clean && npm run test && npm run stats && npm run bench && npm run toc", | ||
"precommit": "lint-staged" | ||
}, | ||
"main": "dist/derivable.js", | ||
"module": "dist/derivable.es.js", | ||
"typings": "dist/derivable.d.ts", | ||
"typescript": { | ||
"definition": "dist/derivable.d.ts" | ||
"lint-staged": { | ||
"*.{js,md}": [ | ||
"prettier --write", | ||
"git add" | ||
] | ||
}, | ||
"@std/esm": "cjs", | ||
"keywords": [ | ||
@@ -41,33 +48,20 @@ "immutable", | ||
], | ||
"babel": { | ||
"env": { | ||
"test": { | ||
"plugins": [ | ||
"transform-es2015-modules-commonjs" | ||
] | ||
} | ||
} | ||
}, | ||
"jest": { | ||
"testRegex": ".*_test.js$" | ||
}, | ||
"devDependencies": { | ||
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.0", | ||
"babel-register": "^6.7.2", | ||
"@std/esm": "^0.15.0", | ||
"benchmark": "^2.1.0", | ||
"bluebird": "^2.9.34", | ||
"chai": "^3.5.0", | ||
"colors": "^1.1.2", | ||
"coveralls": "^2.11.9", | ||
"cross-env": "^5.1.1", | ||
"doctoc": "^1.0.0", | ||
"eslint": "^4.10.0", | ||
"eslint": "^4.11.0", | ||
"eslint-plugin-es5": "^1.1.0", | ||
"husky": "^0.14.3", | ||
"immutable": "^3.7.4", | ||
"jest": "^21.2.1", | ||
"lint-staged": "^5.0.0", | ||
"mobx": "^2.3.3", | ||
"np": "^2.16.0", | ||
"rollup": "^0.51.1", | ||
"rollup-plugin-uglify": "^2.0.1", | ||
"source-map-support": "^0.3.2" | ||
"prettier": "^1.8.2", | ||
"rollup": "^0.51.6", | ||
"rollup-plugin-buble": "^0.17.0", | ||
"rollup-plugin-uglify": "^2.0.1" | ||
}, | ||
@@ -74,0 +68,0 @@ "repository": { |
251
README.md
<h1 align="center">DerivableJS</h1> | ||
<h3 align="center">State made simple → Effects made easy</h3> | ||
[](https://www.npmjs.com/package/derivable) [](https://travis-ci.org/ds300/derivablejs) [](https://coveralls.io/github/ds300/derivablejs?branch=new-algo) [](https://gitter.im/ds300/derivablejs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](http://futurice.com/blog/sponsoring-free-time-open-source-activities?utm_source=github&utm_medium=spice&utm_campaign=derivablejs) [](http://github.com) | ||
--- | ||
## [](https://www.npmjs.com/package/derivable) [](https://travis-ci.org/ds300/derivablejs) [](https://coveralls.io/github/ds300/derivablejs?branch=new-algo) [](https://gitter.im/ds300/derivablejs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](http://futurice.com/blog/sponsoring-free-time-open-source-activities?utm_source=github&utm_medium=spice&utm_campaign=derivablejs) [](http://github.com) | ||
Derivables are an Observable-like state container with superpowers. Think [MobX](https://github.com/mobxjs/mobx) distilled to a potent essence, served with two heaped tablespoons of extra performance, a garnish of declarative effects management, and a healthy side-salad of immutability. | ||
Derivables are an Observable-like state container with superpowers. Think | ||
[MobX](https://github.com/mobxjs/mobx) distilled to a potent essence, served | ||
with two heaped tablespoons of extra performance, a garnish of declarative | ||
effects management, and a healthy side-salad of immutability. | ||
<!-- START doctoc generated TOC please keep comment here to allow auto update --> | ||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> | ||
* [Quick start](#quick-start) | ||
* [Reactors](#reactors) | ||
* [Key differences with MobX](#key-differences-with-mobx) | ||
* [API / Documentation](#api--documentation) | ||
* [Usage](#usage) | ||
* [With React](#with-react) | ||
* [With Immutable](#with-immutable) | ||
* [Debugging](#debugging) | ||
* [Examples](#examples) | ||
* [Contributing](#contributing) | ||
* [Inspiration <3](#inspiration-3) | ||
* [License](#license) | ||
- [Quick start](#quick-start) | ||
- [Reactors](#reactors) | ||
- [Key differences with MobX](#key-differences-with-mobx) | ||
- [API / Documentation](#api--documentation) | ||
- [Usage](#usage) | ||
- [With React](#with-react) | ||
- [With Immutable](#with-immutable) | ||
- [Debugging](#debugging) | ||
- [Examples](#examples) | ||
- [Browser](#browser) | ||
- [Contributing](#contributing) | ||
- [Inspiration <3](#inspiration-3) | ||
- [License](#license) | ||
<!-- END doctoc generated TOC please keep comment here to allow auto update --> | ||
@@ -33,78 +34,89 @@ | ||
- **Atoms** | ||
* **Atoms** | ||
Atoms are simple mutable references to immutable values. They represent the ground truth from which all else is derived. | ||
Atoms are simple mutable references to immutable values. They represent the | ||
ground truth from which all else is derived. | ||
```javascript | ||
import {atom} from 'derivable'; | ||
```js | ||
import { atom } from "derivable"; | ||
const $Name = atom('Richard'); | ||
const name = atom("Richard"); | ||
$Name.get(); // => 'Richard' | ||
name.get(); // => 'Richard' | ||
$Name.set('William'); | ||
name.set("William"); | ||
$Name.get(); // => 'William' | ||
name.get(); // => 'William' | ||
``` | ||
<em>N.B. The dollar-sign prefix is just a simple convention I use to create a visual distinction between ordinary values and derivable values.</em> | ||
* **Derivations** | ||
- **Derivations** | ||
Derivations are declarative transformations of values held in atoms. You can | ||
create them with the `derive` function. | ||
Derivations are declarative transformations of values held in atoms. You can create them with the `derive` function. | ||
```js | ||
import { derive } from "derivable"; | ||
```javascript | ||
import {derive} from 'derivable'; | ||
const cyber = word => | ||
word | ||
.toUpperCase() | ||
.split("") | ||
.join(" "); | ||
const cyber = word => word.toUpperCase().split('').join(' '); | ||
const cyberName = derive(() => cyber(name.get())); | ||
const $cyberName = derive(() => | ||
cyber($Name.get()) | ||
); | ||
cyberName.get(); // 'W I L L I A M' | ||
$cyberName.get(); // 'W I L L I A M' | ||
name.set("Sarah"); | ||
$Name.set('Sarah'); | ||
$cyberName.get(); // 'S A R A H' | ||
cyberName.get(); // 'S A R A H' | ||
``` | ||
Unlike atoms, derivations cannot be modified in-place with a `.set` method. Their values change only when one or more of the values that they depend upon change. Here is an example with two dependencies. | ||
Unlike atoms, derivations cannot be modified in-place with a `.set` method. | ||
Their values change only when one or more of the values that they depend upon | ||
change. Here is an example with two dependencies. | ||
```javascript | ||
const $Transformer = atom(cyber); | ||
```js | ||
const transformer = atom(cyber); | ||
const $transformedName = derive(() => | ||
$Transformer.get()($Name.get()) | ||
); | ||
const transformedName = derive(() => transformer.get()(name.get())); | ||
$transformedName.get(); // => 'S A R A H' | ||
transformedName.get(); // => 'S A R A H' | ||
const reverse = string => string.split('').reverse().join(''); | ||
const reverse = string => | ||
string | ||
.split("") | ||
.reverse() | ||
.join(""); | ||
$Transformer.set(reverse); | ||
transformer.set(reverse); | ||
$transformedName.get(); // => 'haraS' | ||
transformedName.get(); // => 'haraS' | ||
$Name.set('Fabian'); | ||
name.set("Fabian"); | ||
$transformedName.get(); // => 'naibaF' | ||
transformedName.get(); // => 'naibaF' | ||
``` | ||
`derive` takes a function of zero arguments which should | ||
dereference one or more Derivables to compute the new derived value. DerivableJS then sneakily monitors who | ||
is dereferencing who to infer the parent-child relationships. | ||
`derive` takes a function of zero arguments which should dereference one or | ||
more Derivables to compute the new derived value. DerivableJS then sneakily | ||
monitors who is dereferencing who to infer the parent-child relationships. | ||
## Reactors | ||
Declarative state management is nice in and of itself, but the real benefits come from how it enables us to more effectively manage side effects. DerivableJS has a really nice story on this front: changes in atoms or derivations can be monitored by things called **Reactors**, which do not themselves have any kind of 'current value', but are more like independent agents which exist solely for executing side effects. | ||
Declarative state management is nice in and of itself, but the real benefits | ||
come from how it enables us to more effectively manage side effects. DerivableJS | ||
has a really nice story on this front: changes in atoms or derivations can be | ||
monitored by things called **Reactors**, which do not themselves have any kind | ||
of 'current value', but are more like independent agents which exist solely for | ||
executing side effects. | ||
Let's have a look at a tiny example app which greets the user: | ||
```javascript | ||
import {atom, derive, transact} from 'derivable' | ||
```js | ||
import { atom, derive, transact } from "derivable"; | ||
// global application state | ||
const $Name = atom("World"); // the name of the user | ||
const $CountryCode = atom("en"); // for i18n | ||
const name = atom("World"); // the name of the user | ||
const countryCode = atom("en"); // for i18n | ||
@@ -117,24 +129,17 @@ // static constants don't need to be wrapped | ||
cn: "您好", | ||
fr: "Bonjour", | ||
fr: "Bonjour" | ||
}; | ||
// derive a greeting message based on the user's name and country. | ||
const $greeting = derive(() => | ||
greetings[$CountryCode.get()] | ||
); | ||
const $message = derive(() => | ||
`${$greeting.get()}, ${$name.get()}!` | ||
); | ||
const greeting = derive(() => greetings[countryCode.get()]); | ||
const message = derive(() => `${greeting.get()}, ${name.get()}!`); | ||
// set up a Reactor to print the message every time it changes, as long as | ||
// we know how to greet people in the current country. | ||
$message.react( | ||
msg => console.log(msg), | ||
{when: $greeting} | ||
); | ||
message.react(msg => console.log(msg), { when: greeting }); | ||
// $> Hello, World! | ||
$CountryCode.set("de"); | ||
countryCode.set("de"); | ||
// $> Hallo, World! | ||
$Name.set("Dagmar"); | ||
name.set("Dagmar"); | ||
// $> Hallo, Dagmar! | ||
@@ -144,4 +149,4 @@ | ||
transact(() => { | ||
$CountryCode.set("fr"); | ||
$Name.set("Étienne"); | ||
countryCode.set("fr"); | ||
name.set("Étienne"); | ||
}); | ||
@@ -151,5 +156,5 @@ // $> Bonjour, Étienne! | ||
// if we set the country code to a country whose greeting we don't know, | ||
// $greeting becomes undefined, so the $message reactor won't run | ||
// In fact, the value of $message won't even be recomputed. | ||
$CountryCode.set('dk'); | ||
// `greeting` becomes undefined, so the `message` reactor won't run | ||
// In fact, the value of `message` won't even be recomputed. | ||
countryCode.set("dk"); | ||
// ... crickets chirping | ||
@@ -164,36 +169,41 @@ ``` | ||
- Smaller API surface area. | ||
* Smaller API surface area. | ||
There are far fewer *kinds of thing* in DerivableJS, and therefore fewer | ||
things to learn and fewer surprising exceptions and spooky corners. This | ||
reduces noise and enhances one's ability to grok the concepts and wield the | ||
tools on offer. It also shrinks the set of tools | ||
on offer, but maybe that's not a bad thing: | ||
There are far fewer _kinds of thing_ in DerivableJS, and therefore fewer | ||
things to learn and fewer surprising exceptions and spooky corners. This | ||
reduces noise and enhances one's ability to grok the concepts and wield the | ||
tools on offer. It also shrinks the set of tools on offer, but maybe that's | ||
not a bad thing: | ||
> It seems that perfection is attained not when there is nothing more to add, but when there is nothing more to remove. | ||
> It seems that perfection is attained not when there is nothing more to add, | ||
> but when there is nothing more to remove. | ||
<em>- Antoie de Saint Exupéry</em> | ||
_- Antoie de Saint Exupéry_ | ||
- No transparent dereferencing and assignment. | ||
* No transparent dereferencing and assignment. | ||
It is always necessary to call `.get` on derivables to find out what's inside, and you always have to call `.set` on atoms to change what's inside. | ||
This provides a consistent semantic and visual | ||
distinction between ordinary values and derivable values. | ||
It is always necessary to call `.get` on derivables to find out what's inside, | ||
and you always have to call `.set` on atoms to change what's inside. This | ||
provides a consistent semantic and visual distinction between ordinary values | ||
and derivable values. | ||
- No observable map and array types. | ||
* No observable map and array types. | ||
So you probably have to use something extra like Immutable or [icepick](https://github.com/aearly/icepick) to deal with collections. Not great if you're just out to get | ||
shit done fast, but the benefits of immutable | ||
collections become more and more valuable as projects | ||
mature and grow in scope. | ||
So you probably have to use something extra like Immutable, | ||
[icepick](https://github.com/aearly/icepick) or | ||
[pure javascript immutable arrays](https://vincent.billey.me/pure-javascript-immutable-array/) | ||
to deal with collections. Not great if you're just out to get shit done fast, | ||
but the benefits of immutable collections become more and more valuable as | ||
projects mature and grow in scope. | ||
- More subtle control over reactors | ||
* More subtle control over reactors | ||
DerivableJS has a tidy and flexible declarative system for defining when reactors should start and stop. This | ||
is rather nice to use for managing many kinds of side effects. | ||
DerivableJS has a tidy and flexible declarative system for defining when | ||
reactors should start and stop. This is rather nice to use for managing many | ||
kinds of side effects. | ||
- Speed | ||
* Speed | ||
DerivableJS is finely tuned, and propagates change | ||
significantly faster than MobX. \[link to benchmark-results.html forthcoming\] | ||
DerivableJS is finely tuned, and propagates change significantly faster than | ||
MobX. \[link to benchmark-results.html forthcoming\] | ||
@@ -206,17 +216,25 @@ ## API / Documentation | ||
DerivableJS is fairly mature, and has been used enough in production by various people to be considered a solid beta-quality piece of kit. | ||
DerivableJS is fairly mature, and has been used enough in production by various | ||
people to be considered a solid beta-quality piece of kit. | ||
### With React | ||
The fantastic project [react-derivable](https://github.com/andreypopp/react-derivable) lets you use | ||
derivables in your render method, providing seamless interop with component-local state and props. | ||
The fantastic project | ||
[react-derivable](https://github.com/andreypopp/react-derivable) lets you use | ||
derivables in your render method, providing seamless interop with | ||
component-local state and props. | ||
### With Immutable | ||
DerivableJS works spiffingly with [Immutable](https://github.com/facebook/immutable), which | ||
is practically required if your app deals with medium-to-large collections. | ||
DerivableJS works spiffingly with | ||
[Immutable](https://github.com/facebook/immutable), which is practically | ||
required if your app deals with medium-to-large collections. | ||
### Debugging | ||
Due to inversion of control, the stack traces you get when your derivations throw errors can be totally unhelpful. There is a nice way to solve this problem for dev time. See [setDebugMode](https://ds300.github.com/derivablejs/#derivable-setDebugMode) for more info. | ||
Due to inversion of control, the stack traces you get when your derivations | ||
throw errors can be totally unhelpful. There is a nice way to solve this problem | ||
for dev time. See | ||
[setDebugMode](https://ds300.github.com/derivablejs/#derivable-setDebugMode) for | ||
more info. | ||
@@ -227,22 +245,15 @@ ### Examples | ||
### Browser | ||
Either with browserify/webpack/common-js-bundler-du-jour, or clone the repo, run `npm install && npm run build`, then grab the UMD bundle from `dist/derivable.umd[.min].js` (source maps are also available). | ||
```javascript | ||
import { withEquality } from 'derivable' | ||
const { atom, derive, ..._} = withEquality(myCustomEqualityChecker); | ||
``` | ||
## Contributing | ||
I heartily welcome questions, feature requests, bug reports, and general suggestions/criticism on the github issue tracker. I also welcome bugfixes via pull request (please read CONTRIBUTING.md before sumbmitting). | ||
I heartily welcome questions, feature requests, bug reports, and general | ||
suggestions/criticism on the github issue tracker. I also welcome bugfixes via | ||
pull request (please read CONTRIBUTING.md before sumbmitting). | ||
## Inspiration <3 | ||
- [Are we there yet?](https://www.infoq.com/presentations/Are-We-There-Yet-Rich-Hickey) | ||
- The [re-frame README](https://github.com/Day8/re-frame) | ||
- [ratom.cljs](https://github.com/reagent-project/reagent/blob/master/src/reagent/ratom.cljs) | ||
- [Turning the database inside out](https://www.youtube.com/watch?v=fU9hR3kiOK0) | ||
- [Simple Made Easy](https://www.infoq.com/presentations/Simple-Made-Easy) | ||
* [Are we there yet?](https://www.infoq.com/presentations/Are-We-There-Yet-Rich-Hickey) | ||
* The [re-frame README](https://github.com/Day8/re-frame) | ||
* [ratom.cljs](https://github.com/reagent-project/reagent/blob/master/src/reagent/ratom.cljs) | ||
* [Turning the database inside out](https://www.youtube.com/watch?v=fU9hR3kiOK0) | ||
* [Simple Made Easy](https://www.infoq.com/presentations/Simple-Made-Easy) | ||
@@ -249,0 +260,0 @@ ## License |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
17
270
316861
2271
1