vaderjs 1.3.3-alpha-52 → 1.3.3-alpha-56

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
@@ -84,11 +84,14 @@ import Mycomponent from './src/mycomponent.jsx'
84
84
  export default class extends Component {
85
85
  constructor() {
86
86
  super();
87
- this.key = '2'
87
+ this.key = 2 // you can explicitly set key
88
88
  }
89
89
  render() {
90
90
  return <>
91
- <div key={this.key}>
91
+ ${/**
92
+ or set it directly to the element and hydration will grab it
93
+ **/}
94
+ <div key={2}>
92
95
  <p>Hello World</p>
93
96
  </div>
94
97
  <Mycomponent ..props />
@@ -106,17 +109,45 @@ Function based components
106
109
  import Mycomponent from './src/mycomponent.jsx'
107
110
  // function components have direct access to request and response both param way and using this.request or this.response!
108
111
  export default function(req, res){
109
- this.key = ''
112
+ this.key = '' // you can explicitly set key
110
113
 
111
114
  return <>
115
+ ${/**
116
+ or set it directly to the element and hydration will grab it
117
+ **/}
118
+ <div key="somevalue">
112
119
  <h1>hello world</>
113
120
  <Mycomponent ...props />
121
+ </div>
114
122
  </>
115
123
  }
116
124
 
117
125
  ```
118
126
 
127
+ ### Styling
119
128
 
129
+ Vaderjs has two types of in javascript styling - css modules and inline jsx styling
130
+ ```jsx
131
+
132
+ // inline
133
+ <button style={{color:'red'}}>Button</button>
134
+
135
+ // css module
136
+
137
+ //public/app.module.css
138
+ `
139
+ .container{
140
+ color:red;
141
+ font-size:20px
142
+ }
143
+ `
144
+
145
+ // import file
146
+ import style from 'public/app.module.css' // this gets replaced with the compiled css output
147
+
148
+ <button style={{...style.container}}>Button </button>
149
+
150
+ ```
120
151
  ### State Management
121
152
  Vaderjs uses partial hydration & full reflection
122
153
 
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-alpha-52",
5
+ "version": "1.3.3-alpha-56",
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(t,e){this.routes=[],this.middlewares=[],this.errorMiddlewares=[],this.listeners=[],this.basePath=t}get(t,e){this.routes.push({path:t,handler:e,method:"get"})}use(t){console.log(t),this.middlewares.push(t)}listen(t,e){t||(t=Math.random().toString(36).substring(7)),this.listeners.push(t),1===this.listeners.length?this.handleRoute(window.location.hash):this.listeners.pop(),e&&e(),window.onhashchange=()=>{this.handleRoute(window.location.hash)}}extractParams(t,e){const s=t.split("/"),r=e.split("/"),n={};return s.forEach(((t,e)=>{if(t.startsWith(":")){const s=t.slice(1);n[s]=r[e]}else if(t.startsWith("*")){r.slice(e).forEach(((t,e)=>{n[e]=t}))}})),n}extractQueryParams(t){const e=t.split("?")[1];if(!e)return{};const s={};return e.split("&").forEach((t=>{const[e,r]=t.split("=");s[e]=r})),s}handleRoute(t){let e=200,s=t=t.slice(1),r=this.routes.find((e=>{if(e.path===t)return!0;if(""===t&&"/"===e.path)return!0;if(t.includes("?")&&(t=t.split("?")[0]),e.path.includes("*")||e.path.includes(":")){const s=e.path.split("/"),r=t.split("/");if(s.length!==r.length&&!e.path.endsWith("*"))return!1;for(let t=0;t<s.length;t++){const e=s[t],n=r[t];if(!e.startsWith(":")&&!e.startsWith("*")&&e!==n)return!1}return!0}const r=this.extractParams(e.path,s);return Object.keys(r).length>0}));r||(r=this.routes.find((t=>{if(t.path.includes("/404"))return this.error=!0,!0;!this.error&&t.path.includes("/404")&&(window.location.hash=this.basePath)})),e=r?200:404);const n=this.extractQueryParams(s),o=r&&r.path?this.extractParams(r.path,s):{},a={headers:{},params:o,query:n,path:t,method:r?r.method:"get"};window.$CURRENT_URL=a.path,window.$FULL_URL=window.location.href.replace("#","");const i={status:e,log:t=>{void 0===t?console.log(`${a.path} ${a.method} ${i.status} ${a.timestamp}`):console.table({"Request Path":a.path,"Request Method":r.method,"Response Status":i.status,"Request Timestamp":a.timestamp})},refresh:()=>{this.handleRoute(window.location.hash)},redirect:t=>{!t.startsWith("/")&&(t=`/${t}`),window.location.hash=`#${t}`},render:async(t,e,s)=>{try{let a=new Component;if("function"==typeof(r=t.default)&&/^class\s/.test(Function.prototype.toString.call(r))){let e=new t.default;a.state=e.state,console.log(a.state),a=e}else{let r=t.default.toString(),i=r.split("this.key")[1].split("=")[1].split('"')[1],l=(r.match(/return\s*`([\s\S]*)`/),r.split("return")[1].split("`")[0]);l=l.replace(/,\s*$/,""),a.key=i;let h={key:a.key,render:()=>t.default.apply?t.default.apply(a,[e,s]):new t.default,request:e,response:s,params:o,queryParams:n,reset:a.reset.bind(a),onMount:a.onMount.bind(a),useState:null,router:{use:a.router.use.bind(a)},bindMount:a.bindMount.bind(a),memoize:a.memoize.bind(a),createComponent:a.createComponent.bind(a),isChild:!1,useState:a.useState.bind(a),parseStyle:a.parseStyle.bind(a),bind:a.bind.bind(a),hydrate:a.hydrate.bind(a)};a.render=h.render,a=h}if(!document.querySelector("#root"))throw new Error("Root element not found, please add an element with id root");a.reset(),a.components={},a.request=e,a.response=s,a.router.use&&!a.isChild?await new Promise((async t=>{if(await a.router.use(e,s),e.pause){let s=setInterval((()=>{e.pause||(t(),clearInterval(s))}),1e3)}else t()})):a.router.use&&a.isChild&&console.warn("Router.use() is not supported in child components");const i=await a.render();document.querySelector("#root").innerHTML=i,a.bindMount(),a.onMount()}catch(t){console.error(t)}var r},setQuery:t=>{let e="";Object.keys(t).forEach(((s,r)=>{e+=`${0===r?"?":"&"}${s}=${t[s]}`}));let s=window.location.hash.split("?")[0];e=e.replace("/","-").replaceAll("/","-"),window.location.hash=`${s}${e}`},send:t=>{document.querySelector("#root").innerHTML=t},json:t=>{const e=document.querySelector("#root");e.innerHTML="";const s=document.createElement("pre");s.textContent=JSON.stringify(t,null,2),e.appendChild(s)}};middlewares.forEach((t=>{t(a,i)})),r&&r.handler(a,i)}}window.VaderRouter=VaderRouter;export default VaderRouter;
1
+ import{Component}from"./vader.js";let middlewares=[];class VaderRouter{constructor(t,e){this.routes=[],this.middlewares=[],this.errorMiddlewares=[],this.listeners=[],this.basePath=t}get(t,e){this.routes.push({path:t,handler:e,method:"get"})}use(t){console.log(t),this.middlewares.push(t)}listen(t,e){t||(t=Math.random().toString(36).substring(7)),this.listeners.push(t),1===this.listeners.length?this.handleRoute(window.location.hash):this.listeners.pop(),e&&e(),window.onhashchange=()=>{this.handleRoute(window.location.hash)}}extractParams(t,e){const s=t.split("/"),r=e.split("/"),n={};return s.forEach(((t,e)=>{if(t.startsWith(":")){const s=t.slice(1);n[s]=r[e]}else if(t.startsWith("*")){r.slice(e).forEach(((t,e)=>{n[e]=t}))}})),n}extractQueryParams(t){const e=t.split("?")[1];if(!e)return{};const s={};return e.split("&").forEach((t=>{const[e,r]=t.split("=");s[e]=r})),s}handleRoute(t){let e=200,s=t=t.slice(1),r=this.routes.find((e=>{if(e.path===t)return!0;if(""===t&&"/"===e.path)return!0;if(t.includes("?")&&(t=t.split("?")[0]),e.path.includes("*")||e.path.includes(":")){const s=e.path.split("/"),r=t.split("/");if(s.length!==r.length&&!e.path.endsWith("*"))return!1;for(let t=0;t<s.length;t++){const e=s[t],n=r[t];if(!e.startsWith(":")&&!e.startsWith("*")&&e!==n)return!1}return!0}const r=this.extractParams(e.path,s);return Object.keys(r).length>0}));r||(r=this.routes.find((t=>{if(t.path.includes("/404"))return this.error=!0,!0;!this.error&&t.path.includes("/404")&&(window.location.hash=this.basePath)})),e=r?200:404);const n=this.extractQueryParams(s),o=r&&r.path?this.extractParams(r.path,s):{},i={headers:{},params:o,query:n,path:t,method:r?r.method:"get"};window.$CURRENT_URL=i.path,window.$FULL_URL=window.location.href.replace("#","");const a={status:e,log:t=>{void 0===t?console.log(`${i.path} ${i.method} ${a.status} ${i.timestamp}`):console.table({"Request Path":i.path,"Request Method":r.method,"Response Status":a.status,"Request Timestamp":i.timestamp})},refresh:()=>{this.handleRoute(window.location.hash)},redirect:t=>{!t.startsWith("/")&&(t=`/${t}`),window.location.hash=`#${t}`},render:async(t,e,s)=>{try{let i=new Component;if("function"==typeof(r=t.default)&&/^class\s/.test(Function.prototype.toString.call(r))){let e=new t.default;i.state=e.state,console.log(i.state),i=e}else{let r=t.default.toString(),a=r.split("this.key")[1]?r.split("this.key")[1].split("=")[1].split(";")[0].trim():r.split('key="')?r.split('key="')[1].split('"')[0]:null,l=(r.match(/return\s*`([\s\S]*)`/),r.split("return")[1].split("`")[0]);l=l.replace(/,\s*$/,""),i.key=a;let h={key:i.key,render:()=>t.default.apply?t.default.apply(i,[e,s]):new t.default,request:e,response:s,params:o,queryParams:n,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),hydrate:i.hydrate.bind(i)};i.render=h.render,i=h}if(!document.querySelector("#root"))throw new Error("Root element not found, please add an element with id root");i.reset(),i.components={},i.request=e,i.response=s,i.router.use&&!i.isChild?await new Promise((async t=>{if(await i.router.use(e,s),e.pause){let s=setInterval((()=>{e.pause||(t(),clearInterval(s))}),1e3)}else t()})):i.router.use&&i.isChild&&console.warn("Router.use() is not supported in child components");const a=await i.render();document.querySelector("#root").innerHTML=a,i.bindMount(),i.onMount()}catch(t){console.error(t)}var r},setQuery:t=>{let e="";Object.keys(t).forEach(((s,r)=>{e+=`${0===r?"?":"&"}${s}=${t[s]}`}));let s=window.location.hash.split("?")[0];e=e.replace("/","-").replaceAll("/","-"),window.location.hash=`${s}${e}`},send:t=>{document.querySelector("#root").innerHTML=t},json:t=>{const e=document.querySelector("#root");e.innerHTML="";const s=document.createElement("pre");s.textContent=JSON.stringify(t,null,2),e.appendChild(s)}};middlewares.forEach((t=>{t(i,a)})),r&&r.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=[];export const strictMount=(e,t)=>{let n=setInterval((()=>{mounts.find((t=>t.key===e))&&(clearInterval(n),t())}),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,n){function s(e){return"function"==typeof e&&/^class\s/.test(Function.prototype.toString.call(e))}let r=s(e)?new e(t):null;if(!e)throw new Error("Component must be defined");if(!t.key)throw new Error("new components must have a key");if(s(e.default?e.default:e))r.props=t,r.children=n,r.props.children=n.join(""),r.parentNode=this,r.request=this.request,r.response=this.response,r.key=t.key||null;else{e.default&&(e=e.default);let s=new Component(t),o=e.toString(),i=o.includes("this.key")?o.split("this.key")[1].split("=")[1].split('"')[1]:null,u=(o.match(/return\s*`([\s\S]*)`/),o.split("return")[1].split("`")[0]);u=u.replace(/,\s*$/,""),t.children=n.join("");let l=e.apply(s,[t]);s.key=i,t.key=i,r={key:t.key?t.key:i,render:()=>l,request:this.request,response:this.response,reset:s.reset.bind(s),onMount:s.onMount.bind(s),parentNode:this,useState:s.useState.bind(s),useReducer:s.useReducer.bind(s),useRef:s.useRef.bind(s),router:{use:s.router.use.bind(s)},bindMount:s.bindMount.bind(s),memoize:s.memoize.bind(s),createComponent:s.createComponent.bind(s),isChild:!0,parseStyle:s.parseStyle.bind(s),components:{},onUnmount:s.onUnmount.bind(s),onMount:s.onMount.bind(s),functions:[],memoizes:[]}}return this.components[t.key]||(this.components[t.key]=r),this.children.push(r),this.components[t.key]}reset(){console.log("reset"),Object.keys(this.components).forEach((e=>{this.components[e].onUnmount(),delete this.components[e]})),this.state={},this.children=[]}memoize(e){if(!e.key)throw new Error("Component must have a static key");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;let n=t.render();return n&&n.split(">,").length>1&&(n=n.replaceAll(">,",">")),`<div key="${e.key}">${n}</div>`}parseStyle(e){let t="";return Object.keys(e).forEach((n=>{let s=e[n];n=n.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g,"$1-$2").toLowerCase(),t+=`${n}:${s};`})),t}bindMount(){mounts.push(this)}domDifference(e,t){let n=[];for(let s=0;s<e.length;s++){let r=e[s],o=t[s];r&&o&&!r.isEqualNode(o)&&n.push({type:"replace",old:r,new:o.cloneNode(!0)})}return n}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(this.key)if(e){let t=(new DOMParser).parseFromString(this.render(),"text/html").body.firstChild,n=document.body.querySelectorAll(`[ref="${e}"]`),s=t.querySelectorAll(`[ref="${e}"]`),r=this.domDifference(n,s);this.updateChangedElements(r)}else{const e=document.querySelector(`[key="${this.key}"]`);if(e){let t=(new DOMParser).parseFromString(this.render(),"text/html").body.firstChild,n=e.querySelectorAll("*"),s=t.querySelectorAll("*"),r=this.domDifference(n,s);this.updateChangedElements(r)}else console.error("Target element not found.")}}patch(e,t){const n=this.domDifference(e,t);this.updateChangedElements(n)}handleObject(obj){try{obj=JSON.parse(obj)}catch(e){}return eval(obj)}bind(e,t,n,s,r,...o){s+=this.key;let i={},u=(r=r.replace(/,,/g,",")).replaceAll(",,",",");for(var l in o){let e=o[l];i[u.split(",")[l]]=e}r=r.replace(",,",",");let a=new Function(`${r}`,`\n return (async (${r}) => { \n ${e.toString()}\n })(${Object.keys(i).join(",")}) \n `);return a=a.bind(this),this.functions.find((e=>e.ref===s))||document.addEventListener(`$dispatch_#id=${s}`,(n=>{let{name:r,event:o}=n.detail;if(r===s){let n=this.functions.find((e=>e.ref===s)).params;Object.keys(n).forEach((e=>{n[e]instanceof CustomEvent&&delete n[e],void 0===n[e]?delete n[e]:n[e]})),t?e(o,...Object.values(n)):a(...Object.values(n))}})),window.callFunction=(e,t)=>{document.dispatchEvent(new CustomEvent(`$dispatch_#id=${e}`,{detail:{name:e,params:null,event:t}}))},this.functions.find((e=>e.ref===s))?!t&&(this.functions.find((e=>e.ref===s)).params=i):this.functions.push({ref:s,params:i}),n?e:`((event)=>{event.target.ev = event; callFunction('${s}', event.target.ev)})(event)`}useState(e,t){this.state[e]||(this.state[e]=t);let n=()=>this.state[e],s=n();return[s,(t,r)=>{this.state[e]=t,this.hydrate(r),s=n()}]}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,n=null){return[(()=>this.state[e])(),t=>{const s=n?n(this.state[e],t):t;this.state[e]=s}]}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)=>{states[e]||(states[e]=t);return[states[e],(t,n)=>{states[e]=t,this.hydrate(n)}]};export const useReducer=(e,t)=>[e,e=>{}];export const useRef=e=>({current:e,bind:""});export default{Component:Component,useRef:useRef,useReducer:useReducer,useState:useState,strictMount:strictMount};
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 n=setInterval((()=>{document.querySelector(`[key="${e}"]`)&&!hasRan.includes(e)&&(clearInterval(n),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,n){function s(e){return"function"==typeof e&&/^class\s/.test(Function.prototype.toString.call(e))}let r=s(e)?new e(t):null;if(!e)throw new Error("Component must be defined");if(!t.key)throw new Error("new components must have a key");let o=new Component(t);if(s(e.default?e.default:e))r.props=t,r.children=n,r.props.children=n.join(""),r.parentNode=this,r.request=this.request,r.response=this.response,r.key=t.key||null,o=r;else{e.default&&(e=e.default);let s=e.toString(),i=s.includes("this.key")?s.split("this.key")[1].split("=")[1].split('"')[1]:null;t.children=n.join(""),o.key=i,t.key=i,r={key:t.key?t.key:i,render:()=>e.apply(o,[t]),request:this.request,response:this.response,reset:o.reset.bind(o),onMount:o.onMount.bind(o),parentNode:this,useState:o.useState.bind(o),useReducer:o.useReducer.bind(o),useRef:o.useRef.bind(o),router:{use:o.router.use.bind(o)},bindMount:o.bindMount.bind(o),memoize:o.memoize.bind(o),createComponent:o.createComponent.bind(o),isChild:!0,parseStyle:o.parseStyle.bind(o),components:{},onUnmount:o.onUnmount.bind(o),onMount:o.onMount.bind(o),hydrate:o.hydrate.bind(o),functions:[],memoizes:[],state:{}},o.render=r.render.bind(r),o=r}return this.components[t.key]||(this.components[t.key]=o),this.children.push(o),this.components[t.key]}reset(){Object.keys(this.components).forEach((e=>{this.components[e].onUnmount(),delete this.components[e]})),this.state={},this.children=[]}memoize(e){if(!e.key)throw new Error("Component must have a static key");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;let n=t.render();return n&&n.split(">,").length>1&&(n=n.replaceAll(">,",">")),`<div key="${e.key}">${n}</div>`}parseStyle(e){let t="";return Object.keys(e).forEach((n=>{let s=e[n];n=n.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g,"$1-$2").toLowerCase(),t+=`${n}:${s};`})),t}bindMount(){mounts.push(this)}domDifference(e,t){let n=[];for(let s=0;s<e.length;s++){let r=e[s],o=t[s];r&&o&&!r.isEqualNode(o)&&n.push({type:"replace",old:r,new:o.cloneNode(!0)})}return n}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){let t=(new DOMParser).parseFromString(this.render(),"text/html").body.firstChild,n=document.body.querySelectorAll(`[ref="${e}"]`),s=t.querySelectorAll(`[ref="${e}"]`),r=this.domDifference(n,s);this.updateChangedElements(r)}else{let e=this.key?document.querySelector(`[key="${this.key}"]`):null,t=(new DOMParser).parseFromString(this.render(),"text/html").body.firstChild;if(!e&&(e=document.querySelector(`[key="${t.attributes?.key?.value||null}"]`)),!e)return void console.error('Hydration failed, component not found got ensure you have set key="a value" on the component or this.key inside of function or render method body');e.innerHTML=t.innerHTML}}patch(e,t){const n=this.domDifference(e,t);this.updateChangedElements(n)}handleObject(obj){try{obj=JSON.parse(obj)}catch(e){}return eval(obj)}bind(e,t,n,s,r,...o){s=s+this.key||2022;let i={},u=(r=r.replace(/,,/g,",")).replaceAll(",,",",");for(var a in o){let e=o[a];i[u.split(",")[a]]=e}r=r.replace(",,",",");let d=new Function(`${r}`,`\n return (async (${r}) => { \n ${e.toString()}\n })(${Object.keys(i).join(",")}) \n `);return d=d.bind(this),this.functions.find((e=>e.ref===s))||document.addEventListener(`$dispatch_#id=${s}`,(n=>{let{name:r,event:o}=n.detail;if(r===s){let n=this.functions.find((e=>e.ref===s)).params;Object.keys(n).forEach((e=>{n[e]instanceof CustomEvent&&delete n[e],void 0===n[e]?delete n[e]:n[e]})),t?e(o,...Object.values(n)):d(...Object.values(n))}})),window.callFunction=(e,t)=>{document.dispatchEvent(new CustomEvent(`$dispatch_#id=${e}`,{detail:{name:e,params:null,event:t}}))},this.functions.find((e=>e.ref===s))?!t&&(this.functions.find((e=>e.ref===s)).params=i):this.functions.push({ref:s,params:i}),n?e:`((event)=>{event.target.ev = event; callFunction('${s}', event.target.ev)})(event)`}useState(e,t){this.state[e]||(this.state[e]=t);let n=()=>this.state[e],s=n();return[s,(t,r)=>{this.state[e]=t,this.hydrate(r),s=n()}]}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,n=null){this.state[e]||(this.state[e]=t);const s=()=>this.state[e];let r=s();return[s(),(t,o)=>{const i=n(r,t)??t;this.state[e]=i,this.hydrate(o),r=s()}]}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)=>{states[e]||(states[e]=t);return[states[e],(t,n)=>{states[e]=t,this.hydrate(n)}]};export const useReducer=(e,t)=>[e,e=>{}];export const useRef=e=>({current:e,bind:""});export default{Component:Component,useRef:useRef,useReducer:useReducer,useState:useState,strictMount:strictMount};
package/vader.js CHANGED
@@ -2,75 +2,81 @@
2
2
  import fs from "fs";
