vaderjs 1.3.3-alpha-44 → 1.3.3-alpha-46
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 +19 -2
- package/client/index.js +207 -326
- package/package.json +3 -2
- package/runtime/router.js +1 -333
- package/runtime/vader.js +1 -547
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-46",
|
|
6
6
|
"bin": {
|
|
7
7
|
"vader": "./vader.js"
|
|
8
8
|
},
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"email": "malikwhitterb@gmail.com"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"glob": "latest"
|
|
30
|
+
"glob": "latest",
|
|
31
|
+
"terser":"latest"
|
|
31
32
|
}
|
|
32
33
|
}
|
package/runtime/router.js
CHANGED
|
@@ -1,333 +1 @@
|
|
|
1
|
-
import { Component }
|
|
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
|
-
* @method get
|
|
36
|
-
* @param {String} path
|
|
37
|
-
* @param {Function} handler
|
|
38
|
-
* @param {{a:b}} req request object
|
|
39
|
-
* @description This method is used to register a get route
|
|
40
|
-
* @returns {void}
|
|
41
|
-
* @memberof Express
|
|
42
|
-
*/
|
|
43
|
-
get(path, handler) {
|
|
44
|
-
|
|
45
|
-
this.routes.push({
|
|
46
|
-
path,
|
|
47
|
-
handler,
|
|
48
|
-
method: 'get',
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* @method use
|
|
53
|
-
* @description This method allows you to use middlewares
|
|
54
|
-
* @param {Function} middleware
|
|
55
|
-
*/
|
|
56
|
-
|
|
57
|
-
use(/* path, */ middleware) {
|
|
58
|
-
console.log(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
|
-
this.listeners.push(port);
|
|
76
|
-
if (this.listeners.length === 1) {
|
|
77
|
-
this.handleRoute(window.location.hash);
|
|
78
|
-
}else{
|
|
79
|
-
this.listeners.pop();
|
|
80
|
-
}
|
|
81
|
-
if (callback) {
|
|
82
|
-
callback();
|
|
83
|
-
}
|
|
84
|
-
window.onhashchange = () => {
|
|
85
|
-
this.handleRoute(window.location.hash);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* @method extractParams
|
|
90
|
-
* @description This method is used to extract parameters from the route path
|
|
91
|
-
* @param {*} routePath
|
|
92
|
-
* @param {*} hash
|
|
93
|
-
* @returns {Object} params
|
|
94
|
-
* @memberof Express
|
|
95
|
-
*/
|
|
96
|
-
|
|
97
|
-
extractParams(routePath, hash) {
|
|
98
|
-
const routeParts = routePath.split('/');
|
|
99
|
-
const hashParts = hash.split('/');
|
|
100
|
-
const params = {};
|
|
101
|
-
routeParts.forEach((part, index) => {
|
|
102
|
-
if (part.startsWith(':')) {
|
|
103
|
-
const paramName = part.slice(1);
|
|
104
|
-
params[paramName] = hashParts[index];
|
|
105
|
-
}else if(part.startsWith('*')){
|
|
106
|
-
let array = hashParts.slice(index)
|
|
107
|
-
array.forEach((i, index)=>{
|
|
108
|
-
params[index] = i
|
|
109
|
-
})
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
return params;
|
|
113
|
-
}
|
|
114
|
-
extractQueryParams(hash){
|
|
115
|
-
|
|
116
|
-
const queryParams = hash.split('?')[1];
|
|
117
|
-
if(!queryParams){
|
|
118
|
-
return {};
|
|
119
|
-
}
|
|
120
|
-
const params = {};
|
|
121
|
-
queryParams.split('&').forEach((param)=>{
|
|
122
|
-
const [key, value] = param.split('=');
|
|
123
|
-
params[key] = value;
|
|
124
|
-
})
|
|
125
|
-
return params;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* @method handleRoute
|
|
130
|
-
* @param {String} hash
|
|
131
|
-
* @description This method is used to handle the route
|
|
132
|
-
*/
|
|
133
|
-
|
|
134
|
-
handleRoute(hash) {
|
|
135
|
-
hash = hash.slice(1);
|
|
136
|
-
let status = 200;
|
|
137
|
-
let paramsCatchall = {}
|
|
138
|
-
let hashBefore = hash;
|
|
139
|
-
let route = this.routes.find((route) => {
|
|
140
|
-
if (route.path === hash) {
|
|
141
|
-
return true;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if(hash === '' && route.path === '/'){
|
|
145
|
-
return true
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if(hash.includes('?')){
|
|
149
|
-
hash = hash.split('?')[0]
|
|
150
|
-
}
|
|
151
|
-
if (route.path.includes('*') || route.path.includes(':')) {
|
|
152
|
-
const routeParts = route.path.split('/');
|
|
153
|
-
const hashParts = hash.split('/');
|
|
154
|
-
|
|
155
|
-
if (routeParts.length !== hashParts.length && !route.path.endsWith('*')) {
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
for (let index = 0; index < routeParts.length; index++) {
|
|
160
|
-
const routePart = routeParts[index];
|
|
161
|
-
const hashPart = hashParts[index];
|
|
162
|
-
|
|
163
|
-
if (routePart.startsWith(':') || routePart.startsWith('*')) {
|
|
164
|
-
|
|
165
|
-
continue;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (routePart !== hashPart) {
|
|
169
|
-
|
|
170
|
-
return false;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return true;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const params = this.extractParams(route.path, hashBefore);
|
|
178
|
-
return Object.keys(params).length > 0;
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
if (!route) {
|
|
183
|
-
route = this.routes.find((errorRoute) => {
|
|
184
|
-
if (errorRoute.path.includes('/404')){
|
|
185
|
-
this.error = true;
|
|
186
|
-
return true;
|
|
187
|
-
} else if (!this.error && errorRoute.path.includes('/404')){
|
|
188
|
-
window.location.hash = this.basePath
|
|
189
|
-
}
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
status = route ? 200 : 404;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const queryParams = this.extractQueryParams(hashBefore);
|
|
196
|
-
const params = route && route.path ? this.extractParams(route.path, hashBefore) : {};
|
|
197
|
-
const req = {
|
|
198
|
-
headers: {},
|
|
199
|
-
params: params,
|
|
200
|
-
query: queryParams,
|
|
201
|
-
path: hash,
|
|
202
|
-
method: route ? route.method : 'get',
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
// @ts-ignore
|
|
206
|
-
window.$CURRENT_URL = req.path
|
|
207
|
-
|
|
208
|
-
// @ts-ignore
|
|
209
|
-
window.$FULL_URL = window.location.href.replace('#', '')
|
|
210
|
-
|
|
211
|
-
const res = {
|
|
212
|
-
status: status,
|
|
213
|
-
/**
|
|
214
|
-
* @method log
|
|
215
|
-
* @param {String} type
|
|
216
|
-
* @description This method is used to log the request and response
|
|
217
|
-
*/
|
|
218
|
-
log: (type) => {
|
|
219
|
-
if(type === undefined){
|
|
220
|
-
console.log(`${req.path} ${req.method} ${res.status} ${req.timestamp}`);
|
|
221
|
-
}else{
|
|
222
|
-
console.table({
|
|
223
|
-
'Request Path': req.path,
|
|
224
|
-
'Request Method': route.method,
|
|
225
|
-
'Response Status': res.status,
|
|
226
|
-
'Request Timestamp': req.timestamp,
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
},
|
|
230
|
-
refresh: () => {
|
|
231
|
-
this.handleRoute(window.location.hash);
|
|
232
|
-
},
|
|
233
|
-
redirect: (path) => {
|
|
234
|
-
!path.startsWith('/') ? path = `/${path}` : null;
|
|
235
|
-
window.location.hash = `#${path}`;
|
|
236
|
-
},
|
|
237
|
-
render: async (/**@type {Component} */ Component, req, res) => {
|
|
238
|
-
try {
|
|
239
|
-
if(!Component.default || !Component.default.constructor){
|
|
240
|
-
let message = !Component.default ? `Router expected a default exported component ie: export default class Component` : !Component.default.constructor ? 'Component is not a class' : null;
|
|
241
|
-
throw new Error(message);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
// Create an instance of the component
|
|
246
|
-
Component = Component.default ? new Component.default() : Component.constructor ? new Component() : Component;
|
|
247
|
-
|
|
248
|
-
// Set the 'mounted' flag to true
|
|
249
|
-
Component.mounted = true;
|
|
250
|
-
|
|
251
|
-
// Check if the root element exists
|
|
252
|
-
if (!document.querySelector('#root')) {
|
|
253
|
-
throw new Error('Root element not found, please add an element with id root');
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Reset component state
|
|
257
|
-
Component.reset();
|
|
258
|
-
Component.components = {};
|
|
259
|
-
Component.request = req;
|
|
260
|
-
Component.response = res;
|
|
261
|
-
|
|
262
|
-
// Check if the component has a router and is not a child component
|
|
263
|
-
if (Component.router.use && !Component.isChild) {
|
|
264
|
-
|
|
265
|
-
// Allow pausing the route and run code before rendering
|
|
266
|
-
await new Promise(async (resolve) => {
|
|
267
|
-
await Component.router.use(req, res)
|
|
268
|
-
if(req.pause){
|
|
269
|
-
let timer = setInterval(() => {
|
|
270
|
-
if(!req.pause){
|
|
271
|
-
resolve();
|
|
272
|
-
clearInterval(timer);
|
|
273
|
-
}
|
|
274
|
-
}, 1000);
|
|
275
|
-
}else{
|
|
276
|
-
resolve();
|
|
277
|
-
}
|
|
278
|
-
});
|
|
279
|
-
} else if (Component.router.use && Component.isChild) {
|
|
280
|
-
console.warn('Router.use() is not supported in child components');
|
|
281
|
-
}
|
|
282
|
-
const renderedContent = await Component.render();
|
|
283
|
-
document.querySelector('#root').innerHTML = renderedContent;
|
|
284
|
-
Component.bindMount();
|
|
285
|
-
Component.onMount();
|
|
286
|
-
|
|
287
|
-
} catch (error) {
|
|
288
|
-
console.error(error);
|
|
289
|
-
}
|
|
290
|
-
},
|
|
291
|
-
setQuery: (query) => {
|
|
292
|
-
let queryString = '';
|
|
293
|
-
Object.keys(query).forEach((key, index) => {
|
|
294
|
-
queryString += `${index === 0 ? '?' : '&'}${key}=${query[key]}`;
|
|
295
|
-
});
|
|
296
|
-
let route = window.location.hash.split('?')[0];
|
|
297
|
-
queryString = queryString.replace('/', '-').replaceAll('/', '-')
|
|
298
|
-
window.location.hash = `${route}${queryString}`;
|
|
299
|
-
},
|
|
300
|
-
send: (data) => {
|
|
301
|
-
document.querySelector('#root').innerHTML = data;
|
|
302
|
-
},
|
|
303
|
-
json: (data) => {
|
|
304
|
-
const rootElement = document.querySelector('#root');
|
|
305
|
-
|
|
306
|
-
// Clear existing content in #root
|
|
307
|
-
rootElement.innerHTML = '';
|
|
308
|
-
|
|
309
|
-
// Create a <pre> element
|
|
310
|
-
const preElement = document.createElement('pre');
|
|
311
|
-
|
|
312
|
-
// Set the text content of the <pre> element with formatted JSON
|
|
313
|
-
preElement.textContent = JSON.stringify(data, null, 2);
|
|
314
|
-
|
|
315
|
-
// Append the <pre> element to the #root element
|
|
316
|
-
rootElement.appendChild(preElement);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
};
|
|
320
|
-
middlewares.forEach((middleware) => {
|
|
321
|
-
middleware(req, res);
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
route ? route.handler(req, res) : null;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
window.VaderRouter = VaderRouter;
|
|
331
|
-
|
|
332
|
-
export default VaderRouter;
|
|
333
|
-
|
|
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("/"),o={};return s.forEach(((t,e)=>{if(t.startsWith(":")){const s=t.slice(1);o[s]=r[e]}else if(t.startsWith("*")){r.slice(e).forEach(((t,e)=>{o[e]=t}))}})),o}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],o=r[t];if(!e.startsWith(":")&&!e.startsWith("*")&&e!==o)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 o=this.extractQueryParams(s),n=r&&r.path?this.extractParams(r.path,s):{},a={headers:{},params:n,query:o,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*$/,"");let h=t.default.apply?t.default.apply(a,[e,s]):new t.default;a.key=i;let u={key:i,render:()=>h,request:e,response:s,params:n,queryParams:o,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};a.render=u.render,a=u}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;
|