vaderjs 1.3.3-alpha-3 → 1.3.3-alpha-5
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 +1 -0
- package/package.json +4 -12
- package/runtime/{static/index.html → index.html} +1 -1
- package/runtime/vader.js +552 -0
- package/vader.js +96 -116
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -2,20 +2,12 @@
|
|
|
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-5",
|
|
6
6
|
"bin": {
|
|
7
7
|
"vader": "./vader.js"
|
|
8
8
|
},
|
|
9
|
-
"scripts": {
|
|
10
|
-
"build": "bunx vader --build",
|
|
11
|
-
"watch": "bun run vader --watch",
|
|
12
|
-
"help": "bunx vader"
|
|
13
|
-
},
|
|
14
9
|
"type": "module",
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
},
|
|
18
|
-
"peerDependencies": {
|
|
19
|
-
"typescript": "^5.0.0"
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"glob": "latest"
|
|
20
12
|
}
|
|
21
|
-
}
|
|
13
|
+
}
|
package/runtime/vader.js
ADDED
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
|
|
2
|
+
window.params = {};
|
|
3
|
+
window.Vader = {
|
|
4
|
+
version: "1.3.2",
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
let errors = {
|
|
8
|
+
"SyntaxError: Unexpected token '<'": "You forgot to enclose tags in a fragment <></>",
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const path = {
|
|
12
|
+
basename: (path) => {
|
|
13
|
+
return path.split("/").pop();
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
window.queryRef = (ref) => {
|
|
19
|
+
return document.querySelector(`[data-ref="${ref}"]`)
|
|
20
|
+
}
|
|
21
|
+
window.reinvoke = (eventtype, element) => {
|
|
22
|
+
const eventListener = (e) => {
|
|
23
|
+
return e
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// Check if the event listener has not been added before adding it
|
|
27
|
+
if (!element._eventListenerAdded) {
|
|
28
|
+
element.addEventListener(eventtype, eventListener);
|
|
29
|
+
|
|
30
|
+
// Set the flag to indicate that the event listener has been added
|
|
31
|
+
element._eventListenerAdded = true;
|
|
32
|
+
|
|
33
|
+
// Trigger the event without overwriting existing data or listeners
|
|
34
|
+
element.dispatchEvent(new Event(eventtype));
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
let invokes = []
|
|
42
|
+
let hasran = [];
|
|
43
|
+
let states = {};
|
|
44
|
+
let mounts = [];
|
|
45
|
+
export const strictMount = (key, callback) => {
|
|
46
|
+
let interval = setInterval(() => {
|
|
47
|
+
if(mounts.find(mount => mount.key === key)
|
|
48
|
+
&& !hasran.includes(callback.toString())
|
|
49
|
+
){
|
|
50
|
+
callback();
|
|
51
|
+
clearInterval(interval)
|
|
52
|
+
|
|
53
|
+
hasran.push(callback.toString());
|
|
54
|
+
}
|
|
55
|
+
},0);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
window.delegate = (event) => {
|
|
59
|
+
return event.detail.target
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let components = {};
|
|
63
|
+
|
|
64
|
+
let style = document.createElement("style");
|
|
65
|
+
document.head.appendChild(style);
|
|
66
|
+
|
|
67
|
+
const parseStyles = async (styles, className = '') => {
|
|
68
|
+
let css = await fetch(styles).then((res) => res.text());
|
|
69
|
+
let classes = css.split("}");
|
|
70
|
+
let parsedClasses = {};
|
|
71
|
+
classes.forEach((cls) => {
|
|
72
|
+
|
|
73
|
+
let name = cls.split(".")[1];
|
|
74
|
+
let value = cls.split("{")[1]
|
|
75
|
+
let keys = value.split(";");
|
|
76
|
+
let newKeys = [];
|
|
77
|
+
keys.forEach((key) => {
|
|
78
|
+
if (key.includes(":")) {
|
|
79
|
+
let newKey = key.split(":")[0].trim();
|
|
80
|
+
let newValue = key.split(":")[1].trim();
|
|
81
|
+
newKeys.push(`${newKey}: "${newValue}"`);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
value = `{${newKeys.join(",")}}`;
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
parsedClasses[name] = JSON.stringify(value);
|
|
88
|
+
});
|
|
89
|
+
return parsedClasses;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
export const stylis = {
|
|
94
|
+
/**
|
|
95
|
+
* @method create
|
|
96
|
+
* @param {*} styles
|
|
97
|
+
* @returns {Object} classes
|
|
98
|
+
* @description This method allows you to create css classes from an object
|
|
99
|
+
*/
|
|
100
|
+
create: async (/**@type {string} */ styles) => {
|
|
101
|
+
|
|
102
|
+
return await parseStyles(styles);
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @method mem
|
|
108
|
+
* @param {Component} component
|
|
109
|
+
* @returns {Component} Stateless Component
|
|
110
|
+
* @description This method allows you to memoize a component - this means it will be intialized only once and can be reused multiple times baased on a static key
|
|
111
|
+
*/
|
|
112
|
+
export const mem = (/**@type {Component}**/ component) => {
|
|
113
|
+
// ensure component is instance of Component
|
|
114
|
+
switch (true) {
|
|
115
|
+
case !(component instanceof Component):
|
|
116
|
+
throw new Error("component must be an instance of Component");
|
|
117
|
+
case !component.key:
|
|
118
|
+
throw new Error("component must have a static key");
|
|
119
|
+
// check if key was randomly generated
|
|
120
|
+
}
|
|
121
|
+
let key = component.key;
|
|
122
|
+
if (!components[key]) {
|
|
123
|
+
components[key] = component;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return components[key];
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @method invoke
|
|
131
|
+
* @description This method allows you to invoke a function from its id
|
|
132
|
+
* @param {*} name
|
|
133
|
+
* @param {*} params
|
|
134
|
+
* @returns
|
|
135
|
+
* @example
|
|
136
|
+
* invoke(this.functions['test'], 'hello') // this will invoke the function test with the params hello
|
|
137
|
+
*/
|
|
138
|
+
|
|
139
|
+
let functions = {};
|
|
140
|
+
|
|
141
|
+
export const invoke = (func, params) => {
|
|
142
|
+
let name = func.name;
|
|
143
|
+
|
|
144
|
+
window[name] = function (params) {
|
|
145
|
+
return func(params);
|
|
146
|
+
}
|
|
147
|
+
window[name] = window[name].bind(this);
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
return `${name}(${params})`;
|
|
151
|
+
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Represents a component in the Vader framework.
|
|
156
|
+
*/
|
|
157
|
+
export class Component {
|
|
158
|
+
/**
|
|
159
|
+
* Creates an instance of Component.
|
|
160
|
+
*/
|
|
161
|
+
constructor() {
|
|
162
|
+
this.state = {};
|
|
163
|
+
this.key = null;
|
|
164
|
+
this.components = {};
|
|
165
|
+
this.mounted = false;
|
|
166
|
+
this.checkIFMounted();
|
|
167
|
+
this.currenthtml = null;
|
|
168
|
+
window.listeners = [];
|
|
169
|
+
this.functionMap = new Map();
|
|
170
|
+
this.freeMemoryFromFunctions();
|
|
171
|
+
this.memoizes = []
|
|
172
|
+
this.children = []
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
createComponent(/**@type {Component}**/component, props, children) {
|
|
176
|
+
|
|
177
|
+
if (!component) {
|
|
178
|
+
throw new Error("Component must be defined");
|
|
179
|
+
}
|
|
180
|
+
if(!props.key){
|
|
181
|
+
throw new Error('new components must have a key')
|
|
182
|
+
}
|
|
183
|
+
let comp = new component();
|
|
184
|
+
|
|
185
|
+
comp['props'] = props;
|
|
186
|
+
comp.children = children;
|
|
187
|
+
comp.props.children = children.join('')
|
|
188
|
+
comp.parentNode = this;
|
|
189
|
+
comp.key = props.key || null;
|
|
190
|
+
this.components[props.key] = comp
|
|
191
|
+
this.children.push(comp)
|
|
192
|
+
return this.components[props.key]
|
|
193
|
+
}
|
|
194
|
+
memoize(/**@type {Component}**/component){
|
|
195
|
+
if(!component.key){
|
|
196
|
+
throw new Error('Component must have a static key')
|
|
197
|
+
}
|
|
198
|
+
switch(true){
|
|
199
|
+
case !this.memoizes.includes(component.key):
|
|
200
|
+
this.memoizes.push(component.key)
|
|
201
|
+
this.components[component.key] = component;
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
let comp = this.components[component.key];
|
|
206
|
+
let h = comp.render()
|
|
207
|
+
|
|
208
|
+
if(h && h.split('>,').length > 1){
|
|
209
|
+
h = h.replaceAll('>,', '>')
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return `<div key="${component.key}">${h}</div>`
|
|
213
|
+
}
|
|
214
|
+
parseStyle(styles){
|
|
215
|
+
let css = ''
|
|
216
|
+
Object.keys(styles).forEach((key) => {
|
|
217
|
+
let value = styles[key]
|
|
218
|
+
key = key.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase()
|
|
219
|
+
css += `${key}:${value};`
|
|
220
|
+
})
|
|
221
|
+
return css
|
|
222
|
+
}
|
|
223
|
+
bindMount(){
|
|
224
|
+
mounts.push(this)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Hydrates the component by updating the HTML content if it has changed.
|
|
229
|
+
* @private
|
|
230
|
+
*/
|
|
231
|
+
hydrate() {
|
|
232
|
+
if (this.key) {
|
|
233
|
+
|
|
234
|
+
const el = document.querySelector(`[key="${this.key}"]`);
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
if (el) {
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
// Render the new HTML content
|
|
241
|
+
const newHtml = this.render();
|
|
242
|
+
// Compare the new HTML with the cached content
|
|
243
|
+
if (newHtml !== this.currentHtml) {
|
|
244
|
+
// Update the HTML only if it has changed
|
|
245
|
+
el.innerHTML = newHtml;
|
|
246
|
+
|
|
247
|
+
// Update the cached HTML content
|
|
248
|
+
this.currentHtml = newHtml;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Handles an object by parsing it as JSON and evaluating it.
|
|
256
|
+
* @param {string} obj - The object to handle.
|
|
257
|
+
* @returns {*} - The evaluated object.
|
|
258
|
+
* @prvate
|
|
259
|
+
*/
|
|
260
|
+
handleObject(obj) {
|
|
261
|
+
try {
|
|
262
|
+
obj = JSON.parse(obj);
|
|
263
|
+
} catch (error) {
|
|
264
|
+
// Handle JSON parsing error if needed
|
|
265
|
+
}
|
|
266
|
+
return eval(obj);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Frees memory from functions that have not been used for a certain period of time.
|
|
271
|
+
* @private
|
|
272
|
+
*/
|
|
273
|
+
freeMemoryFromFunctions() {
|
|
274
|
+
setInterval(() => {
|
|
275
|
+
for (var [key, value] in this.functionMap) {
|
|
276
|
+
if (Date.now() - value.lastUsed > 1000) {
|
|
277
|
+
this.functionMap.delete(key);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}, 1000);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Binds a function to the component.
|
|
285
|
+
* @param {string} funcData - The function data.
|
|
286
|
+
* @param {string} p - The parameter.
|
|
287
|
+
* @param {string} ref - The reference.
|
|
288
|
+
* @returns {string} - A valid inline JS function call.
|
|
289
|
+
*/
|
|
290
|
+
bind(funcData, d) {
|
|
291
|
+
|
|
292
|
+
const name = `func_${crypto ? crypto.getRandomValues(new Uint32Array(1))[0] : Math.random()}`;
|
|
293
|
+
|
|
294
|
+
var dynamicFunction = (params) => {
|
|
295
|
+
let func = new Function(`return (async (${params}) => {
|
|
296
|
+
console.log('called')
|
|
297
|
+
${funcData}
|
|
298
|
+
})()`);
|
|
299
|
+
func = func.bind(this);
|
|
300
|
+
func(params);
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
dynamicFunction = dynamicFunction.bind(this);
|
|
304
|
+
if (!this.functionMap.has(name)) {
|
|
305
|
+
document.addEventListener(`call_${name}`, (e) => {
|
|
306
|
+
|
|
307
|
+
dynamicFunction();
|
|
308
|
+
this.functionMap.set(e.detail.name, {
|
|
309
|
+
lastUsed: Date.now(),
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
this.functionMap.set(name, {
|
|
315
|
+
lastUsed: Date.now(),
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
window.call = (name, eventdata, params) => {
|
|
319
|
+
document.dispatchEvent(
|
|
320
|
+
new CustomEvent(`call_${name}`, {
|
|
321
|
+
detail: { name: `call_${name}`, target: eventdata },
|
|
322
|
+
})
|
|
323
|
+
);
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
// Return a valid inline js function call
|
|
327
|
+
return d.jsx ? dynamicFunction : `
|
|
328
|
+
((event) => {
|
|
329
|
+
event.target.setAttribute('data-ref', '${d.ref}');
|
|
330
|
+
let reference = event.target.getAttribute('data-ref');
|
|
331
|
+
event.target.eventData = event;
|
|
332
|
+
let domquery = queryRef(reference);
|
|
333
|
+
domquery.eventData = event;
|
|
334
|
+
domquery.eventData.detail.target = domquery;
|
|
335
|
+
call('${name}', {event:domquery.eventData}, '${d.params}')
|
|
336
|
+
})(event)
|
|
337
|
+
`;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Calls a function with the specified parameters. and dispatches an event.
|
|
342
|
+
* @param {string} func - The function name.
|
|
343
|
+
* @param {...*} params - The function parameters.
|
|
344
|
+
*/
|
|
345
|
+
callFunction(func, isInlineJsx, ...params) {
|
|
346
|
+
if(!isInlineJsx && params[0] && params[0].detail){
|
|
347
|
+
let el = params[0].detail.target.event.target
|
|
348
|
+
params[0].data = el.value;
|
|
349
|
+
params[0] = params[0].detail.target.event
|
|
350
|
+
}
|
|
351
|
+
func = func.replace(/'/g, '');
|
|
352
|
+
document.dispatchEvent(new CustomEvent(func, { detail: { name: func, params: params } }));
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Uses a function with the specified parameters.
|
|
357
|
+
* @param {Function} func - The function to use.
|
|
358
|
+
* @param {string} params - The function parameters.
|
|
359
|
+
* @param {boolean} [isInlineJsx=false] - Indicates if the function is an inline JSX.
|
|
360
|
+
* @returns {string} - The function call.
|
|
361
|
+
*/
|
|
362
|
+
useFunction(func, params, isInlineJsx = false) {
|
|
363
|
+
const sanitizedFuncName = func.name.trim().replace(/\s+/g, '_');
|
|
364
|
+
|
|
365
|
+
if (!invokes.includes(`'${sanitizedFuncName}'${this.key}`)) {
|
|
366
|
+
invokes.push(`'${sanitizedFuncName}'${this.key}`);
|
|
367
|
+
document.addEventListener(`call_${sanitizedFuncName}_${this.key}`, (e) => {
|
|
368
|
+
let { name, params } = e.detail;
|
|
369
|
+
if (name === `call_${sanitizedFuncName}_${this.key}`) {
|
|
370
|
+
let isarray = Array.isArray(params);
|
|
371
|
+
|
|
372
|
+
func(...(isarray ? params : [params]));
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
func = func.bind(this);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
try {
|
|
380
|
+
params = JSON.parse(params);
|
|
381
|
+
} catch (error) {
|
|
382
|
+
// Handle JSON parsing error if needed
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const returnString = isInlineJsx
|
|
386
|
+
? `'call_${sanitizedFuncName}_${this.key}'`
|
|
387
|
+
: `document.dispatchEvent(new CustomEvent('call_${sanitizedFuncName}_${this.key}', { detail: { name: 'call_${sanitizedFuncName}_${this.key}', params: ${JSON.stringify(params)} } }))`;
|
|
388
|
+
|
|
389
|
+
return returnString;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Uses state to dynamically update the component.
|
|
394
|
+
* @method useState
|
|
395
|
+
* @param {string} [key=null] - The auto-generated key.
|
|
396
|
+
* @param {*} initialState - The initial state.
|
|
397
|
+
* @param {Component.render} [func=null] - The render function.
|
|
398
|
+
* @returns {Array} - An array containing the state value and the setter function.
|
|
399
|
+
*/
|
|
400
|
+
useState(key = null, initialState) {
|
|
401
|
+
if (!this.state[key]) {
|
|
402
|
+
this.state[key] = initialState;
|
|
403
|
+
}
|
|
404
|
+
const getValue = () => this.state[key];
|
|
405
|
+
const set = (newValue) => {
|
|
406
|
+
this.state[key] = newValue;
|
|
407
|
+
this.hydrate();
|
|
408
|
+
};
|
|
409
|
+
return [getValue, set];
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
useRef(key = null, initialState) {
|
|
413
|
+
if (!this.state[key]) {
|
|
414
|
+
this.state[key] = initialState;
|
|
415
|
+
}
|
|
416
|
+
const getValue = () => this.state[key];
|
|
417
|
+
const set = (newValue) => {
|
|
418
|
+
this.state[key] = newValue;
|
|
419
|
+
this.hydrate();
|
|
420
|
+
};
|
|
421
|
+
return {
|
|
422
|
+
bind: key,
|
|
423
|
+
current: () => document.querySelector(`[ref="${key}"]`) || this.state[key],
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
useReducer(key = null, initialState, func = null) {
|
|
428
|
+
const getValue = () => this.state[key];
|
|
429
|
+
const set = (newValue) => {
|
|
430
|
+
|
|
431
|
+
this.hydrate();
|
|
432
|
+
};
|
|
433
|
+
return [getValue, set];
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Placeholder for content to be rendered.
|
|
438
|
+
* @method render
|
|
439
|
+
*/
|
|
440
|
+
render() {}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Checks if the component is mounted and triggers the onMount method.
|
|
444
|
+
* @private
|
|
445
|
+
*/
|
|
446
|
+
checkIFMounted() {
|
|
447
|
+
if (this.mounted) return;
|
|
448
|
+
let timer = setInterval(() => {
|
|
449
|
+
if (document.querySelector('[key="' + this.key + '"]')) {
|
|
450
|
+
clearInterval(timer);
|
|
451
|
+
this.mounted = true;
|
|
452
|
+
this.onMount();
|
|
453
|
+
}
|
|
454
|
+
}, 120);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Method that is called when the component is mounted.
|
|
459
|
+
* @method onMount
|
|
460
|
+
*/
|
|
461
|
+
onMount() {}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
let cache = {};
|
|
469
|
+
/**
|
|
470
|
+
* @method require
|
|
471
|
+
* @description Import CommonJS modules like Node.js for the browser
|
|
472
|
+
* @param {string} path
|
|
473
|
+
* @param {Boolean} noresolve - used to tell if the path should be automatically handled or manually handled - this is false by default
|
|
474
|
+
* @returns
|
|
475
|
+
*/
|
|
476
|
+
export const require = async (path, noresolve = false) => {
|
|
477
|
+
|
|
478
|
+
if (cache[path]) {
|
|
479
|
+
return cache[path];
|
|
480
|
+
}
|
|
481
|
+
let file = ''
|
|
482
|
+
try {
|
|
483
|
+
file = await fetch(path).then((res) => res.text());
|
|
484
|
+
} catch (error) {
|
|
485
|
+
console.error(error)
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
file = file + `\n//# sourceURL=${path}\n`;
|
|
489
|
+
|
|
490
|
+
let filetype = path.split(".").pop();
|
|
491
|
+
switch (true) {
|
|
492
|
+
case filetype === "js":
|
|
493
|
+
let exports = file.match(/module.exports\s*=\s*{.*}/gs) || file.match(/exports\s*=\s*{.*}/gs);
|
|
494
|
+
exports = exports ? exports[0] : null;
|
|
495
|
+
|
|
496
|
+
if (exports) {
|
|
497
|
+
let keys = exports.split("{")[1].split("}")[0].split(",");
|
|
498
|
+
let returnstring = "";
|
|
499
|
+
keys.forEach((key) => {
|
|
500
|
+
key = key.trim();
|
|
501
|
+
returnstring += `${key},`;
|
|
502
|
+
});
|
|
503
|
+
returnstring = `return {${returnstring}}`;
|
|
504
|
+
file = file += returnstring;
|
|
505
|
+
file = file.replaceAll(exports, "");
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
return new Function(`return (async () => { ${file} })()`)();
|
|
509
|
+
case filetype === "jsx":
|
|
510
|
+
return new Function(`return (async () => { ${file} })()`)()
|
|
511
|
+
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
window.require = require;
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* @method useState - type
|
|
520
|
+
* @param {*} initialState
|
|
521
|
+
* @returns {Array} [value, set]
|
|
522
|
+
* @description Allows you to use state to dynamically update your component
|
|
523
|
+
*/
|
|
524
|
+
export const useState = (initialState) => {
|
|
525
|
+
let value = initialState;
|
|
526
|
+
if (key && !states[key]) {
|
|
527
|
+
this.states[key] = initialState;
|
|
528
|
+
}
|
|
529
|
+
return [value, (newValue) => {}];
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
const constants = {};
|
|
533
|
+
let constantCounter = 0;
|
|
534
|
+
|
|
535
|
+
export const constant = (value) => {
|
|
536
|
+
const key = `constant_${constantCounter++}`;
|
|
537
|
+
if (!constants[key]) {
|
|
538
|
+
constants[key] = value;
|
|
539
|
+
}
|
|
540
|
+
return constants[key];
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
export default {
|
|
544
|
+
Component,
|
|
545
|
+
require,
|
|
546
|
+
invoke,
|
|
547
|
+
mem,
|
|
548
|
+
constant,
|
|
549
|
+
useState,
|
|
550
|
+
strictMount,
|
|
551
|
+
stylis,
|
|
552
|
+
}
|
package/vader.js
CHANGED
|
@@ -1,24 +1,20 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
import { Glob } from "bun";
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import { glob, globSync, globStream, globStreamSync, Glob } from 'glob'
|
|
4
|
+
|
|
6
5
|
let bundleSize = 0;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
case !fs.existsSync(process.cwd() + "/src"):
|
|
18
|
-
fs.mkdirSync(process.cwd() + "/src");
|
|
19
|
-
break;
|
|
6
|
+
if(!fs.existsSync(process.cwd() + '/dist')){
|
|
7
|
+
fs.mkdirSync(process.cwd() + '/dist')
|
|
8
|
+
fs.mkdirSync(process.cwd() + '/dist/public')
|
|
9
|
+
fs.mkdirSync(process.cwd() + '/dist/src')
|
|
10
|
+
fs.mkdirSync(process.cwd() + '/dist/pages')
|
|
11
|
+
}else if(!fs.existsSync(process.cwd() + '/dist/public')){
|
|
12
|
+
fs.mkdirSync(process.cwd() + '/dist/public')
|
|
13
|
+
}else if(!fs.existsSync(process.cwd() + '/src') && !fs.existsSync(process.cwd() + '/dist/src')){
|
|
14
|
+
fs.mkdirSync(process.cwd() + '/dist/src')
|
|
15
|
+
fs.mkdirSync(process.cwd() + '/src')
|
|
20
16
|
}
|
|
21
|
-
|
|
17
|
+
|
|
22
18
|
function Compiler(func) {
|
|
23
19
|
let string = func;
|
|
24
20
|
let comments = string
|
|
@@ -222,7 +218,8 @@ function Compiler(func) {
|
|
|
222
218
|
otherdata["jsx"] = isJSXComponent;
|
|
223
219
|
otherdata["ref"] = ref;
|
|
224
220
|
|
|
225
|
-
newvalue = newvalue.
|
|
221
|
+
newvalue = newvalue.split('\n').map(line => line.trim() ? line.trim() + ';' : line).join('\n');
|
|
222
|
+
|
|
226
223
|
let newatribute = `${attributeName}="\${this.bind(\`${newvalue}\` ${isJSXComponent ? "" : ","
|
|
227
224
|
}${JSON.stringify(otherdata)} )}"`;
|
|
228
225
|
|
|
@@ -258,8 +255,9 @@ function Compiler(func) {
|
|
|
258
255
|
params ? (otherdata["params"] = params) : null;
|
|
259
256
|
otherdata["jsx"] = isJSXComponent;
|
|
260
257
|
otherdata["ref"] = ref;
|
|
261
|
-
|
|
262
|
-
|
|
258
|
+
// since js is all in one line split it
|
|
259
|
+
newvalue = newvalue.split('\n').map(line => line.trim() ? line.trim() + ';' : line).join('\n');
|
|
260
|
+
let newattribute = `${attributeName}="\${this.bind(\`${newvalue}\` ${isJSXComponent ? "" : ","}${JSON.stringify(otherdata)} )}"`;
|
|
263
261
|
newattribute = newattribute.replace(/\s+/g, " ")
|
|
264
262
|
string = string.replace(old, newattribute);
|
|
265
263
|
}
|
|
@@ -581,91 +579,86 @@ async function Build() {
|
|
|
581
579
|
globalThis.isBuilding = true
|
|
582
580
|
console.log('Compiling......')
|
|
583
581
|
let reader = async (file) => {
|
|
584
|
-
let text = await
|
|
582
|
+
let text = await fs.readFileSync(file, "utf8");
|
|
585
583
|
return text;
|
|
586
584
|
};
|
|
587
585
|
let writer = async (file, data) => {
|
|
588
|
-
|
|
586
|
+
switch (true) {
|
|
587
|
+
case !fs.existsSync(file):
|
|
588
|
+
fs.mkdirSync(file.split('/').slice(0, -1).join('/'), { recursive: true })
|
|
589
|
+
break;
|
|
590
|
+
}
|
|
591
|
+
await fs.writeFileSync(file, data);
|
|
589
592
|
|
|
590
593
|
return { _written: true };
|
|
591
594
|
};
|
|
592
595
|
|
|
593
596
|
|
|
594
|
-
const
|
|
595
|
-
|
|
596
|
-
|
|
597
|
+
const glb = await glob("**/**/**/**.{jsx,js}", {
|
|
598
|
+
ignore: ["node_modules/**/*", "dist/**/*"],
|
|
599
|
+
cwd: process.cwd() + '/pages/',
|
|
600
|
+
absolute: true,
|
|
601
|
+
recursive: true
|
|
602
|
+
});
|
|
603
|
+
for await (let file of glb) {
|
|
604
|
+
|
|
605
|
+
let origin = file.split(process.cwd())[1] || file
|
|
606
|
+
let fileName = file.split(process.cwd() + '/pages/')[1]
|
|
597
607
|
file = file.split(process.cwd() + '/pages/')[1]
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
assetPrefix: "_next/static/",
|
|
604
|
-
fileExtensions: [".jsx", ".js"],
|
|
605
|
-
});
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
let m = router.match(origin.includes('/pages/index.jsx') ? '/' : '/' + file)
|
|
609
|
-
router.reload()
|
|
610
|
-
|
|
611
|
-
if (!m) {
|
|
612
|
-
console.error(`Error: ${file} is not a valid route\nFollow Proper Routing Structure:
|
|
613
|
-
`)
|
|
614
|
-
console.info(`
|
|
615
|
-
/pages/index.jsx
|
|
616
|
-
/pages/folder/index.jsx
|
|
617
|
-
/pages/folder/[param].jsx
|
|
618
|
-
`)
|
|
619
|
-
process.exit(1)
|
|
620
|
-
}
|
|
608
|
+
|
|
609
|
+
file === 'index.jsx' ? file = '/' : null
|
|
610
|
+
let isBasePath = file === '/' ? true : false
|
|
611
|
+
// ex: /pages/index.jsx - / or /pages/[id].jsx - /:id or /pages/folder/index.jsx - /folder
|
|
612
|
+
let aburl = origin.split('pages')[1].split('.jsx')[0].replace('.jsx', '').replace('/index', '').replace('/_', '/:').replace('/[', '/:').replace(']', '')
|
|
621
613
|
|
|
614
|
+
aburl.includes('[') ? aburl = '/' + aburl.split('[')[0].replace('/', '') : null
|
|
615
|
+
|
|
622
616
|
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
617
|
+
|
|
618
|
+
|
|
619
|
+
|
|
626
620
|
|
|
627
621
|
let obj = {
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
src: m.src,
|
|
634
|
-
pathname: writtenpath || m.pathname,
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
let data = await reader(process.cwd() + "/pages/" + file)
|
|
622
|
+
url: isBasePath ? '/' : aburl,
|
|
623
|
+
pathname: origin,
|
|
624
|
+
}
|
|
625
|
+
let data = await reader(process.cwd() + origin)
|
|
626
|
+
|
|
638
627
|
data = Compiler(data)
|
|
639
|
-
await writer(process.cwd() + "/dist/pages/" +
|
|
628
|
+
await writer(process.cwd() + "/dist/pages/" + fileName, data);
|
|
640
629
|
let params = obj.params ? Object.keys(obj.params).map((r) => {
|
|
641
630
|
r = r.replace('[', '').replace(']', '')
|
|
642
631
|
return `:${r}`
|
|
643
632
|
}) : ''
|
|
644
633
|
|
|
645
|
-
|
|
634
|
+
|
|
646
635
|
|
|
647
636
|
|
|
648
637
|
|
|
649
638
|
let js = `
|
|
650
|
-
router.get('${obj.
|
|
651
|
-
res.render(await require('
|
|
639
|
+
router.get('${obj.url}', async (req, res) => {
|
|
640
|
+
res.render(await require('.${obj.pathname}'), req, res)
|
|
652
641
|
})
|
|
653
|
-
//@desc ${obj.
|
|
642
|
+
//@desc ${obj.pathname}
|
|
654
643
|
` + '\n'
|
|
655
644
|
|
|
656
645
|
|
|
657
646
|
|
|
658
|
-
let before =
|
|
647
|
+
let before = fs.existsSync(process.cwd() + "/dist/app.js") ? await reader(process.cwd() + "/dist/app.js") : ''
|
|
659
648
|
|
|
660
649
|
let newfile = before + '\n' + js
|
|
661
|
-
if (!before.includes(`//@desc ${obj.
|
|
650
|
+
if (!before.includes(`//@desc ${obj.pathname}`)) {
|
|
662
651
|
await writer(process.cwd() + "/dist/app.js", newfile);
|
|
663
652
|
}
|
|
664
653
|
|
|
665
654
|
}
|
|
666
655
|
|
|
667
|
-
|
|
668
|
-
const scannedSourceFiles = await
|
|
656
|
+
|
|
657
|
+
const scannedSourceFiles = await glob("**/**.{jsx,js}", {
|
|
658
|
+
ignore: ["node_modules/**/*", "dist/**/*"],
|
|
659
|
+
cwd: process.cwd() + '/src/',
|
|
660
|
+
absolute: true,
|
|
661
|
+
});
|
|
669
662
|
scannedSourceFiles.forEach(async (file) => {
|
|
670
663
|
|
|
671
664
|
file = file.split(process.cwd() + '/src/')[1]
|
|
@@ -678,57 +671,43 @@ async function Build() {
|
|
|
678
671
|
await writer(process.cwd() + "/dist/src/" + file, data);
|
|
679
672
|
})
|
|
680
673
|
|
|
681
|
-
const scannedPublicFiles =
|
|
674
|
+
const scannedPublicFiles = await glob("**/**.{css,js,html}", {
|
|
675
|
+
ignore: ["node_modules/**/*", "dist/**/*"],
|
|
676
|
+
cwd: process.cwd() + '/public/',
|
|
677
|
+
absolute: true,
|
|
678
|
+
});
|
|
682
679
|
scannedPublicFiles.forEach(async (file) => {
|
|
683
680
|
file = file.split(process.cwd() + '/public/')[1]
|
|
684
681
|
let data = await reader(process.cwd() + "/public/" + file)
|
|
685
682
|
bundleSize += fs.statSync(process.cwd() + "/public/" + file).size;
|
|
686
683
|
await writer(process.cwd() + "/dist/public/" + file, data);
|
|
687
|
-
})
|
|
688
|
-
const scannedFiles = await
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
684
|
+
})
|
|
685
|
+
const scannedFiles = await glob("**/**.{css,js,html}", {
|
|
686
|
+
ignore: ["node_modules/**/*", "dist/**/*"],
|
|
687
|
+
cwd: process.cwd() + "/runtime/",
|
|
688
|
+
absolute: true,
|
|
689
|
+
})
|
|
692
690
|
|
|
693
691
|
if (!fs.existsSync(process.cwd() + "/dist/index.html")) {
|
|
694
692
|
scannedFiles.forEach(async (file) => {
|
|
693
|
+
file = file.split(process.cwd() + '/runtime/')[1]
|
|
695
694
|
|
|
696
695
|
if (file === "app.js") {
|
|
697
696
|
return
|
|
698
697
|
}
|
|
699
|
-
bundleSize += fs.statSync(process.cwd() +
|
|
700
|
-
let data = await reader(process.cwd() +
|
|
698
|
+
bundleSize += fs.statSync(process.cwd() + "/runtime/" + file).size;
|
|
699
|
+
let data = await reader(process.cwd() + "/runtime/" + file)
|
|
701
700
|
await writer(process.cwd() + "/dist/" + file, data);
|
|
702
701
|
});
|
|
703
|
-
|
|
704
|
-
bundleSize += fs.statSync(
|
|
705
|
-
process.cwd() + '/node_modules/vaderjs/' + "/runtime/" + file
|
|
706
|
-
).size;
|
|
707
|
-
let data = await reader(process.cwd() + '/node_modules/vaderjs/' + "/runtime/" + file);
|
|
708
|
-
await writer(process.cwd() + "/dist/public/vader/" + file, data);
|
|
709
|
-
});
|
|
702
|
+
|
|
710
703
|
}
|
|
711
704
|
|
|
712
|
-
|
|
713
|
-
if (!fs.existsSync(process.cwd() + "/dist/index.html")) {
|
|
714
|
-
scannedFiles.forEach(async (file) => {
|
|
715
|
-
|
|
716
|
-
bundleSize += fs.statSync(process.cwd() + '/node_modules/vaderjs/' + "/runtime/static/" + file).size;
|
|
717
|
-
let data = await reader(process.cwd() + '/node_modules/vaderjs/' + "/runtime/static/" + file);
|
|
718
|
-
await writer(process.cwd() + "/dist/" + file, data);
|
|
719
|
-
});
|
|
720
|
-
scannedVaderFiles.forEach(async (file) => {
|
|
721
|
-
bundleSize += fs.statSync(
|
|
722
|
-
process.cwd() + "/runtime/" + file
|
|
723
|
-
).size;
|
|
724
|
-
let data = await reader(process.cwd() + "/runtime/" + file);
|
|
725
|
-
await writer(process.cwd() + '/node_modules/vaderjs/' + "/dist/public/vader/" + file, data);
|
|
726
|
-
});
|
|
727
|
-
}
|
|
705
|
+
|
|
728
706
|
console.log(`Compilation completed`)
|
|
729
707
|
globalThis.isBuilding = false
|
|
730
708
|
}
|
|
731
709
|
import { watch } from "fs";
|
|
710
|
+
import { url } from "inspector";
|
|
732
711
|
|
|
733
712
|
switch (true) {
|
|
734
713
|
case process.argv.includes('--watch'):
|
|
@@ -737,19 +716,20 @@ switch (true) {
|
|
|
737
716
|
Vader.js v1.3.3
|
|
738
717
|
`)
|
|
739
718
|
Build()
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
719
|
+
|
|
720
|
+
const watcher = watch(
|
|
721
|
+
process.cwd() + '/pages',
|
|
722
|
+
{ recursive: true },
|
|
723
|
+
(event, filename) => {
|
|
724
|
+
if (event == 'change'
|
|
725
|
+
&& !globalThis.isBuilding
|
|
726
|
+
) {
|
|
727
|
+
Build()
|
|
728
|
+
}
|
|
729
|
+
},
|
|
730
|
+
);
|
|
731
|
+
watcher.on('error', (err) => console.log(err))
|
|
732
|
+
|
|
753
733
|
break;
|
|
754
734
|
case process.argv.includes('--build'):
|
|
755
735
|
|