3
3
  import { glob, globSync, globStream, globStreamSync, Glob, } from 'glob'
4
4
  let bundleSize = 0;
5
- if (!fs.existsSync(process.cwd() + '/dist')) {
6
- fs.mkdirSync(process.cwd() + '/dist')
7
- fs.mkdirSync(process.cwd() + '/dist/public')
8
- fs.mkdirSync(process.cwd() + '/dist/src')
9
- fs.mkdirSync(process.cwd() + '/dist/pages')
10
- }
11
-
12
- if (!fs.existsSync(process.cwd() + '/dist/public')) {
13
- fs.mkdirSync(process.cwd() + '/dist/public')
14
- }
15
-
16
- if (!fs.existsSync(process.cwd() + '/src') && !fs.existsSync(process.cwd() + '/dist/src')) {
17
- fs.mkdirSync(process.cwd() + '/dist/src')
18
- fs.mkdirSync(process.cwd() + '/src')
5
+ let errorCodes = {
6
+ "SyntaxError: Unexpected token '<'": "You forgot to enclose tags in a fragment <></>",
19
7
  }
8
+ /**
9
+ * define directories
10
+ */
11
+ let dirs = {
12
+ ...fs.existsSync(process.cwd() + '/pages') ? { pages: true } : { pages: false },
13
+ ...fs.existsSync(process.cwd() + '/src') ? { components: true } : { components: false },
14
+ ...fs.existsSync(process.cwd() + '/public') ? { public: true } : { public: false },
15
+ ...fs.existsSync(process.cwd() + '/dist') ? { dist: true } : { dist: false },
16
+ ...fs.existsSync(process.cwd() + '/dist/pages') ? { distpages: true } : { distpages: false },
17
+ ...fs.existsSync(process.cwd() + '/dist/src') ? { distcomponents: true } : { distcomponents: false },
18
+ ...fs.existsSync(process.cwd() + '/dist/public') ? { distpublic: true } : { distpublic: false },
19
+ }
20
+
21
+
22
+ Object.keys(dirs).map((key, index) => {
23
+ if (!dirs[key]) {
24
+ fs.mkdirSync('./' + key)
25
+ }
26
+ }).filter(Boolean)[0]
27
+
20
28
 
21
- function Compiler(func) {
29
+
30
+
31
+ function Compiler(func, file) {
22
32
  let string = func;
23
33
  let returns = []
24
- let comments = string
25
-
26
- .match(/\{\s*\/\*.*\*\/\s*}/gs)
27
- ?.map((comment) => comment.trim());
34
+ let comments = string.match(/\{\s*\/\*.*\*\/\s*}/gs)?.map((comment) => comment.trim());
28
35
 
29
36
  let savedfuncnames = [];
30
- let functions = string
31
- .match(
32
- /(?:const|let)\s*([a-zA-Z0-9_-]+)\s*=\s*function\s*\(([^)]*)\)|function\s*([a-zA-Z0-9_-]+)\s*\(([^)]*)\)/gs
33
- )
37
+ let functions = string.match(
38
+ /(?:const|let)\s*([a-zA-Z0-9_-]+)\s*=\s*function\s*\(([^)]*)\)|function\s*([a-zA-Z0-9_-]+)\s*\(([^)]*)\)/gs
39
+ )
34
40
  ?.map((match) => match.trim());
