UNPKG

xsm

Version:

XSM - State Management made eXtraordinarily simple for React, Vue, Angular, Svelte

303 lines (277 loc) 7.2 kB
let _data = {}; let config = {}; let sharedState = {}; let sublist = new Map(); let debug=false; let trace=false; let fwsetstate, fwinitstate, fwumount, fwcname, thisless, debugTrace; function initstate(self, key, val) { let v = get(key); if( v === undefined ) { self[key] = val; set(key, val); } else { self[key] = v; } } export function setTrace(val) { trace = val; debugTrace = debug || trace; } export function setDebug(val) { debug = val; debugTrace = debug || trace; } function printinfo(self, key=null, val=null) { let name; if( fwcname && self ) name = fwcname(self); else name = 'none'; let printfunc = console.log; if( trace ) { printfunc = console.trace; } printfunc('cname', name, 'key', key, 'val', val, '\n store', {..._data}); } const frameworkcfg = { React: { umount: 'componentWillUnmount', setstate: self => (key, val) => { self[key] = val; if( debugTrace ) printinfo(self, key, val); self.forceUpdate(); return self; }, initstate, cname: self => self.constructor.name, }, Vue: { umount: 'destroyed', setstate: self => (key, val) => { self[key] = val; if( debugTrace ) printinfo(self, key, val); return self.$forceUpdate(); }, initstate, cname: self => self.$options._componentTag }, Angular: { umount: 'ngOnDestroy', setstate: self => (key, val) => { self[key] = val; if( debugTrace ) printinfo(self, key, val); }, initstate, cname: self => self.constructor.name, }, Svelte: { umount: null, setstate: self => (key, val) => { self[key](val); if( debugTrace ) printinfo(self, key, val); }, initstate: () => null, cname: self => '', }, }; function rmkey(key) { _data[key] = undefined; } function rmsub(self, key) { const cblist = sublist.get(key); for(let i=0; i<cblist.length; i++) { if( cblist[i].self === self ) { cblist.splice(i, 1) if( cblist.length === 0 ) { sublist.delete(key); if( !sharedState[key] ) rmkey(key); } return; } } } function addsub(key, cb, self) { if( !sublist.has(key) ) sublist.set(key, []); let subitem = sublist.get(key); subitem.push({self, cb: (key,val) => cb(key,val)}) return subitem.length-1; } export function set(key, val) { let cblst = sublist.get(key); if( cblst ) { if( cblst.length == 1 ) { cblst[0].cb(key, val); } else { for(let i=0; i<cblst.length; i++) { cblst[i].cb(key, val); } } } _data[key] = val; if( (debugTrace) && !cblst ) printinfo(null, key, val); } export function setMany(kv) { Object.keys(kv).forEach(key => { set(key, kv[key]) }); } export function get(key) { return _data[key]; } export function unbindState(bindings) { return rmStateBinding(bindings); } function rmStateBinding(self, opt) { let map; if( thisless ) { if( !self && opt ) { map = opt; self = opt; } else if( self && arguments.length === 1 ) { map = self; } else { console.log('no binding'); return; } } else { if( opt ) map = opt; else if( config.bindings ) map = config.bindings[fwcname(self)]; else return; } Object.keys(map).forEach(key => { if( debugTrace ) printinfo('removing key', key, 'from', self); rmsub(self, key); }); } export function bindState(self, opt) { let map; if( thisless ) { if( !self && opt ) { map = opt; self = opt; } else if( arguments.length === 1 ) { map = self; } else { console.trace('no binding self=', self, 'opt=', opt, 'arguments.length', arguments.length); return; } } else { if( opt ) map = opt; else if( config.bindings ) map = config.bindings[fwcname(self)]; else return; } let id, statecb; let frameworkcb = fwsetstate(self); Object.keys(map).forEach(key => { fwinitstate(self, key, map[key]); id = addsub(key, frameworkcb, self); //ref[key] = id; }); if( config.framework ) { let umount = self[fwumount]; if( umount ) { umount = umount.bind(self); self[fwumount] = function classDestroy() { rmStateBinding(self, map); return umount(); }; } else { if( !thisless ) { self[fwumount] = function classDestroy() { rmStateBinding(self, map); }; } } } else { console.log('default framework is none'); } } export function reset(key, opt) { if(key) { delete _data[key]; } else { _data = {}; } } function addSharedState(bindings) { Object.keys(bindings).forEach(key => { sharedState[key] = true; }); } function setSharedState(bindings) { let keylist = {}; Object.keys(bindings).forEach(key => { const component = bindings[key]; Object.keys(component).forEach(state => { if( keylist[state]) keylist[state] += 1; else keylist[state]= 1; }); }); Object.keys(keylist).forEach(key => { if( keylist[key]>1 ) { sharedState[key] = true; } }); if( debugTrace ) printinfo(null, 'sharedState', sharedState); } export function setup(opt) { if( !opt ) return; let val; Object.keys(opt).forEach(key => { val = opt[key]; config[key] = val; if( key === 'framework' ) { if( opt[key] === 'Svelte' ) thisless = true; else thisless = false; fwinitstate = frameworkcfg[val].initstate; fwsetstate = frameworkcfg[val].setstate; fwumount = frameworkcfg[val].umount; fwcname = frameworkcfg[val].cname; } else if( key === 'bindings' ) { setSharedState(val) } else if( key === 'sharedBindings' ) { addSharedState(val) } else if( key === 'trace' ) { setTrace(val) trace = val; } else if( key === 'debug' ) { setDebug(val) debug = val; } else { console.log('not supported option ', key); } }); } export const setcfg = setup; const usm = { setup, setcfg, set, get, reset, rmsub, addsub, bindState, setDebug, setTrace, }; export default usm;