-
-
Save staltz/f02ee6f2cf8eb134b887 to your computer and use it in GitHub Desktop.
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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