35
41
 
36
42
  let functionNames = [];
37
43
 
38
- if (functions) {
39
- functions.forEach((func) => {
40
- if (
41
- !func.match(
42
- /(?:const|let)\s*([a-zA-Z0-9_-]+)\s*=\s*function\s*\(([^)]*)\)|function\s*([a-zA-Z0-9_-]+)\s*\(([^)]*)\)/gs
43
- )
44
- ) {
45
- return;
46
- }
47
44
 
48
- let name = func.split(" ")[1].split("(")[0].trim();
45
+ functions && functions.forEach((func) => {
46
+ if (
47
+ !func.match(
48
+ /(?:const|let)\s*([a-zA-Z0-9_-]+)\s*=\s*function\s*\(([^)]*)\)|function\s*([a-zA-Z0-9_-]+)\s*\(([^)]*)\)/gs
49
+ )
50
+ ) {
51
+ return;
52
+ }
49
53
 
50
- let lines = string.match(/return\s*\<>.*\<\/>/gs);
54
+ let name = func.split(" ")[1].split("(")[0].trim();
51
55
 
52
- if (lines) {
53
- for (let i = 0; i < lines.length; i++) {
54
- let line = lines[i];
56
+ let lines = string.match(/return\s*\<>.*\<\/>/gs);
55
57
 
56
- if (!functionNames.includes(name)) {
57
- functionNames.push(name);
58
- }
58
+ if (lines) {
59
+ for (let i = 0; i < lines.length; i++) {
60
+ let line = lines[i];
61
+
62
+ if (!functionNames.includes(name)) {
63
+ functionNames.push(name);
59
64
  }
60
65
  }
61
- });
62
- }
66
+ }
67
+ });
68
+
63
69
  // get all Obj({}) and parse to JSON.stringify
