vaderjs 1.3.3-alpha-152 → 1.3.3-alpha-160
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 +9 -5
- package/package.json +5 -4
- package/runtime/router.js +1 -1
- package/runtime/vader.js +1 -1
- package/vader.js +212 -236
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
[](https://github.com/Postr-Inc/Vader.js/blob/main/LICENSE) [](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={(
|
|
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 {
|
|
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
|
-
|
|
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={(
|
|
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-alpha-
|
|
5
|
+
"version": "1.3.3-alpha-160",
|
|
6
6
|
"bin": {
|
|
7
7
|
"vader": "./vader.js"
|
|
8
8
|
},
|
|
@@ -27,8 +27,9 @@
|
|
|
27
27
|
"email": "malikwhitterb@gmail.com"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"glob": "latest",
|
|
31
|
-
"
|
|
32
|
-
"
|
|
30
|
+
"glob": "latest",
|
|
31
|
+
"puppeteer":"latest",
|
|
32
|
+
"dotenv":"latest"
|
|
33
|
+
|
|
33
34
|
}
|
|
34
35
|
}
|
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
|
|
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
|
|
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
|
@@ -7,17 +7,23 @@ import { WebSocketServer } from 'ws'
|
|
|
7
7
|
import { watch } from "fs";
|
|
8
8
|
import path from 'path'
|
|
9
9
|
let config = await import('file://' + process.cwd() + '/vader.config.js').then((e) => e.default || e)
|
|
10
|
+
let writer = async (file, data) => {
|
|
11
|
+
globalThis.isWriting = file
|
|
12
|
+
switch (true) {
|
|
13
|
+
case !fs.existsSync(file):
|
|
14
|
+
fs.mkdirSync(file.split('/').slice(0, -1).join('/'), { recursive: true })
|
|
15
|
+
break;
|
|
16
|
+
}
|
|
17
|
+
if (globalThis.isWriting !== file) {
|
|
18
|
+
return
|
|
19
|
+
}
|
|
20
|
+
await fs.writeFileSync(file, data);
|
|
10
21
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* define directories
|
|
19
|
-
*/
|
|
20
|
-
|
|
22
|
+
globalThis.isWriting = null
|
|
23
|
+
return { _written: true };
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
let bundleSize = 0;
|
|
21
27
|
|
|
22
28
|
if (!fs.existsSync(process.cwd() + '/dist')) {
|
|
23
29
|
fs.mkdirSync(process.cwd() + '/dist')
|
|
@@ -34,44 +40,13 @@ if (typeof process.env.isCloudflare !== "undefined" || !fs.existsSync(process.cw
|
|
|
34
40
|
|
|
35
41
|
|
|
36
42
|
function Compiler(func, file) {
|
|
37
|
-
let string = func;
|
|
38
|
-
// Remove block comments
|
|
39
|
-
|
|
43
|
+
let string = func;
|
|
40
44
|
let returns = []
|
|
41
45
|
let comments = string.match(/\{\s*\/\*.*\*\/\s*}/gs)?.map((comment) => comment.trim());
|
|
42
46
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
)
|
|
47
|
-
?.map((match) => match.trim());
|
|
48
|
-
|
|
49
|
-
let functionNames = [];
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
functions && functions.forEach((func) => {
|
|
53
|
-
if (
|
|
54
|
-
!func.match(
|
|
55
|
-
/(?:const|let)\s*([a-zA-Z0-9_-]+)\s*=\s*function\s*\(([^)]*)\)|function\s*([a-zA-Z0-9_-]+)\s*\(([^)]*)\)/gs
|
|
56
|
-
)
|
|
57
|
-
) {
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
let name = func.split(" ")[1].split("(")[0].trim();
|
|
62
|
-
|
|
63
|
-
let lines = string.match(/return\s*\<>.*\<\/>/gs);
|
|
64
|
-
|
|
65
|
-
if (lines) {
|
|
66
|
-
for (let i = 0; i < lines.length; i++) {
|
|
67
|
-
let line = lines[i];
|
|
68
|
-
|
|
69
|
-
if (!functionNames.includes(name)) {
|
|
70
|
-
functionNames.push(name);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
});
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
75
50
|
|
|
76
51
|
// get all Obj({}) and parse to JSON.stringify
|
|
77
52
|
|
|
@@ -87,6 +62,51 @@ function Compiler(func, file) {
|
|
|
87
62
|
|
|
88
63
|
let childs = [];
|
|
89
64
|
|
|
65
|
+
const spreadAttributeRegex = /\s*([a-zA-Z0-9_-]+)(\s*\$\s*=\s*{{((?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*)}})/gs;
|
|
66
|
+
let spreadMatch;
|
|
67
|
+
while ((spreadMatch = spreadAttributeRegex.exec(string)) !== null) {
|
|
68
|
+
let [, element, spread] = spreadMatch;
|
|
69
|
+
let isJSXComponent = element.match(/[A-Z]/) ? true : false;
|
|
70
|
+
if (isJSXComponent) {
|
|
71
|
+
continue
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
let old = spread;
|
|
75
|
+
|
|
76
|
+
// turn spread into attributes
|
|
77
|
+
spread = spread.replace(/\s*$\s*=\s*/, "");
|
|
78
|
+
spread = spread.replace(/{{/, "");
|
|
79
|
+
spread = spread.replace(/}}/, "");
|
|
80
|
+
spread = spread.replace(/\$\s*=\s*/, "");
|
|
81
|
+
|
|
82
|
+
// turn : into =
|
|
83
|
+
|
|
84
|
+
// do not split inner Objects ex: {color: 'red', background: {color: 'blue'}} -> {color: 'red', background: {color: 'blue'}}
|
|
85
|
+
let splitByCommas = spread.split(/,(?![^{]*})/g);
|
|
86
|
+
splitByCommas = splitByCommas.map((e) => e.trim())
|
|
87
|
+
splitByCommas = splitByCommas.map((e) => {
|
|
88
|
+
switch (true) {
|
|
89
|
+
case e.includes('function') || e.includes('=>'):
|
|
90
|
+
e = e.replace(/:(.*)/gs, '={$1}')
|
|
91
|
+
break;
|
|
92
|
+
case e.includes('style'):
|
|
93
|
+
e = e.replace(/:(.*)/gs, '="${this.parseStyle($1)}"')
|
|
94
|
+
break;
|
|
95
|
+
case e.includes('[') && e.includes(']'):
|
|
96
|
+
e = e.replace(/:(.*)/gs, '={$1.join(" ")}')
|
|
97
|
+
break;
|
|
98
|
+
default:
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return e.trim()
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
let newSpread = `\t` + splitByCommas.join(' ') + `\t`
|
|
105
|
+
|
|
106
|
+
string = string.replace(old, newSpread);
|
|
107
|
+
|
|
108
|
+
}
|
|
109
|
+
|
|
90
110
|
|
|
91
111
|
|
|
92
112
|
function extractAttributes(code) {
|
|
@@ -98,41 +118,40 @@ function Compiler(func, file) {
|
|
|
98
118
|
const attributeRegex =
|
|
99
119
|
/\s*([a-zA-Z0-9_-]+)(\s*=\s*("([^"\\]*(\\.[^"\\]*)*)"|'([^'\\]*(\\.[^'\\]*)*)'|\{(?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*\}|(?:\([^)]*\)|\{[^}]*\}|()=>\s*(?:\{[^}]*\})?)|\[[^\]]*\]))?/gs;
|
|
100
120
|
|
|
101
|
-
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
|
|
102
124
|
const functionAttributeRegex = /\s*([a-zA-Z0-9_-]+)(\s*=\s*{((?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*)})/gs;
|
|
103
125
|
|
|
104
126
|
let attributesList = [];
|
|
105
127
|
|
|
106
|
-
|
|
128
|
+
let spreadAttributes = [];
|
|
129
|
+
let spreadMatch;
|
|
130
|
+
/**
|
|
131
|
+
* @search - handle spread for html elements
|
|
132
|
+
* @keywords - spread, spread attributes, spread props, spread html attributes
|
|
133
|
+
*/
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @search - handle function parsing for html elements
|
|
138
|
+
* @keywords - function, function attributes, function props, function html attributes
|
|
139
|
+
*
|
|
140
|
+
*/
|
|
107
141
|
let functionAttributes = [];
|
|
108
142
|
let functionMatch;
|
|
109
143
|
while ((functionMatch = functionAttributeRegex.exec(code)) !== null) {
|
|
110
|
-
let [, attributeName, attributeValue] = functionMatch;
|
|
111
144
|
|
|
145
|
+
let [, attributeName, attributeValue] = functionMatch;
|
|
112
146
|
let attribute = {};
|
|
113
147
|
|
|
114
|
-
if (attributeValue && attributeValue.includes("=>") || attributeValue && attributeValue.includes("function")
|
|
115
|
-
|
|
116
|
-
|
|
148
|
+
if (attributeValue && attributeValue.includes("=>") || attributeValue && attributeValue.includes("function")
|
|
149
|
+
&& !spreadFunctions.includes(attributeValue)
|
|
150
|
+
) {
|
|
151
|
+
|
|
117
152
|
let ref = Math.random().toString(36).substring(2).split('').filter((e) => !Number(e)).join('')
|
|
118
153
|
let old = `${attributeName}${attributeValue}`
|
|
119
|
-
|
|
120
|
-
string.split("\n").forEach((line) => {
|
|
121
|
-
if (line.includes(name) && line.includes("function")) {
|
|
122
|
-
line = line.trim();
|
|
123
|
-
line = line.replace(/\s+/g, " ");
|
|
124
|
-
|
|
125
|
-
let ps = line.split("(").slice(1).join("(").split(")")[0].trim();
|
|
126
|
-
|
|
127
|
-
// remove comments
|
|
128
|
-
ps = ps.match(/\/\*.*\*\//gs)
|
|
129
|
-
? ps.replace(ps.match(/\/\*.*\*\//gs)[0], "")
|
|
130
|
-
: ps;
|
|
131
|
-
functionparams.push({ ref: ref, name: name, params: ps });
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
});
|
|
154
|
+
|
|
136
155
|
let elementMatch = string.match(/<([a-zA-Z0-9_-]+)([^>]*)>/gs);
|
|
137
156
|
let isJSXComponent = false;
|
|
138
157
|
elementMatch.forEach((element) => {
|
|
@@ -186,8 +205,7 @@ function Compiler(func, file) {
|
|
|
186
205
|
newvalue = newvalue.replace(/}\s*$/, '');
|
|
187
206
|
|
|
188
207
|
|
|
189
|
-
|
|
190
|
-
functionparams.length > 0 ? params = params + ',' + functionparams.map((e) => e.name).join(',') : null
|
|
208
|
+
|
|
191
209
|
|
|
192
210
|
newvalue = newvalue.replaceAll(',,', ',')
|
|
193
211
|
let paramnames = params ? params.split(',').map((e) => e.trim()) : null
|
|
@@ -210,6 +228,10 @@ function Compiler(func, file) {
|
|
|
210
228
|
}
|
|
211
229
|
}
|
|
212
230
|
|
|
231
|
+
/**
|
|
232
|
+
* @search - handle attributes for html elements
|
|
233
|
+
* @keywords - attributes, props, html attributes
|
|
234
|
+
*/
|
|
213
235
|
let match;
|
|
214
236
|
while ((match = elementRegex.exec(code)) !== null) {
|
|
215
237
|
let [, element, attributes] = match;
|
|
@@ -234,8 +256,7 @@ function Compiler(func, file) {
|
|
|
234
256
|
let returns = code.match(/return\s*\<>.*\<\/>|return\s*\(.*\)/gs);
|
|
235
257
|
|
|
236
258
|
return returns || [];
|
|
237
|
-
}
|
|
238
|
-
// throw error if return is not wrapped in <></> or
|
|
259
|
+
}
|
|
239
260
|
if (string.match(/return\s*\<>|return\s*\(.*\)/gs) && !string.match(/return\s*\<>.*\<\/>|return\s*\(.*\)/gs)
|
|
240
261
|
|| string.match(/return\s*\<[a-zA-Z0-9_-]+.*>/gs)
|
|
241
262
|
) {
|
|
@@ -251,6 +272,10 @@ function Compiler(func, file) {
|
|
|
251
272
|
let outerReturn = extractOuterReturn(string);
|
|
252
273
|
let contents = "";
|
|
253
274
|
let updatedContents = "";
|
|
275
|
+
/**
|
|
276
|
+
* @search - handle return [...]
|
|
277
|
+
* @keywords - return, return jsx, return html, return [...]
|
|
278
|
+
*/
|
|
254
279
|
outerReturn.forEach((returnStatement) => {
|
|
255
280
|
|
|
256
281
|
let lines = returnStatement.split("\n");
|
|
@@ -264,13 +289,12 @@ function Compiler(func, file) {
|
|
|
264
289
|
}
|
|
265
290
|
let usesBraces = returnStatement.match(/return\s*\(/gs) ? true : false;
|
|
266
291
|
|
|
267
|
-
|
|
268
|
-
// Remove trailing ']' or trailing )
|
|
292
|
+
|
|
269
293
|
contents = contents.trim().replace(/\]$/, "")
|
|
270
294
|
contents = contents.replace(/\)$/, "");
|
|
271
295
|
usesBraces ? !contents.includes('<>') ? contents = `<>${contents}</>` : null : null
|
|
272
296
|
updatedContents = contents;
|
|
273
|
-
|
|
297
|
+
let attributes = extractAttributes(contents);
|
|
274
298
|
|
|
275
299
|
let newAttributes = [];
|
|
276
300
|
let oldAttributes = [];
|
|
@@ -349,9 +373,7 @@ function Compiler(func, file) {
|
|
|
349
373
|
valuestate = valuestate.match(regex) ? valuestate.match(regex)[0].split("useState(")[1].split(")")[0].trim() : valuestate
|
|
350
374
|
|
|
351
375
|
|
|
352
|
-
let newState = `${varType} [${key}, ${setKey}] = this.useState('${key}', ${valuestate}
|
|
353
|
-
|
|
354
|
-
`;
|
|
376
|
+
let newState = `${varType} [${key}, ${setKey}] = this.useState('${key}', ${valuestate}`;
|
|
355
377
|
string = string.replace(line, newState);
|
|
356
378
|
break;
|
|
357
379
|
case line.includes("useRef") && !line.includes("import"):
|
|
@@ -396,25 +418,24 @@ function Compiler(func, file) {
|
|
|
396
418
|
string = string.replaceAll('../src', './src')
|
|
397
419
|
|
|
398
420
|
function parseComponents(body, isChild) {
|
|
399
|
-
let componentRegex = /<([A-Z][A-Za-z0-9_-]+)([^>]*)
|
|
421
|
+
let componentRegex = /<([A-Z][A-Za-z0-9_-]+)\s*([^>]*)>\s*([\s\S]*?)\s*<\/\1>|<([A-Z][A-Za-z0-9_-]+)([^]*?)\/>/gs;
|
|
400
422
|
|
|
401
423
|
let componentMatch = body.match(componentRegex);
|
|
402
424
|
let topComponent = "";
|
|
403
425
|
componentMatch?.forEach(async (component) => {
|
|
404
426
|
|
|
405
427
|
let [, element, attributes] = component;
|
|
406
|
-
|
|
428
|
+
let before = component;
|
|
429
|
+
component = component.trim().replace(/\s+/g, " ");
|
|
407
430
|
|
|
408
431
|
!isChild ? (topComponent = component) : null;
|
|
409
|
-
|
|
432
|
+
|
|
410
433
|
|
|
411
434
|
let myChildrens = [];
|
|
412
435
|
|
|
413
436
|
let name = component.split("<")[1].split(">")[0].split(" ")[0].replace("/", "");
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
const dynamicAttributesRegex = /(\w+)(?:="([^"]*)")?(?:='([^']*)')?(?:=\{([^}]*)\})?(?:=\{(.*?)\})?(?:={([^}]*)})?(?:{([^}]*)})?|(?:{(?:[^{}]+|\{(?:[^{}]+|\{[^}]*\})*\})*\})|(\.{3}\{(?:[^{}]+|\{(?:[^{}]+|\{[^}]*\})*\})*\})/gs;
|
|
417
|
-
|
|
437
|
+
let componentAttributes = component.split("<")[1].split(">")[0].split(" ").join(" ").replace(name, "").trim();
|
|
438
|
+
const dynamicAttributesRegex = /(\w+)(?:="([^"]*)")?(?:='([^']*)')?(?:=\{([^}]*)\})?(?:=\{(.*?)\})?(?:={([^}]*)})?(?:{([^}]*)})?|(?:{(?:[^{}]+|\{(?:[^{}]+|\{[^}]*\})*\})*\})|(\.{3}\{(?:[^{}]+|\{(?:[^{}]+|\{[^}]*\})*\})*\})|\$=\{(?:[^{}]+|\{(?:[^{}]+|\{[^}]*\})*\})*\}/gs;
|
|
418
439
|
|
|
419
440
|
|
|
420
441
|
|
|
@@ -425,119 +446,21 @@ function Compiler(func, file) {
|
|
|
425
446
|
let filteredProps = [];
|
|
426
447
|
let isWithinComponent = false;
|
|
427
448
|
let componentName = name
|
|
449
|
+
let currentProps = []
|
|
428
450
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
// If the component is encountered, start collecting props
|
|
433
|
-
isWithinComponent = true;
|
|
434
|
-
filteredProps.push(prop);
|
|
435
|
-
} else if (isWithinComponent && prop.includes('=')) {
|
|
436
|
-
|
|
437
|
-
if (prop.includes('${')) {
|
|
438
|
-
// if it has an object inside of it then we should just do soemting:object else we should do something: `${object}`
|
|
439
|
-
|
|
440
|
-
prop = prop.replace('="', ':').replace('}"', '}')
|
|
441
|
-
if (prop.includes('${')) {
|
|
442
|
-
prop = prop.replace('="', ':')
|
|
443
|
-
prop = prop.replace('${', '')
|
|
444
|
-
prop = prop.replace('}', '')
|
|
445
|
-
|
|
446
|
-
}
|
|
447
|
-
if (prop.includes('="${{')) {
|
|
448
|
-
prop = prop.replace('${{', '{')
|
|
449
|
-
prop = prop.replace('}}', '}')
|
|
450
|
-
prop = prop.replace('="', ':')
|
|
451
|
-
prop = prop.replace('}"', '}')
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
}
|
|
455
|
-
if (prop.startsWith('={')) {
|
|
456
|
-
prop = prop.replace('={', ':`${')
|
|
457
|
-
prop.replace('} ', '}`')
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
if (prop.includes('function')) {
|
|
461
|
-
// parse 'function' to function
|
|
462
|
-
prop = prop.replace("'", '')
|
|
463
|
-
|
|
464
|
-
if (prop.endsWith("}'")) {
|
|
465
|
-
prop = prop.replace("}'", '}')
|
|
466
|
-
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
prop = prop.replace('=function', ':function')
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
filteredProps.push(prop);
|
|
473
|
-
|
|
451
|
+
let $_ternaryprops = []
|
|
452
|
+
|
|
453
|
+
component = component.replaceAll(/\s+/g, " ");
|
|
474
454
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
// Check if spread props are within curly braces
|
|
481
|
-
if (prop.startsWith('{') && prop.endsWith('}')) {
|
|
482
|
-
const spreadObject = prop
|
|
483
|
-
const hasOtherObjects = spreadObject.split(',').filter((e) => e.includes(':')).length > 0;
|
|
484
|
-
|
|
485
|
-
const isValidSpread = spreadObject.includes('...');
|
|
486
|
-
|
|
487
|
-
let processedSpreadObject = '';
|
|
488
|
-
if (isValidSpread) {
|
|
489
|
-
// Split the spreadObject by commas and process each part individually
|
|
490
|
-
const parts = spreadObject.split(',').map((part) => {
|
|
491
|
-
if (part.trim().startsWith('{') && part.trim().endsWith('}')) {
|
|
492
|
-
const nestedParts = part
|
|
493
|
-
.trim()
|
|
494
|
-
.slice(1, -1) // Remove outer {}
|
|
495
|
-
.split(',')
|
|
496
|
-
.map((nestedPart) => {
|
|
497
|
-
return nestedPart.includes('...') ? nestedPart.trim().replace(/\.\.\./, '') : `...${nestedPart.trim()}`;
|
|
498
|
-
});
|
|
499
|
-
return `{${nestedParts.join(',')}}`;
|
|
500
|
-
} else {
|
|
501
|
-
return part.includes('...') ? part.trim() : part.trim().startsWith('{') ? `...${part.trim()}` : `${part.trim()}`;
|
|
502
|
-
}
|
|
503
|
-
});
|
|
504
|
-
if (!parts.join(',').includes('{(')) {
|
|
505
|
-
|
|
506
|
-
processedSpreadObject = `${parts.join(',')}`
|
|
507
|
-
|
|
508
|
-
} else {
|
|
509
|
-
let prop = parts.join(',')
|
|
510
|
-
prop = prop.replaceAll('{(', '(')
|
|
511
|
-
prop = prop.replaceAll(')}', ')')
|
|
512
|
-
processedSpreadObject = prop
|
|
513
|
-
}
|
|
514
|
-
if (prop.includes('{{')) {
|
|
515
|
-
let prop = parts.join(',')
|
|
516
|
-
prop = prop.replaceAll('{{', '{')
|
|
517
|
-
prop = prop.replaceAll('}}', '}')
|
|
518
|
-
processedSpreadObject = prop
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
} else {
|
|
523
|
-
// Process nested structures within the object
|
|
524
|
-
processedSpreadObject = `{...${spreadObject}}`;
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
const $propsKey = `$props_${Math.random().toString(36).substring(2)}`;
|
|
528
|
-
filteredProps.push(`${$propsKey}:${processedSpreadObject}`);
|
|
529
|
-
}
|
|
530
|
-
}
|
|
455
|
+
component = component.replace(componentAttributes, '')
|
|
456
|
+
$_ternaryprops.forEach((prop) => {
|
|
457
|
+
component = component.replace(prop, '')
|
|
458
|
+
})
|
|
531
459
|
|
|
532
|
-
|
|
533
|
-
isWithinComponent = false;
|
|
534
|
-
}
|
|
535
|
-
}
|
|
460
|
+
let children = component.split(`<${name}`)[1].split(`</${name}>`)[0].trim().replace(/\s+/g, " ").trim().replace(/,$/, '').replace('>', '').replace(/\/$/, '').trim()
|
|
536
461
|
|
|
537
|
-
// get inner content of <Component>inner content</Component>
|
|
538
|
-
let children = new RegExp(`<${name}[^>]*>(.*?)<\/${name}>`, "gs").exec(component) ? new RegExp(`<${name}[^>]*>(.*?)<\/${name}>`, "gs").exec(component)[1] : null;
|
|
539
462
|
|
|
540
|
-
props = filteredProps.join(',')
|
|
463
|
+
props = filteredProps.join(',').replace(/\s+/g, " ").trim().replace(/,$/, '')
|
|
541
464
|
|
|
542
465
|
let savedname = name;
|
|
543
466
|
|
|
@@ -555,16 +478,16 @@ function Compiler(func, file) {
|
|
|
555
478
|
childs.forEach((child) => {
|
|
556
479
|
if (child.parent == name) {
|
|
557
480
|
let html = child.children.match(
|
|
558
|
-
/<([
|
|
481
|
+
/<([A-Z][A-Za-z0-9_-]+)([^>]*)>(.*?)<\/\1>|<([A-Z][A-Za-z0-9_-]+)([^]*?)\/>/gs
|
|
559
482
|
);
|
|
560
483
|
if (html) {
|
|
561
484
|
html = html.map((h) => h.trim().replace(/\s+/g, " ")).join(" ");
|
|
562
|
-
let before = child.children;
|
|
563
485
|
child.children = child.children.replaceAll(html, `${html}`);
|
|
564
486
|
// remove duplicate quotes
|
|
565
487
|
}
|
|
566
488
|
|
|
567
489
|
myChildrens.push(child.children);
|
|
490
|
+
childs = childs.filter((e) => e.parent !== name);
|
|
568
491
|
}
|
|
569
492
|
});
|
|
570
493
|
|
|
@@ -585,8 +508,10 @@ function Compiler(func, file) {
|
|
|
585
508
|
* @memoize - memoize a component to be remembered on each render and replace the old jsx
|
|
586
509
|
*/
|
|
587
510
|
|
|
511
|
+
|
|
588
512
|
let replace = "";
|
|
589
|
-
replace = `\${this.memoize(this.createComponent(${savedname}, {${props}}, [\`${myChildrens.join(
|
|
513
|
+
replace = `\${this.memoize(this.createComponent(${savedname}, {${props}}, [\`${myChildrens.join('')}\`]))}`;
|
|
514
|
+
|
|
590
515
|
|
|
591
516
|
body = body.replace(before, replace);
|
|
592
517
|
});
|
|
@@ -594,12 +519,61 @@ function Compiler(func, file) {
|
|
|
594
519
|
return body;
|
|
595
520
|
}
|
|
596
521
|
|
|
522
|
+
string = string.replaceAll('vaderjs/client', '/vader.js')
|
|
597
523
|
|
|
524
|
+
const importRegex = /import\s*([^\s,]+|\{[^}]+\})\s*from\s*(['"])(.*?)\2/g;
|
|
525
|
+
const imports = string.match(importRegex);
|
|
526
|
+
let replaceMents = [];
|
|
598
527
|
|
|
599
|
-
// replace all comments
|
|
600
528
|
|
|
601
|
-
|
|
602
|
-
|
|
529
|
+
for (let match of imports) {
|
|
530
|
+
let path = match.split('from')[1].trim().replace(/'/g, '').replace(/"/g, '').trim()
|
|
531
|
+
switch (true) {
|
|
532
|
+
case path && !path.includes('./') && !path.includes('/vader.js') && !path.includes('/vaderjs/client') && !path.startsWith('src') && !path.startsWith('public') && !path.includes('http') && !path.includes('https'):
|
|
533
|
+
let componentFolder = fs.existsSync(process.cwd() + '/node_modules/' + path) ? process.cwd() + '/node_modules/' + path : process.cwd() + '/node_modules/' + path.split('/')[0]
|
|
534
|
+
componentFolder = componentFolder.split(process.cwd())[1]
|
|
535
|
+
if (!fs.existsSync(process.cwd() + componentFolder)) {
|
|
536
|
+
throw new Error('Could not find ' + path + ' at ' + match + ' in file ' + file)
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (!fs.existsSync(process.cwd() + '/dist/src/' + componentFolder.split('/').slice(2).join('/'))) {
|
|
540
|
+
fs.mkdirSync(process.cwd() + '/dist/src/' + componentFolder.split('/').slice(2).join('/'), { recursive: true })
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
let baseFolder = componentFolder.split('node_modules')[1].split('/')[1]
|
|
544
|
+
let glp = globSync('**/**/**/**.{jsx,js}', {
|
|
545
|
+
cwd: process.cwd() + '/node_modules/' + baseFolder + '/',
|
|
546
|
+
absolute: true,
|
|
547
|
+
recursive: true
|
|
548
|
+
})
|
|
549
|
+
for (let file of glp) {
|
|
550
|
+
let text = fs.readFileSync(file, "utf8");
|
|
551
|
+
if (!file.endsWith('.js') && file.endsWith('.jsx')) {
|
|
552
|
+
text = Compiler(text, file);
|
|
553
|
+
|
|
554
|
+
}
|
|
555
|
+
let dest = file.split('node_modules')[1]
|
|
556
|
+
dest = dest.split(baseFolder)[1]
|
|
557
|
+
// write to dist
|
|
558
|
+
writer(process.cwd() + '/dist/src/' + baseFolder + dest, text)
|
|
559
|
+
let importname = match.split('import')[1].split('from')[0].trim()
|
|
560
|
+
let oldImportstring = match.split('from')[1].trim().replace(/'/g, '').replace(/"/g, '').trim()
|
|
561
|
+
let newImport = `/src/${baseFolder + dest}`
|
|
562
|
+
newImport = newImport.replaceAll('.jsx', '.js').replaceAll('\\', '/')
|
|
563
|
+
replaceMents.push({ match: oldImportstring, replace: newImport })
|
|
564
|
+
console.log(`📦 imported Node Package ${baseFolder} `)
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
break;
|
|
569
|
+
default:
|
|
570
|
+
break;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
for (let replace of replaceMents) {
|
|
575
|
+
string = string.replaceAll(replace.match, replace.replace)
|
|
576
|
+
}
|
|
603
577
|
|
|
604
578
|
string = string.replaceAll(/\$\{[^{]*\.{3}/gs, (match) => {
|
|
605
579
|
if (match.includes('...')) {
|
|
@@ -652,7 +626,8 @@ function Compiler(func, file) {
|
|
|
652
626
|
if (line.includes('import')) {
|
|
653
627
|
// Regular expression for matching import() statements
|
|
654
628
|
let asyncimportMatch = line.match(/import\s*\((.*)\)/gs);
|
|
655
|
-
|
|
629
|
+
// handle import { Component } from 'vaderjs/runtime/vader.js'
|
|
630
|
+
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);
|
|
656
631
|
|
|
657
632
|
if (asyncimportMatch) {
|
|
658
633
|
asyncimportMatch.forEach(async (match) => {
|
|
@@ -731,6 +706,10 @@ function Compiler(func, file) {
|
|
|
731
706
|
case path && path.includes('.css'):
|
|
732
707
|
string = string.replace(beforeimport, '')
|
|
733
708
|
newImport = ``
|
|
709
|
+
break;
|
|
710
|
+
case path && !path.startsWith('./') && !path.includes('/vader.js') && !path.startsWith('src') && !path.startsWith('public') &&
|
|
711
|
+
path.match(/^[A-Za-z0-9_-]+$/gs) && !path.includes('http') && !path.includes('https'):
|
|
712
|
+
|
|
734
713
|
break;
|
|
735
714
|
default:
|
|
736
715
|
let beforePath = path
|
|
@@ -789,28 +768,7 @@ async function Build() {
|
|
|
789
768
|
return text;
|
|
790
769
|
};
|
|
791
770
|
|
|
792
|
-
|
|
793
|
-
globalThis.isWriting = file
|
|
794
|
-
switch (true) {
|
|
795
|
-
case !fs.existsSync(file):
|
|
796
|
-
fs.mkdirSync(file.split('/').slice(0, -1).join('/'), { recursive: true })
|
|
797
|
-
break;
|
|
798
|
-
}
|
|
799
|
-
if (globalThis.isWriting !== file) {
|
|
800
|
-
return
|
|
801
|
-
}
|
|
802
|
-
await fs.writeFileSync(file, data);
|
|
803
|
-
|
|
804
|
-
globalThis.isWriting = null
|
|
805
|
-
return { _written: true };
|
|
806
|
-
};
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
// Process files in the 'pages' directory
|
|
812
|
-
let appjs = '';
|
|
813
|
-
let hasWritten = []
|
|
771
|
+
|
|
814
772
|
function ssg(routes = []) {
|
|
815
773
|
globalThis.isBuilding = true
|
|
816
774
|
console.log(`Generating html files for ${routes.length} routes`)
|
|
@@ -966,33 +924,49 @@ async function Build() {
|
|
|
966
924
|
headless: "new", args: ['--no-sandbox', '--disable-setuid-sandbox'],
|
|
967
925
|
warning: false,
|
|
968
926
|
})
|
|
969
|
-
|
|
927
|
+
|
|
928
|
+
const browserPID = browser.process().pid
|
|
970
929
|
try {
|
|
971
930
|
|
|
972
931
|
route.url = route.url.replaceAll(/\/:[a-zA-Z0-9_-]+/gs, '')
|
|
973
932
|
let page = await browser.newPage();
|
|
974
933
|
await page.goto(`http://localhost:${port}/`, { waitUntil: 'networkidle2' });
|
|
975
|
-
await page.
|
|
934
|
+
await page.on('console', msg => console.log('PAGE LOG:', msg.text()));
|
|
935
|
+
await page.on('error', err => console.log('PAGE LOG:', err));
|
|
936
|
+
await page.on('pageerror', err => console.log('PAGE LOG:', err));
|
|
937
|
+
await page.evaluate(() => {
|
|
938
|
+
window.onerror = function (msg, url, lineNo, columnNo, error) {
|
|
939
|
+
console.log(msg, url, lineNo, columnNo, error)
|
|
940
|
+
}
|
|
941
|
+
})
|
|
942
|
+
await page.waitForSelector('#root', { timeout: 10000 })
|
|
976
943
|
await page.evaluate(() => {
|
|
977
944
|
document.getElementById('meta').remove()
|
|
978
945
|
document.querySelector('#isServer').innerHTML = 'window.isServer = false'
|
|
979
946
|
if (document.head.getAttribute('prerender') === 'false') {
|
|
980
947
|
document.querySelector('#root').innerHTML = ''
|
|
948
|
+
console.log(`Disabled prerendering for ${window.location.pathname}`)
|
|
981
949
|
}
|
|
982
|
-
})
|
|
950
|
+
})
|
|
983
951
|
const html = await page.content();
|
|
984
952
|
|
|
985
953
|
await page.close();
|
|
986
954
|
await writer(process.cwd() + '/dist/' + (route.url === '/' ? 'index.html' : `${route.url}/` + 'index.html'), html)
|
|
987
955
|
await browser.close();
|
|
956
|
+
server.close()
|
|
957
|
+
|
|
988
958
|
} catch (error) {
|
|
989
|
-
|
|
959
|
+
server.close()
|
|
990
960
|
await browser.close();
|
|
991
961
|
}
|
|
992
962
|
finally {
|
|
993
963
|
await browser.close();
|
|
994
964
|
server.close()
|
|
995
965
|
}
|
|
966
|
+
try {
|
|
967
|
+
process.kill(browserPID)
|
|
968
|
+
} catch (error) {
|
|
969
|
+
}
|
|
996
970
|
|
|
997
971
|
|
|
998
972
|
})
|
|
@@ -1036,7 +1010,6 @@ async function Build() {
|
|
|
1036
1010
|
data = Compiler(data, origin);
|
|
1037
1011
|
|
|
1038
1012
|
|
|
1039
|
-
|
|
1040
1013
|
await writer(process.cwd() + "/dist/" + fileName.replace('.jsx', '.js'), data).then(async () => {
|
|
1041
1014
|
|
|
1042
1015
|
|
|
@@ -1199,6 +1172,7 @@ async function Build() {
|
|
|
1199
1172
|
console.log(`📦 Build completed: Build Size -> ${Math.round(bundleSize / 1000)}kb`)
|
|
1200
1173
|
|
|
1201
1174
|
bundleSize = 0;
|
|
1175
|
+
|
|
1202
1176
|
return true
|
|
1203
1177
|
}
|
|
1204
1178
|
const s = () => {
|
|
@@ -1328,7 +1302,9 @@ Vader.js v1.3.3
|
|
|
1328
1302
|
}
|
|
1329
1303
|
}).on('error', (err) => console.log(err))
|
|
1330
1304
|
})
|
|
1305
|
+
let p = process.argv[process.argv.indexOf('--watch') + 1] || process.env.PORT || 3000
|
|
1331
1306
|
|
|
1307
|
+
process.env.PORT = p
|
|
1332
1308
|
s()
|
|
1333
1309
|
|
|
1334
1310
|
globalThis.listen = true;
|
|
@@ -1357,19 +1333,19 @@ url: http://localhost:${port}
|
|
|
1357
1333
|
default:
|
|
1358
1334
|
console.log(`
|
|
1359
1335
|
Vader.js is a reactive framework for building interactive applications for the web built ontop of bun.js!
|
|
1360
|
-
|
|
1336
|
+
|
|
1361
1337
|
Usage: vader <command>
|
|
1362
|
-
|
|
1338
|
+
|
|
1363
1339
|
Commands:
|
|
1364
|
-
--watch
|
|
1365
|
-
|
|
1340
|
+
--watch (port) Watch the pages folder for changes with hot reloading
|
|
1341
|
+
|
|
1366
1342
|
--build Build the project to ./dist
|
|
1367
|
-
|
|
1368
|
-
--serve Serve the project on a port (default 3000)
|
|
1369
|
-
|
|
1370
|
-
Learn more about vader: https://vader-js.pages.dev/
|
|
1371
1343
|
|
|
1372
|
-
|
|
1344
|
+
--serve (400) Serve the project on a port (default 3000 or process.env.PORT)
|
|
1345
|
+
|
|
1346
|
+
Learn more about vader: https://vader-js.pages.dev/
|
|
1347
|
+
|
|
1348
|
+
`)
|
|
1373
1349
|
break;
|
|
1374
1350
|
|
|
1375
1351
|
}
|