An idea for scoping Cycle.js child components/dialogues in the context of their parent. Any driver can optionally supply a scope() function, which returns a scoped instance of itself. A driver can also supply an unscope() function which returns a transformed instance of its associated sink. Anything that is scope-unaware is preserved.
function runInScope(main, sources, context, ...args) { | |
if(!main) { | |
throw new Error('A "main" function must be supplied, which will be called in scope and from which a (sinks) object will be returned'); | |
} | |
if(!sources) { | |
throw new Error('A source drivers object must be supplied, to which scoping can be applied'); | |
} | |
if(!context) { | |
throw new Error('A scope context object must be supplied, either as a string, or as an object of key/value pairs'); | |
} | |
// Prepare the scoped sources object, preserving all drivers that have no | |
// concept of scoping, and applying either a universal scope context to all | |
// drivers, or a scope context per driver, on an opt-in basis. | |
let scopedSources = {}; | |
for(let key of sources) { | |
let source = sources[key]; | |
if(context && typeof source.scope === 'function') { | |
let scopeContext = typeof context === 'string' ? context : context[key]; | |
if(typeof scopeContext !== 'undefined' && scopeContext !== null) { | |
source = source.scope(scopeContext); | |
} | |
} | |
scopedSources[key] = source; | |
} | |
// The main function is now called in the context of the constrained scope | |
let sinks = main(scopedSources, ...args); | |
// Each driver can now optionally apply a transform to the returned sink with | |
// which it is associated. Note that the `unscope()` function is called against | |
// the scoped driver instance in case that driver instance retained scope state | |
// information internally that it may wish to use when unscoping the sink | |
// object. If not, it will still have context provided via the second argument | |
// passed to `unscope()`. | |
for(let key of sinks) { | |
let sink = sinks[key]; | |
let source = scopedSources[key]; | |
if(source && context && typeof source.unscope === 'function') { | |
let scopeContext = typeof context === 'string' ? context : context[key]; | |
if(typeof scopeContext !== 'undefined' && scopeContext !== null) { | |
sinks[key] = source.unscope(sink, scopeContext); | |
} | |
} | |
} | |
return sinks; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment