Skip to content

Instantly share code, notes, and snippets.

@wafna
Last active April 26, 2018 00:06
Show Gist options
  • Save wafna/dc50d9180ba62db4ffc8ac3be11edf3b to your computer and use it in GitHub Desktop.
Save wafna/dc50d9180ba62db4ffc8ac3be11edf3b to your computer and use it in GitHub Desktop.
Proxy mutable state with notifications and transformations.
/*
MVar is a facility for data flow among components and APIs.
*/
const assertFunction = (f, msg) => {
if (typeof f !== 'function')
throw new Error('Function required: ' + msg);
};
/**
* Generically produces a new MVar chained after the given MVar.
* @param m The given MVar.
* @param f The subscribing function.
* @returns {*} An MVar object.
* @private
*/
const _after = (m, f) => {
assertFunction(f, '');
const n = {
take: m.take,
put: v => {
m.put(v);
f(v);
return n;
},
before: f => _before(n, f),
after: f => _after(n, f)
};
return n;
};
/**
* Generically produces a new MVar chained before the given MVar.
* @param m The given MVar.
* @param f The transforming function.
* @returns {*} An MVar object.
* @private
*/
const _before = (m, f) => {
assertFunction(f);
const n = {
take: m.take,
put: v => {
m.put(f(v));
return n;
},
before: f => _before(n, f),
after: f => _after(n, f)
};
return n;
};
/**
* Creates an object that encapsulates a mutable value.
* This is used to hook data update notifications, transform data from other sources, and proxy
* data collection to other components, typically down the hierarchy.
* Undefined values are forbidden.
*/
export const MVar = value => {
if (value === undefined)
throw new Error('Undefined values are forbidden.');
const m = {
take: () => value,
put: v => {
if (v === undefined)
throw new Error('Undefined values are forbidden.');
value = v;
return m;
},
/**
* Create a new MVar that executes function f after the value is set.
* Typically, f redraws a component.
* @param f Takes the incoming value.
*/
after: f => _after(m, f),
/**
* Creates a new MVar that maps new values through f before setting.
* Useful to coerce data, like ids from select options.
* @param f
*/
before: f => _before(m, f),
};
return m;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment