diff --git a/.gitignore b/.gitignore index 24d8869..5064a90 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ dev -node_modules \ No newline at end of file +node_modules +deno.lock \ No newline at end of file diff --git a/.npmignore b/.npmignore index b51ba3b..834a949 100644 --- a/.npmignore +++ b/.npmignore @@ -1,3 +1,5 @@ dev docs -.gitignore \ No newline at end of file +.gitignore +deno.json +deno.lock \ No newline at end of file diff --git a/README.md b/README.md index 9f7363a..d43dc93 100644 --- a/README.md +++ b/README.md @@ -110,4 +110,4 @@ function Canvas() { ## License -hstd is [WTFPL licensed](LICENSE). +hstd is [MIT licensed](LICENSE). diff --git a/docs/main.js b/docs/main.js index 6652735..219887d 100644 --- a/docs/main.js +++ b/docs/main.js @@ -105,7 +105,7 @@ export default function() {
- Hstd = HyperStandard is a minimal JavaScript library to build simple, reactive, extensible web interface. + hstd = HyperStandard is a minimal JavaScript library to build simple, reactive, extensible web interface.
@@ -131,7 +131,7 @@ export default function() {

License

- Hstd is ${Link("https://www.wtfpl.net", "WTFPL licensed")}. + hstd is ${Link("https://opensource.org/license/mit", "MIT licensed")}.
`; diff --git a/docs/mod.js b/docs/mod.js index 84cf863..541086f 100644 --- a/docs/mod.js +++ b/docs/mod.js @@ -1 +1 @@ -var M={},F=function*(t=52){let e=0;for(;e++141)+(n>156)}},I=()=>String.fromCharCode(...F()),w=Symbol.for("PTR_IDENTIFIER"),h=t=>t?.[w],$=(t,e)=>t?.constructor===e,S=t=>Object.isFrozen(t)&&Array.isArray(t),P={or:(t,e)=>t||e,and:(t,e)=>t&&e,xor:(t,e)=>t^e,sum:(t,e)=>t+e,sub:(t,e)=>t-e,mul:(t,e)=>t*e,div:(t,e)=>t/e,mod:(t,e)=>t%e},k=Object.assign({[Symbol.toPrimitive]([t],e){return typeof e=="string"?e==="string"&&typeof t=="function"?this.publish():t.toString():e===w},watch(t,e){return e&&t[2].set(e,[t[1].push(e)-1,!0]),this},abort(t,e){if(e){let n=t[2].get(e);n[1]=!1,delete t[1][n?.[0]]}return this},into([t],e=n=>n){let n=f(e(t));return this.watch(r=>n.$=e(r)),n},until(t,e){return new Promise(n=>{let r=o=>(typeof e=="function"?e(o):o===e)?(this.abort(r),n(this)):0;this.watch(r)})},switch(){return this.$=!this.$,this},not(){return this.into(t=>!t)},bool(){return this.into(t=>!!t)},tick(){let t=!1;return this.into(()=>t=!t)},toString(t,e){let n=h(e),r=this.into(o=>o.toString(n?e.$:e));return n&&e.watch(o=>r.$=this.$.toString(o)),r},publish(t){let e=Symbol(t[3]);return M[e]=this,e},text(){let t=new Text(this.$);return this.watch(e=>t.textContent=e),[t]}},...Object.keys(P).map(t=>({[t](e,n){let r=h(n),o=P[t],i=this.into(l=>o(l,r?n.$:n));return r&&n.watch(l=>i.$=o(this.$,l)),i}}))),f=(t,[e,n]=[])=>{let r=[],o=new WeakMap,i=Object.assign({name:"$"},n),l=function(u,c,a){return(c||u!==s[0])&&(s[0]=u,r.forEach(m=>o.get(m)?.[1]?m(u):0)),a},s=[t,r,o,x+(n?.name||""),l];return new Proxy(Object.defineProperties(Object(function(...u){let[c]=s;return $(c,Function)?c.apply(null,u):c}),{name:{value:i.name}}),{get(u,c,a){let[m]=s,Y=typeof c;return c==="$"?m:c==="refresh"?l.bind(null,m,!0,a):c==="constructor"||c===w?!0:c===Symbol.hasInstance?()=>!1:k[c]?.bind?.(a,s)||($(m[c],Function)?function(...g){let y=g.map((b,L)=>h(b)?b.watch(N=>(y[L]=N,E.$=a.$[c](...y))).$:b),E=a.into(b=>b[c](...y));return E}:a.into(g=>g[c]))},set(u,c,a){if(c=="$"){let m=e?e(a):a;$(m,Promise)?m.then(l):l(m)}else s[0][c]=h(a)?a.watch(m=>s[0][c]=m).$:a;return!0}})},H=(t,e)=>{let n=I(),r=t.join(n),o=new RegExp(n,"g"),i=e.map((u,c)=>h(u)?u.watch(()=>(i[c]=u.$,s.$=l())).$:u),l=(u=0)=>r.replaceAll(o,()=>i[u++]),s=f(l());return s},W=(t,...e)=>(S(t)&&S(t?.raw)?H:f)(t,e),x;for(;(x=I())in globalThis;);Object.defineProperty(globalThis,x,{value:t=>M[t],configurable:!1,enumerable:!1});var d=(t,e)=>{let n={},r=new Proxy({},{get(l,s){return s===Symbol.toPrimitive?i:s==="$"?i():(n[s]||=f(t.bind(null,s),void 0,{name:e?e(s):""})).publish()}}),o=f(l=>{let s={};return Object.keys(l).forEach(u=>s[r[u]]=l[u]),s}),i=()=>o.publish();return r};var j="\0",p=new WeakMap,T=function(t,e,n){j.includes(`\0${t}\0`)||(globalThis.addEventListener(t,r=>p.get(r.target)?.[t]?.forEach(o=>o(r)),{passive:!0}),j+=t+"\0"),p.has(n)||p.set(n,{}),(p.get(n)[t]||=[]).push(e)},z=d(T,t=>"on."+t);var O=Symbol.for("HTML_IDENTIFIER"),A=new WeakMap,B=document.createDocumentFragment(),D={[Symbol.toPrimitive](t){return typeof t=="string"?[...this[Symbol.iterator]().map(e=>e.outerHTML)].join(""):t===O},toString(){return this[Symbol.toPrimitive]("string")}},_={get(t,e){let n=t[e];return typeof n=="function"&&n.toString().endsWith("() { [native code] }")?n.bind(t):n}},R=(t,e)=>Reflect.ownKeys(e).forEach(G.bind(null,t,e)),G=function(t,e,n){let[r,o]=t,i=e[n],l=typeof n;if(l=="symbol"){let s=globalThis[n.description.slice(0,52)]?.(n);if(!h(s))return;let u=s.$(i,o);if(u?.constructor!==Object)return;R(t,u)}else l=="string"&&(h(i)?(o[n]=i.watch(s=>o[n]=s).$,"\0value\0checked\0".includes(`\0${n}\0`)&&n in o&&T("input",({target:{[n]:s}})=>i.$="number\0range".includes(o.type)?Number(s):s,o)):n=="id"&&!(i in r)?r[i]=new Proxy(o,_):o[n]=i)},Z=function([t,e],n,r,o,i){let l=n[i];e[i]?R([r,o],l):o.replaceWith(...l[Symbol.toPrimitive]?.(O)?l:h(l)?l.text():[new Text(l)]),o.removeAttribute(t)},K=function(t,e){let n=t[2](),r={};return n.querySelectorAll(`[${t[0]}]`).forEach(Z.bind(null,t,e,r)),Object.assign(n.childNodes,D,{then(o){return o(r),this}})},q=(t,...e)=>{let n=A.get(t);if(!n){let r=t.join(""),o=0,i;for(;r.includes(i="t"+(BigInt(Math.floor(Math.random()*Number.MAX_SAFE_INTEGER))**8n).toString(36)););r=t.join(i);let l=i.length,s=[...r.matchAll(new RegExp(`<(?:(!--|\\/[^a-zA-Z])|(\\/?[a-zA-Z][^>\\s]*)|(\\/?$))[\\s].*?${i}`,"g"))].map(({0:{length:a},index:m})=>m+a),u=[],c=document.createElement("div");B.appendChild(c),c.innerHTML=r.replaceAll(i,(a,m)=>(u[o++]=s.includes(m+l))?i:`
`),A.set(t,n=K.bind(null,[i,u,c.cloneNode.bind(c,!0)]))}return n(e)};var Q=/[A-Z]{1}/g,X={},v=t=>X[t]||="-"+t.toLowerCase(),J={},C=t=>J[t]||=t.replaceAll(Q,v),U=d(function(t,e,{style:n}){let r=C(t);n.setProperty(r,h(e)?e.watch(o=>n.setProperty(r,o)).$:e)},t=>"css-"+C(t));export{W as $,U as css,q as h,z as on,d as prop}; +var g=t=>{let e=new WeakMap,r;return n=>e.has(n)?e.get(n):(e.set(n,r=t(n)),r)};var M="\0",R=g(()=>({})),d=function(t,e,r){M.includes(`\0${t}\0`)||(globalThis.addEventListener(t,n=>R(n.target)[t]?.forEach?.(o=>o(n)),{passive:!0}),M+=t+"\0"),(R(r)[t]||=[]).push(e)};var f=(t,e)=>t?.constructor===e,x=t=>Object.isFrozen(t)&&f(t,Array);var{Promise:P,Function:T}=globalThis,S=Symbol.for("PTR_IDENTIFIER"),a=t=>t?.[S],C=()=>String.fromCharCode(...B()),A={},B=function*(t=52){let e=0;for(;e++141)+(r>156)}},j={or:(t,e)=>t||e,and:(t,e)=>t&&e,xor:(t,e)=>t^e,sum:(t,e)=>t+e,sub:(t,e)=>t-e,mul:(t,e)=>t*e,div:(t,e)=>t/e,mod:(t,e)=>t%e},W=Object.assign({[Symbol.toPrimitive]([t],e){return typeof e=="string"?e==="string"&&f(t,T)?this.publish():t.toString():e===S},watch(t,e){return e&&t[2].set(e,[t[1].push(e)-1,!0]),this},abort(t,e){if(e){let r=t[2].get(e);r[1]=!1,delete t[1][r?.[0]]}return this},into([t],e=r=>r){let r=o=>{let c=e(o);return f(c,P)?(c.then(s=>n.$=s),void 0):n.$=c},n=b();return r(t),this.watch(r),n},until(t,e){return new P(r=>{let n=o=>(f(e,T)?e(o):o===e)?(this.abort(n),r(this)):0;this.watch(n)})},switch(){return this.$=!this.$,this},not(){return this.into(t=>!t)},bool(){return this.into(t=>!!t)},isit(t,e){return this.into(r=>r?t:e)},tick(){let t=!1;return this.into(()=>t=!t)},toString(t,e){let r=a(e),n=this.into(o=>o.toString(r?e.$:e));return r&&e.watch(o=>n.$=this.$.toString(o)),n},publish(t){let e=Symbol(t[3]);return A[e]=this,e},text(){let t=new Text(this.$);return this.watch(e=>t.textContent=e),[t]},timeout(t,e){let r=b(this.$),n;return this.watch(o=>{clearTimeout(n),n=setTimeout(()=>r.$=o,a(e)?e.$:e)}),r}},...Object.keys(j).map(t=>({[t](e,r){let n=a(r),o=j[t],c=this.into(s=>o(s,n?r.$:r));return n&&r.watch(s=>c.$=o(this.$,s)),c}}))),b=(t,[e,r]=[])=>{let n=[],o=new WeakMap,c=Object.assign({name:"$",writable:!0},r),s=function(u,l,m){return(l||u!==i[0])&&(i[0]=u,n.forEach(h=>o.get(h)?.[1]?h(u):0)),m},i=[t,n,o,E+(r?.name||"")];return new Proxy(Object.defineProperties(Object(function(...u){let[l]=i;return f(l,T)?l.apply(null,u):l}),{name:{value:c.name}}),{get(u,l,m){let[h]=i;return l==="$"?h:l==="refresh"?s.bind(null,h,!0,m):l==="constructor"||l===S?!0:l===Symbol.hasInstance?()=>!1:W[l]?.bind?.(m,i)||(f(h[l],T)?function(...y){let w=y.map((p,N)=>a(p)?p.watch(z=>(w[N]=z,I.$=m.$[l](...w))).$:p),I=m.into(p=>p[l](...w));return I}:m.into(y=>y[l]))},set(u,l,m){if(c.writable)if(l=="$"){let h=e?e(m):m;f(h,P)?h.then(s):s(h)}else i[0][l]=a(m)?m.watch(h=>i[0][l]=h).$:m;return!0}})},E;for(;(E=C())in globalThis;);Object.defineProperty(globalThis,E,{value:t=>A[t],configurable:!1,enumerable:!1});var _=g(t=>{let e=C();return[t.join(e),new RegExp(e,"g")]}),k=(t,e)=>{let[r,n]=_(t),o=e.map((i,u)=>a(i)?i.watch(()=>(o[u]=i.$,s.$=c())).$:i),c=(i=0)=>r.replaceAll(n,()=>o[i++]),s=b(c());return s},F={};var at=new Proxy((t,...e)=>(x(t)&&x(t?.raw)?k:b)(t,e),{get:(t,e)=>{if(e===Symbol.hasInstance)return a;let r=F[e];return!r&&!f(globalThis[e],Function)&&(r=F[e]=b(globalThis[e]),d("resize",({target:n})=>r.$=n[e],globalThis)),r||D[e]}}),D=b(globalThis);var O=Symbol.for("HTML_IDENTIFIER"),G=document.createDocumentFragment(),K={[Symbol.toPrimitive](t){return typeof t=="string"?[...this[Symbol.iterator]().map(e=>e.outerHTML)].join(""):t===O},toString(){return this[Symbol.toPrimitive]("string")}},Z={get(t,e){let r=t[e];return f(r,Function)?r.bind(t):r}},H=(t,e)=>Reflect.ownKeys(e).forEach(q.bind(null,t,e)),q=function(t,e,r){let[n,o]=t,c=e[r],s=typeof r;if(s=="symbol"){let i=globalThis[r.description.slice(0,52)]?.(r);if(!a(i))return;let u=i.$(c,o);if(u?.constructor!==Object)return;H(t,u)}else s=="string"&&(a(c)?(o[r]=c.watch(i=>o[r]=i).$,"\0value\0checked\0".includes(`\0${r}\0`)&&r in o&&d("input",({target:{[r]:i}})=>c.$="number\0range".includes(o.type)?Number(i):i,o)):r=="id"&&!(c in n)?n[c]=new Proxy(o,Z):o[r]=c)},Q=function([t,e],r,n,o,c){let s=r[c];e[c]?H([n,o],s):o.replaceWith(...s[Symbol.toPrimitive]?.(O)?s:a(s)?s.text():[new Text(s)]),o.removeAttribute(t)},X=function(t,e){let r=t[2](),n={};return r.querySelectorAll(`[${t[0]}]`).forEach(Q.bind(null,t,e,n)),Object.assign(r.childNodes,K,{then(o){return o(n),this}})},J=g(t=>{let e=t.join(""),r=0,n="t";for(;e.includes(n+=BigInt(Math.floor(Math.random()*Number.MAX_SAFE_INTEGER)).toString(36)););e=t.join(n);let o=n.length,c=[...e.matchAll(new RegExp(`<(?:(!--|\\/[^a-zA-Z])|(\\/?[a-zA-Z][^>\\s]*)|(\\/?$))[\\s].*?${n}`,"g"))].map(({0:{length:u},index:l})=>l+u),s=[],i=document.createElement("div");return G.appendChild(i),i.innerHTML=e.replaceAll(n,(u,l)=>(s[r++]=c.includes(l+o))?n:`
`),X.bind(null,[n,s,i.cloneNode.bind(i,!0)])}),dt=(t,...e)=>J(t)(e);var $=(t,e)=>{let r={},n=new Proxy({},{get(s,i){return i===Symbol.toPrimitive?c:i==="$"?c():(r[i]||=b(t.bind(null,i),void 0,{name:e?e(i):""})).publish()}}),o=b(s=>{let i={};return Reflect.ownKeys(s).forEach(u=>i[n[u]]=s[u]),i}),c=()=>o.publish();return n};var xt=$(d,t=>"on."+t);var U=/[A-Z]{1}/g,Y={},v=t=>Y[t]||="-"+t.toLowerCase(),V={},L=t=>V[t]||=t.replaceAll(U,v),Et=$(function(t,e,{style:r}){let n=L(t);r.setProperty(n,a(e)?e.watch(o=>r.setProperty(n,o)).$:e)},t=>"css-"+L(t));export{at as $,Et as css,dt as h,xt as on}; diff --git a/package-lock.json b/package-lock.json index ab50944..fc97c39 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "libh", - "version": "0.0.108", + "version": "0.1.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "libh", - "version": "0.0.108", + "version": "0.1.7", "license": "WTFPL" } } diff --git a/package.json b/package.json index 206336c..f9be916 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hstd", - "version": "0.1.1", + "version": "0.1.7", "description": "simple library to build reactive, extensive, reusable web interface.", "type": "module", "main": "./src/mod.js", diff --git a/src/$.js b/src/$.js index bd51562..c233783 100644 --- a/src/$.js +++ b/src/$.js @@ -1,366 +1,73 @@ -const - - publishedPtr = {}, - - resolverSignatureGenCB = function*(length = 52) { - let c = 0; - while(c++ < length) { - let buf = Math.floor(Math.random() * 31) - yield 0x7f + buf + (buf > 0x8d) + (buf > 0x9c) - }; - }, - - createSignature = () => String.fromCharCode(...resolverSignatureGenCB()), - - PTR_IDENTIFIER = Symbol.for("PTR_IDENTIFIER"), - - isPtr = (ptr) => ptr?.[PTR_IDENTIFIER], - - isConstructedFrom = (object, proto) => object?.constructor === proto, - - isFrozenArray = (arr) => Object.isFrozen(arr) && Array.isArray(arr), - - logicOps = { - or: (a, b) => a || b, - and: (a, b) => a && b, - xor: (a, b) => a ^ b, - - sum: (a, b) => a + b, - sub: (a, b) => a - b, - mul: (a, b) => a * b, - div: (a, b) => a / b, - mod: (a, b) => a % b, - - // rsh: (a, b) => a >> b, - // ursh: (a, b) => a >>> b, - // lsh: (a, b) => a << b, - }, - - opTemp = Object.assign( - - { - - [Symbol.toPrimitive]([value], hint) { - - return ( - typeof hint === "string" - ? hint === "string" && typeof value == "function" - ? this.publish() - : value.toString() - : hint === PTR_IDENTIFIER - ); - - }, - - watch(buffer, watcherFn) { - - if(watcherFn) { - buffer[2].set(watcherFn, [ - buffer[1].push(watcherFn) - 1, - !0 - ]) - }; - - return this; - - }, - - abort(buffer, watcherFn) { - - if(watcherFn) { - const info = buffer[2].get(watcherFn); - info[1] = !1; - delete buffer[1][info?.[0]]; - }; - - return this; - - }, - - into([value], transformerFn = $ => $) { - - const newPtr = createPtr(transformerFn(value)) - - this.watch($ => newPtr.$ = transformerFn($)); - - return newPtr; - }, - - until(_, value) { - - return new Promise(r => { - - const watcherFn = $ => (typeof value == "function" ? value($) : $ === value) - ? (this.abort(watcherFn), r(this)) - : 0 - ; - - this.watch(watcherFn); - - }) - }, - - // refresh(buffer) { - // buffer[4]?.(0, true, this); - // return this; - // }, - - // sync(buffer, ...ptrs) { - // ptrs.forEach(ptr => isPtr(ptr) ? ptr.watch($ => this.$ = this.$) : 0) - // }, - - switch() { - - this.$ = !this.$; - - return this; - - }, - - not() { - - return this.into($ => !$) - - }, - - bool() { - - return this.into($ => !!$) - - }, - - tick() { - - let bool = false; - - return this.into(() => bool = !bool) - - }, - - toString(_, base) { - - const - isPtrCache = isPtr(base), - ptr = this.into($ => $.toString(isPtrCache ? base.$ : base)) - ; - - isPtrCache ? base.watch($ => ptr.$ = this.$.toString($)) : 0; - - return ptr; - - }, - - publish(buffer) { - - const symbol = Symbol(buffer[3]); - - publishedPtr[symbol] = this; - - return symbol; - - }, - - text() { - - const text = new Text(this.$); - - this.watch($ => text.textContent = $); +import { listen } from "./core/listen.js"; +import { createCache } from "./core/cache.js"; +import { isFrozenArray, isConstructedFrom } from "./core/checker.js"; +import { createPointer, createSignature, isPointer } from "./core/pointer.js"; - return [text] - - } - }, - - ...Object.keys(logicOps).map(op => ({ - - [op](_, value) { - - const - isPtrCache = isPtr(value), - boolOp = logicOps[op], - ptr = this.into($ => boolOp($, isPtrCache ? value.$ : value)) - ; - - isPtrCache ? value.watch($ => ptr.$ = boolOp(this.$, $)) : 0; - - return ptr; - - } - - })), - - // ...Object.keys(Math).filter(x => typeof Math[x] == "function").map(x => ({ - // [x](buffer, args) { - // - // } - // })) - - ), - - createPtr = (value, [setter, options] = []) => { - - const - watchers = [], - watcherInfo = new WeakMap(), - formattedOptions = Object.assign({ name: "$" }, options), - execWatcher = function (value, force, ptr) { - (force || (value !== buffer[0])) - ? (buffer[0] = value, watchers.forEach(fn => watcherInfo.get(fn)?.[1] ? fn(value) : 0)) - : 0 - ; - return ptr; - }, - buffer = [ - value, - watchers, - watcherInfo, - signature + (options?.name || ""), - execWatcher - ] - ; - - return new Proxy( - - Object.defineProperties(Object(function(...args) { - - const [tmp] = buffer; - - return isConstructedFrom(tmp, Function) ? tmp.apply(null, args) : tmp; - - }), { name: { value: formattedOptions.name } }), - - { - - get(_, prop, reciever) { - - const - [tmp] = buffer, - typeofProp = typeof prop - ; - - return ( - - // typeofProp == "string" - - // string - - /**? */ prop === "$" ? tmp - : prop === "refresh" ? execWatcher.bind(null, tmp, !0, reciever) - : prop === "constructor" ? !0 - - - : prop === PTR_IDENTIFIER ? !0 - : prop === Symbol.hasInstance ? () => !1 - - : ( - opTemp[prop]?.bind?.(reciever, buffer) || ( - - isConstructedFrom(tmp[prop], Function) - - ? function(...args) { - - const - argMap = args.map((arg, i) => ( - - isPtr(arg) - - ? arg.watch($ => ( - argMap[i] = $, - ptrBuf.$ = reciever.$[prop](...argMap) - )).$ - - : arg - )), - - ptrBuf = reciever.into($ => $[prop](...argMap)) - ; - - return ptrBuf - - } - - : reciever.into($ => $[prop]) - - ) - ) - - // symbol - - - // : ("" - - // ) - ); - - }, - - set(_, prop, newValue) { - - if(prop == "$") { - - const tmp = setter ? setter(newValue) : newValue; - - isConstructedFrom(tmp, Promise) ? tmp.then(execWatcher) : execWatcher(tmp) - - } else { - - buffer[0][prop] = ( - isPtr(newValue) - ? newValue.watch($ => buffer[0][prop] = $).$ - : newValue - ) - } +const - return !0; + getLiteralTempCache = createCache((s) => { - } + const code = createSignature(); - } + return [s.join(code), new RegExp(code, "g")] - ) - }, + }), createTemp = (s, v) => { const - code = createSignature(), - temp = s.join(code), - tempMatcherRegex = new RegExp(code, "g"), + [temp, tempMatcherRegex] = getLiteralTempCache(s), vMap = v.map((vt, i) => ( - isPtr(vt) + isPointer(vt) ? vt.watch(() => (vMap[i] = vt.$, ptr.$ = refreshTemp())).$ : vt )), refreshTemp = (x = 0) => temp.replaceAll(tempMatcherRegex, () => vMap[x++]), - ptr = createPtr(refreshTemp()) + ptr = createPointer(refreshTemp()) ; return ptr; }, - // createEffect = (watcher, ...ptrs) => { - // const tmp = createPtr(watcher()); + globalPropPtrCache = {}, + + globalPropCaptureTarget = "\0innerWidth\0innerHeight\0outerWidth\0outerHeight\0", - // ptrs.forEach((ptr) => ptr.watch(() => tmp.$ = watcher())); + // valueFetcherRAFCallback = () => { + + // } - // return tmp; + $ = new Proxy( + (x, ...y) => (isFrozenArray(x) && isFrozenArray(x?.raw) ? createTemp : createPointer)(x, y), + { + get: (_, prop) => { - // }, + if(prop === Symbol.hasInstance) return isPointer; - $ = (x, ...y) => (isFrozenArray(x) && isFrozenArray(x?.raw) ? createTemp : createPtr)(x, y) -; + let tmp = globalPropPtrCache[prop]; -let signature; + if(!tmp && !isConstructedFrom(globalThis[prop], Function)) { -while((signature = createSignature()) in globalThis); + tmp = globalPropPtrCache[prop] = createPointer(globalThis[prop]); + + listen( + "resize", + ({ target }) => tmp.$ = target[prop], + globalThis, + ); + + } + + return tmp || globalPtr[prop]; + + } + } + ) +; -Object.defineProperty(globalThis, signature, { - value: (symbol) => publishedPtr[symbol], - configurable: !1, - enumerable: !1 -}); +const globalPtr = createPointer(globalThis); /** * @@ -369,4 +76,4 @@ Object.defineProperty(globalThis, signature, { * @param { object } options * @returns { object } */ -export { $, isPtr, createPtr }; \ No newline at end of file +export { $ }; \ No newline at end of file diff --git a/src/core/cache.js b/src/core/cache.js new file mode 100644 index 0000000..4f57d9c --- /dev/null +++ b/src/core/cache.js @@ -0,0 +1,11 @@ +export const createCache = (setter) => { + + const cacheMap = new WeakMap(); + let resultBuf; + + return (template) => (cacheMap.has(template) + ? cacheMap.get(template) + : (cacheMap.set(template, resultBuf = setter(template)), resultBuf) + ); + +} \ No newline at end of file diff --git a/src/core/checker.js b/src/core/checker.js new file mode 100644 index 0000000..3bc8dea --- /dev/null +++ b/src/core/checker.js @@ -0,0 +1,7 @@ +export const + + isConstructedFrom = (object, proto) => object?.constructor === proto, + + isFrozenArray = (arr) => Object.isFrozen(arr) && isConstructedFrom(arr, Array) + +; \ No newline at end of file diff --git a/src/core/listen.js b/src/core/listen.js new file mode 100644 index 0000000..abafa4e --- /dev/null +++ b/src/core/listen.js @@ -0,0 +1,35 @@ +import { createCache } from "./cache.js"; + +let registeredEvent = "\0"; + +const + + targetCache = createCache(() => ({})), + + /** + * @param { string } eventName + * @param { Function } callbackFn + * @param { HTMLElement } ref + * + * @returns { void } + */ + listen = function (eventName, callbackFn, ref) { + + if(!registeredEvent.includes(`\0${eventName}\0`)) { + + globalThis.addEventListener( + eventName, + e => targetCache(e.target)[eventName]?.forEach?.(x => x(e)), + { passive: !0 } + ); + + registeredEvent += eventName + "\0"; + + }; + + (targetCache(ref)[eventName] ||= []).push(callbackFn); + + } +; + +export { listen }; \ No newline at end of file diff --git a/src/core/pointer.js b/src/core/pointer.js new file mode 100644 index 0000000..12e3190 --- /dev/null +++ b/src/core/pointer.js @@ -0,0 +1,346 @@ +import { isConstructedFrom } from "./checker.js"; + +const + + { Promise, Function } = globalThis, + + PTR_IDENTIFIER = Symbol.for("PTR_IDENTIFIER"), + + isPointer = (ptr) => ptr?.[PTR_IDENTIFIER], + + createSignature = () => String.fromCharCode(...resolverSignatureGenCB()), + + publishedPtr = {}, + + resolverSignatureGenCB = function*(length = 52) { + let c = 0; + while(c++ < length) { + let buf = Math.floor(Math.random() * 31) + yield 0x7f + buf + (buf > 0x8d) + (buf > 0x9c) + }; + }, + + logicOps = { + or: (a, b) => a || b, + and: (a, b) => a && b, + xor: (a, b) => a ^ b, + + sum: (a, b) => a + b, + sub: (a, b) => a - b, + mul: (a, b) => a * b, + div: (a, b) => a / b, + mod: (a, b) => a % b, + + // rsh: (a, b) => a >> b, + // ursh: (a, b) => a >>> b, + // lsh: (a, b) => a << b, + }, + + opTemp = Object.assign( + + { + + [Symbol.toPrimitive]([value], hint) { + + return ( + typeof hint === "string" + ? hint === "string" && isConstructedFrom(value, Function) + ? this.publish() + : value.toString() + : hint === PTR_IDENTIFIER + ); + + }, + + watch(buffer, watcherFn) { + + if(watcherFn) { + buffer[2].set(watcherFn, [ + buffer[1].push(watcherFn) - 1, + !0 + ]) + }; + + return this; + + }, + + abort(buffer, watcherFn) { + + if(watcherFn) { + const info = buffer[2].get(watcherFn); + info[1] = !1; + delete buffer[1][info?.[0]]; + }; + + return this; + + }, + + into([value], transformerFn = $ => $) { + + const + binder = value => { + const tmp = transformerFn(value); + return isConstructedFrom(tmp, Promise) + ? (tmp.then($ => newPtr.$ = $), undefined) + : newPtr.$ = tmp; + }, + newPtr = createPointer() + ; + + binder(value); + + this.watch(binder); + + return newPtr; + }, + + until(_, value) { + + return new Promise(r => { + + const watcherFn = $ => (isConstructedFrom(value, Function) ? value($) : $ === value) + ? (this.abort(watcherFn), r(this)) + : 0 + ; + + this.watch(watcherFn); + + }) + }, + + switch() { + + this.$ = !this.$; + + return this; + + }, + + not() { + + return this.into($ => !$) + + }, + + bool() { + + return this.into($ => !!$) + + }, + + isit(ifTrue, ifFalse) { + + return this.into($ => $ ? ifTrue : ifFalse); + + }, + + tick() { + + let bool = false; + + return this.into(() => bool = !bool) + + }, + + toString(_, base) { + + const + isPtrCache = isPointer(base), + ptr = this.into($ => $.toString(isPtrCache ? base.$ : base)) + ; + + isPtrCache ? base.watch($ => ptr.$ = this.$.toString($)) : 0; + + return ptr; + + }, + + publish(buffer) { + + const symbol = Symbol(buffer[3]); + + publishedPtr[symbol] = this; + + return symbol; + + }, + + text() { + + const text = new Text(this.$); + + this.watch($ => text.textContent = $); + + return [text] + + }, + + timeout(_, delay) { + + const ptr = createPointer(this.$); + let timeoutIdBuf; + + this.watch($ => { + clearTimeout(timeoutIdBuf); + timeoutIdBuf = setTimeout(() => ptr.$ = $, isPointer(delay) ? delay.$ : delay) + }) + + return ptr; + + }, + }, + + ...Object.keys(logicOps).map(op => ({ + + [op](_, value) { + + const + isPtrCache = isPointer(value), + boolOp = logicOps[op], + ptr = this.into($ => boolOp($, isPtrCache ? value.$ : value)) + ; + + isPtrCache ? value.watch($ => ptr.$ = boolOp(this.$, $)) : 0; + + return ptr; + + } + + })), + + // ...Object.keys(Math).filter(x => typeof Math[x] == "function").map(x => ({ + // [x](buffer, args) { + // + // } + // })) + + ), + + createPointer = (value, [setter, options] = []) => { + + const + watchers = [], + watcherInfo = new WeakMap(), + formattedOptions = Object.assign({ name: "$", writable: true }, options), + execWatcher = function (value, force, ptr) { + (force || (value !== buffer[0])) + ? (buffer[0] = value, watchers.forEach(fn => watcherInfo.get(fn)?.[1] ? fn(value) : 0)) + : 0 + ; + return ptr; + }, + buffer = [ + value, + watchers, + watcherInfo, + signature + (options?.name || "") + ] + ; + + return new Proxy( + + Object.defineProperties(Object(function(...args) { + + const [tmp] = buffer; + + return isConstructedFrom(tmp, Function) ? tmp.apply(null, args) : tmp; + + }), { name: { value: formattedOptions.name } }), + + { + + get(_, prop, reciever) { + + const + [tmp] = buffer + ; + + return ( + prop === "$" ? tmp + : prop === "refresh" ? execWatcher.bind(null, tmp, !0, reciever) + : prop === "constructor" ? !0 + + + : prop === PTR_IDENTIFIER ? !0 + : prop === Symbol.hasInstance ? () => !1 + + : ( + opTemp[prop]?.bind?.(reciever, buffer) || ( + + isConstructedFrom(tmp[prop], Function) + + ? function(...args) { + + const + argMap = args.map((arg, i) => ( + + isPointer(arg) + + ? arg.watch($ => ( + argMap[i] = $, + ptrBuf.$ = reciever.$[prop](...argMap) + )).$ + + : arg + )), + + ptrBuf = reciever.into($ => $[prop](...argMap)) + ; + + return ptrBuf + + } + + : reciever.into($ => $[prop]) + + ) + ) + ); + + }, + + set(_, prop, newValue) { + + if(formattedOptions.writable) { + + if(prop == "$") { + + const tmp = setter ? setter(newValue) : newValue; + + isConstructedFrom(tmp, Promise) ? tmp.then(execWatcher) : execWatcher(tmp) + + } else { + + buffer[0][prop] = ( + isPointer(newValue) + ? newValue.watch($ => buffer[0][prop] = $).$ + : newValue + ) + } + } + + + return !0; + + } + + } + + ) + } +; + +let signature; + +while((signature = createSignature()) in globalThis); + +Object.defineProperty(globalThis, signature, { + value: (symbol) => publishedPtr[symbol], + configurable: !1, + enumerable: !1 +}); + + +export { createPointer, createSignature, isPointer } \ No newline at end of file diff --git a/src/prop.js b/src/core/prop.js similarity index 62% rename from src/prop.js rename to src/core/prop.js index e59831d..0a76f74 100644 --- a/src/prop.js +++ b/src/core/prop.js @@ -1,4 +1,4 @@ -import { createPtr } from "./$.js" +import { createPointer } from "./pointer.js" /** * @@ -16,16 +16,16 @@ export const prop = (callback, nameFn) => { return ( prop === Symbol.toPrimitive ? publisher : prop === "$" ? publisher() - : (cache[prop] ||= createPtr(callback.bind(null, prop), undefined, { name: nameFn ? nameFn(prop) : "" })).publish() + : (cache[prop] ||= createPointer(callback.bind(null, prop), undefined, { name: nameFn ? nameFn(prop) : "" })).publish() ) } }), - bundled = createPtr((value) => { + bundled = createPointer((value) => { const buf = {}; - Object.keys(value).forEach((prop) => buf[proxy[prop]] = value[prop]); + Reflect.ownKeys(value).forEach((prop) => buf[proxy[prop]] = value[prop]); return buf; diff --git a/src/css.js b/src/css.js index da71abc..70a2701 100644 --- a/src/css.js +++ b/src/css.js @@ -1,5 +1,5 @@ -import { isPtr } from "./$.js" -import { prop } from "./prop.js"; +import { prop } from "./core/prop.js"; +import { isPointer } from "./core/pointer.js" const @@ -23,7 +23,7 @@ const formedStylePropBuf, - isPtr(styleValue) + isPointer(styleValue) ? styleValue.watch($ => styleDec.setProperty(formedStylePropBuf, $)).$ : styleValue ) diff --git a/src/h.js b/src/h.js index 5dde032..d1e8685 100644 --- a/src/h.js +++ b/src/h.js @@ -1,12 +1,12 @@ -import { isPtr } from "./$.js"; -import { aEL } from "./on.js"; +import { listen } from "./core/listen.js"; +import { isPointer } from "./core/pointer.js"; +import { createCache } from "./core/cache.js"; +import { isConstructedFrom } from "./core/checker.js"; const HTML_IDENTIFIER = Symbol.for("HTML_IDENTIFIER"), - elementTempMap = new WeakMap(), - df = document.createDocumentFragment(), fragmentTemp = { @@ -31,10 +31,7 @@ const const targetValue = target[prop]; - return ( - typeof targetValue == "function" && - targetValue.toString().endsWith("() { [native code] }") - ) + return isConstructedFrom(targetValue, Function) ? targetValue.bind(target) : targetValue ; @@ -55,7 +52,7 @@ const if(attrPropType == "symbol") { const attrPtr = globalThis[attrProp.description.slice(0, 52)]?.(attrProp); - if(!isPtr(attrPtr)) return; + if(!isPointer(attrPtr)) return; const buf = attrPtr.$(attrValue, ref); if(buf?.constructor !== Object) return; @@ -64,11 +61,11 @@ const } else if(attrPropType == "string") { - if(isPtr(attrValue)) { + if(isPointer(attrValue)) { ref[attrProp] = attrValue.watch($ => ref[attrProp] = $).$; - if("\0value\0checked\0".includes(`\0${attrProp}\0`) && attrProp in ref) aEL( + if("\0value\0checked\0".includes(`\0${attrProp}\0`) && attrProp in ref) listen( "input", ({ target: { [attrProp]: value } }) => attrValue.$ = ( "number\0range".includes(ref.type) @@ -102,7 +99,7 @@ const ref.replaceWith(...( vBody[Symbol.toPrimitive]?.(HTML_IDENTIFIER) ? vBody - : isPtr(vBody) ? vBody.text() + : isPointer(vBody) ? vBody.text() : [new Text(vBody)] )); @@ -132,29 +129,17 @@ const } ); - } -; - -/** - * @param { TemplateStringsArray } s - * @param { (string | number | { [key: (string | symbol)]: any })[] } v - * - * @returns { NodeList } - */ - -export const h = (s, ...v) => { - - let createElementTemp = elementTempMap.get(s); + }, - if(!createElementTemp) { + getHTMLTempCache = createCache((s) => { let joined = s.join(""), replacementCounter = 0, - tokenBuf + tokenBuf = "t" ; - while(joined.includes(tokenBuf = "t" + (BigInt(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)) ** 8n).toString(36))); + while(joined.includes(tokenBuf += BigInt(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)).toString(36))); joined = s.join(tokenBuf); @@ -176,8 +161,16 @@ export const h = (s, ...v) => { : `
` ); - elementTempMap.set(s, createElementTemp = elementTempBase.bind(null, [tokenBuf, placeholder, node.cloneNode.bind(node, !0)])) - }; + return elementTempBase.bind(null, [tokenBuf, placeholder, node.cloneNode.bind(node, !0)]); + + }) +; + +/** + * @param { TemplateStringsArray } s + * @param { (string | number | { [key: (string | symbol)]: any })[] } v + * + * @returns { NodeList } + */ - return createElementTemp(v) -}; \ No newline at end of file +export const h = (s, ...v) => getHTMLTempCache(s)(v); \ No newline at end of file diff --git a/src/mod.js b/src/mod.js index 2e73485..f77d220 100644 --- a/src/mod.js +++ b/src/mod.js @@ -1,5 +1,4 @@ -export { $ } from "./$.js" -export { h } from "./h.js" -export { on } from "./on.js" -export { css } from "./css.js" -export { prop } from "./prop.js" \ No newline at end of file +export * from "./$.js" +export * from "./h.js" +export * from "./on.js" +export * from "./css.js" \ No newline at end of file diff --git a/src/on.js b/src/on.js index 1c7b339..f71a374 100644 --- a/src/on.js +++ b/src/on.js @@ -1,42 +1,16 @@ -import { prop } from "./prop.js"; - -let registeredEvent = "\0"; +import { prop } from "./core/prop.js"; +import { listen } from "./core/listen.js"; const - targetMap = new WeakMap(), - - /** - * @param { string } eventName - * @param { Function } callbackFn - * @param { HTMLElement } ref - * - * @returns { void } - */ - aEL = function (eventName, callbackFn, ref) { - - if(!registeredEvent.includes(`\0${eventName}\0`)) { - globalThis.addEventListener( - eventName, - e => targetMap.get(e.target)?.[eventName]?.forEach(x => x(e)), - { passive: !0 } - ); - registeredEvent += eventName + "\0"; - }; - - if(!targetMap.has(ref)) targetMap.set(ref, {}); - - (targetMap.get(ref)[eventName] ||= []).push(callbackFn); - - }, - on = prop( - aEL, + listen, prop => "on." + prop ) + ; -export { on, aEL } \ No newline at end of file +export { on } \ No newline at end of file