vaderjs 1.3.3-7bn28b17d42e1 → 1.3.3-7u27417d42e1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -81,7 +81,7 @@ export default function(req, res){
81
81
 
82
82
  return <>
83
83
  <h1>${count}</h1>
84
- <button onClick={(event)=>{setCount(++count)}}>
84
+ <button onClick={(event)=>{setCount(count + 1)}}>
85
85
  </>
86
86
  }
87
87
 
@@ -130,7 +130,7 @@ export function Layout({title, keywords, description, children}){
130
130
 
131
131
  export default function (req, res){
132
132
  return <>
133
- <Layout ${{title:'home', description:'home page', keywords:'vader.js', logo:''}}>
133
+ <Layout $={{title:'home', description:'home page', keywords:'vader.js', logo:''}}>
134
134
  <h1> Hello World</h1>
135
135
  </Layout>
136
136
  </>
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "vaderjs",
3
3
  "description": "A Reactive library aimed to helping you build reactive applications inspired by react.js",
4
4
  "module": "vader.js",
5
- "version": "1.3.3-7bn28b17d42e1",
5
+ "version": "1.3.3-7u27417d42e1",
6
6
  "bin": {
7
7
  "vader": "./vader.js"
8
8
  },
package/runtime/vader.js CHANGED
@@ -1 +1 @@
1
- window.Vader={version:"1.3.3"},window.componentRegistry={};let errors={"SyntaxError: Unexpected token '<'":"You forgot to enclose tags in a fragment <></>"},mounts=[],lastRoute=null,hasRan=[];export const strictMount=(e,t)=>{let s=setInterval((()=>{document.querySelector(`[key="${e}"]`)&&!hasRan.includes(e)&&(clearInterval(s),t(),hasRan.push(e))}),120)};export class Component{constructor(e={}){this.$_vaderElement=!0,this.state={},this.key=null,this.components={},this.mounted=!1,this.checkIFMounted(),this.memoizes=[],this.functions=[],this.props={children:"",$:{},...e},this.children=[],this.noKey=!1,this.parentNode={},this.request={headers:{},method:"GET",params:{},path:"",query:{}},this.response={json:e=>{},send:e=>{},redirect:e=>{},render:async e=>{},log:e=>{},setQuery:e=>{}},this.router={use:e=>{}}}createComponent(e,t,s){function r(e){return"function"==typeof e&&/^class\s/.test(Function.prototype.toString.call(e))}let n=r(e)?new e(t):null;if(!e)throw new Error("Component must be defined");let i=[],o=new Component(t);if(r(e))n.props=t||{},n.props.children=s.join("")||[],n.props.children=s.join(""),n.parentNode=this,n.type="class ",n.request=this.request,n.response=this.response,n.key=n.props.key?n.props.key:Math.random(),o=n;else{e.toString();o.key=e.toString().split('key="')[1]?e.toString().split('key="')[1].split('"')[0]:null,t=t?{...t,...i.reduce(((e,t)=>({...e,...t})),{}),children:s.join("")||[]}:{children:s.join("")||[]};let r={key:o.key?o.key:Math.random(),isUnique:!!o.key,render:()=>e.apply(o,[t]),request:this.request,isChild:!0,response:this.response,params:this.request.params,queryParams:this.request.query,reset:o.reset.bind(o),onMount:o.onMount.bind(o),useState:null,router:{use:o.router.use.bind(o)},bindMount:o.bindMount.bind(o),memoize:o.memoize.bind(o),createComponent:o.createComponent.bind(o),isChild:!1,useState:o.useState.bind(o),parseStyle:o.parseStyle.bind(o),bind:o.bind.bind(o),useRef:o.useRef.bind(o),request:this.request,response:this.response,useReducer:o.useReducer.bind(o),hydrate:o.hydrate.bind(o),onUnmount:o.onUnmount.bind(o),type:"function",parentNoe:this,props:{...t,children:s.join("")||[]}};o.render=r.render,o=r,o.props.children=s.join("")||[]}return this.components[o.key]||(this.components[o.key]=o),!this.children.includes(o)&&this.children.push(o),this.components[o.key]}reset(){Object.keys(this.components).forEach((e=>{this.components[e].onUnmount(),delete this.components[e]})),this.state={},this.children=[]}memoize(e){if(!0==!this.memoizes.includes(e.key))this.memoizes.push(e.key),this.components[e.key]=e;let t=this.components[e.key];"class"!==t.type||t.$_vaderElement||console.error(`class ${t.constructor.name} must extend Component`),t.bindMount(),t.parentNode=this,t.props=e.props,t.request=this.request,t.response=this.response,t.onMount=e.onMount.bind(e),t.onUnmount=e.onUnmount.bind(e);let s=t.render();return s&&s.split(">,").length>1&&(s=s.replaceAll(">,",">")),t.nokey||t.noKey?s:`<div key="${t.key}">${s}</div>`}parseStyle(e){let t="";return Object.keys(e).forEach((s=>{let r=e[s];s=s.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g,"$1-$2").toLowerCase(),t+=`${s}:${r};`})),t}bindMount(){mounts.push(this)}domDifference(e,t){let s=[];for(let r=0;r<e.length;r++){let n=e[r],i=t[r];if(n&&i&&n.childNodes.length>0&&i.childNodes.length>0){switch(!0){case n.attributes&&i.attributes&&n.attributes.length!==i.attributes.length:s.push({type:"attributeSwap",old:n,new:i});break;case!n.isEqualNode(i)&&n.nodeName===i.nodeName&&n.textContent!==i.textContent:s.push({type:"replace",old:n,new:i})}let e=this.domDifference(Array.from(n.childNodes),Array.from(i.childNodes));return s.push(...e),s}n.isEqualNode(i)||n.nodeName!==i.nodeName||n.textContent===i.textContent?!n&&i&&s.push({type:"add",old:n,new:i}):s.push({type:"replace",old:n,new:i})}return s}updateChangedElements(e){e.forEach((e=>{if(e)switch(e.type){case"replace":if(e.old.panrntNode&&"BODY"===e.old.parentNode.nodeName)return;e.old.replaceWith(e.new.cloneNode(!0));break;case"remove":e.old.remove();break;case"attributeSwap":let t=Array.from(e.old.attributes),s=Array.from(e.new.attributes);t.forEach((t=>{e.old.removeAttribute(t.name)})),s.forEach((t=>{e.old.setAttribute(t.name,t.value)}));break;case"add":e.old.appendChild(e.new.cloneNode(!0))}}))}hydrate(e){if(e){let t=(new DOMParser).parseFromString(this.render(),"text/html").body.querySelectorAll(`[ref="${e.bind?e.bind:e}"]`),s=document.querySelectorAll(`[ref="${e?e.bind:e}"]`);t.forEach((e=>{let t=Array.from(s).find((t=>t.getAttribute("ref")===e.getAttribute("ref")));if(t){let s=this.domDifference(Array.from(t.childNodes),Array.from(e.childNodes));this.updateChangedElements([s])}}))}else{let e=this.key?document.querySelector(`[key="${this.key}"]`):null;if(e){let t=(new DOMParser).parseFromString(this.render(),"text/html").body.querySelector(`[key="${this.key}"]`),s=e,r=this.domDifference([s],[t]);this.updateChangedElements(r)}}}patch(e,t){const s=this.domDifference(e,t);this.updateChangedElements(s)}handleObject(obj){try{obj=JSON.parse(obj)}catch(e){}return eval(obj)}bind(e,t,s,r,...n){return s+=this.key,window["callFunctions"+this.key]=(e,t)=>{let s=this.functions.find((t=>t.ref===e));s&&s.func(t)},this.functions.find((e=>e.ref===s))||this.functions.push({ref:s,func:e}),t?e:`((event)=>{callFunctions${this.key} ? callFunctions${this.key}('${s}', event) : null})(event)`}setState(e,t){this.state=e,this.hydrate(t)}useState(e,t){this.state.hasOwnProperty(e)||(this.state[e]=t);return[(()=>this.state[e])(),(t,s)=>{this.state[e]=t,this.hydrate(s)}]}useRef(e=null,t){this.state[e]||(this.state[e]=t);return{bind:e+this.key,current:(()=>document.querySelector(`[ref="${e+this.key}"]`)||t)()}}useReducer(e=null,t,s=null){this.state[e]||(this.state[e]=t);const r=()=>this.state[e];let n=r();return[r(),(t,i)=>{const o=s(n,t)??t;this.state[e]=o,this.hydrate(i),n=r()}]}render(){}checkIFMounted(){new MutationObserver((e=>{e.forEach((e=>{e.target.querySelector(`[key="${this.key}"]`)&&!this.mounted&&(this.onMount(),this.mounted=!0),Array.from(e.removedNodes).find((e=>e.attributes&&e.attributes.key&&e.attributes.key.value===this.key))&&(this.onUnmount(),this.reset())}))})).observe(document.body,{childList:!0,subtree:!0})}onMount(){}onUnmount(){}}export const useState=(e,t)=>{this.state[e]||(this.state[e]=t);return[states[e],(t,s)=>{states[e]=t,this.hydrate(s)}]};export const useReducer=(e,t)=>[e,e=>{}];export const useRef=e=>({current:e,bind:""});export class Link extends Component{constructor(e){super(e),this.props=e,this.link=document.createElement("a"),this.key=e.href+Math.random(),this.nokey=!0}render(){return this.link.innerHTML=this.props.children,this.link.setAttribute("id",this.props?.href),this.link.style=this.props?.style,this.link.setAttribute("class",this.props?.class||this.props?.className),this.link.setAttribute("onclick",this.props?.href?.includes("https")||this.props?.href?.includes("http")?`window.open('${this.props.href}', '${this.props.action||"_blank"}').focus()`:`window.history.pushState({}, '', '${this.props?.href}'); window.dispatchEvent(new Event('popstate'));`),this.link.outerHTML}}export class Image extends Component{constructor(e){super(e),this.props={src:e.src,class:e.class,style:e.style,blur:e.blur,width:e.width,height:e.height,optimize:e.optimize||!0,loader:e.loader||!0,alt:e.alt||"image",ref:e.ref||null},this.key=e.src+Math.random(),this.img=document.createElement("img"),this.placeholder=document.createElement("div")}render(){if(window.isServer)return"";let[e,t]=this.useState("loaded",!1),s=this.useRef("hookref",null),r=this.props.width?this.props.width:window.innerWidth/2,n=this.props.height?this.props.height:window.innerHeight/2;if(!this.props.src)throw new Error("Image src is required");return this.img.setAttribute("src",this.props.src),this.img.setAttribute("class",this.props.class),this.img.setAttribute("style",this.props.style?this.props.style:""),this.img.setAttribute("width",r),this.img.setAttribute("ref",s.bind),this.img.referrerPolicy="no-referrer",this.img.setAttribute("height",n),this.img.setAttribute("loading","lazy"),this.img.setAttribute("alt",this.props.alt),this.props.blur&&this.img.setAttribute("style",`filter: blur(${this.props.blur}px);`),this.props.optimize&&this.img.setAttribute("style",`image-rendering: -webkit-optimize-contrast; object-fit: cover; object-position: center; ${this.props.style?this.props.style:""}`),!this.props.loader||e||window.isServer||(this.placeholder.setAttribute("style",`width: ${r}px; height: ${n}px; background: #eee;`),this.placeholder.setAttribute("class","vader-image-placeholder"),this.placeholder.innerHTML=this.props.loader,window.isServer)?void 0:(this.img.onload=()=>{t(!0,s.bind)},`<span ref="${s.bind}">${e?this.img.outerHTML:this.placeholder.outerHTML}</span>`)}}export class Html extends Component{constructor(e){super(e),this.props={children:e.children,lang:e.lang||"en",attributes:e.attributes||{}},this.key="html",this.html=document.createElement("div")}render(){return this.html.setAttribute("lang",this.props.lang?this.props.lang:"en"),window.isServer?(this.html.innerHTML=this.props.children,this.props.attributes&&Object.keys(this.props.attributes).forEach((e=>{this.html.setAttribute(e,this.props.attributes[e])})),this.html.innerHTML):this.props.children}onMount(){console.log("Document Has Been Mounted")}}export class Head extends Component{constructor(e){super(e),this.props=e,this.key="head",this.head=document.createElement("head"),this.eagerScripts=document.querySelectorAll("script[eager]")}render(){if(!window.isServer&&this.props?.updateOnReload){this.props.children=(new DOMParser).parseFromString(this.props.children,"text/html").head;let e=this.props.children.querySelector("title");e&&e.textContent&&(console.log("title",e.textContent),document.querySelector("title").textContent=e.textContent),this.props.children.querySelectorAll("meta").forEach((e=>{let t=e.getAttribute("name"),s=e.getAttribute("content");t&&s&&document.querySelector(`meta[name="${t}"]`).setAttribute("content",s)})),this.props.children.querySelectorAll("link").forEach((e=>{let t=e.getAttribute("rel"),s=e.getAttribute("href");t&&s&&document.querySelector(`link[rel="${t}"]`).setAttribute("href",s)}))}return""}onMount(){if(!this.state.hasMounted&&window.isServer){document.head.innerHTML=this.props.children+document.head.innerHTML,document.querySelectorAll("script[eager]").forEach((async e=>{if(!e.getAttribute("src"))throw new Error("Eager scripts must be external");e.remove();let t=e.getAttribute("src"),s=document.createElement("script"),r=null;await fetch(t).then((e=>{if(404===e.status)throw document.documentElement.setAttribute("error",JSON.stringify({error:`File ${t} not found`,status:404})),new Error(`File ${t} not found`);return e.text()})).then((e=>{r=e})).catch((e=>{throw e})),s.innerHTML=r,s.setAttribute("srcid",t),document.querySelector(`[srcid="${t}"]`)||document.head.prepend(s)})),this.state.hasMounted=!0}}}export class Script extends Component{constructor(e){super(e),this.props={children:e.children},this.key="script",this.script=document.createElement("script")}render(){return this.script.innerHTML=this.props.children.split("\n").join(";\n"),this.script.outerHTML}onMount(){document.head.appendChild(this.script),document.body.querySelector(`[key="${this.key}"]`).remove()}}export default{Component:Component,useRef:useRef,useReducer:useReducer,useState:useState,strictMount:strictMount,Link:Link,Image:Image,Head:Head,Script:Script,Html:Html};
1
+ window.Vader={version:"1.3.3"},window.componentRegistry={};let errors={"SyntaxError: Unexpected token '<'":"You forgot to enclose tags in a fragment <></>"},mounts=[],lastRoute=null,hasRan=[];export const strictMount=(e,t)=>{let s=setInterval((()=>{document.querySelector(`[key="${e}"]`)&&!hasRan.includes(e)&&(clearInterval(s),t(),hasRan.push(e))}),120)};export class Component{constructor(e={}){this.$_vaderElement=!0,this.state={},this.key=null,this.components={},this.mounted=!1,this.checkIFMounted(),this.memoizes=[],this.functions=[],this.props={children:"",$:{},...e},this.children=[],this.noKey=!1,this.parentNode={},this.request={headers:{},method:"GET",params:{},path:"",query:{}},this.response={json:e=>{},send:e=>{},redirect:e=>{},render:async e=>{},log:e=>{},setQuery:e=>{}},this.router={use:e=>{}}}createComponent(e,t,s){function isClass(e){return"function"==typeof e&&/^class\s/.test(Function.prototype.toString.call(e))}let r=isClass(e)?new e(t):null;if(!e)throw new Error("Component must be defined");let n=[],i=new Component(t);if(isClass(e))r.props=t||{},r.props.children=s.join("")||[],r.props.children=s.join(""),r.parentNode=this,r.type="class ",r.request=this.request,r.response=this.response,r.key=r.props.key?r.props.key:Math.random(),i=r;else{e.toString();i.key=e.toString().split('key="')[1]?e.toString().split('key="')[1].split('"')[0]:null,t=t?{...t,...n.reduce(((e,t)=>({...e,...t})),{}),children:s.join("")||[]}:{children:s.join("")||[]};let r={key:i.key?i.key:Math.random(),isUnique:!!i.key,render:()=>e.apply(i,[t]),request:this.request,isChild:!0,response:this.response,params:this.request.params,queryParams:this.request.query,reset:i.reset.bind(i),onMount:i.onMount.bind(i),useState:null,router:{use:i.router.use.bind(i)},bindMount:i.bindMount.bind(i),memoize:i.memoize.bind(i),createComponent:i.createComponent.bind(i),isChild:!1,useState:i.useState.bind(i),parseStyle:i.parseStyle.bind(i),bind:i.bind.bind(i),useRef:i.useRef.bind(i),request:this.request,response:this.response,useReducer:i.useReducer.bind(i),hydrate:i.hydrate.bind(i),onUnmount:i.onUnmount.bind(i),type:"function",parentNoe:this,props:{...t,children:s.join("")||[]}};i.render=r.render,i=r,i.props.children=s.join("")||[]}return this.components[i.key]||(this.components[i.key]=i),!this.children.includes(i)&&this.children.push(i),this.components[i.key]}reset(){Object.keys(this.components).forEach((e=>{this.components[e].onUnmount(),delete this.components[e]})),this.state={},this.children=[]}memoize(e){if(!0==!this.memoizes.includes(e.key))this.memoizes.push(e.key),this.components[e.key]=e;let t=this.components[e.key];"class"!==t.type||t.$_vaderElement||console.error(`class ${t.constructor.name} must extend Component`),t.bindMount(),t.parentNode=this,t.props=e.props,t.request=this.request,t.response=this.response,t.onMount=e.onMount.bind(e),t.onUnmount=e.onUnmount.bind(e);let s=t.render();return s&&s.split(">,").length>1&&(s=s.replaceAll(">,",">")),t.nokey||t.noKey?s:`<div key="${t.key}">${s}</div>`}parseStyle(e){let t="";return Object.keys(e).forEach((s=>{let r=e[s];s=s.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g,"$1-$2").toLowerCase(),t+=`${s}:${r};`})),t}bindMount(){mounts.push(this)}domDifference(e,t){let s=[];for(let r=0;r<e.length;r++){let n=e[r],i=t[r];if(n&&i&&n.childNodes.length>0&&i.childNodes.length>0){switch(!0){case n.attributes&&i.attributes&&n.attributes.length!==i.attributes.length:s.push({type:"attributeSwap",old:n,new:i});break;case!n.isEqualNode(i)&&n.nodeName===i.nodeName&&n.textContent!==i.textContent:s.push({type:"replace",old:n,new:i})}let e=this.domDifference(Array.from(n.childNodes),Array.from(i.childNodes));return s.push(...e),s}n.isEqualNode(i)||n.nodeName!==i.nodeName||n.textContent===i.textContent?!n&&i&&s.push({type:"add",old:n,new:i}):s.push({type:"replace",old:n,new:i})}return s}updateChangedElements(e){e.forEach((e=>{if(e)switch(e.type){case"replace":if(e.old.panrntNode&&"BODY"===e.old.parentNode.nodeName)return;e.old.replaceWith(e.new.cloneNode(!0));break;case"remove":e.old.remove();break;case"attributeSwap":let t=Array.from(e.old.attributes),s=Array.from(e.new.attributes);t.forEach((t=>{e.old.removeAttribute(t.name)})),s.forEach((t=>{e.old.setAttribute(t.name,t.value)}));break;case"add":e.old.appendChild(e.new.cloneNode(!0))}}))}hydrate(e){if(e){let t=(new DOMParser).parseFromString(this.render(),"text/html").body.querySelectorAll(`[ref="${e.bind?e.bind:e}"]`),s=document.querySelectorAll(`[ref="${e?e.bind:e}"]`);t.forEach((e=>{let t=Array.from(s).find((t=>t.getAttribute("ref")===e.getAttribute("ref")));if(t){let s=this.domDifference(Array.from(t.childNodes),Array.from(e.childNodes));this.updateChangedElements([s])}}))}else{let e=this.key?document.querySelector(`[key="${this.key}"]`):null;if(e){let t=(new DOMParser).parseFromString(this.render(),"text/html").body.querySelector(`[key="${this.key}"]`),s=e,r=this.domDifference([s],[t]);this.updateChangedElements(r)}}}patch(e,t){const s=this.domDifference(e,t);this.updateChangedElements(s)}handleObject(obj){try{obj=JSON.parse(obj)}catch(e){}return eval(obj)}bind(e,t,s,r,...n){return s+=this.key,window["callFunctions"+this.key]=(e,t)=>{let s=this.functions.find((t=>t.ref===e));s&&s.func(t)},this.functions.find((e=>e.ref===s))||this.functions.push({ref:s,func:e}),t?e:`((event)=>{callFunctions${this.key} ? callFunctions${this.key}('${s}', event) : null})(event)`}setState(e,t){this.state=e,this.hydrate(t)}useState(e,t){this.state.hasOwnProperty(e)||(this.state[e]=t);return[(()=>this.state[e])(),(t,s)=>{this.state[e]=t,this.hydrate(s)}]}useRef(e=null,t){this.state[e]||(this.state[e]=t);return{bind:e+this.key,current:(()=>document.querySelector(`[ref="${e+this.key}"]`)||t)()}}useReducer(e=null,t,s=null){this.state[e]||(this.state[e]=t);const getValue=()=>this.state[e];let r=getValue();return[getValue(),(t,n)=>{const i=s(r,t)??t;this.state[e]=i,this.hydrate(n),r=getValue()}]}render(){}checkIFMounted(){new MutationObserver((e=>{e.forEach((e=>{e.target.querySelector(`[key="${this.key}"]`)&&!this.mounted&&(this.onMount(),this.mounted=!0),Array.from(e.removedNodes).find((e=>e.attributes&&e.attributes.key&&e.attributes.key.value===this.key))&&(this.onUnmount(),this.reset())}))})).observe(document.body,{childList:!0,subtree:!0})}onMount(){}onUnmount(){}}export const useState=(e,t)=>{this.state[e]||(this.state[e]=t);return[states[e],(t,s)=>{states[e]=t,this.hydrate(s)}]};export const useReducer=(e,t)=>[e,e=>{}];export const useRef=e=>({current:e,bind:""});export class Link extends Component{constructor(e){super(e),this.props=e,this.link=document.createElement("a"),this.key=e.href+Math.random(),this.nokey=!0}render(){return this.link.innerHTML=this.props.children,this.link.setAttribute("id",this.props?.href),this.link.style=this.props?.style,this.link.setAttribute("class",this.props?.class||this.props?.className),this.link.setAttribute("onclick",this.props?.href?.includes("https")||this.props?.href?.includes("http")?`window.open('${this.props.href}', ${this.props.action||"_blank"}).focus()`:`window.history.pushState({}, '', '${this.props?.href}'); window.dispatchEvent(new Event('popstate'));`),this.link.outerHTML}}export class Image extends Component{constructor(e){super(e),this.props={src:e.src,class:e.class,style:e.style,blur:e.blur,width:e.width,height:e.height,optimize:e.optimize||!0,loader:e.loader||!0,alt:e.alt||"image",ref:e.ref||null},this.key=e.src+Math.random(),this.img=document.createElement("img"),this.placeholder=document.createElement("div")}render(){if(window.isServer)return"";let[e,t]=this.useState("loaded",!1),s=this.useRef("hookref",null),r=this.props.width?this.props.width:window.innerWidth/2,n=this.props.height?this.props.height:window.innerHeight/2;if(!this.props.src)throw new Error("Image src is required");return this.img.setAttribute("src",this.props.src),this.img.setAttribute("class",this.props.class),this.img.setAttribute("style",this.props.style?this.props.style:""),this.img.setAttribute("width",r),this.img.setAttribute("ref",s.bind),this.img.referrerPolicy="no-referrer",this.img.setAttribute("height",n),this.img.setAttribute("loading","lazy"),this.img.setAttribute("alt",this.props.alt),this.props.blur&&this.img.setAttribute("style",`filter: blur(${this.props.blur}px);`),this.props.optimize&&this.img.setAttribute("style",`image-rendering: -webkit-optimize-contrast; object-fit: cover; object-position: center; ${this.props.style?this.props.style:""}`),!this.props.loader||e||window.isServer||(this.placeholder.setAttribute("style",`width: ${r}px; height: ${n}px; background: #eee;`),this.placeholder.setAttribute("class","vader-image-placeholder"),this.placeholder.innerHTML=this.props.loader,window.isServer)?void 0:(this.img.onload=()=>{t(!0,s.bind)},`<span ref="${s.bind}">${e?this.img.outerHTML:this.placeholder.outerHTML}</span>`)}}export class Html extends Component{constructor(e){super(e),this.props={children:e.children,lang:e.lang||"en",attributes:e.attributes||{}},this.key="html",this.html=document.createElement("div")}render(){return window.isServer?(this.html.innerHTML=this.props.children,this.html.setAttribute("lang",this.props.lang?this.props.lang:"en"),this.props.attributes&&Object.keys(this.props.attributes).forEach((e=>{this.html.setAttribute(e,this.props.attributes[e])})),this.html.innerHTML):this.props.children}onMount(){console.log("Document Has Been Mounted")}}export class Head extends Component{constructor(e){super(e),this.props=e,this.key="head",this.head=document.createElement("head")}render(){return""}onMount(){if(!this.state.hasMounted&&window.isServer){document.head.innerHTML=this.props.children+document.head.innerHTML,document.querySelectorAll("script[eager]").forEach((async e=>{if(!e.getAttribute("src"))throw new Error("Eager scripts must be external");e.remove();let t=e.getAttribute("src"),s=document.createElement("script"),r=null;await fetch(t).then((e=>{if(404===e.status)throw document.documentElement.setAttribute("error",JSON.stringify({error:`File ${t} not found`,status:404})),new Error(`File ${t} not found`);return e.text()})).then((e=>{r=e})).catch((e=>{throw e})),s.innerHTML=r,s.setAttribute("srcid",t),document.querySelector(`[srcid="${t}"]`)||document.head.prepend(s)})),this.state.hasMounted=!0}}}export class Script extends Component{constructor(e){super(e),this.props={children:e.children},this.key="script",this.script=document.createElement("script")}render(){return this.script.innerHTML=this.props.children.split("\n").join(";\n"),this.script.outerHTML}onMount(){document.head.appendChild(this.script),document.body.querySelector(`[key="${this.key}"]`).remove()}}export default{Component:Component,useRef:useRef,useReducer:useReducer,useState:useState,strictMount:strictMount,Link:Link,Image:Image,Head:Head,Script:Script,Html:Html};
package/vader.js CHANGED
@@ -117,7 +117,7 @@ function Compiler(func, file) {
117
117
  let functionAttributes = [];
118
118
  let spreadFunctions = [];
119
119
  let functionMatch;
120
-
120
+
121
121
  /**
122
122
  * @search - handle attributes for html elements
123
123
  * @keywords - attributes, props, html attributes
@@ -139,8 +139,60 @@ function Compiler(func, file) {
139
139
  attributesList.push({ element, attributes: elementAttributes });
140
140
  }
141
141
 
142
+ let spreadMatch;
143
+ while ((spreadMatch = spreadAttributeRegex.exec(code)) !== null) {
144
+ let [, element, spread] = spreadMatch;
145
+ let isJSXComponent = element.match(/^[A-Z]/) ? true : false;
146
+ if (isJSXComponent) {
147
+ continue;
148
+ }
149
+ let old = spread;
150
+ spread = spread.trim().replace(/\s+/g, " ");
151
+ // re,pve $={ and }
152
+ spread = spread.replace(/\s*\$\s*=\s*{\s*{/gs, '')
153
+
154
+ // replace trailing }
155
+ spread = spread.replace(/}}\s*$/, '').replace(/}\s*}$/, '')
156
+ let splitByCommas = spread.split(/,(?![^{}]*})/gs)
157
+ // remove empty strings
158
+ splitByCommas = splitByCommas.filter((e) => e.split(':')[0].trim().length > 0)
159
+ splitByCommas = splitByCommas.map((e, index) => {
160
+ let key = e.split(':')[0].trim()
161
+ switch (true) {
162
+ case e.includes('function') && !e.includes('this.bind') || e && e.includes('=>') && !e.includes('this.bind'):
163
+ let value = e.split(':')[1].trim()
164
+ let ref = Math.random().toString(36).substring(2).split('').filter((e) => !Number(e)).join('');
165
+ value = `this.bind(${value}, false, "${ref}", "")`
166
+ e = `${key}="\${${value}}"`
167
+ break;
168
+ case e.includes('style:'):
169
+ let v2 = e.split('style:')[1].trim().replace(/,$/, '')
170
+ v2 = v2.replace(/,$/, '')
171
+ e = `${key}="\${this.parseStyle(${v2})}"`
172
+ break;
173
+
174
+ default:
175
+ let v = e.split(':')
176
+ key = v[0].trim()
177
+ // remove key from v
178
+ v.shift()
179
+ v = v.join(' ')
180
+ e = `${key}="\${${v}}"`
181
+
182
+ break;
183
+ }
142
184
 
143
185
 
186
+ return e;
187
+ });
188
+
189
+
190
+ let newSpread = splitByCommas.join(' ').trim().replace(/,$/, '');
191
+
192
+ // remove trailing }
193
+ string = string.replace(old, newSpread);
194
+ }
195
+
144
196
  while ((functionMatch = functionAttributeRegex.exec(code)) !== null) {
145
197
 
146
198
  let [, attributeName, attributeValue] = functionMatch;
@@ -164,17 +216,17 @@ function Compiler(func, file) {
164
216
  .split("<")[1]
165
217
  .split(">")[0]
166
218
  .split(" ")[0];
167
- isJSXComponent = elementTag.match(/^[A-Z]/) ? true : false;
219
+ isJSXComponent = elementTag.match(/^[A-Z]/) ? true : false;
168
220
  }
169
221
  });
170
- if (isJSXComponent) {
222
+ if (isJSXComponent) {
171
223
  continue
172
224
  }
173
225
  // add ; after newlines
174
226
 
175
227
 
176
228
  let newvalue = attributeValue.includes('=>') ? attributeValue.split("=>").slice(1).join("=>").trim() : attributeValue.split("function").slice(1).join("function").trim()
177
-
229
+
178
230
  // add ; after newlines
179
231
 
180
232
 
@@ -226,14 +278,14 @@ function Compiler(func, file) {
226
278
  newvalue = newvalue.replace(/\(\s*=>/gs, '=>').replace(/\function\s*\([^\)]*\)\s*\{/gs, '{')
227
279
  newvalue = newvalue + `\n /**@id=${ref}**/ \n`
228
280
 
229
- let bind = !isJSXComponent && `${attributeName}="\$\{this.bind(function(){${newvalue}}.bind(this), ${isJSXComponent}, "${ref}", "${paramnames ? paramnames.map((e, index) => {
281
+ let bind = !isJSXComponent && `${attributeName}="\$\{this.bind(function(){${newvalue}}.bind(this), ${isJSXComponent}, "${ref}", "${paramnames ? paramnames.map((e, index) => {
230
282
  if (e.length < 1) return ''
231
283
  if (e.length > 0) {
232
284
  index == 0 ? e : ',' + e
233
285
  }
234
286
  return e
235
287
  }) : ''}" ${params ? params.split(',').map((e) => e.trim()).filter(Boolean).map((e) => `,${e}`).join('') : ''})}"`
236
-
288
+
237
289
  string = string.replace(old, bind)
238
290
  }
239
291
  }
@@ -360,15 +412,9 @@ function Compiler(func, file) {
360
412
  switch (true) {
361
413
  case line.includes("useState") && !line.includes("import"):
362
414
  let varType = line.split("[")[0]
363
- if (!line.split("=")[0].split(",")[1]) {
364
- throw new Error('You forgot to value selector (useState) ' + ' at ' + `${file}:${string.split(line)[0].split('\n').length}`)
365
- }
366
415
  let key = line.split("=")[0].split(",")[0].trim().split('[')[1];
367
416
 
368
- if (!line.split("=")[0].split(",")[1]) {
369
- throw new Error('You forgot to add a setter (useState) ' + ' at ' + `${file}:${string.split(line)[0].split('\n').length}`)
370
- }
371
- let setKey = line.split("=")[0].split(",")[1].trim().replace("]", "");
417
+ let setKey = line.split("=")[0].trim().split(",")[1].trim().replace("]", "");
372
418
  key = key.replace("[", "").replace(",", "");
373
419
  let valuestate = line.split("=")[1].split("useState(")[1];
374
420
 
@@ -437,71 +483,37 @@ function Compiler(func, file) {
437
483
  let myChildrens = [];
438
484
 
439
485
  let name = component.split("<")[1].split(">")[0].split(" ")[0].replace("/", "");
440
- let componentAttributes = component.split("<")[1].split(">")[0].split(" ").join(" ").replace(name, "").trim();
441
- let props = component.includes('/>') ? component.split(`<`)[1].split('/>')[0] : component.split(`<`)[1].split(`>`)[0]
442
- props = props.replaceAll(/\s+/g, " ").trim()
486
+ let componentAttributes = component.split("<")[1].split(">")[0].split(" ").join(" ").replace(name, "").trim();
487
+ let props = component.includes('/>')? component.split(`<`)[1].split('/>')[0] : component.split(`<`)[1].split(`>`)[0]
488
+ props = props.replaceAll(/\s+/g, " ").trim()
443
489
  props = props.replace(name, '').trim()
444
490
  component = component.replace(componentAttributes, '')
445
- // or spread attributes {...{}, ...{}}
446
- const dynamicAttributesRegex = /([a-zA-Z0-9_-]+)\s*=\s*("(?:[^"\\]*(?:\\.[^"\\]*)*)"|'(?:[^'\\]*(?:\\.[^'\\]*)*)'|\{(?:[^{}]|(?:\{(?:[^{}]|(?:\{(.*.*?)\})*)*\})*)*\}|(?:\([^)]*\)|()\s*=>\s*(?:\{.*.*\})?|\{.*\})|\[[^\]]*\])|\${\{.*\}}/gs;
491
+ const dynamicAttributesRegex = /([a-zA-Z0-9_-]+)\s*=\s*("(?:[^"\\]*(?:\\.[^"\\]*)*)"|'(?:[^'\\]*(?:\\.[^'\\]*)*)'|\{(?:[^{}]|(?:\{(?:[^{}]|(?:\{(.*.*?)\})*)*\})*)*\}|(?:\([^)]*\)|()\s*=>\s*(?:\{.*.*\})?|\{.*\})|\[[^\]]*\])/gs;
447
492
 
448
493
  const attributeObject = {};
449
- let propstring = ''
494
+
450
495
  let $_ternaryprops = []
451
- let spreadRegex = /\$\{.*\}/gs;
452
- let spreadMatch;
453
- let hasSpread = false;
454
- while ((spreadMatch = spreadRegex.exec(props)) !== null) {
455
- let spread = spreadMatch[0].trim().replace(/\s+/g, " ");
456
- if (!spread.includes('...')) {
457
- continue
458
- }
459
- let old = spread;
460
- spread = spread.trim().replace(/\s+/g, " ");
461
- //${...( loaded ? { title: "Malik Whitten - Blog" } : { title: "Loading" } )} -> ...( loaded ? { title: "Malik Whitten - Blog" } : { title: "Loading" } )
462
-
463
- let spreadContent = spread.match(/\$\{.*\}/gs) ? spread.match(/\$\{.*.*\}/gs)[0] : null
464
- spreadContent = spread.split('${')[1]
465
-
466
- spreadContent = spread.replace(/\${/, '')
467
- spreadContent = spreadContent.replaceAll(/\s+/g, " ").trim()
468
- spreadContent = spreadContent.replace(')}', ')').replace('}}', '}')
469
-
470
- propstring += spreadContent + ','
471
- hasSpread = true
472
-
473
- }
474
496
 
475
497
  let match;
476
-
498
+ let propstring = ''
477
499
  // props right now is just a string with all of them on one line and a space between each
478
500
  while ((match = dynamicAttributesRegex.exec(props)) !== null) {
479
501
  let str = match[0].trim().replace(/\s+/g, " ");
480
502
  if (!str.includes('=')) {
481
503
  continue
482
- }
483
-
484
- if (hasSpread) {
485
-
486
- console.log('\x1b[33m', '🚨 Code confliction detected', '\x1b[0m')
487
- let line = string.split(match[0])[0].split('\n').length
488
- try {
489
- throw new Error('You cannot use spread props and named props\n on the same component at ' + match[0] + ' at ' + `${file}:${line}`)
490
- } catch (error) {
491
- console.error(error)
492
- process.exit(1)
493
- }
494
- }
495
-
496
- str = str.replaceAll(/\s+/g, " ")
504
+ }
505
+
506
+
507
+ str = str.replaceAll(/\s+/g, " ")
497
508
  str = str.split('=')
498
- let key = str[0].trim()
509
+ let key = str[0].trim()
499
510
  let value = str.slice(1).join('=').trim().match(/\{.*\}/gs) ? str.slice(1).join('=').trim().match(/\{.*\}/gs)[0] : str.slice(1).join('=').trim();
500
-
501
-
511
+
512
+
513
+
502
514
  let isObject = value.startsWith('{{') && value.endsWith('}}')
503
- if (isObject) {
504
- value = value.split('{{')[1].split('}}')[0].trim()
515
+ if (isObject) {
516
+ value = value.split('{{')[1].split('}}')[0].trim()
505
517
  value = `{${value}}`
506
518
  propstring += `${key}:${value},`
507
519
  } else {
@@ -510,8 +522,8 @@ function Compiler(func, file) {
510
522
  propstring += `${key}:${value},`
511
523
  }
512
524
  propstring = propstring.replaceAll(/\s+/g, " ").trim()
513
-
514
- }
525
+
526
+ }
515
527
  component = component.replaceAll(/\s+/g, " ");
516
528
 
517
529
  component = component.replace(componentAttributes, '')
@@ -578,7 +590,7 @@ function Compiler(func, file) {
578
590
  let replaceMents = [];
579
591
 
580
592
 
581
- if (imports) {
593
+ if(imports){
582
594
  for (let match of imports) {
583
595
  let path = match.split('from')[1].trim().replace(/'/g, '').replace(/"/g, '').trim()
584
596
  switch (true) {
@@ -588,11 +600,11 @@ function Compiler(func, file) {
588
600
  if (!fs.existsSync(process.cwd() + componentFolder)) {
589
601
  throw new Error('Could not find ' + path + ' at ' + match + ' in file ' + file)
590
602
  }
591
-
603
+
592
604
  if (!fs.existsSync(process.cwd() + '/dist/src/' + componentFolder.split('/').slice(2).join('/'))) {
593
605
  fs.mkdirSync(process.cwd() + '/dist/src/' + componentFolder.split('/').slice(2).join('/'), { recursive: true })
594
606
  }
595
-
607
+
596
608
  let baseFolder = componentFolder.split('node_modules')[1].split('/')[1]
597
609
  let glp = globSync('**/**/**/**.{jsx,js}', {
598
610
  cwd: process.cwd() + '/node_modules/' + baseFolder + '/',
@@ -603,7 +615,7 @@ function Compiler(func, file) {
603
615
  let text = fs.readFileSync(file, "utf8");
604
616
  if (!file.endsWith('.js') && file.endsWith('.jsx')) {
605
617
  text = Compiler(text, file);
606
-
618
+
607
619
  }
608
620
  let dest = file.split('node_modules')[1]
609
621
  dest = dest.split(baseFolder)[1]
@@ -615,8 +627,8 @@ function Compiler(func, file) {
615
627
  replaceMents.push({ match: oldImportstring, replace: newImport })
616
628
  console.log(`📦 imported Node Package ${baseFolder} `)
617
629
  }
618
-
619
-
630
+
631
+
620
632
  break;
621
633
  default:
622
634
  break;
@@ -641,7 +653,7 @@ function Compiler(func, file) {
641
653
  string = string.replaceAll(/\$\{\/\*.*\*\/\}/gs, "");
642
654
  string = string.replaceAll("<>", "`").replaceAll("</>", "`");
643
655
  string = string.replaceAll(".jsx", ".js");
644
-
656
+
645
657
 
646
658
  string = string
647
659
  .replaceAll("className", "class")
@@ -807,17 +819,15 @@ function Compiler(func, file) {
807
819
 
808
820
  globalThis.isBuilding = false
809
821
  globalThis.isWriting = null
810
-
822
+ const glb = await glob("**/**/**/**.{jsx,js}", {
823
+ ignore: ["node_modules/**/*", "dist/**/*"],
824
+ cwd: process.cwd() + '/pages/',
825
+ absolute: true,
826
+ recursive: true
827
+ });
811
828
  let hasRendered = []
812
829
 
813
830
  async function Build() {
814
- const glb = await glob("**/**/**/**.{jsx,js}", {
815
- ignore: ["node_modules/**/*", "dist/**/*"],
816
- cwd: process.cwd() + '/pages/',
817
- absolute: true,
818
- recursive: true
819
- });
820
-
821
831
  globalThis.isBuilding = true
822
832
  console.log(globalThis.isProduction ? 'Creating Optimized Production Build\n' : '')
823
833
  let str = `Page \t\t\t\t Size\n`
@@ -895,7 +905,7 @@ async function Build() {
895
905
  page.on('crash', () => {
896
906
  console.error(`Render process crashed for ${route.url}`)
897
907
  });
898
-
908
+
899
909
  await page.goto(`http://localhost:${port}${route.url}`, { waitUntil: 'networkidle2' });
900
910
 
901
911
  page.evaluate(() => {
@@ -939,8 +949,8 @@ async function Build() {
939
949
  browser.close()
940
950
  })
941
951
  hasRendered = []
942
- globalThis.isBuilding = false
943
-
952
+ globalThis.isBuilding = false
953
+
944
954
  }
945
955
 
946
956
  if (hasRendered.length === routes.length) {
@@ -956,7 +966,6 @@ async function Build() {
956
966
  }
957
967
  }
958
968
  globalThis.routes = []
959
- globalThis.paramRoutes = []
960
969
 
961
970
  for await (let file of glb) {
962
971
  // Normalize file paths
@@ -1055,46 +1064,10 @@ async function Build() {
1055
1064
  }
1056
1065
 
1057
1066
 
1058
- if (obj.url.includes(':') && !paramRoutes.includes(obj.url)) {
1059
- globalThis.paramRoutes.push({ fileName: fileName, url: obj.url, html: '/' + (isBasePath ? 'index.html' : `${obj.url}/` + 'index.html') })
1060
- } else {
1061
-
1067
+ if (!obj.url.includes(':')) {
1062
1068
  globalThis.routes.push({ fileName: fileName, url: obj.url, html: '/' + (isBasePath ? 'index.html' : `${obj.url}/` + 'index.html') })
1063
1069
  }
1064
1070
 
1065
- // check if route has a index.html file
1066
-
1067
- if (!fs.existsSync(process.cwd() + '/dist/' + (isBasePath ? 'index.html' : `${obj.url}/` + 'index.html'))
1068
- && !obj.url.includes(':') && !globalThis.isProduction
1069
- ) {
1070
- let document = `<!DOCTYPE html>
1071
- <html lang="en">
1072
- <head>
1073
- <meta charset="UTF-8">
1074
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
1075
- <title>${obj.url}</title>
1076
- <script>
1077
- window.routes = JSON.parse('${JSON.stringify(globalThis.routes)}')
1078
- </script>
1079
- <script type="module">
1080
- import VaderRouter from '/router.js'
1081
- const router = new VaderRouter('${obj.url}')
1082
- router.get('${obj.url}', async (req, res) => {
1083
- let module = await import('/${obj.url === '/' ? 'index.js' : obj.url + '.js'}')
1084
- if(Object.keys(module).includes('$prerender') && !module.$prerender){
1085
- document.head.setAttribute('prerender', 'false')
1086
- }
1087
- res.render(module, req, res, module.$metadata)
1088
- })
1089
- router.listen(3000)
1090
- </script>
1091
- </head>
1092
- <body>
1093
- <div id="root"></div>
1094
- </body>
1095
- </html>`
1096
- writer(process.cwd() + '/dist/' + (isBasePath ? 'index.html' : `${obj.url}/` + 'index.html'), document)
1097
- }
1098
1071
 
1099
1072
  let stats = {
1100
1073
  route: obj.url.padEnd(30),
@@ -1112,8 +1085,7 @@ async function Build() {
1112
1085
 
1113
1086
  globalThis.routeDocuments = []
1114
1087
  globalThis.routes.map((route) => {
1115
- let equalparamroute = globalThis.paramRoutes.map((e) => {
1116
- console
1088
+ let equalparamroute = globalThis.routes.map((e) => {
1117
1089
  if (e.url.includes(':')) {
1118
1090
  let url = e.url.split('/:')[0]
1119
1091
  if (url && route.url === url) {
@@ -1188,13 +1160,13 @@ async function Build() {
1188
1160
  `;
1189
1161
  globalThis.routeDocuments.push({ url: route.url, document: document })
1190
1162
  })
1191
-
1192
- if (globalThis.devMode && !globalThis.oneAndDone) {
1163
+
1164
+ if(globalThis.devMode && !globalThis.oneAndDone){
1193
1165
  ssg(globalThis.routes)
1194
1166
  globalThis.oneAndDone = true
1195
1167
  console.log(`In Development Mode, Prerendering ${globalThis.routes.length} pages... Once`)
1196
- }
1197
- else if (globalThis.isProduction) {
1168
+ }
1169
+ else if(globalThis.isProduction){
1198
1170
  ssg(globalThis.routes)
1199
1171
  }
1200
1172
 
@@ -1279,7 +1251,7 @@ async function Build() {
1279
1251
  let data = await reader(process.cwd() + "/node_modules/vaderjs/runtime/" + file)
1280
1252
  await writer(process.cwd() + "/dist/" + file, data);
1281
1253
  });
1282
-
1254
+
1283
1255
 
1284
1256
  }
1285
1257
 
@@ -1287,29 +1259,7 @@ async function Build() {
1287
1259
 
1288
1260
  globalThis.isProduction ? console.log(`Total Bundle Size: ${Math.round(bundleSize / 1000)}kb`) : null
1289
1261
  bundleSize = 0;
1290
- if (!globalThis.isBuilding) {
1291
- let folders = fs.readdirSync(process.cwd() + '/dist/', { withFileTypes: true })
1292
-
1293
- folders.forEach((folder) => {
1294
- // exclude files
1295
- if (folder.name.includes('src') || folder.name.includes('public') || folder.name.includes('pages')
1296
- || !folder.isDirectory()
1297
- ) {
1298
- return
1299
- }
1300
-
1301
- let existsInPages = fs.existsSync(process.cwd() + '/pages/' + folder.name)
1302
1262
 
1303
- if (existsInPages) {
1304
- return
1305
- }
1306
- fs.rm(process.cwd() + '/dist/' + folder.name, { recursive: true }, (err) => {
1307
- if (err) {
1308
- throw err
1309
- }
1310
- })
1311
- })
1312
- }
1313
1263
  return true
1314
1264
  }
1315
1265
  const s = (port) => {
@@ -1319,7 +1269,7 @@ const s = (port) => {
1319
1269
  const validExtensions = ['.js', '.css', '.mjs', '.cjs', '.html', '.json', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.mp4', '.webm', '.ogg', '.map']
1320
1270
 
1321
1271
  if (!validExtensions.some(ext => req.url.endsWith(ext))) {
1322
- req.url = req.url + '/'
1272
+ req.url = req.url !== '/' ? req.url.split('/')[1] : req.url;
1323
1273
  req.url = path.join(process.cwd(), 'dist', req.url, 'index.html');
1324
1274
  } else {
1325
1275
  req.url = path.join(process.cwd(), 'dist', req.url);
@@ -1397,7 +1347,7 @@ const s = (port) => {
1397
1347
  return 'application/octet-stream';
1398
1348
  }
1399
1349
  }
1400
-
1350
+
1401
1351
  server.listen(port, () => {
1402
1352
  console.log(`Server is running on port ${port}`);
1403
1353
  globalThis.ws = ws
@@ -1412,7 +1362,7 @@ switch (true) {
1412
1362
 
1413
1363
  globalThis.devMode = true
1414
1364
  globalThis.isProduction = false
1415
-
1365
+
1416
1366
  let p = process.env.PORT || config.port || process.argv.includes('-p') ? process.argv[process.argv.indexOf('-p') + 1] : 3000
1417
1367
  globalThis.oneAndDone = false
1418
1368
  console.log(`
@@ -1444,7 +1394,7 @@ Vader.js v${fs.readFileSync(process.cwd() + '/node_modules/vaderjs/package.json'
1444
1394
  Build()
1445
1395
  }
1446
1396
  }).on('error', (err) => console.log(err))
1447
- })
1397
+ })
1448
1398
  s(p)
1449
1399
 
1450
1400
  globalThis.listen = true;