64
70
 
65
71
  let objects = string.match(/Obj\({.*}\)/gs);
66
- if (objects) {
67
- objects.forEach((obj) => {
68
- let key = obj.split("Obj")[1].split("(")[1].split(")")[0].trim();
69
- let newobj = obj.replaceAll(`Obj(${key})`, `${key}`);
70
- // let newobj = obj.replaceAll(`Obj(${key})`, `JSON.parse('${key}')`)
71
- string = string.replaceAll(obj, `this.handleObject('${newobj}')`);
72
- });
73
- }
72
+
73
+ objects && objects.forEach((obj) => {
74
+ let key = obj.split("Obj")[1].split("(")[1].split(")")[0].trim();
75
+ let newobj = obj.replaceAll(`Obj(${key})`, `${key}`);
76
+ // let newobj = obj.replaceAll(`Obj(${key})`, `JSON.parse('${key}')`)
77
+ string = string.replaceAll(obj, `this.handleObject('${newobj}')`);
78
+ });
79
+
74
80
 
75
81
  let childs = [];
76
82
 
@@ -142,79 +148,80 @@ function Compiler(func) {
142
148
 
143
149
  let currentParams = params
144
150
  let name = functionNames.map((name) => { return newvalue.includes(name) ? name : null }).filter(Boolean)[0]
145
- if (name) {
151
+ switch (true) {
152
+ case name:
146
153
 
147
- if (newvalue.includes('function')) {
148
- return
149
- }
154
+ if (newvalue.includes('function')) {
155
+ return
156
+ }
150
157
 
151
- name && string.split("\n").forEach((line) => {
152
- if (line.includes(name) && line.includes("function")) {
153
- line = line.trim();
154
- line = line.replace(/\s+/g, " ");
158
+ name && string.split("\n").forEach((line) => {
159
+ if (line.includes(name) && line.includes("function")) {
160
+ line = line.trim();
161
+ line = line.replace(/\s+/g, " ");
155
162
 
156
- let ps = line.split("(").slice(1).join("(").split(")")[0].trim();
163
+ let ps = line.split("(").slice(1).join("(").split(")")[0].trim();
157
164
 
158
- // remove comments
159
- ps = ps.match(/\/\*.*\*\//gs)
160
- ? ps.replace(ps.match(/\/\*.*\*\//gs)[0], "")
161
- : ps;
165
+ // remove comments
166
+ ps = ps.match(/\/\*.*\*\//gs)
167
+ ? ps.replace(ps.match(/\/\*.*\*\//gs)[0], "")
168
+ : ps;
162
169
 
163
- functionparams.push({ ref: ref, name: name, params: ps });
164
- }
165
- });
166
- let hasParams = newvalue.includes("(") && newvalue.includes(")");
167
- let isJSXComponent = false;
168
- let elementMatch = string.match(/<([a-zA-Z0-9_-]+)([^>]*)>/gs);
169
- elementMatch.forEach((element) => {
170
- element = element.trim().replace(/\s+/g, " ");
171
- if (element.includes(attributeName)) {
172
- let elementTag = element
173
- .split("<")[1]
174
- .split(">")[0]
175
- .split(" ")[0];
176
- isJSXComponent = elementTag.match(/^[A-Z]/) ? true : false;
177
- }
178
- });
170
+ functionparams.push({ ref: ref, name: name, params: ps });
171
+ }
172
+ });
173
+ let isJSXComponent = false;
174
+ let elementMatch = string.match(/<([a-zA-Z0-9_-]+)([^>]*)>/gs);
175
+ elementMatch.forEach((element) => {
176
+ element = element.trim().replace(/\s+/g, " ");
177
+ if (element.includes(attributeName)) {
178
+ let elementTag = element
179
+ .split("<")[1]
180
+ .split(">")[0]
181
+ .split(" ")[0];
182
+ isJSXComponent = elementTag.match(/^[A-Z]/) ? true : false;
183
+ }
184
+ });
179
185
 
180
- let functionParmas = functionparams.map((param) => { return param.params }).join(',')
181
- let suppliedParams = newvalue.split("(")[1].split(")")[0].trim();
186
+ let functionParmas = functionparams.map((param) => { return param.params }).join(',')
187
+ let suppliedParams = newvalue.split("(")[1].split(")")[0].trim();
182
188
 
183
- let replacement = `this.bind(${name}, true, ${isJSXComponent ? true : false}, '${ref}', "${functionParmas}", event, ${suppliedParams || null})`
184
- let newattribute = `${attributeName}="\${${replacement}}", usesEvent="true", eventType="${attributeName}",data-ref="${ref}", `
189
+ let replacement = `this.bind(${name}, true, ${isJSXComponent ? true : false}, '${ref}', "${functionParmas}", event, ${suppliedParams || null})`
190
+ let newattribute = `${attributeName}="\${${replacement}}", usesEvent="true", eventType="${attributeName}",data-ref="${ref}", `
185
191
 
186
- string = string.replace(old, newattribute);
192
+ string = string.replace(old, newattribute);
193
+ break;
194
+ default:
195
+ let elementMatch1 = string.match(/<([a-zA-Z0-9_-]+)([^>]*)>/gs);
196
+ let isJSXComponent1 = false;
197
+ elementMatch1.forEach((element) => {
198
+ element = element.trim().replace(/\s+/g, " ");
199
+ if (element.includes(attributeName)) {
200
+ let elementTag = element
201
+ .split("<")[1]
202
+ .split(">")[0]
203
+ .split(" ")[0];
204
+ isJSXComponent1 = elementTag.match(/^[A-Z]/) ? true : false;
205
+ }
187
206
 
207
+ });
208
+
209
+
210
+ let otherdata = {};
211
+ params ? (otherdata["params"] = params) : null;
212
+ otherdata["jsx"] = isJSXComponent1;
213
+ otherdata["ref"] = ref;
214
+ // since js is all in one line split it
215
+ newvalue = newvalue.split('\n').map(line => line.trim() ? line.trim() + ';' : line).join('\n');
216
+ let paramString = params ? params.split(' ').map(param => param + ',').join('') : "";
217
+ paramString = paramString.replaceAll(',,', ',')
218
+ let jsxAttribute = `${attributeName}=function(${paramString}){${newvalue}}.bind(this),`
219
+ let newattribute2 = `${attributeName}="\${this.bind(\`${newvalue}\`, false, ${isJSXComponent1 ? true : false}, '${ref}', "${paramString}", ${params || null})}", usesEvent="true", eventType="${attributeName}",data-ref="${ref}", `
220
+ newattribute2 = newattribute2.replace(/\s+/g, " ")
221
+ string = string.replace(old, isJSXComponent1 ? jsxAttribute : newattribute2);
222
+ break;
188
223
  }
189
- else {
190
- let elementMatch = string.match(/<([a-zA-Z0-9_-]+)([^>]*)>/gs);
191
- let isJSXComponent = false;
192
- elementMatch.forEach((element) => {
193
- element = element.trim().replace(/\s+/g, " ");
194
- if (element.includes(attributeName)) {
195
- let elementTag = element
196
- .split("<")[1]
197
- .split(">")[0]
198
- .split(" ")[0];
199
- isJSXComponent = elementTag.match(/^[A-Z]/) ? true : false;
200
- }
201
224
 
202
- });
203
-
204
-
205
- let otherdata = {};
206
- params ? (otherdata["params"] = params) : null;
207
- otherdata["jsx"] = isJSXComponent;
208
- otherdata["ref"] = ref;
209
- // since js is all in one line split it
210
- newvalue = newvalue.split('\n').map(line => line.trim() ? line.trim() + ';' : line).join('\n');
211
- let paramString = params ? params.split(' ').map(param => param + ',').join('') : "";
212
- paramString = paramString.replaceAll(',,', ',')
213
- let jsxAttribute = `${attributeName}=function(${paramString}){${newvalue}}.bind(this),`
214
- let newattribute = `${attributeName}="\${this.bind(\`${newvalue}\`, false, ${isJSXComponent ? true : false}, '${ref}', "${paramString}", ${params || null})}", usesEvent="true", eventType="${attributeName}",data-ref="${ref}", `
215
- newattribute = newattribute.replace(/\s+/g, " ")
216
- string = string.replace(old, isJSXComponent ? jsxAttribute : newattribute);
217
- }
218
225
  }
219
226
  }
220
227
 
@@ -239,10 +246,16 @@ function Compiler(func) {
239
246
 
240
247
  function extractOuterReturn(code) {
241
248
  // match return [...]
242
- let returns = code.match(/return\s*\<>.*\<\/>/gs);
249
+ let returns = code.match(/return\s*\<>.*\<\/>/gs)
243
250
 
244
251
  return returns || [];
245
252
  }
253
+ // throw error if return is not wrapped in <></> if return is found and not wrapped in <></> or <div></div> and not <><div></div></>
254
+ if (string.match(/return\s*\<>/gs) && !string.match(/return\s*\<>.*\<\/>/gs)
255
+ || string.match(/return\s*\<[a-zA-Z0-9_-]+.*>/gs)
256
+ ) {
257
+ throw new SyntaxError("You forgot to enclose jsx in a fragment <></> at line " + string.split(/return\s*\<[a-zA-Z0-9_-]+.*>/gs)[0].split('\n').length + ' in file ' + file)
258
+ }
246
259
 
247
260
  let outerReturn = extractOuterReturn(string);
248
261
  let contents = "";
@@ -281,7 +294,9 @@ function Compiler(func) {
281
294
  value = value.replace("=", "");
282
295
  value == "undefined" ? (value = '"') : (value = value);
283
296
 
284
- key == 'style' ? value = `{this.parseStyle({${value.split('{{')[1].split('}}')[0]}})}` : null
297
+ key == 'style'
298
+ && value.includes("{{")
299
+ ? value = `{this.parseStyle({${value.split('{{')[1].split('}}')[0]}})}` : null
285
300
 
286
301
 
287
302
  value = `="\$${value}",`;
@@ -309,8 +324,7 @@ function Compiler(func) {
309
324
  let code = "";
310
325
  for (let i = 0; i < lines.length; i++) {
311
326
  let line = lines[i];
312
- if (line.match(/return\s*\<>/gs)) {
313
- }
327
+
314
328
  code += line + "\n";
315
329
  }
316
330
 
@@ -341,164 +355,71 @@ function Compiler(func) {
341
355
  }
342
356
  let lines = string.split("\n");
343
357
  lines.forEach((line) => {
358
+
344
359
  if (
345
360
  line.includes("let") ||
346
361
  line.includes("const") ||
347
362
  line.includes("var")
348
363
  ) {
349
- if (line.includes("useState") && !line.includes("import")) {
350
- line = line.trim();
351
- // derive [key, value] from line
352
- let varType = line.split(" ")[0];
353
- let type = ''
354
- let key = line
355
- .split("=")[0]
356
- .split(" ")[1]
357
- .trim()
358
- .replace("[", "")
359
- .replace(",", "");
360
- let setKey = line.split("=")[0].split(",")[1].trim().replace("]", "");
364
+ switch (true) {
365
+ case line.includes("useState") && !line.includes("import"):
366
+ let varType = line.split("[")[0]
367
+ let key = line.split("=")[0].split(",")[0].trim().split('[')[1];
361
368
 
362
- key = key.replace("[", "").replace(",", "");
363
- let value = line.split("=")[1].split("useState(")[1]
369
+ let setKey = line.split("=")[0].trim().split(",")[1].trim().replace("]", "");
370
+ key = key.replace("[", "").replace(",", "");
371
+ let valuestate = line.split("=")[1].split("useState(")[1];
364
372
 
365
- let regex = /useState\((.*)\)/gs
366
- value = value.match(regex) ? value.match(regex)[0].split("useState(")[1].split(")")[0].trim() : value
367
- switch (true) {
368
- case value.startsWith("'"):
369
- type = "String"
370
- break;
371
- case value.startsWith('"'):
372
- type = "String"
373
- break;
374
- case value.startsWith("`"):
375
- type = "String"
376
- break;
377
- case value.startsWith("{"):
378
- type = "Object"
379
- break;
380
- case value.startsWith("["):
381
- type = "Array"
382
- break;
383
- case value.includes("function"):
384
- type = "Function"
385
- break;
386
- case value.includes("=>"):
387
- type = "Function"
388
- break;
389
- case value.includes("true"):
390
- type = "Boolean"
391
- break;
392
- case value.includes("false"):
393
- type = "Boolean"
394
- break;
395
- case value.includes("null"):
396
- type = "Null"
397
- break;
398
- case value.includes("undefined"):
399
- type = "Undefined"
400
- break;
401
- case value.includes("?") && value.includes(":"):
402
- type = "Any"
403
- break;
404
- default:
405
- type = "*"
406
- break;
407
- }
373
+ let regex = /useState\((.*)\)/gs;
374
+ valuestate = valuestate.match(regex) ? valuestate.match(regex)[0].split("useState(")[1].split(")")[0].trim() : valuestate
408
375
 
409
- let typejsdoc = `/** @type {${type}} */`;
410
376
 
377
+ let newState = `${varType} [${key}, ${setKey}] = this.useState('${key}', ${valuestate}
378
+
379
+ `;
380
+ string = string.replace(line, newState);
381
+ break;
382
+ case line.includes("useRef") && !line.includes("import"):
383
+ line = line.trim();
384
+ let typeref = line.split(" ")[0]
411
385
 
412
- let newState = `${varType} [${typejsdoc}${key}, ${setKey}] = this.useState('${key}', ${value}
413
-
414
- `;
386
+ let keyref = line.split(typeref)[1].split("=")[0].trim().replace("[", "").replace(",", "");
415
387
 
416
388
 
417
- // get setkey calls and replace with this.setKey
418
- string.split("\n").forEach((line) => {
419
- if (line.includes(setKey) && !line.includes("useState")) {
420
- string = string.replace(line, line);
421
- }
389
+ let valueref = line.split("=")[1].split("useRef(")[1];
422
390
 
423
- if (line.includes(key)) {
424
- line = line.replace(key, `this.states['${key}']`);
391
+ let newStateref = `${typeref} ${keyref} = this.useRef('${keyref}', ${valueref}`;
392
+ string = string.replace(line, newStateref);
393
+ break;
394
+ case line.includes("useReducer") && !line.includes("import"):
395
+ line = line.trim();
396
+ line = line.replaceAll(/\s+/g, " ");
425
397
 
426
- string = string.replace(line, line);
427
- }
428
- });
429
- string = string.replace(line, newState);
430
- } else if (line.includes("useRef") && !line.includes("import")) {
431
- line = line.trim();
432
- // let ref = useRef(null)
433
- let type = line.split(" ")[0];
434
- let key = line.split("=")[0].split(" ")[1].trim();
435
- let value = line.split("=")[1].split("useRef(")[1]
436
-
437
- let regex = /useState\((.*)\)/gs
438
- value = value.match(regex) ? value.match(regex)[0].split("useRef(")[1].split(")")[0].trim() : value
439
- let newState = `${type} ${key} = this.useRef('${key}', ${value}`;
440
-
441
- string = string.replace(line, newState);
442
- } else if (line.includes("useReducer") && !line.includes("import")) {
443
- //ex: const [state, dispatch] = useReducer(function, initialState);
444
-
445
- line = line.trim();
446
- line = line.replaceAll(/\s+/g, " ");
447
-
448
- // derive [key, value] from line
449
- let varType = line.split(" ")[0];
450
- let type = ''
451
- let key = line
452
- .split("=")[0]
453
- .split(" ")[1]
454
- .trim()
455
- .replace("[", "")
456
- .replace(",", "");
457
- let setKey = line.split("=")[0].split(",")[1].trim().replace("]", "");
458
- let reducer = line.split("=")[1].split("useReducer(")[1]
459
- let newState = `${varType} [${key}, ${setKey}] = this.useReducer('${key}', ${line.includes('=>') ? reducer + '=>{' : reducer}`
460
- string = string.replace(line, newState);
461
- }
462
- }
463
- });
398
+ let varTypereducer = line.split(" ")[0];
399
+ let keyreducer = line
400
+ .split("=")[0]
401
+ .split(" ")[1]
402
+ .trim()
403
+ .replace("[", "")
404
+ .replace(",", "");
405
+ let setKeyreducer = line.split("=")[0].trim().split(",")[1].trim().replace("]", "");
464
406
 
465
- // create a polyfill for Array.prototype.filter
466
-
467
- /**
468
- * @method Delete
469
- * @param {*} item
470
- * @returns {Array} array
471
- * @description Delete an item from an array
472
- */
473
- Array.prototype.delete = function (item) {
474
- let array = this;
475
- array.forEach((i, index) => {
476
- switch (true) {
477
- case typeof i === "object":
478
- if (JSON.stringify(i) === JSON.stringify(item)) {
479
- array.splice(index, 1);
480
- }
481
- break;
482
- default:
483
- if (i === item) {
484
- array.splice(index, 1);
485
- }
407
+ let reducer = line.split("=")[1].split("useReducer(")[1];
408
+
409
+ let newStatereducer = `${varTypereducer} [${keyreducer}, ${setKeyreducer}] = this.useReducer('${keyreducer}', ${line.includes('=>') ? reducer + '=>{' : reducer}`;
410
+
411
+ string = string.replace(line, newStatereducer);
486
412
  break;
487
413
  }
488
- });
489
414
 
490
- return array;
491
- };
415
+ }
416
+ });
417
+
492
418
 
493
- // replaceall comments ${/* */} with ''
494
419
  string = string.replaceAll(/\$\{\/\*.*\*\/\}/gs, "");
495
420
 
496
421
  string = string.replaceAll('../src', './src')
497
422
 
498
-
499
- // capture <Component />, <Component></Component>, and <Component>content</Component>
500
-
501
- // Example usage
502
423
  function parseComponents(body, isChild) {
503
424
  let componentRegex =
504
425
  /<([A-Z][a-zA-Z0-9_-]+)([^>]*)\/>|<([A-Z][a-zA-Z0-9_-]+)([^>]*)>(.*?)<\/\3>/gs;
@@ -614,11 +535,35 @@ function Compiler(func) {
614
535
  string = string
615
536
  .replaceAll("className", "class")
616
537
  .replaceAll("classname", "class");
538
+ string = string.replaceAll(/\$\{\/\*.*\*\/\}/gs, "");
617
539
 
540
+ string = string.replaceAll('../src', './src')
618
541
  string += `\n\n //wascompiled`;
619
542
 
620
543
  string = string.replaceAll("undefined", "");
544
+ const parse = (css) => {
545
+ let styles = {};
546
+ let currentSelector = '';
547
+
548
+ css.split('\n').forEach(line => {
549
+ line = line.trim();
550
+
551
+ if (line.endsWith('{')) {
552
+ // Start of a block, extract the selector
553
+ currentSelector = line.slice(0, -1).trim();
554
+ styles[currentSelector] = {};
555
+ } else if (line.endsWith('}')) {
556
+ // End of a block
557
+ currentSelector = '';
558
+ } else if (line.includes(':') && currentSelector) {
559
+ // Inside a block and contains key-value pair
560
+ let [key, value] = line.split(':').map(part => part.trim());
561
+ styles[currentSelector][key] = value;
562
+ }
563
+ });
621
564
 
565
+ return styles;
566
+ };
622
567
  string.split('\n').forEach(line => {
623
568
  if (line.includes('import')) {
624
569
  // Regular expression for matching import() statements
@@ -630,11 +575,21 @@ function Compiler(func) {
630
575
  let beforeimport = match
631
576
  let path = match.split('(')[1].split(')')[0].trim()
632
577
  let newImport = ''
578
+ let name = match.split('import')[1].split('from')[0].trim()
633
579
  switch (true) {
634
580
  case path && path.includes('json'):
635
581
  path = path.replace(';', '')
636
- newImport = `JSON.parse(await fetch(${path}).then(res => res.json()))`
582
+ newImport = `let ${name} = await fetch('${path}').then(res => res.json())`
637
583
 
584
+ break;
585
+ case path && path.includes('module.css'):
586
+ let css = await fs.readFileSync(process.cwd() + path, 'utf8')
587
+ css = css.replaceAll('.', '')
588
+ if (!name) {
589
+ throw new Error('Could not find name for css module ' + path + ' at' + beforeimport + ' file' + file)
590
+ }
591
+ newImport = `let ${name} = ${JSON.stringify(parse(css))}`
592
+ console.log(newImport)
638
593
  break;
639
594
  default:
640
595
  let deep = path.split('/').length - 1
@@ -651,7 +606,6 @@ function Compiler(func) {
651
606
 
652
607
  path = path.replaceAll('.jsx', '.js');
653
608
  newImport = `await import(${path})`
654
-
655
609
  }
656
610
  if (newImport) {
657
611
  string = string.replace(beforeimport, newImport)
@@ -660,54 +614,63 @@ function Compiler(func) {
660
614
  }
661
615
 
662
616
  if (regularimportMatch) {
663
- regularimportMatch.forEach(async (match) => {
664
-
617
+ for (let match of regularimportMatch) {
665
618
  let beforeimport = match
666
619
  let path = match.split('from')[1].trim()
667
620
  let newImport = ''
668
621
  let name = match.split('import')[1].split('from')[0].trim()
669
- switch (true) {
670
- case path && path.includes('json'):
671
- path = path.replace(';', '')
672
- // remove any ../
673
- path = path.replaceAll('../', '')
674
- path = `src/${path.replace(/'/g, '')}`
675
- newImport = `let ${name} = await fetch('${path}').then(res => res.json())`
676
622
 
677
- string = string.replace(beforeimport, newImport)
678
- break;
679
- default:
680
- let beforePath = path
681
- let deep = path.split('/').length - 1
682
- for (let i = 0; i < deep; i++) {
683
- path = path.split('../').join('')
684
- path = path.split('./').join('')
685
- }
686
- path = path.replace(/'/g, '').trim().replace(/"/g, '').trim()
687
- // remove double / from path
688
- path = path.split('//').join('/')
689
- if (!path.startsWith('./') && !path.includes('/vader.js') && !path.startsWith('src')) {
690
- path.includes('src') ? path.split('src')[1] : null
691
- path = '/src/' + path
692
- } else if (path.startsWith('src')) {
693
- path = '/' + path
694
- }
695
- path = path.replaceAll('.jsx', '.js');
696
- let html = fs.existsSync(process.cwd() + '/dist/index.html') ? fs.readFileSync(process.cwd() + '/dist/index.html', 'utf8') : ''
697
- if (!html.includes(`<link rel="modulepreload" href="${path.replace(/'/g, '').trim()}">`)) {
698
- if (!html.includes(`</head>`)) {
699
- throw new Error('Could not find </head> in index.html')
700
- }
701
- let preload = `<link rel="modulepreload" href="${path.trim()}"><link rel="preload" href="${path.trim()}" as="script">`
623
+ if (path && path.includes('json')) {
624
+ path = path.replace(';', '')
625
+ newImport = `let ${name} = await fetch('${path}').then(res => res.json())`
626
+ } else if (path && path.includes('module.css')) {
702
627
 
703
- html = html.replace('</head>', `${preload}</head>`)
628
+ path = path.replace(';', '')
629
+ path = path.replace(/'/g, '').trim().replace(/"/g, '').trim()
630
+ path = path.replaceAll('.jsx', '.js');
631
+ path = path.replaceAll('../', '');
632
+ let css = fs.readFileSync(process.cwd() + '/' + path, 'utf8')
704
633
 
705
- fs.writeFileSync(process.cwd() + '/dist/index.html', html)
706
- }
634
+ newImport = `let ${name} = ${JSON.stringify(parse(css))}`
635
+ string = string.replace(beforeimport, newImport)
636
+ } else {
637
+ let beforePath = path
638
+ let deep = path.split('/').length - 1
639
+ for (let i = 0; i < deep; i++) {
640
+ path = path.split('../').join('')
641
+ path = path.split('./').join('')
642
+ }
643
+ path = path.replace(/'/g, '').trim().replace(/"/g, '').trim()
644
+ // remove double / from path
645
+ path = path.split('//').join('/')
646
+ if (!path.startsWith('./') && !path.includes('/vader.js') && !path.startsWith('src')) {
647
+ path.includes('src') ? path.split('src')[1] : null
648
+ path = '/src/' + path
649
+ } else if (path.startsWith('src')) {
650
+ path = '/' + path
651
+ }
652
+ path = path.replaceAll('.jsx', '.js');
707
653
 
708
- string = string.replace(beforePath, "'" + path + "'")
654
+
655
+ string = string.replace(beforePath, "'" + path + "'")
709
656
  }
710
- })
657
+ let html = fs.existsSync(process.cwd() + '/dist/index.html') ? fs.readFileSync(process.cwd() + '/dist/index.html', 'utf8') : ''
658
+ if (!html.includes(`<link rel="preload" href="${path.replace(/'/g, '').trim()}" as="${path.replace(/'/g, '').trim().includes('.css') ? 'style' : 'script'}">`)) {
659
+ if (!html.includes(`</head>`)) {
660
+ throw new Error('Could not find </head> in index.html')
661
+ }
662
+ let preload = `${!path.trim().includes('.css') ? `<link rel="modulepreload" href="${path.trim()}">` : ''}<link rel="preload" href="${path.trim()}" as="${path.trim().includes('.css') ? 'style' : 'script'}">`
663
+ html = html.replace('</head>', `${preload}\n</head>`)
664
+
665
+ fs.writeFileSync(process.cwd() + '/dist/index.html', html)
666
+ }
667
+ if (newImport) {
668
+ string = string.replace(beforeimport, newImport)
669
+ }
670
+
671
+ }
672
+
673
+
711
674
  }
712
675
  }
713
676
 
@@ -783,7 +746,7 @@ async function Build() {
783
746
 
784
747
 
785
748
  let data = await fs.readFileSync(origin, "utf8");
786
- data = Compiler(data)
749
+ data = Compiler(data, origin);
787
750
 
788
751
 
789
752
 
@@ -799,7 +762,7 @@ async function Build() {
799
762
  })
800
763
  await writer(process.cwd() + "/dist/pages/" + fileName.replace('.jsx', '.js'), minified.code)
801
764
  } catch (error) {
802
- console.log(error)
765
+ console.log(error)
803
766
  }
804
767
  })
805
768
 
@@ -820,7 +783,6 @@ async function Build() {
820
783
 
821
784
 
822
785
 
823
- console.log(`Compilation finished`)
824
786
 
825
787
  }
826
788
 
@@ -835,6 +797,7 @@ async function Build() {
835
797
  cwd: process.cwd() + '/node_modules/vaderjs/runtime',
836
798
  absolute: true,
837
799
  });
800
+
838
801
  scannedVaderFiles.forEach(async (file) => {
839
802
  file = file.replace(/\\/g, '/');
840
803
 
@@ -854,20 +817,20 @@ async function Build() {
854
817
 
855
818
  let data = await reader(process.cwd() + "/src/" + name)
856
819
  if (name.includes('.jsx')) {
857
- data = Compiler(data)
820
+ data = Compiler(data, process.cwd() + "/src/" + name);
858
821
 
859
822
  await writer(process.cwd() + "/dist/src/" + name.split('.jsx').join('.js'), data).then(async () => {
860
823
  let { minify } = await import('terser')
861
- try {
862
- let minified = await minify(data, {
863
- ecma: " 2016",
864
- module: true,
865
- compress: true,
866
- })
867
- await writer(process.cwd() + "/dist/src/" + name.replace('.jsx', '.js'), minified.code)
868
- } catch (error) {
869
- console.log(error)
870
- }
824
+ try {
825
+ let minified = await minify(data, {
826
+ ecma: " 2016",
827
+ module: true,
828
+ compress: true,
829
+ })
830
+ await writer(process.cwd() + "/dist/src/" + name.replace('.jsx', '.js'), minified.code)
831
+ } catch (error) {
832
+ console.log(error)
833
+ }
871
834
 
872
835
  })
873
836
  return
@@ -894,16 +857,19 @@ async function Build() {
894
857
  absolute: true,
895
858
  })
896
859
 
860
+
897
861
  if (!fs.existsSync(process.cwd() + "/dist/index.html")) {
898
862
 
899
863
  scannedFiles.forEach(async (file) => {
900
864
  file = file.split(process.cwd() + '/runtime/')[1]
901
865
 
902
- if (file === "app.js") {
903
- return
904
- }
905
- if (file.includes('index.html') && fs.existsSync(process.cwd() + "/runtime/" + file)) {
866
+ let objCase = {
867
+ ...file == "app.js" ? { exit: true } : null,
868
+ ...file.includes("index.html") && fs.existsSync(process.cwd() + "/runtime/" + file) ? { exit: true } : null,
906
869
 
870
+ }
871
+ if (objCase.exit) {
872
+ console.log('exiting')
907
873
  return
908
874
  }
909
875
  bundleSize += fs.statSync(process.cwd() + "/runtime/" + file).size;
@@ -914,6 +880,9 @@ async function Build() {
914
880
  }
915
881
 
916
882
  globalThis.isBuilding = false
883
+ console.log(`Build complete! ${Math.round(bundleSize / 1000)}${bundleSize > 1000 ? 'kb' : 'bytes'} written to ./dist`)
884
+ bundleSize = 0;
885
+ return true
917
886
  }
918
887
  import { watch } from "fs";
919
888
 
@@ -925,33 +894,24 @@ switch (true) {
925
894
  Vader.js v1.3.3
926
895
  - Watching for changes in ./pages
927
896
  - Watching for changes in ./src
897
+ - Watching for changes in ./public
928
898
  `)
929
- Build()
899
+ !globalThis.isBuilding ? Build() : null
900
+
901
+
902
+ Array.from(Array(3).keys()).forEach((i) => {
903
+ let p = `${process.cwd()}${i == 0 ? '/pages/' : i == 1 ? '/src/' : '/public/'}`
904
+
905
+ watch(p
906
+ , { recursive: true }, (event, filename) => {
907
+ if (event == 'change'
908
+ && !globalThis.isBuilding
909
+ ) {
910
+ Build()
911
+ }
912
+ }).on('error', (err) => console.log(err))
913
+ })
930
914
 
931
- const watcher = watch(
932
- process.cwd() + '/pages',
933
- { recursive: true },
934
- (event, filename) => {
935
- if (event == 'change'
936
- && !globalThis.isBuilding
937
- ) {
938
- Build()
939
- }
940
- },
941
- );
942
- const watcher2 = watch(
943
- process.cwd() + '/src',
944
- { recursive: true },
945
- (event, filename) => {
946
- if (event == 'change'
947
- && !globalThis.isBuilding
948
- ) {
949
- Build()
950
- }
951
- },
952
- );
953
- watcher2.on('error', (err) => console.log(err))
954
- watcher.on('error', (err) => console.log(err))
955
915
 
956
916
  break;
957
917
  case process.argv.includes('--build'):