vaderjs 1.3.3-alpha-117 → 1.3.3-alpha-119

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/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-117",
5
+ "version": "1.3.3-alpha-119",
6
6
  "bin": {
7
7
  "vader": "./vader.js"
8
8
  },
package/runtime/router.js CHANGED
@@ -1 +1,446 @@
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]}`;this.checkroute(t)||(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").innerHTML,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)},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 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.history.pushState({},"","/404"),window.dispatchEvent(new Event("popstate")),this.error=!0,!1):!(this.error||!e.url.includes("/404"))||void 0)),t=n?200:404);const o=this.extractQueryParams(r),s=n&&n.path?this.extractParams(n.path,r):{};Object.keys(s).forEach((e=>{s[e]=s[e].split("?")?s[e].split("?")[0]:s[e]}));const i={headers:{},params:s,query:o,path:e,fileUrl:window.location.href.split(window.location.origin)[1],url:window.location.href,method:n?n.method:"get",pause:!1,timestamp:Date.now()};window.$CURRENT_URL=i.path,window.$FULL_URL=window.location.href.replace("#","");const a={status:t,log:e=>{void 0===e?console.log(`${i.path} ${i.method} ${a.status} ${i.timestamp}`):console.table({"Request Path":i.path,"Request Method":n.method,"Response Status":a.status,"Request Timestamp":i.timestamp})},refresh:()=>{this.handleRoute(window.location.pathname)},redirect:e=>{!e.startsWith("/")&&(e=`/${e}`),window.history.pushState({},"",e),window.dispatchEvent(new Event("popstate"))},render:async(e,t,r,n)=>{function i(e){return"function"==typeof e&&/^class\s/.test(Function.prototype.toString.call(e))}try{let n=new Component;if(i(e.default)){let t=new e.default;n.state=t.state,n=t}else{if(e.default.toString().includes("this.key"))throw new Error('Using this.key is not supported in functional components use the attribute key="a value" instead');n.key=e.default.toString().split('key="')[1]?e.default.toString().split('key="')[1].split('"')[0]:null;let i={key:n.key,render:()=>e.default.apply(n,[t,r]),request:t,response:r,params:s,queryParams:o,reset:n.reset.bind(n),onMount:n.onMount.bind(n),useState:null,router:{use:n.router.use.bind(n)},bindMount:n.bindMount.bind(n),memoize:n.memoize.bind(n),createComponent:n.createComponent.bind(n),isChild:!1,useState:n.useState.bind(n),parseStyle:n.parseStyle.bind(n),bind:n.bind.bind(n),useRef:n.useRef.bind(n),useReducer:n.useReducer.bind(n),onMount:n.onMount.bind(n),onUnmount:n.onUnmount.bind(n),hydrate:n.hydrate.bind(n)};n.render=i.render,n=i}if(!document.querySelector("#root"))throw new Error("Root element not found, please add an element with id root");n.reset(),n.components={},n.request=t,n.response=r,n.router.use&&!n.isChild?await new Promise((async o=>{if(i(e.default))if(i(e.default))switch(await n.router.use(t,r),t.pause){case!0:console.log("pausing",t.pause);let e=setInterval((()=>{t.pause?console.log("still pausing",t.pause):(clearInterval(e),o())}),1e3);break;case!1:o()}else o();else switch(await e.default.apply(n,[t,r]),await n.router.use(t,r),t.pause){case!0:let e=setInterval((()=>{t.pause?console.log("still pausing request",t.url):(clearInterval(e),o())}),1e3);break;case!1:o()}})):n.router.use&&n.isChild&&console.warn("Router.use() is not supported in child components");const a=await n.render();document.querySelector("#root").innerHTML!==a&&(document.querySelector("#root").innerHTML=a),n.bindMount(),n.onMount()}catch(e){console.error(e)}},setQuery:e=>{let t="";Object.keys(e).forEach(((r,n)=>{t+=`${0===n?"?":"&"}${r}=${e[r]}`}));let r=window.location.hash.split("?")[0];t=t.replace("/","-").replaceAll("/","-"),window.location.hash=`${r}${t}`},send:e=>{document.querySelector("#root").innerHTML=e},json:e=>{const t=document.querySelector("#root");t.innerHTML="";const r=document.createElement("pre");r.textContent=JSON.stringify(e,null,2),t.appendChild(r)}};middlewares.forEach((e=>{e(i,a)})),n&&n.handler(i,a)}}window.VaderRouter=VaderRouter;export default VaderRouter;
1
+ import { Component } from "./vader.js";
2
+
3
+ let middlewares = [];
4
+
5
+
6
+
7
+ /**
8
+ * @class VaderRouter
9
+ * @description - creates an instance of Vader Express Router
10
+ *
11
+ * @param {String} path
12
+ * @param {Function} handler
13
+ * @param {object} req request object
14
+ * @param {object} res response object
15
+ * @returns {Object} Express
16
+ *
17
+ */
18
+ class VaderRouter{
19
+ /**
20
+ * @constructor
21
+ * @param {*} basePath
22
+ *
23
+ */
24
+ constructor(/**@type {string}**/basePath, /**@type {number}**/port) {
25
+ this.routes = [];
26
+ this.middlewares = [];
27
+ this.errorMiddlewares = [];
28
+ this.listeners = [];
29
+
30
+ this.basePath = basePath;
31
+
32
+
33
+ }
34
+
35
+ /**
36
+ * @method get
37
+ * @param {String} path
38
+ * @param {Function} handler
39
+ * @param {{a:b}} req request object
40
+ * @description This method is used to register a get route
41
+ * @returns {void}
42
+ * @memberof Express
43
+ */
44
+ get(path, handler) {
45
+ this.routes.push({
46
+ path,
47
+ handler,
48
+ method: 'get',
49
+ });
50
+
51
+ }
52
+ /**
53
+ * @method use
54
+ * @description This method allows you to use middlewares
55
+ * @param {Function} middleware
56
+ */
57
+
58
+ use(/* path, */ middleware) {
59
+ this.middlewares.push(middleware);
60
+ }
61
+
62
+ /**
63
+ * @method listen
64
+ * @param {String} port - unique id for the listener
65
+ * @param {Function} callback - callback function
66
+ * @description This method is used to start listening to the routes
67
+ * @returns {void}
68
+ *
69
+ */
70
+
71
+ listen(port, callback) {
72
+ if(!port){
73
+ port = Math.random().toString(36).substring(7);
74
+ }
75
+ window.onpopstate = async (e) => {
76
+ let route = window.location.pathname
77
+ let baseRoute = `/${route.split('/')[1]}`
78
+ if(!this.checkroute(route)){
79
+ route = '/404'
80
+ }
81
+ let html = new DOMParser().parseFromString(await fetch(baseRoute, {
82
+ cache: 'reload'
83
+ }).then((res)=>res.text()), 'text/html').documentElement
84
+
85
+
86
+ document.querySelector('#root').innerHTML = html.querySelector('#root').innerHTML;
87
+ document.title = html.querySelector('title').innerHTML;
88
+ document.querySelector('script[id="router"]').remove();
89
+ let newscript = document.createElement('script');
90
+ newscript.id = 'router';
91
+ newscript.innerHTML = html.querySelector('script[id="router"]').innerHTML;
92
+ newscript.setAttribute('type', 'module');
93
+ document.body.appendChild(newscript);
94
+ }
95
+
96
+ this.listeners.push(port);
97
+ if (this.listeners.length === 1) {
98
+ console.log(window.location.pathname)
99
+ this.handleRoute(window.location.pathname);
100
+ }else{
101
+ this.listeners.pop();
102
+ }
103
+ if (callback) {
104
+ callback();
105
+ }
106
+
107
+ }
108
+ /**
109
+ * @method extractParams
110
+ * @description This method is used to extract parameters from the route path
111
+ * @param {*} routePath
112
+ * @param {*} hash
113
+ * @returns {Object} params
114
+ * @memberof Express
115
+ */
116
+
117
+ extractParams(routePath, hash) {
118
+ const routeParts = routePath.split('/').filter((part) => part !== '');
119
+ const hashParts = hash.split('/').filter((part) => part !== '');
120
+ const params = {};
121
+ routeParts.forEach((part, index) => {
122
+ if (part.startsWith(':')) {
123
+ const paramName = part.slice(1);
124
+ params[paramName] = hashParts[index];
125
+ }else if(part.startsWith('*')){
126
+ let array = hashParts.slice(index)
127
+ array.forEach((i, index)=>{
128
+ params[index] = i
129
+ })
130
+ };
131
+ });
132
+ return params;
133
+ }
134
+ extractQueryParams(hash){
135
+
136
+ const queryParams = hash.split('?')[1];
137
+ if(!queryParams){
138
+ return {};
139
+ }
140
+ const params = {};
141
+ queryParams.split('&').forEach((param)=>{
142
+ const [key, value] = param.split('=');
143
+ params[key] = value;
144
+ })
145
+ return params;
146
+ }
147
+
148
+ checkroute(hash){
149
+ let route = this.routes.find((route) => {
150
+ if (route.path === hash) {
151
+ return true;
152
+ }
153
+
154
+ if(hash === '' && route.path === '/'){
155
+ return true
156
+ }
157
+
158
+ if(hash.includes('?')){
159
+ hash = hash.split('?')[0]
160
+ }
161
+ if (route.path.includes('*') || route.path.includes(':')) {
162
+ const routeParts = route.path.split('/').filter((part) => part !== '');
163
+ const hashParts = hash.split('/').filter((part) => part !== '');
164
+ if (routeParts.length !== hashParts.length && !route.path.endsWith('*')) {
165
+ return false;
166
+ }
167
+
168
+ for (let index = 0; index < routeParts.length; index++) {
169
+ const routePart = routeParts[index];
170
+ const hashPart = hashParts[index];
171
+
172
+
173
+ if (routePart.startsWith(':') || routePart.startsWith('*')) {
174
+
175
+ continue;
176
+ }
177
+
178
+ if (routePart !== hashPart) {
179
+ return false;
180
+ }
181
+ }
182
+
183
+ return true;
184
+ }
185
+ const params = this.extractParams(route.path, hash);
186
+ return Object.keys(params).length > 0;
187
+ });
188
+
189
+ return route;
190
+
191
+ }
192
+ /**
193
+ * @method handleRoute
194
+ * @param {String} hash
195
+ * @description This method is used to handle the route
196
+ */
197
+
198
+ handleRoute(hash) {
199
+ let status = 200;
200
+ let paramsCatchall = {}
201
+ let hashBefore = hash;
202
+
203
+ let route = this.checkroute(hash);
204
+ if (!route) {
205
+ route = window.routes.find((errorRoute) => {
206
+ if (errorRoute.url.includes('/404') && !this.error) {
207
+ console.error(`Route ${hash} not found`);
208
+ this.error = true;
209
+ return false
210
+
211
+ } else if (!this.error && errorRoute.url.includes('/404')){
212
+ return true
213
+ }
214
+
215
+ });
216
+
217
+ status = route ? 200 : 404;
218
+ }
219
+
220
+ const queryParams = this.extractQueryParams(hashBefore);
221
+ const params = route && route.path ? this.extractParams(route.path, hashBefore) : paramsCatchall;
222
+
223
+
224
+ // remove queryparams fromparam
225
+ Object.keys(params).forEach((key)=>{
226
+ params[key] = params[key].split('?') ? params[key].split('?')[0] : params[key];
227
+ })
228
+ const req = {
229
+ headers: {},
230
+ params: params,
231
+ query: queryParams,
232
+ path: hash,
233
+ fileUrl: window.location.href.split(window.location.origin)[1],
234
+ url: window.location.href,
235
+ method: route ? route.method : 'get',
236
+ pause: false,
237
+ timestamp: Date.now(),
238
+ };
239
+
240
+ // @ts-ignore
241
+ window.$CURRENT_URL = req.path
242
+
243
+ // @ts-ignore
244
+ window.$FULL_URL = window.location.href.replace('#', '')
245
+
246
+ const res = {
247
+ status: status,
248
+ /**
249
+ * @method log
250
+ * @param {String} type
251
+ * @description This method is used to log the request and response
252
+ */
253
+ log: (type) => {
254
+ if(type === undefined){
255
+ console.log(`${req.path} ${req.method} ${res.status} ${req.timestamp}`);
256
+ }else{
257
+ console.table({
258
+ 'Request Path': req.path,
259
+ 'Request Method': route.method,
260
+ 'Response Status': res.status,
261
+ 'Request Timestamp': req.timestamp,
262
+ });
263
+ }
264
+ },
265
+ refresh: () => {
266
+ this.handleRoute(window.location.pathname)
267
+ },
268
+ redirect: (path) => {
269
+ !path.startsWith('/') ? path = `/${path}` : null;
270
+ window.history.pushState({}, '', path);
271
+ window.dispatchEvent(new Event('popstate'));
272
+ },
273
+ render: async (/**@type {Component} */ component, req, res, metadata) => {
274
+ function isClass(funcOrClass) {
275
+ return typeof funcOrClass === 'function' &&
276
+ /^class\s/.test(Function.prototype.toString.call(funcOrClass));
277
+ }
278
+
279
+ try {
280
+ let c = new Component();
281
+ if(!isClass(component.default)){
282
+ let render = component.default.toString();
283
+ if(render.includes('this.key')){
284
+ throw new Error('Using this.key is not supported in functional components use the attribute key="a value" instead')
285
+ }
286
+
287
+
288
+
289
+ c.key = component.default.toString().split('key="')[1] ? component.default.toString().split('key="')[1].split('"')[0] : null;
290
+
291
+ let comp = {
292
+ key: c.key,
293
+ render: () => {
294
+ return component.default.apply(c, [req, res])
295
+ },
296
+ request: req,
297
+ response: res,
298
+ params: params,
299
+ queryParams: queryParams,
300
+ reset: c.reset.bind(c),
301
+ onMount: c.onMount.bind(c),
302
+ useState: null,
303
+ router: {
304
+ use: c.router.use.bind(c),
305
+ },
306
+ bindMount: c.bindMount.bind(c),
307
+ memoize: c.memoize.bind(c),
308
+ createComponent: c.createComponent.bind(c),
309
+ isChild: false,
310
+ useState: c.useState.bind(c),
311
+ parseStyle: c.parseStyle.bind(c),
312
+ bind: c.bind.bind(c),
313
+ useRef: c.useRef.bind(c),
314
+ useReducer: c.useReducer.bind(c),
315
+ onMount: c.onMount.bind(c),
316
+ onUnmount: c.onUnmount.bind(c),
317
+ hydrate: c.hydrate.bind(c),
318
+ }
319
+ c.render = comp.render;
320
+ c = comp;
321
+
322
+ }else{
323
+ let comp = new component.default();
324
+ c.state = comp.state;
325
+ c = comp;
326
+ }
327
+
328
+
329
+
330
+
331
+
332
+
333
+
334
+
335
+
336
+ // Check if the root element exists
337
+ if (!document.querySelector('#root')) {
338
+ throw new Error('Root element not found, please add an element with id root');
339
+ }
340
+
341
+ c.reset();
342
+ c.components = {};
343
+ c.request = req;
344
+ c.response = res;
345
+ if (c.router.use && !c.isChild) {
346
+ await new Promise(async (resolve) => {
347
+ if(!isClass(component.default) ){
348
+ await component.default.apply(c, [req, res])
349
+ await c.router.use(req, res)
350
+ switch(req.pause){
351
+ case true:
352
+ let timer = setInterval(() => {
353
+ if (!req.pause) {
354
+ clearInterval(timer);
355
+ resolve();
356
+ }else{
357
+ console.log('still pausing request', req.url)
358
+ }
359
+ }, 1000);
360
+ break;
361
+ case false:
362
+ resolve();
363
+ break;
364
+ }
365
+ }else if(isClass(component.default)){
366
+
367
+ await c.router.use(req, res)
368
+ switch(req.pause){
369
+ case true:
370
+ console.log('pausing', req.pause)
371
+ let timer = setInterval(() => {
372
+ if (!req.pause) {
373
+ clearInterval(timer);
374
+ resolve();
375
+ }else{
376
+ console.log('still pausing', req.pause)
377
+ }
378
+ }, 1000);
379
+ break;
380
+ case false:
381
+ resolve();
382
+ break;
383
+ }
384
+ }else{
385
+ resolve();
386
+ }
387
+ });
388
+
389
+
390
+ } else if (c.router.use && c.isChild) {
391
+ console.warn('Router.use() is not supported in child components');
392
+ }
393
+ const renderedContent = await c.render();
394
+ if( document.querySelector('#root').innerHTML !== renderedContent){
395
+ document.querySelector('#root').innerHTML = renderedContent;
396
+ }
397
+ c.bindMount();
398
+ c.onMount();
399
+
400
+ } catch (error) {
401
+ console.error(error);
402
+ }
403
+ },
404
+ setQuery: (query) => {
405
+ let queryString = '';
406
+ Object.keys(query).forEach((key, index) => {
407
+ queryString += `${index === 0 ? '?' : '&'}${key}=${query[key]}`;
408
+ });
409
+ let route = window.location.hash.split('?')[0];
410
+ queryString = queryString.replace('/', '-').replaceAll('/', '-')
411
+ window.location.hash = `${route}${queryString}`;
412
+ },
413
+ send: (data) => {
414
+ document.querySelector('#root').innerHTML = data;
415
+ },
416
+ json: (data) => {
417
+ const rootElement = document.querySelector('#root');
418
+
419
+ // Clear existing content in #root
420
+ rootElement.innerHTML = '';
421
+
422
+ // Create a <pre> element
423
+ const preElement = document.createElement('pre');
424
+
425
+ // Set the text content of the <pre> element with formatted JSON
426
+ preElement.textContent = JSON.stringify(data, null, 2);
427
+
428
+ // Append the <pre> element to the #root element
429
+ rootElement.appendChild(preElement);
430
+ }
431
+
432
+ };
433
+ middlewares.forEach((middleware) => {
434
+ middleware(req, res);
435
+ });
436
+
437
+ route ? route.handler(req, res) : null;
438
+ }
439
+
440
+
441
+ }
442
+
443
+ window.VaderRouter = VaderRouter;
444
+
445
+ export default VaderRouter;
446
+
@@ -0,0 +1,3 @@
1
+ {
2
+ "rewrites": [{ "source": "/:path*", "destination": "/index.html" }]
3
+ }
package/vader.js CHANGED
@@ -21,11 +21,14 @@ if (!fs.existsSync(process.cwd() + '/dist')) {
21
21
 
22
22
 
23
23
 
24
+
24
25
  if (typeof process.env.isCloudflare !== "undefined" || !fs.existsSync(process.cwd() + '/dist/index.html')) {
25
26
  let htmlFile = fs.readFileSync(process.cwd() + "/node_modules/vaderjs/runtime/index.html", 'utf8')
26
27
  fs.writeFileSync(process.cwd() + "/dist/index.html", htmlFile)
27
28
  }
28
29
 
30
+
31
+
29
32
  function Compiler(func, file) {
30
33
  let string = func;
31
34
  // Remove block comments
@@ -957,7 +960,7 @@ async function Build() {
957
960
  cwd: process.cwd() + '/src/',
958
961
  absolute: true,
959
962
  });
960
- const scannedVaderFiles = await glob("**/**.{html,js}", {
963
+ const scannedVaderFiles = await glob("**/**.{html,js,json}", {
961
964
  cwd: process.cwd() + '/node_modules/vaderjs/runtime',
962
965
  absolute: true,
963
966
  });