vaderjs 1.3.3-5b5a772ebe58 → 1.3.3-8924566yt812

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
@@ -14,7 +14,7 @@
14
14
  [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/Postr-Inc/Vader.js/blob/main/LICENSE) [![npm version](https://img.shields.io/npm/v/vaderjs.svg?style=flat)](https://www.npmjs.com/package/vaderjs)
15
15
 
16
16
 
17
-
17
+ > Do not use any alpha versions as these where changed multiple times any version under latest is considered lts and are deemed to be stable
18
18
  ## Get Started
19
19
 
20
20
  2. Install vaderjs
@@ -81,7 +81,7 @@ export default function(req, res){
81
81
 
82
82
  return <>
83
83
  <h1>${count}</h1>
84
- <button onClick={(count, setCount)=>{setCount(count + 1)}}>
84
+ <button onClick={(event)=>{setCount(count + 1)}}>
85
85
  </>
86
86
  }
87
87
 
@@ -126,9 +126,11 @@ export function Layout({title, keywords, description, children}){
126
126
 
127
127
  // pages/index.jsx
128
128
 
129
+ //$= is a ternary operator used for spread like nesting
130
+
129
131
  export default function (req, res){
130
132
  return <>
131
- <Layout {...{title:'home', description:'home page', keywords:'vader.js', logo:''}}>
133
+ <Layout $={{title:'home', description:'home page', keywords:'vader.js', logo:''}}>
132
134
  <h1> Hello World</h1>
133
135
  </Layout>
134
136
  </>
@@ -173,6 +175,8 @@ export default class MyApp extends Component{
173
175
  contructor(){
174
176
  super()
175
177
  this.key = 'static key for state changes'
178
+ // or
179
+ this.nokey // disable element generation
176
180
  }
177
181
 
178
182
  render(){
@@ -215,7 +219,7 @@ return <>
215
219
  </>
216
220
  ```
217
221
 
218
- and lower level invokes - these operate the same just allow you to pass items from top level to lower level: ex - I have a variable named car and i want the button to log it i can pass it as a parameter to allow it to be added to the buttons function scope
222
+ Low level invokes are considered top level and can access - any value above the scope !!
219
223
 
220
224
  ```jsx
221
225
  let car = {
@@ -223,7 +227,7 @@ let car = {
223
227
  price: 'toomiuch'
224
228
  }
225
229
  return <>
226
- <button onclick={(car)=>{
230
+ <button onclick={(event)=>{
227
231
  console.log(car.model)
228
232
  }}>Log</button>
229
233
  ```
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-5b5a772ebe58",
5
+ "version": "1.3.3-8924566yt812",
6
6
  "bin": {
7
7
  "vader": "./vader.js"
8
8
  },
package/runtime/router.js CHANGED
@@ -1 +1 @@
1
- import{Component}from"./vader.js";let middlewares=[];class VaderRouter{constructor(e,t){this.routes=[],this.middlewares=[],this.errorMiddlewares=[],this.listeners=[],this.basePath=e}get(e,t){this.routes.push({path:e,handler:t,method:"get"})}use(e){this.middlewares.push(e)}listen(e,t){e||(e=Math.random().toString(36).substring(7)),window.onpopstate=async e=>{let t=window.location.pathname,r=`/${t.split("/")[1]}`;console.log("route",t),this.checkroute(t)||window.devMode||(t="/404");let n=(new DOMParser).parseFromString(await fetch(r,{cache:"reload"}).then((e=>e.text())),"text/html").documentElement;document.querySelector("#root").innerHTML=n.querySelector("#root").innerHTML,document.title=n.querySelector("title")?n.querySelector("title").innerHTML:document.title,document.querySelector('script[id="router"]').remove();let o=document.createElement("script");o.id="router",o.innerHTML=n.querySelector('script[id="router"]').innerHTML,o.setAttribute("type","module"),document.body.appendChild(o)},window.rehydrate=async()=>{window.location.reload()},this.listeners.push(e),1===this.listeners.length?this.handleRoute(window.location.pathname):this.listeners.pop(),t&&t()}extractParams(e,t){const r=e.split("/").filter((e=>""!==e)),n=t.split("/").filter((e=>""!==e)),o={};return r.forEach(((e,t)=>{if(e.startsWith(":")){const r=e.slice(1);o[r]=n[t]}else if(e.startsWith("*")){n.slice(t).forEach(((e,t)=>{o[t]=e}))}})),o}extractQueryParams(e){const t=e.split("?")[1];if(!t)return{};const r={};return t.split("&").forEach((e=>{const[t,n]=e.split("=");r[t]=n})),r}checkroute(e){return e=e.endsWith("/")?e.slice(0,-1):e,this.routes.find((t=>{if(t.path===e)return!0;if(""===e&&"/"===t.path)return!0;if(e.includes("?")&&(e=e.split("?")[0]),t.path.includes("*")||t.path.includes(":")){const r=t.path.split("/").filter((e=>""!==e)),n=e.split("/").filter((e=>""!==e));if(r.length!==n.length&&!t.path.endsWith("*"))return!1;for(let e=0;e<r.length;e++){const t=r[e],o=n[e];if(!t.startsWith(":")&&!t.startsWith("*")&&t!==o)return!1}return!0}const r=this.extractParams(t.path,e);return Object.keys(r).length>0}))}handleRoute(e){let t=200,r=e,n=this.checkroute(e);n||(n=window.routes.find((e=>!e.url.includes("/404")||this.error||window.devMode?!(this.error||!e.url.includes("/404"))||void 0:(window.history.pushState({},"","/404"),window.dispatchEvent(new Event("popstate")),this.error=!0,!1))),t=n?200:404);const o=this.extractQueryParams(r),s=n&&n.path?this.extractParams(n.path,r):{};Object.keys(s).forEach((e=>{s[e]=s[e].split("?")?s[e].split("?")[0]:s[e]}));const i={headers:{},params:s,query:o,path:e,fileUrl:window.location.href.split(window.location.origin)[1],url:window.location.href,method:n?n.method:"get",pause:!1,timestamp:Date.now()};window.$CURRENT_URL=i.path,window.$FULL_URL=window.location.href.replace("#","");const a={status:t,log:e=>{void 0===e?console.log(`${i.path} ${i.method} ${a.status} ${i.timestamp}`):console.table({"Request Path":i.path,"Request Method":n.method,"Response Status":a.status,"Request Timestamp":i.timestamp})},refresh:()=>{this.handleRoute(window.location.pathname)},redirect:e=>{!e.startsWith("/")&&(e=`/${e}`),window.history.pushState({},"",e),window.dispatchEvent(new Event("popstate"))},render:async(e,t,r,n)=>{function i(e){return"function"==typeof e&&/^class\s/.test(Function.prototype.toString.call(e))}try{let n=new Component;if(i(e.default)){let t=new e.default;n.state=t.state,n=t}else{if(e.default.toString().includes("this.key"))throw new Error('Using this.key is not supported in functional components use the attribute key="a value" instead');n.key=e.default.toString().split('key="')[1]?e.default.toString().split('key="')[1].split('"')[0]:null;let i={key:n.key,render:()=>e.default.apply(n,[t,r]),request:t,response:r,params:s,queryParams:o,reset:n.reset.bind(n),onMount:n.onMount.bind(n),useState:null,router:{use:n.router.use.bind(n)},bindMount:n.bindMount.bind(n),memoize:n.memoize.bind(n),createComponent:n.createComponent.bind(n),isChild:!1,useState:n.useState.bind(n),parseStyle:n.parseStyle.bind(n),bind:n.bind.bind(n),useRef:n.useRef.bind(n),useReducer:n.useReducer.bind(n),onMount:n.onMount.bind(n),onUnmount:n.onUnmount.bind(n),hydrate:n.hydrate.bind(n)};n.render=i.render,n=i}if(!document.querySelector("#root"))throw new Error("Root element not found, please add an element with id root");n.reset(),n.components={},n.request=t,n.response=r,n.router.use&&!n.isChild?await new Promise((async o=>{if(i(e.default))if(i(e.default))switch(await n.router.use(t,r),t.pause){case!0:console.log("pausing",t.pause);let e=setInterval((()=>{t.pause?console.log("still pausing",t.pause):(clearInterval(e),o())}),1e3);break;case!1:o()}else o();else switch(await e.default.apply(n,[t,r]),await n.router.use(t,r),t.pause){case!0:let e=setInterval((()=>{t.pause?console.log("still pausing request",t.url):(clearInterval(e),o())}),1e3);break;case!1:o()}})):n.router.use&&n.isChild&&console.warn("Router.use() is not supported in child components");const a=await n.render();document.querySelector("#root").innerHTML!==a&&(document.querySelector("#root").innerHTML=a),n.bindMount(),n.onMount()}catch(e){console.error(e)}},setQuery:e=>{let t="";Object.keys(e).forEach(((r,n)=>{t+=`${0===n?"?":"&"}${r}=${e[r]}`}));let r=window.location.hash.split("?")[0];t=t.replace("/","-").replaceAll("/","-"),window.location.hash=`${r}${t}`},send:e=>{document.querySelector("#root").innerHTML=e},json:e=>{const t=document.querySelector("#root");t.innerHTML="";const r=document.createElement("pre");r.textContent=JSON.stringify(e,null,2),t.appendChild(r)}};middlewares.forEach((e=>{e(i,a)})),n&&n.handler(i,a)}}window.VaderRouter=VaderRouter;export default VaderRouter;
1
+ import{Component}from"./vader.js";let middlewares=[];class VaderRouter{constructor(e,t){this.routes=[],this.middlewares=[],this.errorMiddlewares=[],this.listeners=[],this.basePath=e}get(e,t){this.routes.push({path:e,handler:t,method:"get"})}use(e){this.middlewares.push(e)}listen(e,t){e||(e=Math.random().toString(36).substring(7)),window.onpopstate=async e=>{let t=window.location.pathname,r=`/${t.split("/")[1]}`;console.log("route",t),this.checkroute(t)||window.devMode||(t="/404");let n=(new DOMParser).parseFromString(await fetch(r,{cache:"reload"}).then((e=>e.text())),"text/html").documentElement;document.querySelector("#root").innerHTML=n.querySelector("#root").innerHTML,document.title=n.querySelector("title")?n.querySelector("title").innerHTML:document.title,document.querySelector('script[id="router"]').remove();let o=document.createElement("script");o.id="router",o.innerHTML=n.querySelector('script[id="router"]').innerHTML,o.setAttribute("type","module"),document.body.appendChild(o)},window.rehydrate=async()=>{window.location.reload()},this.listeners.push(e),1===this.listeners.length?this.handleRoute(window.location.pathname):this.listeners.pop(),t&&t()}extractParams(e,t){const r=e.split("/").filter((e=>""!==e)),n=t.split("/").filter((e=>""!==e)),o={};return r.forEach(((e,t)=>{if(e.startsWith(":")){const r=e.slice(1);o[r]=n[t]}else if(e.startsWith("*")){n.slice(t).forEach(((e,t)=>{o[t]=e}))}})),o}extractQueryParams(e){const t=e.split("?")[1];if(!t)return{};const r={};return t.split("&").forEach((e=>{const[t,n]=e.split("=");r[t]=n})),r}checkroute(e){return e=e.endsWith("/")?e.slice(0,-1):e,this.routes.find((t=>{if(t.path===e)return!0;if(""===e&&"/"===t.path)return!0;if(e.includes("?")&&(e=e.split("?")[0]),t.path.includes("*")||t.path.includes(":")){const r=t.path.split("/").filter((e=>""!==e)),n=e.split("/").filter((e=>""!==e));if(r.length!==n.length&&!t.path.endsWith("*"))return!1;for(let e=0;e<r.length;e++){const t=r[e],o=n[e];if(!t.startsWith(":")&&!t.startsWith("*")&&t!==o)return!1}return!0}const r=this.extractParams(t.path,e);return Object.keys(r).length>0}))}handleRoute(e){let t=200,r=e,n=this.checkroute(e);n||(n=window.routes.find((e=>!e.url.includes("/404")||this.error||window.devMode?!(this.error||!e.url.includes("/404"))||void 0:(window.history.pushState({},"","/404"),window.dispatchEvent(new Event("popstate")),this.error=!0,!1))),t=n?200:404);const o=this.extractQueryParams(r),s=n&&n.path?this.extractParams(n.path,r):{};Object.keys(s).forEach((e=>{s[e]=s[e].split("?")?s[e].split("?")[0]:s[e]}));const i={headers:{},params:s,query:o,path:e,fileUrl:window.location.href.split(window.location.origin)[1],url:window.location.href,method:n?n.method:"get",pause:!1,timestamp:Date.now()};window.$CURRENT_URL=i.path,window.$FULL_URL=window.location.href.replace("#","");const a={status:t,log:e=>{void 0===e?console.log(`${i.path} ${i.method} ${a.status} ${i.timestamp}`):console.table({"Request Path":i.path,"Request Method":n.method,"Response Status":a.status,"Request Timestamp":i.timestamp})},refresh:()=>{this.handleRoute(window.location.pathname)},redirect:e=>{!e.startsWith("/")&&(e=`/${e}`),window.history.pushState({},"",e),window.dispatchEvent(new Event("popstate"))},render:async(e,t,r,n)=>{function isClass(e){return"function"==typeof e&&/^class\s/.test(Function.prototype.toString.call(e))}try{let n=new Component;if(isClass(e.default)){let t=new e.default;n.state=t.state,n=t}else{e.default.toString();n.key=e.default.toString().split('key="')[1]?e.default.toString().split('key="')[1].split('"')[0]:null;let i=e.default.toString().split("this.key")[1]?e.default.toString().split("this.key")[1].split("=")[1].split(";")[0].trim().replaceAll('"',""):null;i&&(n.key=i),console.log("key",n.key);let a={key:n.key,render:()=>{let o=document.createElement("div");return n.key&&o.setAttribute("key",n.key),o.innerHTML=e.default.apply(n,[t,r]),o.outerHTML},request:t,response:r,params:s,queryParams:o,reset:n.reset.bind(n),onMount:n.onMount.bind(n),useState:null,router:{use:n.router.use.bind(n)},bindMount:n.bindMount.bind(n),memoize:n.memoize.bind(n),createComponent:n.createComponent.bind(n),isChild:!1,useState:n.useState.bind(n),parseStyle:n.parseStyle.bind(n),bind:n.bind.bind(n),useRef:n.useRef.bind(n),useReducer:n.useReducer.bind(n),onMount:n.onMount.bind(n),onUnmount:n.onUnmount.bind(n),hydrate:n.hydrate.bind(n)};n.render=a.render,n=a}if(!document.querySelector("#root"))throw new Error("Root element not found, please add an element with id root");n.reset(),n.components={},n.request=t,n.response=r,n.router.use&&!n.isChild?await new Promise((async o=>{if(isClass(e.default))if(isClass(e.default))switch(await n.router.use(t,r),t.pause){case!0:console.log("pausing",t.pause);let e=setInterval((()=>{t.pause?console.log("still pausing",t.pause):(clearInterval(e),o())}),1e3);break;case!1:o()}else o();else switch(await e.default.apply(n,[t,r]),await n.router.use(t,r),t.pause){case!0:let e=setInterval((()=>{t.pause?console.log("still pausing request",t.url):(clearInterval(e),o())}),1e3);break;case!1:o()}})):n.router.use&&n.isChild&&console.warn("Router.use() is not supported in child components");const i=await n.render();document.querySelector("#root").innerHTML!==i&&(document.querySelector("#root").innerHTML=i),n.bindMount(),n.onMount()}catch(e){console.error(e)}},setQuery:e=>{let t="";Object.keys(e).forEach(((r,n)=>{t+=`${0===n?"?":"&"}${r}=${e[r]}`}));let r=window.location.hash.split("?")[0];t=t.replace("/","-").replaceAll("/","-"),window.location.hash=`${r}${t}`},send:e=>{document.querySelector("#root").innerHTML=e},json:e=>{const t=document.querySelector("#root");t.innerHTML="";const r=document.createElement("pre");r.textContent=JSON.stringify(e,null,2),t.appendChild(r)}};middlewares.forEach((e=>{e(i,a)})),n&&n.handler(i,a)}}window.VaderRouter=VaderRouter;export default VaderRouter;
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=[],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(){this.state={},this.key=null,this.components={},this.mounted=!1,this.checkIFMounted(),this.memoizes=[],this.functions=[],this.children=[],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=new Component(t);if(r(e))n.props=t||{},n.props.children=s.join("")||[],n.props.children=s.join(""),n.parentNode=this,n.request=this.request,n.response=this.response,n.key=n.props.key?n.props.key:Math.random(),i=n;else{e.toString();i.key=e.toString().split('key="')[1]?e.toString().split('key="')[1].split('"')[0]:null;let r=[];Object.keys(t).forEach((e=>{e.startsWith("$props")&&(r.push(t[e]),delete t[e])})),t=t?{...t,...r.reduce(((e,t)=>({...e,...t})),{}),children:s.join("")||[]}:{children:s.join("")||[]};let n={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),parentNoe:this,props:{...t,children:s.join("")||[]}};i.render=n.render,i=n,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];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(">,",">")),`<span key="${e.key}" >${s}</span>`}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];n&&i&&!n.isEqualNode(i)&&s.push({type:"replace",old:n,new:i.cloneNode(!0)})}return s}updateChangedElements(e){e.forEach((e=>{switch(e.type){case"replace":e.old.parentNode.replaceChild(e.new,e.old);break;case"remove":e.old.remove();break;case"add":e.old.appendChild(e.new.cloneNode(!0))}}))}hydrate(e){if(e){console.log("hydrating");let t=(new DOMParser).parseFromString(this.render(),"text/html").body.querySelector(`[ref="${e}"]`);document.querySelector(`[ref="${e}"]`);document.querySelector(`[ref="${e}"]`).replaceWith(t)}else{let e=this.key?document.querySelector(`[key="${this.key}"]`):null;e&&(e.innerHTML=this.render())}}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)=>{console.log("called");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)`}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()}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.link.setAttribute("onclick",`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=await fetch(t).then((e=>e.text()));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=[],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(){this.state={},this.key=null,this.components={},this.mounted=!1,this.checkIFMounted(),this.memoizes=[],this.functions=[],this.children=[],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 i=new Component(t);if(isClass(e))r.props=t||{},r.props.children=s.join("")||[],r.props.children=s.join(""),r.parentNode=this,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;let r=[];Object.keys(t).forEach((e=>{if(e.startsWith("$props")&&(r.push(t[e]),delete t[e]),e.startsWith("$_ternary")){let s=t[e];delete t[e],Object.keys(s).forEach((e=>{t[e]=s[e]}))}})),t=t?{...t,...r.reduce(((e,t)=>({...e,...t})),{}),children:s.join("")||[]}:{children:s.join("")||[]};let n={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),parentNoe:this,props:{...t,children:s.join("")||[]}};i.render=n.render,i=n,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];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?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 i=e[r],n=t[r];i&&n&&!i.isEqualNode(n)&&s.push({type:"replace",old:i,new:n.cloneNode(!0)})}return s}updateChangedElements(e){e.forEach((e=>{switch(e.type){case"replace":e.old.replaceWith(e.new);break;case"remove":e.old.remove();break;case"add":e.old.appendChild(e.new.cloneNode(!0))}}))}hydrate(e){if(e){console.log("hydrating");let t=(new DOMParser).parseFromString(this.render(),"text/html").body.querySelector(`[ref="${e}"]`);document.querySelector(`[ref="${e}"]`);document.querySelector(`[ref="${e}"]`).replaceWith(t)}else{if(this.key?document.querySelector(`[key="${this.key}"]`):null){let e=(new DOMParser).parseFromString(this.render(),"text/html").body.querySelector(`[key="${this.key}"]`),t=document.querySelector(`[key="${this.key}"]`),s=this.domDifference(t.children,e.children);this.updateChangedElements(s)}}}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,...i){return s+=this.key,window["callFunctions"+this.key]=(e,t)=>{console.log("called");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,i)=>{const n=s(r,t)??t;this.state[e]=n,this.hydrate(i),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.link.setAttribute("onclick",`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,i=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",i),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: ${i}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=await fetch(t).then((e=>e.text()));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
@@ -22,16 +22,8 @@ let writer = async (file, data) => {
22
22
  globalThis.isWriting = null
23
23
  return { _written: true };
24
24
  };
25
-
26
- let start = Date.now()
27
- let bundleSize = 0;
28
- let errorCodes = {
29
- "SyntaxError: Unexpected token '<'": "You forgot to enclose tags in a fragment <></>",
30
- }
31
- /**
32
- * define directories
33
- */
34
-
25
+
26
+ let bundleSize = 0;
35
27
 
36
28
  if (!fs.existsSync(process.cwd() + '/dist')) {
37
29
  fs.mkdirSync(process.cwd() + '/dist')
@@ -48,58 +40,63 @@ if (typeof process.env.isCloudflare !== "undefined" || !fs.existsSync(process.cw
48
40
 
49
41
 
50
42
  function Compiler(func, file) {
51
- let string = func;
52
- // Remove block comments
53
-
43
+ let string = func;
54
44
  let returns = []
55
45
  let comments = string.match(/\{\s*\/\*.*\*\/\s*}/gs)?.map((comment) => comment.trim());
56
46
 
57
- let savedfuncnames = [];
58
- let functions = string.match(
59
- /(?:const|let)\s*([a-zA-Z0-9_-]+)\s*=\s*function\s*\(([^)]*)\)|function\s*([a-zA-Z0-9_-]+)\s*\(([^)]*)\)/gs
60
- )
61
- ?.map((match) => match.trim());
47
+
48
+
49
+
50
+
62
51
 
63
- let functionNames = [];
52
+ let childs = [];
64
53
 
54
+ const spreadAttributeRegex = /\s*([a-zA-Z0-9_-]+)(\s*\$\s*=\s*{{((?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*)}})/gs;
55
+ let spreadMatch;
56
+ while ((spreadMatch = spreadAttributeRegex.exec(string)) !== null) {
57
+ let [, element, spread] = spreadMatch;
58
+ let isJSXComponent = element.match(/[A-Z]/) ? true : false;
59
+ if (isJSXComponent) {
60
+ continue
65
61
 
66
- functions && functions.forEach((func) => {
67
- if (
68
- !func.match(
69
- /(?:const|let)\s*([a-zA-Z0-9_-]+)\s*=\s*function\s*\(([^)]*)\)|function\s*([a-zA-Z0-9_-]+)\s*\(([^)]*)\)/gs
70
- )
71
- ) {
72
- return;
73
62
  }
63
+ let old = spread;
74
64
 
75
- let name = func.split(" ")[1].split("(")[0].trim();
65
+ // turn spread into attributes
66
+ spread = spread.replace(/\s*$\s*=\s*/, "");
67
+ spread = spread.replace(/{{/, "");
68
+ spread = spread.replace(/}}/, "");
69
+ spread = spread.replace(/\$\s*=\s*/, "");
76
70
 
77
- let lines = string.match(/return\s*\<>.*\<\/>/gs);
71
+ // turn : into =
78
72
 
79
- if (lines) {
80
- for (let i = 0; i < lines.length; i++) {
81
- let line = lines[i];
82
-
83
- if (!functionNames.includes(name)) {
84
- functionNames.push(name);
85
- }
73
+ // do not split inner Objects ex: {color: 'red', background: {color: 'blue'}} -> {color: 'red', background: {color: 'blue'}}
74
+ let splitByCommas = spread.split(/,(?![^{]*})/g);
75
+ splitByCommas = splitByCommas.map((e) => e.trim())
76
+ splitByCommas = splitByCommas.map((e) => {
77
+ switch (true) {
78
+ case e.includes('function') || e.includes('=>'):
79
+ e = e.replace(/:(.*)/gs, '={$1}')
80
+ break;
81
+ case e.includes('style'):
82
+ e = e.replace(/:(.*)/gs, '="${this.parseStyle($1)}"')
83
+ break;
84
+ case e.includes('[') && e.includes(']'):
85
+ e = e.replace(/:(.*)/gs, '={$1.join(" ")}')
86
+ break;
87
+ default:
88
+ e = e.replace(/:(.*)/gs, '=$1')
89
+ break;
86
90
  }
87
- }
88
- });
89
-
90
- // get all Obj({}) and parse to JSON.stringify
91
91
 
92
- let objects = string.match(/Obj\({.*}\)/gs);
92
+ return e.trim()
93
+ })
93
94
 
94
- objects && objects.forEach((obj) => {
95
- let key = obj.split("Obj")[1].split("(")[1].split(")")[0].trim();
96
- let newobj = obj.replaceAll(`Obj(${key})`, `${key}`);
97
- // let newobj = obj.replaceAll(`Obj(${key})`, `JSON.parse('${key}')`)
98
- string = string.replaceAll(obj, `this.handleObject('${newobj}')`);
99
- });
95
+ let newSpread = `\t` + splitByCommas.join(' ') + `\t`
100
96
 
97
+ string = string.replace(old, newSpread);
101
98
 
102
- let childs = [];
99
+ }
103
100
 
104
101
 
105
102
 
@@ -112,41 +109,40 @@ function Compiler(func, file) {
112
109
  const attributeRegex =
113
110
  /\s*([a-zA-Z0-9_-]+)(\s*=\s*("([^"\\]*(\\.[^"\\]*)*)"|'([^'\\]*(\\.[^'\\]*)*)'|\{(?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*\}|(?:\([^)]*\)|\{[^}]*\}|()=>\s*(?:\{[^}]*\})?)|\[[^\]]*\]))?/gs;
114
111
 
115
- // only return elements with attribute {()=>{}} or if it also has parameters ex: onclick={(event)=>{console.log(event)}} also get muti line functions
112
+
113
+
114
+
116
115
  const functionAttributeRegex = /\s*([a-zA-Z0-9_-]+)(\s*=\s*{((?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*)})/gs;
117
116
 
118
117
  let attributesList = [];
119
118
 
120
- // handle functions
119
+ let spreadAttributes = [];
120
+ let spreadMatch;
121
+ /**
122
+ * @search - handle spread for html elements
123
+ * @keywords - spread, spread attributes, spread props, spread html attributes
124
+ */
125
+
126
+
127
+ /**
128
+ * @search - handle function parsing for html elements
129
+ * @keywords - function, function attributes, function props, function html attributes
130
+ *
131
+ */
121
132
  let functionAttributes = [];
122
133
  let functionMatch;
123
134
  while ((functionMatch = functionAttributeRegex.exec(code)) !== null) {
124
- let [, attributeName, attributeValue] = functionMatch;
125
135
 
136
+ let [, attributeName, attributeValue] = functionMatch;
126
137
  let attribute = {};
127
138
 
128
- if (attributeValue && attributeValue.includes("=>") || attributeValue && attributeValue.includes("function")) {
129
- let functionparams = [];
130
- // ref with no numbers
139
+ if (attributeValue && attributeValue.includes("=>") || attributeValue && attributeValue.includes("function")
140
+ && !spreadFunctions.includes(attributeValue)
141
+ ) {
142
+
131
143
  let ref = Math.random().toString(36).substring(2).split('').filter((e) => !Number(e)).join('')
132
144
  let old = `${attributeName}${attributeValue}`
133
- functionNames.forEach((name) => {
134
- string.split("\n").forEach((line) => {
135
- if (line.includes(name) && line.includes("function")) {
136
- line = line.trim();
137
- line = line.replace(/\s+/g, " ");
138
-
139
- let ps = line.split("(").slice(1).join("(").split(")")[0].trim();
140
-
141
- // remove comments
142
- ps = ps.match(/\/\*.*\*\//gs)
143
- ? ps.replace(ps.match(/\/\*.*\*\//gs)[0], "")
144
- : ps;
145
- functionparams.push({ ref: ref, name: name, params: ps });
146
-
147
- }
148
- });
149
- });
145
+
150
146
  let elementMatch = string.match(/<([a-zA-Z0-9_-]+)([^>]*)>/gs);
151
147
  let isJSXComponent = false;
152
148
  elementMatch.forEach((element) => {
@@ -200,8 +196,7 @@ function Compiler(func, file) {
200
196
  newvalue = newvalue.replace(/}\s*$/, '');
201
197
 
202
198
 
203
-
204
- functionparams.length > 0 ? params = params + ',' + functionparams.map((e) => e.name).join(',') : null
199
+
205
200
 
206
201
  newvalue = newvalue.replaceAll(',,', ',')
207
202
  let paramnames = params ? params.split(',').map((e) => e.trim()) : null
@@ -224,6 +219,10 @@ function Compiler(func, file) {
224
219
  }
225
220
  }
226
221
 
222
+ /**
223
+ * @search - handle attributes for html elements
224
+ * @keywords - attributes, props, html attributes
225
+ */
227
226
  let match;
228
227
  while ((match = elementRegex.exec(code)) !== null) {
229
228
  let [, element, attributes] = match;
@@ -248,8 +247,7 @@ function Compiler(func, file) {
248
247
  let returns = code.match(/return\s*\<>.*\<\/>|return\s*\(.*\)/gs);
249
248
 
250
249
  return returns || [];
251
- }
252
- // throw error if return is not wrapped in <></> or
250
+ }
253
251
  if (string.match(/return\s*\<>|return\s*\(.*\)/gs) && !string.match(/return\s*\<>.*\<\/>|return\s*\(.*\)/gs)
254
252
  || string.match(/return\s*\<[a-zA-Z0-9_-]+.*>/gs)
255
253
  ) {
@@ -265,6 +263,10 @@ function Compiler(func, file) {
265
263
  let outerReturn = extractOuterReturn(string);
266
264
  let contents = "";
267
265
  let updatedContents = "";
266
+ /**
267
+ * @search - handle return [...]
268
+ * @keywords - return, return jsx, return html, return [...]
269
+ */
268
270
  outerReturn.forEach((returnStatement) => {
269
271
 
270
272
  let lines = returnStatement.split("\n");
@@ -278,13 +280,12 @@ function Compiler(func, file) {
278
280
  }
279
281
  let usesBraces = returnStatement.match(/return\s*\(/gs) ? true : false;
280
282
 
281
- let attributes = extractAttributes(contents);
282
- // Remove trailing ']' or trailing )
283
+
283
284
  contents = contents.trim().replace(/\]$/, "")
284
285
  contents = contents.replace(/\)$/, "");
285
286
  usesBraces ? !contents.includes('<>') ? contents = `<>${contents}</>` : null : null
286
287
  updatedContents = contents;
287
-
288
+ let attributes = extractAttributes(contents);
288
289
 
289
290
  let newAttributes = [];
290
291
  let oldAttributes = [];
@@ -363,9 +364,7 @@ function Compiler(func, file) {
363
364
  valuestate = valuestate.match(regex) ? valuestate.match(regex)[0].split("useState(")[1].split(")")[0].trim() : valuestate
364
365
 
365
366
 
366
- let newState = `${varType} [${key}, ${setKey}] = this.useState('${key}', ${valuestate}
367
-
368
- `;
367
+ let newState = `${varType} [${key}, ${setKey}] = this.useState('${key}', ${valuestate}`;
369
368
  string = string.replace(line, newState);
370
369
  break;
371
370
  case line.includes("useRef") && !line.includes("import"):
@@ -410,25 +409,24 @@ function Compiler(func, file) {
410
409
  string = string.replaceAll('../src', './src')
411
410
 
412
411
  function parseComponents(body, isChild) {
413
- let componentRegex = /<([A-Z][A-Za-z0-9_-]+)([^>]*)>(.*?)<\/\1>|<([A-Z][A-Za-z0-9_-]+)([^]*?)\/>/gs;
412
+ let componentRegex = /<([A-Z][A-Za-z0-9_-]+)\s*([^>]*)>\s*([\s\S]*?)\s*<\/\1>|<([A-Z][A-Za-z0-9_-]+)([^]*?)\/>/gs;
414
413
 
415
414
  let componentMatch = body.match(componentRegex);
416
415
  let topComponent = "";
417
416
  componentMatch?.forEach(async (component) => {
418
417
 
419
418
  let [, element, attributes] = component;
420
-
419
+ let before = component;
420
+ component = component.trim().replace(/\s+/g, " ");
421
421
 
422
422
  !isChild ? (topComponent = component) : null;
423
- let before = component;
423
+
424
424
 
425
425
  let myChildrens = [];
426
426
 
427
427
  let name = component.split("<")[1].split(">")[0].split(" ")[0].replace("/", "");
428
- // some components will have props that have html inside of them we need to only get the props ex: <Header title={<h1>hello</h1>}></Header> -> title={<h1>hello</h1>} // also spread props ex: <Header {...props}></Header> -> {...props} or {...props, title: 'hello'} or {...props, color:{color: 'red'}}
429
- // grab ...( spread props )
430
- const dynamicAttributesRegex = /(\w+)(?:="([^"]*)")?(?:='([^']*)')?(?:=\{([^}]*)\})?(?:=\{(.*?)\})?(?:={([^}]*)})?(?:{([^}]*)})?|(?:{(?:[^{}]+|\{(?:[^{}]+|\{[^}]*\})*\})*\})|(\.{3}\{(?:[^{}]+|\{(?:[^{}]+|\{[^}]*\})*\})*\})/gs;
431
-
428
+ let componentAttributes = component.split("<")[1].split(">")[0].split(" ").join(" ").replace(name, "").trim();
429
+ const dynamicAttributesRegex = /(\w+)(?:="([^"]*)")?(?:='([^']*)')?(?:=\{([^}]*)\})?(?:=\{(.*?)\})?(?:={([^}]*)})?(?:{([^}]*)})?|(?:{(?:[^{}]+|\{(?:[^{}]+|\{[^}]*\})*\})*\})|(\.{3}\{(?:[^{}]+|\{(?:[^{}]+|\{[^}]*\})*\})*\})|\$=\{(?:[^{}]+|\{(?:[^{}]+|\{[^}]*\})*\})*\}/gs;
432
430
 
433
431
 
434
432
 
@@ -439,18 +437,31 @@ function Compiler(func, file) {
439
437
  let filteredProps = [];
440
438
  let isWithinComponent = false;
441
439
  let componentName = name
440
+ let currentProps = []
441
+
442
+ let $_ternaryprops = []
442
443
 
443
444
  for (let prop of props) {
444
445
 
445
446
  if (prop === componentName) {
446
-
447
- // If the component is encountered, start collecting props
447
+
448
448
  isWithinComponent = true;
449
449
  filteredProps.push(prop);
450
450
  } else if (isWithinComponent && prop.includes('=')) {
451
451
 
452
- if (prop.includes('${')) {
453
- // if it has an object inside of it then we should just do soemting:object else we should do something: `${object}`
452
+ if (prop.startsWith('$=')) {
453
+ let old = prop
454
+ prop = prop.replace('$=', '$_ternary=')
455
+
456
+ // remove trailing }
457
+ prop = prop.replace(/}\s*$/, '')
458
+ component = component.replace(old, prop)
459
+ componentAttributes = componentAttributes.replace(old, prop)
460
+
461
+ $_ternaryprops.push(prop)
462
+
463
+ }
464
+ else if (prop.includes('${')) {
454
465
 
455
466
  prop = prop.replace('="', ':').replace('}"', '}')
456
467
  if (prop.includes('${')) {
@@ -467,7 +478,7 @@ function Compiler(func, file) {
467
478
  }
468
479
 
469
480
  }
470
- if (prop.startsWith('={')) {
481
+ else if (prop.startsWith('={')) {
471
482
  prop = prop.replace('={', ':`${')
472
483
  prop.replace('} ', '}`')
473
484
  }
@@ -487,72 +498,25 @@ function Compiler(func, file) {
487
498
  filteredProps.push(prop);
488
499
 
489
500
 
490
- }
491
- else if (isWithinComponent && prop.includes('...')) {
492
-
493
-
494
-
495
- // Check if spread props are within curly braces
496
- if (prop.startsWith('{') && prop.endsWith('}')) {
497
- const spreadObject = prop
498
- const hasOtherObjects = spreadObject.split(',').filter((e) => e.includes(':')).length > 0;
499
-
500
- const isValidSpread = spreadObject.includes('...');
501
-
502
- let processedSpreadObject = '';
503
- if (isValidSpread) {
504
- // Split the spreadObject by commas and process each part individually
505
- const parts = spreadObject.split(',').map((part) => {
506
- if (part.trim().startsWith('{') && part.trim().endsWith('}')) {
507
- const nestedParts = part
508
- .trim()
509
- .slice(1, -1) // Remove outer {}
510
- .split(',')
511
- .map((nestedPart) => {
512
- return nestedPart.includes('...') ? nestedPart.trim().replace(/\.\.\./, '') : `...${nestedPart.trim()}`;
513
- });
514
- return `{${nestedParts.join(',')}}`;
515
- } else {
516
- return part.includes('...') ? part.trim() : part.trim().startsWith('{') ? `...${part.trim()}` : `${part.trim()}`;
517
- }
518
- });
519
- if (!parts.join(',').includes('{(')) {
520
-
521
- processedSpreadObject = `${parts.join(',')}`
522
-
523
- } else {
524
- let prop = parts.join(',')
525
- prop = prop.replaceAll('{(', '(')
526
- prop = prop.replaceAll(')}', ')')
527
- processedSpreadObject = prop
528
- }
529
- if (prop.includes('{{')) {
530
- let prop = parts.join(',')
531
- prop = prop.replaceAll('{{', '{')
532
- prop = prop.replaceAll('}}', '}')
533
- processedSpreadObject = prop
534
- }
535
-
536
501
 
537
- } else {
538
- // Process nested structures within the object
539
- processedSpreadObject = `{...${spreadObject}}`;
540
- }
541
-
542
- const $propsKey = `$props_${Math.random().toString(36).substring(2)}`;
543
- filteredProps.push(`${$propsKey}:${processedSpreadObject}`);
544
- }
545
502
  }
546
503
 
504
+
547
505
  else {
548
506
  isWithinComponent = false;
549
507
  }
550
508
  }
509
+ component = component.replaceAll(/\s+/g, " ");
551
510
 
552
- // get inner content of <Component>inner content</Component>
553
- let children = new RegExp(`<${name}[^>]*>(.*?)<\/${name}>`, "gs").exec(component) ? new RegExp(`<${name}[^>]*>(.*?)<\/${name}>`, "gs").exec(component)[1] : null;
511
+ component = component.replace(componentAttributes, '')
512
+ $_ternaryprops.forEach((prop) => {
513
+ component = component.replace(prop, '')
514
+ })
554
515
 
555
- props = filteredProps.join(',')
516
+ let children = component.split(`<${name}`)[1].split(`</${name}>`)[0].trim().replace(/\s+/g, " ").trim().replace(/,$/, '').replace('>', '').replace(/\/$/, '').trim()
517
+
518
+
519
+ props = filteredProps.join(',').replace(/\s+/g, " ").trim().replace(/,$/, '')
556
520
 
557
521
  let savedname = name;
558
522
 
@@ -573,12 +537,13 @@ function Compiler(func, file) {
573
537
  /<([A-Z][A-Za-z0-9_-]+)([^>]*)>(.*?)<\/\1>|<([A-Z][A-Za-z0-9_-]+)([^]*?)\/>/gs
574
538
  );
575
539
  if (html) {
576
- html = html.map((h) => h.trim().replace(/\s+/g, " ")).join(" ");
540
+ html = html.map((h) => h.trim().replace(/\s+/g, " ")).join(" ");
577
541
  child.children = child.children.replaceAll(html, `${html}`);
578
542
  // remove duplicate quotes
579
543
  }
580
544
 
581
545
  myChildrens.push(child.children);
546
+ childs = childs.filter((e) => e.parent !== name);
582
547
  }
583
548
  });
584
549
 
@@ -599,8 +564,10 @@ function Compiler(func, file) {
599
564
  * @memoize - memoize a component to be remembered on each render and replace the old jsx
600
565
  */
601
566
 
567
+
602
568
  let replace = "";
603
- replace = `\${this.memoize(this.createComponent(${savedname}, {${props}}, [\`${myChildrens.join(" ")}\`]))}`;
569
+ replace = `\${this.memoize(this.createComponent(${savedname}, {${props}}, [\`${myChildrens.join('')}\`]))}`;
570
+
604
571
 
605
572
  body = body.replace(before, replace);
606
573
  });
@@ -613,55 +580,56 @@ function Compiler(func, file) {
613
580
  const importRegex = /import\s*([^\s,]+|\{[^}]+\})\s*from\s*(['"])(.*?)\2/g;
614
581
  const imports = string.match(importRegex);
615
582
  let replaceMents = [];
616
-
617
-
618
- for (let match of imports) {
583
+
584
+
585
+ for (let match of imports) {
619
586
  let path = match.split('from')[1].trim().replace(/'/g, '').replace(/"/g, '').trim()
620
587
  switch (true) {
621
588
  case path && !path.includes('./') && !path.includes('/vader.js') && !path.includes('/vaderjs/client') && !path.startsWith('src') && !path.startsWith('public') && !path.includes('http') && !path.includes('https'):
622
- let componentFolder = fs.existsSync(process.cwd() + '/node_modules/' + path) ? process.cwd() + '/node_modules/' + path : process.cwd() + '/node_modules/' + path.split('/')[0]
623
- componentFolder = componentFolder.split(process.cwd())[1]
624
- if(!fs.existsSync(process.cwd() + componentFolder)){
589
+ let componentFolder = fs.existsSync(process.cwd() + '/node_modules/' + path) ? process.cwd() + '/node_modules/' + path : process.cwd() + '/node_modules/' + path.split('/')[0]
590
+ componentFolder = componentFolder.split(process.cwd())[1]
591
+ if (!fs.existsSync(process.cwd() + componentFolder)) {
625
592
  throw new Error('Could not find ' + path + ' at ' + match + ' in file ' + file)
626
- }
627
-
628
- if(!fs.existsSync(process.cwd() + '/dist/src/' + componentFolder.split('/').slice(2).join('/'))){
629
- fs.mkdirSync(process.cwd() + '/dist/src/' + componentFolder.split('/').slice(2).join('/'), { recursive: true })
593
+ }
594
+
595
+ if (!fs.existsSync(process.cwd() + '/dist/src/' + componentFolder.split('/').slice(2).join('/'))) {
596
+ fs.mkdirSync(process.cwd() + '/dist/src/' + componentFolder.split('/').slice(2).join('/'), { recursive: true })
597
+ }
598
+
599
+ let baseFolder = componentFolder.split('node_modules')[1].split('/')[1]
600
+ let glp = globSync('**/**/**/**.{jsx,js}', {
601
+ cwd: process.cwd() + '/node_modules/' + baseFolder + '/',
602
+ absolute: true,
603
+ recursive: true
604
+ })
605
+ for (let file of glp) {
606
+ let text = fs.readFileSync(file, "utf8");
607
+ if (!file.endsWith('.js') && file.endsWith('.jsx')) {
608
+ text = Compiler(text, file);
609
+
630
610
  }
631
-
632
- let baseFolder = componentFolder.split('node_modules')[1].split('/')[1]
633
- let glp = globSync('**/**/**/**.{jsx,js}', {
634
- cwd: process.cwd() + '/node_modules/' + baseFolder + '/',
635
- absolute: true,
636
- recursive: true
637
- })
638
- for (let file of glp) {
639
- let text = fs.readFileSync(file, "utf8");
640
- if(!file.endsWith('.js') && file.endsWith('.jsx')){
641
- text = Compiler(text, file);
642
- }
643
- let dest = file.split('node_modules')[1]
644
- dest = dest.split(baseFolder)[1]
645
- // write to dist
646
- writer(process.cwd() + '/dist/src/' + baseFolder + dest, text)
647
- let importname = match.split('import')[1].split('from')[0].trim()
648
- let oldImportstring = match.split('from')[1].trim().replace(/'/g, '').replace(/"/g, '').trim()
649
- let newImport = `/src/${baseFolder + dest}`
650
- newImport = newImport.replaceAll('.jsx', '.js').replaceAll('\\', '/')
651
- replaceMents.push({ match: oldImportstring, replace: newImport })
652
- console.log(`📦 imported Node Package ${baseFolder} `)
653
- }
654
-
611
+ let dest = file.split('node_modules')[1]
612
+ dest = dest.split(baseFolder)[1]
613
+ // write to dist
614
+ writer(process.cwd() + '/dist/src/' + baseFolder + dest, text)
615
+ let importname = match.split('import')[1].split('from')[0].trim()
616
+ let oldImportstring = match.split('from')[1].trim().replace(/'/g, '').replace(/"/g, '').trim()
617
+ let newImport = `/src/${baseFolder + dest}`
618
+ newImport = newImport.replaceAll('.jsx', '.js').replaceAll('\\', '/')
619
+ replaceMents.push({ match: oldImportstring, replace: newImport })
620
+ console.log(`📦 imported Node Package ${baseFolder} `)
621
+ }
622
+
655
623
 
656
624
  break;
657
625
  default:
658
626
  break;
659
627
  }
660
- }
661
-
662
- for(let replace of replaceMents){
628
+ }
629
+
630
+ for (let replace of replaceMents) {
663
631
  string = string.replaceAll(replace.match, replace.replace)
664
- }
632
+ }
665
633
 
666
634
  string = string.replaceAll(/\$\{[^{]*\.{3}/gs, (match) => {
667
635
  if (match.includes('...')) {
@@ -716,7 +684,7 @@ function Compiler(func, file) {
716
684
  let asyncimportMatch = line.match(/import\s*\((.*)\)/gs);
717
685
  // handle import { Component } from 'vaderjs/runtime/vader.js'
718
686
  let regularimportMatch = line.match(/import\s*([A-Za-z0-9_-]+)\s*from\s*([A-Za-z0-9_-]+)|import\s*([A-Za-z0-9_-]+)\s*from\s*(".*")|import\s*([A-Za-z0-9_-]+)\s*from\s*('.*')|import\s*([A-Za-z0-9_-]+)\s*from\s*(\{.*\})/gs);
719
-
687
+
720
688
  if (asyncimportMatch) {
721
689
  asyncimportMatch.forEach(async (match) => {
722
690
  let beforeimport = match
@@ -770,7 +738,7 @@ function Compiler(func, file) {
770
738
 
771
739
  let newImport = ''
772
740
  let name = match.split('import')[1].split('from')[0].trim()
773
-
741
+
774
742
 
775
743
  switch (true) {
776
744
  case path && path.includes('json'):
@@ -796,9 +764,9 @@ function Compiler(func, file) {
796
764
  newImport = ``
797
765
  break;
798
766
  case path && !path.startsWith('./') && !path.includes('/vader.js') && !path.startsWith('src') && !path.startsWith('public') &&
799
- path.match(/^[A-Za-z0-9_-]+$/gs) && !path.includes('http') && !path.includes('https'):
800
- console.log(path)
801
- break;
767
+ path.match(/^[A-Za-z0-9_-]+$/gs) && !path.includes('http') && !path.includes('https'):
768
+
769
+ break;
802
770
  default:
803
771
  let beforePath = path
804
772
  let deep = path.split('/').length - 1
@@ -856,14 +824,7 @@ async function Build() {
856
824
  return text;
857
825
  };
858
826
 
859
-
860
-
861
-
862
-
863
-
864
- // Process files in the 'pages' directory
865
- let appjs = '';
866
- let hasWritten = []
827
+
867
828
  function ssg(routes = []) {
868
829
  globalThis.isBuilding = true
869
830
  console.log(`Generating html files for ${routes.length} routes`)
@@ -1019,38 +980,47 @@ async function Build() {
1019
980
  headless: "new", args: ['--no-sandbox', '--disable-setuid-sandbox'],
1020
981
  warning: false,
1021
982
  })
1022
-
983
+
1023
984
  const browserPID = browser.process().pid
1024
985
  try {
1025
986
 
1026
987
  route.url = route.url.replaceAll(/\/:[a-zA-Z0-9_-]+/gs, '')
1027
988
  let page = await browser.newPage();
1028
989
  await page.goto(`http://localhost:${port}/`, { waitUntil: 'networkidle2' });
990
+ await page.on('console', msg => console.log('PAGE LOG:', msg.text()));
991
+ await page.on('error', err => console.log('PAGE LOG:', err));
992
+ await page.on('pageerror', err => console.log('PAGE LOG:', err));
993
+ await page.evaluate(() => {
994
+ window.onerror = function (msg, url, lineNo, columnNo, error) {
995
+ console.log(msg, url, lineNo, columnNo, error)
996
+ }
997
+ })
1029
998
  await page.waitForSelector('#root', { timeout: 10000 })
1030
999
  await page.evaluate(() => {
1031
1000
  document.getElementById('meta').remove()
1032
1001
  document.querySelector('#isServer').innerHTML = 'window.isServer = false'
1033
1002
  if (document.head.getAttribute('prerender') === 'false') {
1034
1003
  document.querySelector('#root').innerHTML = ''
1004
+ console.log(`Disabled prerendering for ${window.location.pathname}`)
1035
1005
  }
1036
- })
1006
+ })
1037
1007
  const html = await page.content();
1038
1008
 
1039
1009
  await page.close();
1040
1010
  await writer(process.cwd() + '/dist/' + (route.url === '/' ? 'index.html' : `${route.url}/` + 'index.html'), html)
1041
1011
  await browser.close();
1042
1012
  server.close()
1043
-
1013
+
1044
1014
  } catch (error) {
1045
1015
  server.close()
1046
- await browser.close();
1016
+ await browser.close();
1047
1017
  }
1048
1018
  finally {
1049
1019
  await browser.close();
1050
- server.close()
1020
+ server.close()
1051
1021
  }
1052
1022
  try {
1053
- process.kill(browserPID )
1023
+ process.kill(browserPID)
1054
1024
  } catch (error) {
1055
1025
  }
1056
1026
 
@@ -1093,10 +1063,10 @@ async function Build() {
1093
1063
 
1094
1064
 
1095
1065
  let data = await fs.readFileSync(origin, "utf8");
1066
+ console.log(`Compiling ${fileName}...`)
1096
1067
  data = Compiler(data, origin);
1097
1068
 
1098
1069
 
1099
-
1100
1070
  await writer(process.cwd() + "/dist/" + fileName.replace('.jsx', '.js'), data).then(async () => {
1101
1071
 
1102
1072
 
@@ -1259,7 +1229,7 @@ async function Build() {
1259
1229
  console.log(`📦 Build completed: Build Size -> ${Math.round(bundleSize / 1000)}kb`)
1260
1230
 
1261
1231
  bundleSize = 0;
1262
-
1232
+
1263
1233
  return true
1264
1234
  }
1265
1235
  const s = () => {
@@ -1389,7 +1359,7 @@ Vader.js v1.3.3
1389
1359
  }
1390
1360
  }).on('error', (err) => console.log(err))
1391
1361
  })
1392
- let p = process.argv[process.argv.indexOf('--watch') + 1] || process.env.PORT || 3000
1362
+ let p = process.argv[process.argv.indexOf('--watch') + 1] || process.env.PORT || 3000
1393
1363
 
1394
1364
  process.env.PORT = p
1395
1365
  s()