/* 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(wire){ let _caches = {}; let _cache_version = null; this.reads = []; this.writes = []; this.filters = new Map(); this.read = (fn,pr) => this.reads.push({fn,pr}); this.write = (fn,pr) => this.writes.push({fn,pr}); this.filter = (name, fn) => this.filters.set(name,fn); this.get = (val,filters = []) => { let real = val; if(filters.length) { if(_cache_version !== wire.version()) { _caches = {}; }; for (const name of filters) { if(_caches[name]) { real = _caches[name]; continue; } let func = this.filters.get(name); if(func) { func(real, e => { real = e; _caches[name] = e; }); } }; _cache_version = wire.version(); }; let fns = this.reads.sort((a,b) => (a?.pr|0) - (b?.pr|0)); for (const { fn } of fns) { fn( real, e => real = e ); }; return real; }; this.set = () => { 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; }; } 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); 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":{ if(Array.isArray(a)) { let k = [...a]; for (let name = 0; name < k.length; name++) { let value = k[name]; if(typeof value == "object") { k[name]=é.freeze(value); } }; Object.freeze(k); return k; }else{ 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(...filters){ if(this.flag & 2) { return this.piping.get(this.value,filters) }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.forEach(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.version = function(){ return this._version; } é.prototype.equalTo = function(value){ return é.isSame(value, this.value) } é.prototype.read = function(argument1, argument2, argument3){ this.flag = this.flag | 2; if(typeof argument1=="string") { this.piping.filter(argument1, argument2, argument3); }else{ this.piping.read(argument1, argument2) } } é.prototype.write = function(value, pr){ this.flag = this.flag | 4; this.piping.write(value, pr) } try{ module.exports = é; }catch{ window.é = é; } })();