diff --git a/package.json b/package.json index 28c4cd6..96b063c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@saqut/wirejs", - "version": "0.1.0", + "version": "0.2.0", "type": "commonjs", "private": false, "description": "Dont use variable, use smart variable wires !", diff --git a/readme.md b/readme.md index aec85a8..ed3bde1 100644 --- a/readme.md +++ b/readme.md @@ -2,7 +2,7 @@ ## Açıklama -WiréS, ReactJS kütüphanesinin useState ve useEffect kancalarından ilham alınarak browser ortamı için tekrar yazılmış bir kütüphanedir. +WiréS, ReactJS kütüphanesinin useState ve watch kancalarından ilham alınarak browser ortamı için tekrar yazılmış bir kütüphanedir. Verileri getter/setter fonksiyonlarıyla sararak gerçek değişikleri algılayan özelliği sayesinde gereksiz güncellemeleri göz ardı eder. Veri ilişkilerini önceden belirleyerek değişiklik olduğunda okunacak ve yazılacak verileri koşullara bağlayabilir, okuma ve yazma öncesi ara katmanlar ekleyebilirsiniz @@ -36,18 +36,18 @@ currency.get(); // --> 25 ## Değişimler -Bir kablonun değerinin değiştiğini `useEffect` özelliğiyle dinleyebilirsiniz veya birden fazla kablonun değişimini aynı anda dinlemek için `é.useEffect` fonksiyonunu kullanabilirsiniz +Bir kablonun değerinin değiştiğini `watch` özelliğiyle dinleyebilirsiniz veya birden fazla kablonun değişimini aynı anda dinlemek için `é.watch` fonksiyonunu kullanabilirsiniz ```javascript let a = é(0); let b = é(0); -a.useEffect(()=>{ +a.watch(()=>{ // a kablosu değiştiğinde burası çalışacak }) -b.useEffect(()=>{ +b.watch(()=>{ // b kablosu değiştiğinde burası çalışacak }) -é.useEffect(()=>{ +é.watch(()=>{ // a veya b değiştiğinde burası çalışacak },[a, b]) ``` @@ -57,17 +57,17 @@ let toplayan = é(0); let toplanan = é(0); let sonuc = é(0); -é.useEffect(()=>{ +é.watch(()=>{ sonuc.set( toplayan.get() + toplanan.get() ) },[toplayan, toplanan]) -toplayan.useEffect(()=>{ +toplayan.watch(()=>{ console.log("Toplayan: ",toplayan.get()) }) -toplanan.useEffect(()=>{ +toplanan.watch(()=>{ console.log("Toplanan: ",toplanan.get()) }) -sonuc.useEffect(()=>{ +sonuc.watch(()=>{ console.log("Değişen Sonuç: ",sonuc.get()) }) diff --git a/wire.js b/wire.js index 2790cb2..9d598e8 100644 --- a/wire.js +++ b/wire.js @@ -1,177 +1,257 @@ -function é(defaultValue) -{ - let value = undefined; - let effects = []; - let piping = é.pipeLine(); - let flag = 0; - let version = 0; - let diff = é.diff; - let get = () => { - return (flag & 2) ? piping.get(value) : value; - }; - let set = (newValue) => { - newValue = é.extract(newValue, value); - (flag & 4) && (newValue = piping.set(newValue)); - if(diff(newValue,value)) - { - (flag & 1) && effects.filter(e => e.o).forEach(k => k()); - value = newValue; - version++; - (flag & 1) && effects.map(e => e.f()); - } - }; - let useEffect = (e) => { - flag = flag | 1; - let k = { - f:e, - o:undefined +/* + 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; }; - requestAnimationFrame(()=> { - k.o = e(); - }) - effects.push(k); } - value = é.extract(defaultValue, value); - return { - get, - set, - useEffect, - fp: é.fingerPrint, - getVersion: () => version, - equalTo: n => é.isSame(n, value), - readLayer: (a,b) => { - flag = flag | 2; - piping.read(a,b) - }, - writeLayer: (a,b) => { - flag = flag | 4; - piping.write(a,b) + 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) } } -} -é.isWire = n => n?.fp == é.fingerPrint; -é.extract = (e,v) => typeof e=='function'?e(v):e; -é.isSame = (a,b) => !é.diff(a,b); -é.fingerPrint = Symbol("wire"); -é.useEffect = (fn, assoc) => -{ - for (const wireVar of assoc) - { - if(é.isWire(wireVar)) + é.fingerPrint = Symbol("wire"); + é.isWire = n => n?.fp == é.fingerPrint; + é.extract = (e,v) => typeof e=='function'?e(v):e; + é.isSame = (a,b) => !é.diff(a,b); + é.watch = (fn, assoc) => { + for (const wireVar of assoc) { - wireVar.useEffect(fn); + 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; } } -}; -é.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; - } -} -é.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) + const adiff = (a,b,c) => { + if(c.includes(a) && c.includes(b)) { - return true + console.error("Circular object detected !") + return cObjectDiff(a,b); } - for(let k = 0; k < a.length; k++) + let typea = a instanceof Array ? 0 : a.byteLength ? 1 : 2; + let typeb = b instanceof Array ? 0 : b.byteLength ? 1 : 2; + if(typea != typeb) { - if(é.diff(a[k], b[k])) + return true; + } + if(typea==0) + { + if(a.length != b.length) { 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)) + for(let k = 0; k < a.length; k++) { - if(é.diff(a[key], b[key], c)) + 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 } - return false } -} -é.cArrDiff = (a,b) => { - return a.length != b.length || !a.every((v,i) => a[i] === v) -}; -é.cObjectDiff = (a,b) => { - return é.cArrDiff( - Object.keys(a), - Object.keys(b) - ); -}; -é.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; - } + const cArrDiff = (a,b) => { + return a.length != b.length || !a.every((v,i) => a[i] === v) }; -} -é.cDiff.adiff = -1; -é.cDiff.some = 0; -é.cDiff.different = 1; -é.pipeLine = () => { - let k = {}; - let reads = []; - let writes = []; - k.read = (fn,pr) => reads.push({fn,pr}); - k.write = (fn,pr) => writes.push({fn,pr}); - k.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 ); + 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; + } }; - return real; + } + 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 + } }; - k.set = (val) => { - let fns = writes.sort((a,b) => (a?.pr|0) - (b?.pr|0)), - real = val; - for (const { fn } of fns) { - fn( real, e => real = e ); + é.prototype.set = function(newValue){ + if(this.flag & 16) + { + return; + } + newValue = é.extract(newValue, this.value); + if(this.flag & 4) + { + newValue = this.piping.set(newValue) }; - return real; + 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; + } }; - return k; -} \ No newline at end of file + 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.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.é = é; + } +})();