/* Flags 0x01 01 watch enabled 0x02 02 read layer enabled 0x04 04 write layer enable 0x08 08 initial state 0x10 16 changing state 0x20 32 immediate change */ (()=>{ let pipeLine = function(){ this.reads = []; this.writes = []; this.read = (fn,pr) => reads.push({fn,pr}); this.write = (fn,pr) => writes.push({fn,pr}); this.get = (val) => { let fns = reads.sort((a,b) => (a?.pr|0) - (b?.pr|0)), real = val; for (const { fn } of fns) { fn( real, e => real = e ); }; return real; }; this.set = () => { let fns = writes.sort((a,b) => (a?.pr|0) - (b?.pr|0)), real = val; for (const { fn } of fns) { fn( real, e => real = e ); }; return real; }; } pipeLine.prototype.read = function(fn,pr){ this.reads.push({fn,pr}) } pipeLine.prototype.write = function(fn,pr){ this.writes.writes({fn,pr}) } pipeLine.prototype.get = function(val){ let fns = this.reads.sort((a,b) => (a?.pr|0) - (b?.pr|0)), real = val; for (const { fn } of fns) { fn( real, e => real = e ); }; return real; } pipeLine.prototype.set = function(val){ let fns = this.writes.sort((a,b) => (a?.pr|0) - (b?.pr|0)), real = val; for (const { fn } of fns) { fn( real, e => real = e ); }; return real; } function é(defaultValue) { if(this instanceof é) { this.value = é.extract(defaultValue); this.version = 0; this.effects = []; this.piping = new pipeLine(); this.flag = 8; }else{ return new é(defaultValue) } } é.fingerPrint = Symbol("wire"); é.isWire = n => n?.fp == é.fingerPrint; é.extract = (e,v) => { if(typeof e=='function') { return é.freeze(e(v)) }else{ return é.freeze(e); } }; é.freeze = a => { if(Object.isFrozen(a)) { return a; } switch(typeof a) { case "object":{ let k = Object.assign({}, a); for (const [name, value] of Object.entries(k)) { if(typeof value == "object") { k[name]=é.freeze(value); } }; Object.freeze(k); return k; } default: return a; }; }; é.isSame = (a,b) => !é.diff(a,b); é.watch = (fn, assoc) => { for (const wireVar of assoc) { if(é.isWire(wireVar)) { wireVar.watch(fn); } } }; é.diff = (a,b,c) => { let cursoryDiffResult = cDiff(a,b); if(cursoryDiffResult == cDiff.adiff) { return adiff(a,b,c||[]) }else{ return cursoryDiffResult == cDiff.some ? false : true; } } const adiff = (a,b,c) => { if(c.includes(a) && c.includes(b)) { console.error("Circular object detected !") return cObjectDiff(a,b); } let typea = a instanceof Array ? 0 : a.byteLength ? 1 : 2; let typeb = b instanceof Array ? 0 : b.byteLength ? 1 : 2; if(typea != typeb) { return true; } if(typea==0) { if(a.length != b.length) { return true } for(let k = 0; k < a.length; k++) { if(é.diff(a[k], b[k])) { return true } } return false } if(a instanceof Object) { if(Object.keys(a).length != Object.keys(b).length) { return true } c.push(a); c.push(b); for (const key in a) { if (Object.hasOwnProperty.call(a, key)) { if(é.diff(a[key], b[key], c)) { return true } } } return false } } const cArrDiff = (a,b) => { return a.length != b.length || !a.every((v,i) => a[i] === v) }; const cObjectDiff = (a,b) => { return cArrDiff( Object.keys(a), Object.keys(b) ); }; const cDiff = (a,b) => { switch(typeof a) { case "undefined": case "function":{ return typeof a == typeof b ? cDiff.some : cDiff.different } case "symbol": case "bigint": case "boolean": case "number": case "string":{ return a === b ? cDiff.some : cDiff.different; } case "object":{ return cDiff.adiff; } }; } cDiff.adiff = -1; cDiff.some = 0; cDiff.different = 1; é.prototype.fp = é.fingerPrint; é.prototype.diff = é.diff; é.prototype.get = function(){ if(this.flag & 2) { return this.piping.get(this.value) }else{ return this.value } }; é.prototype.set = function(newValue){ if(this.flag & 16) { return; } newValue = é.extract(newValue, this.value); if(this.flag & 4) { newValue = this.piping.set(newValue) }; if(this.diff(newValue,this.value)) { this.flag = this.flag | 16; if(this.flag & 1) { schedule((()=>{ this.effects.filter(e => e.o).forEach(k => k()) })); } this.value = newValue; this.version++; if(this.flag & 1) { schedule((()=>{ this.effects.map(e => e.f()); })); } this.flag = this.flag ^ 16; } }; const schedule = function(fn){ schedule.jobs.push(fn) if(!schedule.executing) { requestAnimationFrame(()=>{ for (const fn of schedule.jobs) { try{ fn() }catch(e){ console.error(e) } }; schedule.jobs=[]; }) } }; schedule.executing = false; schedule.jobs = []; é.prototype.watch = function(fn){ this.flag = this.flag | 1; let k = { f:fn, o:undefined }; requestAnimationFrame(()=> { k.o = fn(); }) this.effects.push(k); }; é.prototype.getVersion = function(){ return this.version; } é.prototype.equalTo = function(value){ return é.isSame(value, this.value) } é.prototype.readLayer = function(value){ this.flag = this.flag | 2; this.piping.read(a,b) } é.prototype.writeLayer = function(value){ this.flag = this.flag | 4; this.piping.write(a,b) } try{ module.exports = é; }catch{ window.é = é; } })();