- Notifications
You must be signed in to change notification settings - Fork0
NOTICE: replaced byhttps://github.com/fluents/chain-able
fliphub/flipchain
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
core chaining library, heavily based onwebpack-chain, but not webpack-specific.
writing an api using flipchain means writing a single fluent api, but getting 3 apis as a result!
- 🍉 rehydratable configurations
- ⛓ fluent chainable api
- 🍦 object configs that are easily merged deep
imagine there are 2 people by the water, & the goal is to make 10 splashes.
as with most skills, you get better at skipping rocks the more that you do it.a lot of people cannot skip rocks, or they do not like to skip rocks, but they can still throw rocks and make a splash. think of this like non-fluent/vanilla-calls
Chain.prop()Chain.longer()Chain.intoSomeShapes()
or throwing a really huge rock into the water, and getting the splashes to make more splashes.
Chain.from({prop:null,longer:null,intoSomeShapes:null,})
using method chaining looks similar to skipping rocks
Chain.prop().longer().intoSomeShapes()
writing an application with a fluent interface allows people to use it all three ways, and you only have to write it one way.
constChainedMap=require('./ChainedMapExtendable')classEasyFluentextendsChainedMap{constructor(parent){super(parent)// extend a list of strings for easy chainable methodsthis.extend(['eh'])// same as .extend,// but when called with no arguments,// default is used (`true` in this case)// third param is optionally a prefix for inversified// for example, `no` => `noCanada()` for inverse valuethis.extendPrefixed(['canada'],true,'no')}// if more advanced data changes are needed// or if the syntax is preferred for use with typescript or flowtype// .set, .get, .has are availableigloo(igloo){this.set('igloo',igloo)returnthis}toConfig(){returnthis.entries()}}// {igloo: 'fire', canada: false, eh: 'moose'}constconfig=newEasyFluent().igloo('fire').noCanada().eh('moose').toConfig()// this is == configconsthydrated=newEasyFluent().from(config).toConfig()// canada is now trueconstmerged=newEasyFluent().merge(config).merge({canada:true}).toConfig()
constChainedMap=require('./ChainedMapExtendable')constChainedSet=require('./ChainedSet')classAdvancedextendsChainedMap{staticinit(parent){returnnewAdvanced(parent)}constructor(parent){super(parent)this.list=newChainedSet(this)this.extend(['eh'])this.extendWith(['canada'],true)}addName(name){this.list.add(name)returnthis}igloo(igloo){this.set('igloo',igloo)returnthis}toConfig(){returnObject.assign(this.entries(),{list:this.list.values().map(name=>name),})}// since we have additional data that is not simple key value// we do additional (albeit easy) steps to rehydratefrom(obj){super.from(obj)Object.keys(obj).forEach(key=>{constval=obj[key]switch(key){case'list':returnval.filter(name=>name).forEach(name=>this.addName(name))}})returnthis}// same with `from`// we do additional simple steps to merge in listsmerge(obj){Object.keys(obj).filter(key=>obj[key]).forEach(key=>{constval=obj[key]switch(key){case'list':returnval.filter(name=>name).forEach(v=>this.addName(v))}})// built-in merging// can use `.mergeReal` to merge only `real` values// and `.merge` to merge anysuper.merge(obj)returnthis}}constchain=Advanced.init().igloo('brr').canada().eh('eh!').addName('thing one').addName('thing two')// true, `eh!`chain.has('igloo')chain.get('eh')constresult=chain.toConfig()consthydrated=Advanced.init().from(result).toConfig()constmerged=Advanced.init().merge(hydrated).merge({igloo:'whaaaat'})// can use toConfig,// and safely continue editing `merged`// with a snapshot of the object data saved as `mergedResult`constmergedResult=merged.toConfig()// hydrated === result === {// igloo: 'brr',// canada: 'canada',// eh: 'eh!',// list: [ 'thing one', 'thing two' ]// }// merged === {// igloo: 'whaaaat',// canada: 'canada',// eh: 'eh!',// list: [ 'thing one', 'thing two' ]// }
- there arejsdoc blocks for all methods
- every chain has
.className
for easy debugging - every chain has this.parent
- and this.parent is hidden on inspection by🕵🗜 inspector-gadget for easier debugging
- Set
- prepend => this
- clear => this
- delete => this
- values => array of entries
- has => boolean
- merge => merge an object into the chain
- when => conditional instance callback
(methodsToAlias: Array<string>, methodToAlias: string, [thisArg])
- alias a list of methods
- @returns
this
(obj: Object)
- checks each property of the object
- calls the chains accordingly
- rehydrates a chain from an object
- decorateParent (usingchildparent)
- clear() => this // clearsAll
- delete(key) => this
- entries => {keysAndValues}
- values => Object.values
- get(key) => entry
- has(key) => boolean
- set(key, val) => this
- concat(key, val) => this
- append(key, val) => this
- mergeReal(obj) => this // only merges non-undefined values
- merge(obj) => this
- clean => this
- when => conditional instance callback
lets you chain until the required keys are set via chains, or if they are passed in, then it auto returnsparent
- has chains with
.extends
able to usedefault
values when calling it - also can add
prefixes
(defaultno
) so if you usecache
defaulttrue
, it can addnoCache
which does the inverse - set up for being chains of chains when you add a few decorating chains dynamically
// using `izz` to validate types when settingthis.extendType(['str'],'string')