vaderjs 1.3.2 → 1.3.3-5b5a772ebe58
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 +243 -0
- package/client/index.js +705 -0
- package/package.json +26 -20
- package/runtime/index.html +20 -0
- package/runtime/router.js +1 -0
- package/runtime/vader.js +1 -0
- package/vader.js +1338 -1235
- package/.vscode/settings.json +0 -5
- package/.vscode/vaderjs.autosense.json +0 -5
- package/index.js +0 -12
- package/jsconfig.json +0 -17
- package/readme.md +0 -262
- package/tsconfig.json +0 -18
- package/vader-min.js +0 -1
- package/vaderRouter.js +0 -231
- package/worker-min.js +0 -1
- package/worker.js +0 -226
package/vader.js
CHANGED
|
@@ -1,1335 +1,1438 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
header.includes(">")
|
|
17
|
-
) {
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
let level = header.split("#").length;
|
|
21
|
-
content = content.replace(
|
|
22
|
-
header,
|
|
23
|
-
`<h${level} class="markdown_heading">${header.replace(
|
|
24
|
-
/#/g,
|
|
25
|
-
""
|
|
26
|
-
)}</h${level}>`
|
|
27
|
-
);
|
|
28
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import { glob, globSync, globStream, globStreamSync, Glob, } from 'glob'
|
|
4
|
+
import puppeteer from 'puppeteer';
|
|
5
|
+
import http from 'http'
|
|
6
|
+
import { WebSocketServer } from 'ws'
|
|
7
|
+
import { watch } from "fs";
|
|
8
|
+
import path from 'path'
|
|
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;
|
|
29
16
|
}
|
|
17
|
+
if (globalThis.isWriting !== file) {
|
|
18
|
+
return
|
|
19
|
+
}
|
|
20
|
+
await fs.writeFileSync(file, data);
|
|
30
21
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
content = content.replace(/\*(.*?)\*/g, (match, text) => {
|
|
35
|
-
return `<i class="markdown_italic">${text}</i>`;
|
|
36
|
-
});
|
|
37
|
-
content = content.replace(/`(.*?)`/g, (match, text) => {
|
|
38
|
-
return `<code>${text}</code>`;
|
|
39
|
-
});
|
|
40
|
-
content = content.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, text, url) => {
|
|
41
|
-
return `<a class="markdown_link" href="${url}">${text}</a>`;
|
|
42
|
-
});
|
|
43
|
-
content = content.replace(/!\[([^\]]+)\]\(([^)]+)\)/g, (match, alt, src) => {
|
|
44
|
-
return `<img class="markdown_image" src="${src}" alt="${alt}" />`;
|
|
45
|
-
});
|
|
46
|
-
content = content
|
|
47
|
-
.split("\n")
|
|
48
|
-
.map((line, index, arr) => {
|
|
49
|
-
if (line.match(/^\s*-\s+(.*?)$/gm)) {
|
|
50
|
-
if (index === 0 || !arr[index - 1].match(/^\s*-\s+(.*?)$/gm)) {
|
|
51
|
-
return `<ul class="markdown_unordered" style="list-style-type:disc;list-style:inside"><li>${line.replace(
|
|
52
|
-
/^\s*-\s+(.*?)$/gm,
|
|
53
|
-
"$1"
|
|
54
|
-
)}</li>`;
|
|
55
|
-
} else if (
|
|
56
|
-
index === arr.length - 1 ||
|
|
57
|
-
!arr[index + 1].match(/^\s*-\s+(.*?)$/gm)
|
|
58
|
-
) {
|
|
59
|
-
return `<li>${line.replace(/^\s*-\s+(.*?)$/gm, "$1")}</li></ul>`;
|
|
60
|
-
} else {
|
|
61
|
-
return `<li>${line.replace(/^\s*-\s+(.*?)$/gm, "$1")}</li>`;
|
|
62
|
-
}
|
|
63
|
-
} else {
|
|
64
|
-
return line;
|
|
65
|
-
}
|
|
66
|
-
})
|
|
67
|
-
.join("\n");
|
|
68
|
-
|
|
69
|
-
content = content
|
|
70
|
-
.split("\n")
|
|
71
|
-
.map((line, index, arr) => {
|
|
72
|
-
if (line.match(/^\s*\d+\.\s+(.*?)$/gm)) {
|
|
73
|
-
if (index === 0 || !arr[index - 1].match(/^\s*\d+\.\s+(.*?)$/gm)) {
|
|
74
|
-
return `<ol class="markdown_ordered" style="list-style-type:decimal;"><li>${line.replace(
|
|
75
|
-
/^\s*\d+\.\s+(.*?)$/gm,
|
|
76
|
-
"$1"
|
|
77
|
-
)}</li>`;
|
|
78
|
-
} else if (
|
|
79
|
-
index === arr.length - 1 ||
|
|
80
|
-
!arr[index + 1].match(/^\s*\d+\.\s+(.*?)$/gm)
|
|
81
|
-
) {
|
|
82
|
-
return `<li>${line.replace(/^\s*\d+\.\s+(.*?)$/gm, "$1")}</li></ol>`;
|
|
83
|
-
} else {
|
|
84
|
-
return `<li>${line.replace(/^\s*\d+\.\s+(.*?)$/gm, "$1")}</li>`;
|
|
85
|
-
}
|
|
86
|
-
} else {
|
|
87
|
-
return line;
|
|
88
|
-
}
|
|
89
|
-
})
|
|
90
|
-
.join("\n");
|
|
22
|
+
globalThis.isWriting = null
|
|
23
|
+
return { _written: true };
|
|
24
|
+
};
|
|
91
25
|
|
|
92
|
-
|
|
26
|
+
let start = Date.now()
|
|
27
|
+
let bundleSize = 0;
|
|
28
|
+
let errorCodes = {
|
|
29
|
+
"SyntaxError: Unexpected token '<'": "You forgot to enclose tags in a fragment <></>",
|
|
93
30
|
}
|
|
94
|
-
|
|
95
31
|
/**
|
|
96
|
-
*
|
|
97
|
-
* @description Allows you to get reference to DOM element
|
|
98
|
-
* @param {String} ref
|
|
99
|
-
* @returns {void | Object} {current, update}
|
|
32
|
+
* define directories
|
|
100
33
|
*/
|
|
101
34
|
|
|
102
|
-
export const useRef = (ref) => {
|
|
103
|
-
const element = document.querySelector(`[ref="${ref}"]`);
|
|
104
|
-
const getElement = () => element;
|
|
105
35
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
36
|
+
if (!fs.existsSync(process.cwd() + '/dist')) {
|
|
37
|
+
fs.mkdirSync(process.cwd() + '/dist')
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if (typeof process.env.isCloudflare !== "undefined" || !fs.existsSync(process.cwd() + '/dist/index.html')) {
|
|
44
|
+
let htmlFile = fs.readFileSync(process.cwd() + "/node_modules/vaderjs/runtime/index.html", 'utf8')
|
|
45
|
+
fs.writeFileSync(process.cwd() + "/dist/index.html", htmlFile)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
109
49
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
50
|
+
function Compiler(func, file) {
|
|
51
|
+
let string = func;
|
|
52
|
+
// Remove block comments
|
|
53
|
+
|
|
54
|
+
let returns = []
|
|
55
|
+
let comments = string.match(/\{\s*\/\*.*\*\/\s*}/gs)?.map((comment) => comment.trim());
|
|
56
|
+
|
|
57
|
+
let savedfuncnames = [];
|
|
58
|
+
let functions = string.match(
|
|
59
|
+
/(?:const|let)\s*([a-zA-Z0-9_-]+)\s*=\s*function\s*\(([^)]*)\)|function\s*([a-zA-Z0-9_-]+)\s*\(([^)]*)\)/gs
|
|
60
|
+
)
|
|
61
|
+
?.map((match) => match.trim());
|
|
62
|
+
|
|
63
|
+
let functionNames = [];
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
functions && functions.forEach((func) => {
|
|
67
|
+
if (
|
|
68
|
+
!func.match(
|
|
69
|
+
/(?:const|let)\s*([a-zA-Z0-9_-]+)\s*=\s*function\s*\(([^)]*)\)|function\s*([a-zA-Z0-9_-]+)\s*\(([^)]*)\)/gs
|
|
70
|
+
)
|
|
71
|
+
) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
let name = func.split(" ")[1].split("(")[0].trim();
|
|
76
|
+
|
|
77
|
+
let lines = string.match(/return\s*\<>.*\<\/>/gs);
|
|
78
|
+
|
|
79
|
+
if (lines) {
|
|
80
|
+
for (let i = 0; i < lines.length; i++) {
|
|
81
|
+
let line = lines[i];
|
|
82
|
+
|
|
83
|
+
if (!functionNames.includes(name)) {
|
|
84
|
+
functionNames.push(name);
|
|
85
|
+
}
|
|
116
86
|
}
|
|
117
87
|
}
|
|
118
|
-
};
|
|
88
|
+
});
|
|
119
89
|
|
|
120
|
-
|
|
121
|
-
current: getElement(),
|
|
122
|
-
update
|
|
123
|
-
};
|
|
124
|
-
};
|
|
90
|
+
// get all Obj({}) and parse to JSON.stringify
|
|
125
91
|
|
|
126
|
-
let
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
*
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
92
|
+
let objects = string.match(/Obj\({.*}\)/gs);
|
|
93
|
+
|
|
94
|
+
objects && objects.forEach((obj) => {
|
|
95
|
+
let key = obj.split("Obj")[1].split("(")[1].split(")")[0].trim();
|
|
96
|
+
let newobj = obj.replaceAll(`Obj(${key})`, `${key}`);
|
|
97
|
+
// let newobj = obj.replaceAll(`Obj(${key})`, `JSON.parse('${key}')`)
|
|
98
|
+
string = string.replaceAll(obj, `this.handleObject('${newobj}')`);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
let childs = [];
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
function extractAttributes(code) {
|
|
107
|
+
// Match elements with opening tags
|
|
108
|
+
const elementRegex = /<([a-zA-Z0-9_-]+)([^>]*)>/gs;
|
|
109
|
+
|
|
110
|
+
// Match attributes in an opening tag, including those with ={}
|
|
111
|
+
// Match attributes in an opening tag, including those with ={...}
|
|
112
|
+
const attributeRegex =
|
|
113
|
+
/\s*([a-zA-Z0-9_-]+)(\s*=\s*("([^"\\]*(\\.[^"\\]*)*)"|'([^'\\]*(\\.[^'\\]*)*)'|\{(?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*\}|(?:\([^)]*\)|\{[^}]*\}|()=>\s*(?:\{[^}]*\})?)|\[[^\]]*\]))?/gs;
|
|
114
|
+
|
|
115
|
+
// only return elements with attribute {()=>{}} or if it also has parameters ex: onclick={(event)=>{console.log(event)}} also get muti line functions
|
|
116
|
+
const functionAttributeRegex = /\s*([a-zA-Z0-9_-]+)(\s*=\s*{((?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\})*)*\})*)*)})/gs;
|
|
117
|
+
|
|
118
|
+
let attributesList = [];
|
|
119
|
+
|
|
120
|
+
// handle functions
|
|
121
|
+
let functionAttributes = [];
|
|
122
|
+
let functionMatch;
|
|
123
|
+
while ((functionMatch = functionAttributeRegex.exec(code)) !== null) {
|
|
124
|
+
let [, attributeName, attributeValue] = functionMatch;
|
|
125
|
+
|
|
126
|
+
let attribute = {};
|
|
127
|
+
|
|
128
|
+
if (attributeValue && attributeValue.includes("=>") || attributeValue && attributeValue.includes("function")) {
|
|
129
|
+
let functionparams = [];
|
|
130
|
+
// ref with no numbers
|
|
131
|
+
let ref = Math.random().toString(36).substring(2).split('').filter((e) => !Number(e)).join('')
|
|
132
|
+
let old = `${attributeName}${attributeValue}`
|
|
133
|
+
functionNames.forEach((name) => {
|
|
134
|
+
string.split("\n").forEach((line) => {
|
|
135
|
+
if (line.includes(name) && line.includes("function")) {
|
|
136
|
+
line = line.trim();
|
|
137
|
+
line = line.replace(/\s+/g, " ");
|
|
138
|
+
|
|
139
|
+
let ps = line.split("(").slice(1).join("(").split(")")[0].trim();
|
|
140
|
+
|
|
141
|
+
// remove comments
|
|
142
|
+
ps = ps.match(/\/\*.*\*\//gs)
|
|
143
|
+
? ps.replace(ps.match(/\/\*.*\*\//gs)[0], "")
|
|
144
|
+
: ps;
|
|
145
|
+
functionparams.push({ ref: ref, name: name, params: ps });
|
|
146
|
+
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
let elementMatch = string.match(/<([a-zA-Z0-9_-]+)([^>]*)>/gs);
|
|
151
|
+
let isJSXComponent = false;
|
|
152
|
+
elementMatch.forEach((element) => {
|
|
153
|
+
element = element.trim().replace(/\s+/g, " ");
|
|
154
|
+
if (element.includes(attributeName)) {
|
|
155
|
+
let elementTag = element
|
|
156
|
+
.split("<")[1]
|
|
157
|
+
.split(">")[0]
|
|
158
|
+
.split(" ")[0];
|
|
159
|
+
isJSXComponent = elementTag.match(/^[A-Z]/) ? true : false;
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
// add ; after newlines
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
let newvalue = attributeValue.includes('=>') ? attributeValue.split("=>").slice(1).join("=>").trim() : attributeValue.split("function").slice(1).join("function").trim()
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
newvalue = newvalue.trim();
|
|
170
|
+
|
|
171
|
+
//remove starting {
|
|
172
|
+
newvalue = newvalue.replace("{", "")
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
let params = attributeValue
|
|
177
|
+
.split("=>")[0]
|
|
178
|
+
.split("(")[1]
|
|
179
|
+
.split(")")[0]
|
|
180
|
+
.trim();
|
|
181
|
+
|
|
182
|
+
// remove comments
|
|
183
|
+
params = params.match(/\/\*.*\*\//gs)
|
|
184
|
+
? params.replace(params.match(/\/\*.*\*\//gs)[0], "")
|
|
185
|
+
: params;
|
|
186
|
+
// split first {}
|
|
187
|
+
newvalue = newvalue.trim();
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
newvalue = newvalue.replace(/}\s*$/, '');
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
newvalue = newvalue.trim();
|
|
196
|
+
|
|
197
|
+
// remmove trailing }
|
|
198
|
+
|
|
199
|
+
newvalue = newvalue.trim();
|
|
200
|
+
newvalue = newvalue.replace(/}\s*$/, '');
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
functionparams.length > 0 ? params = params + ',' + functionparams.map((e) => e.name).join(',') : null
|
|
205
|
+
|
|
206
|
+
newvalue = newvalue.replaceAll(',,', ',')
|
|
207
|
+
let paramnames = params ? params.split(',').map((e) => e.trim()) : null
|
|
208
|
+
paramnames = paramnames ? paramnames.filter((e) => e.length > 0) : null
|
|
209
|
+
// remove comments
|
|
210
|
+
paramnames = paramnames ? paramnames.map((e) => e.match(/\/\*.*\*\//gs) ? e.replace(e.match(/\/\*.*\*\//gs)[0], "") : e) : null
|
|
211
|
+
|
|
212
|
+
// add ; after newlines
|
|
213
|
+
newvalue = newvalue.replaceAll(/\n/g, ";\n")
|
|
214
|
+
|
|
215
|
+
let bind = isJSXComponent ? `${attributeName}='function(${params}){${newvalue}}'` : `${attributeName}="\$\{this.bind(function(){${newvalue}}.bind(this), ${isJSXComponent}, "${ref}", "${paramnames ? paramnames.map((e, index) => {
|
|
216
|
+
if (e.length < 1) return ''
|
|
217
|
+
if (e.length > 0) {
|
|
218
|
+
index == 0 ? e : ',' + e
|
|
219
|
+
}
|
|
220
|
+
return e
|
|
221
|
+
}) : ''}" ${params ? params.split(',').map((e) => e.trim()).filter(Boolean).map((e) => `,${e}`).join('') : ''})}"`
|
|
222
|
+
|
|
223
|
+
string = string.replace(old, bind);
|
|
170
224
|
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
let match;
|
|
228
|
+
while ((match = elementRegex.exec(code)) !== null) {
|
|
229
|
+
let [, element, attributes] = match;
|
|
230
|
+
|
|
231
|
+
let attributesMatch;
|
|
232
|
+
let elementAttributes = {};
|
|
233
|
+
|
|
234
|
+
while ((attributesMatch = attributeRegex.exec(attributes)) !== null) {
|
|
235
|
+
let [, attributeName, attributeValue] = attributesMatch;
|
|
236
|
+
|
|
237
|
+
elementAttributes[attributeName] = attributeValue || null;
|
|
184
238
|
}
|
|
185
|
-
);
|
|
186
|
-
/**
|
|
187
|
-
* @property {Array} snapshots
|
|
188
|
-
* @private
|
|
189
|
-
*/
|
|
190
|
-
this.snapshots = [];
|
|
191
|
-
/**
|
|
192
|
-
* @property {Object} dom
|
|
193
|
-
* @description Allows you to get reference to DOM element
|
|
194
|
-
* @returns {void | HTMLElement}
|
|
195
|
-
*
|
|
196
|
-
*/
|
|
197
|
-
this.dom = [];
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* @property {Boolean} cfr
|
|
201
|
-
* @description Allows you to compile html code on the fly - client fly rendering
|
|
202
|
-
*
|
|
203
|
-
*/
|
|
204
|
-
this.cfr = false;
|
|
205
|
-
/**
|
|
206
|
-
* @property {Boolean} worker
|
|
207
|
-
* @description Allows you to use a web worker to compile html code on the fly - client fly rendering
|
|
208
|
-
|
|
209
|
-
*/
|
|
210
|
-
}
|
|
211
239
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
* @description Allows you to create an adapter - this is used to create custom logic
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*/
|
|
218
|
-
adapter(options) {
|
|
219
|
-
// allow you to override the compoent logic
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
223
|
-
init() {
|
|
224
|
-
this.registerComponent();
|
|
225
|
-
}
|
|
240
|
+
attributesList.push({ element, attributes: elementAttributes });
|
|
241
|
+
}
|
|
226
242
|
|
|
227
|
-
|
|
228
|
-
components.push(this);
|
|
243
|
+
return attributesList;
|
|
229
244
|
}
|
|
230
245
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
* @returns {void}
|
|
237
|
-
* @example
|
|
238
|
-
* this.setState('count', 1)
|
|
239
|
-
* */
|
|
240
|
-
setState(key, value) {
|
|
241
|
-
this.states[key] = value;
|
|
242
|
-
this.updateComponent();
|
|
246
|
+
function extractOuterReturn(code) {
|
|
247
|
+
// match return [...]
|
|
248
|
+
let returns = code.match(/return\s*\<>.*\<\/>|return\s*\(.*\)/gs);
|
|
249
|
+
|
|
250
|
+
return returns || [];
|
|
243
251
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
document.querySelector(`[data-component="${this.name}"]`).remove();
|
|
255
|
-
if (!document.querySelector(`[data-component="${this.name}"]`)) {
|
|
256
|
-
components = components.filter(
|
|
257
|
-
(component) => component.name !== this.name
|
|
258
|
-
);
|
|
252
|
+
// throw error if return is not wrapped in <></> or
|
|
253
|
+
if (string.match(/return\s*\<>|return\s*\(.*\)/gs) && !string.match(/return\s*\<>.*\<\/>|return\s*\(.*\)/gs)
|
|
254
|
+
|| string.match(/return\s*\<[a-zA-Z0-9_-]+.*>/gs)
|
|
255
|
+
) {
|
|
256
|
+
|
|
257
|
+
try {
|
|
258
|
+
throw new SyntaxError("You forgot to enclose jsx in a fragment return <> jsx html </> or return (<> jsx html </>) at line " + string.split(/return\s*\<[a-zA-Z0-9_-]+.*>/gs)[0].split('\n').length + ' in file ' + file)
|
|
259
|
+
} catch (error) {
|
|
260
|
+
console.error(error)
|
|
261
|
+
process.exit(1)
|
|
259
262
|
}
|
|
260
263
|
}
|
|
261
264
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
this.$_signal_subscribers[i]
|
|
319
|
-
)
|
|
320
|
-
) {
|
|
321
|
-
break;
|
|
322
|
-
} else {
|
|
323
|
-
this.$_signal_subscribers[i].function(state);
|
|
324
|
-
this.$_signal_subscribers_ran.push(this.$_signal_subscribers[i]);
|
|
325
|
-
return;
|
|
326
|
-
}
|
|
265
|
+
let outerReturn = extractOuterReturn(string);
|
|
266
|
+
let contents = "";
|
|
267
|
+
let updatedContents = "";
|
|
268
|
+
outerReturn.forEach((returnStatement) => {
|
|
269
|
+
|
|
270
|
+
let lines = returnStatement.split("\n");
|
|
271
|
+
|
|
272
|
+
for (let i = 0; i < lines.length; i++) {
|
|
273
|
+
let line = lines[i];
|
|
274
|
+
if (line.match(/return\s*\<>|return\s*\(/gs)) {
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
contents += line + "\n";
|
|
278
|
+
}
|
|
279
|
+
let usesBraces = returnStatement.match(/return\s*\(/gs) ? true : false;
|
|
280
|
+
|
|
281
|
+
let attributes = extractAttributes(contents);
|
|
282
|
+
// Remove trailing ']' or trailing )
|
|
283
|
+
contents = contents.trim().replace(/\]$/, "")
|
|
284
|
+
contents = contents.replace(/\)$/, "");
|
|
285
|
+
usesBraces ? !contents.includes('<>') ? contents = `<>${contents}</>` : null : null
|
|
286
|
+
updatedContents = contents;
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
let newAttributes = [];
|
|
290
|
+
let oldAttributes = [];
|
|
291
|
+
attributes.forEach((attribute) => {
|
|
292
|
+
const { element, attributes } = attribute;
|
|
293
|
+
if (Object.keys(attributes).length === 0) return;
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
newAttributes.push(attribute);
|
|
297
|
+
for (let key in attributes) {
|
|
298
|
+
|
|
299
|
+
let value = attributes[key];
|
|
300
|
+
let oldvalue = value;
|
|
301
|
+
if (value && !value.new) {
|
|
302
|
+
if (value && value.includes("={")) {
|
|
303
|
+
value = value.replace("=", "");
|
|
304
|
+
value == "undefined" ? (value = '"') : (value = value);
|
|
305
|
+
|
|
306
|
+
key == 'style'
|
|
307
|
+
&& value.includes("{{")
|
|
308
|
+
? value = `{this.parseStyle({${value.split('{{')[1].split('}}')[0]}})}` : null
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
value = `="\$${value}",`;
|
|
313
|
+
string = string.replace(oldvalue, value);
|
|
314
|
+
|
|
315
|
+
} else if (value && value.includes("={`")) {
|
|
316
|
+
value = value.replace("=", "");
|
|
317
|
+
|
|
318
|
+
value = `"\$${value}",`;
|
|
319
|
+
string = string.replace(oldvalue, value);
|
|
320
|
+
|
|
327
321
|
}
|
|
322
|
+
} else if (value && value.new) {
|
|
323
|
+
string = string.replace(oldvalue, value.new);
|
|
328
324
|
}
|
|
329
|
-
} else {
|
|
330
|
-
this.$_signal_dispatch_event.detail.hasUpdated = true;
|
|
331
|
-
this.$_signal_dispatch_event.detail.state = state;
|
|
332
|
-
window.dispatchEvent(this.$_signal_dispatch_event);
|
|
333
325
|
}
|
|
334
326
|
});
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
if (comments) {
|
|
332
|
+
comments.forEach((comment) => {
|
|
333
|
+
let before = comment.trim();
|
|
334
|
+
|
|
335
|
+
comment = comment.replaceAll(/\s+/g, " ");
|
|
336
|
+
comment = comment.trim();
|
|
337
|
+
string = string.replace(before, comment);
|
|
338
|
+
let to_remove = comment.split("{")[1].split("}")[0].trim();
|
|
339
|
+
let beforeComment = comment;
|
|
340
|
+
comment = comment.replaceAll(`{ ${to_remove} }`, "");
|
|
341
|
+
|
|
342
|
+
string = string.replace(beforeComment, comment);
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
let lines = string.split("\n");
|
|
346
|
+
lines.forEach((line) => {
|
|
347
|
+
|
|
348
|
+
if (
|
|
349
|
+
line.includes("let") ||
|
|
350
|
+
line.includes("const") ||
|
|
351
|
+
line.includes("var")
|
|
352
|
+
) {
|
|
353
|
+
switch (true) {
|
|
354
|
+
case line.includes("useState") && !line.includes("import"):
|
|
355
|
+
let varType = line.split("[")[0]
|
|
356
|
+
let key = line.split("=")[0].split(",")[0].trim().split('[')[1];
|
|
357
|
+
|
|
358
|
+
let setKey = line.split("=")[0].trim().split(",")[1].trim().replace("]", "");
|
|
359
|
+
key = key.replace("[", "").replace(",", "");
|
|
360
|
+
let valuestate = line.split("=")[1].split("useState(")[1];
|
|
361
|
+
|
|
362
|
+
let regex = /useState\((.*)\)/gs;
|
|
363
|
+
valuestate = valuestate.match(regex) ? valuestate.match(regex)[0].split("useState(")[1].split(")")[0].trim() : valuestate
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
let newState = `${varType} [${key}, ${setKey}] = this.useState('${key}', ${valuestate}
|
|
367
|
+
|
|
368
|
+
`;
|
|
369
|
+
string = string.replace(line, newState);
|
|
370
|
+
break;
|
|
371
|
+
case line.includes("useRef") && !line.includes("import"):
|
|
372
|
+
line = line.trim();
|
|
373
|
+
let typeref = line.split(" ")[0]
|
|
374
|
+
|
|
375
|
+
let keyref = line.split(typeref)[1].split("=")[0].trim().replace("[", "").replace(",", "");
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
let valueref = line.split("=")[1].split("useRef(")[1];
|
|
379
|
+
|
|
380
|
+
let newStateref = `${typeref} ${keyref} = this.useRef('${keyref}', ${valueref}`;
|
|
381
|
+
string = string.replace(line, newStateref);
|
|
382
|
+
break;
|
|
383
|
+
case line.includes("useReducer") && !line.includes("import"):
|
|
384
|
+
line = line.trim();
|
|
385
|
+
line = line.replaceAll(/\s+/g, " ");
|
|
386
|
+
|
|
387
|
+
let varTypereducer = line.split(" ")[0];
|
|
388
|
+
let keyreducer = line
|
|
389
|
+
.split("=")[0]
|
|
390
|
+
.split(" ")[1]
|
|
391
|
+
.trim()
|
|
392
|
+
.replace("[", "")
|
|
393
|
+
.replace(",", "");
|
|
394
|
+
let setKeyreducer = line.split("=")[0].trim().split(",")[1].trim().replace("]", "");
|
|
395
|
+
|
|
396
|
+
let reducer = line.split("=")[1].split("useReducer(")[1];
|
|
397
|
+
|
|
398
|
+
let newStatereducer = `${varTypereducer} [${keyreducer}, ${setKeyreducer}] = this.useReducer('${keyreducer}', ${line.includes('=>') ? reducer + '=>{' : reducer}`;
|
|
399
|
+
|
|
400
|
+
string = string.replace(line, newStatereducer);
|
|
368
401
|
break;
|
|
369
|
-
} else {
|
|
370
|
-
this.$_signal_subscribers[i].function(state);
|
|
371
|
-
this.$_signal_subscribers_ran.push(this.$_signal_subscribers[i]);
|
|
372
|
-
}
|
|
373
402
|
}
|
|
374
|
-
};
|
|
375
|
-
this.$_signal_get = () => {
|
|
376
|
-
return state;
|
|
377
|
-
};
|
|
378
|
-
this.$_signal_call = () => {
|
|
379
|
-
hasCaller = true;
|
|
380
|
-
// @ts-ignore
|
|
381
|
-
this.$_signal_dispatch();
|
|
382
|
-
};
|
|
383
|
-
/**
|
|
384
|
-
* @function $_signal_set
|
|
385
|
-
* @description Allows you to set the value of a signal
|
|
386
|
-
* @param {*} detail
|
|
387
|
-
*/
|
|
388
|
-
this.$_signal_set = (detail) => {
|
|
389
|
-
|
|
390
|
-
setState(detail);
|
|
391
|
-
};
|
|
392
403
|
|
|
393
|
-
return {
|
|
394
|
-
/**
|
|
395
|
-
* @function subscribe
|
|
396
|
-
* @description Allows you to subscribe to a signal
|
|
397
|
-
* @param {*} fn
|
|
398
|
-
* @param {*} runonce
|
|
399
|
-
*/
|
|
400
|
-
subscribe: this.$_signal_subscribe,
|
|
401
|
-
/**
|
|
402
|
-
* @function cleanup
|
|
403
|
-
* @description Allows you to cleanup a signal
|
|
404
|
-
* @param {*} fn
|
|
405
|
-
* @returns {null}
|
|
406
|
-
*/
|
|
407
|
-
cleanup: this.$_signal_cleanup,
|
|
408
|
-
/**
|
|
409
|
-
* @function dispatch
|
|
410
|
-
* @description Allows you to dispatch a signal
|
|
411
|
-
* @returns {null}
|
|
412
|
-
*/
|
|
413
|
-
dispatch: this.$_signal_dispatch,
|
|
414
|
-
/**
|
|
415
|
-
* @function call
|
|
416
|
-
* @description Allows you to call a signal
|
|
417
|
-
* @returns {null}
|
|
418
|
-
*/
|
|
419
|
-
call: this.$_signal_call,
|
|
420
|
-
/**
|
|
421
|
-
* @function set
|
|
422
|
-
* @description Allows you to set the value of a signal
|
|
423
|
-
* @param {*} detail
|
|
424
|
-
* @returns {null}
|
|
425
|
-
*/
|
|
426
|
-
set: this.$_signal_set,
|
|
427
|
-
/**
|
|
428
|
-
* @function get
|
|
429
|
-
* @readonly
|
|
430
|
-
* @description Allows you to get the value of a signal
|
|
431
|
-
* @returns {any}
|
|
432
|
-
*/
|
|
433
|
-
get: this.$_signal_get
|
|
434
|
-
};
|
|
435
|
-
};
|
|
436
|
-
/**
|
|
437
|
-
* @method useAuth
|
|
438
|
-
* @description Allows you to create an auth object
|
|
439
|
-
* @param {Object} options
|
|
440
|
-
* @param {Array} options.rulesets
|
|
441
|
-
* @param {Object} options.user
|
|
442
|
-
* @returns {Object} {can, hasRole, canWithRole, assignRule, revokeRule, canAnyOf, canAllOf, canGroup}
|
|
443
|
-
* @example
|
|
444
|
-
* let auth = this.useAuth({
|
|
445
|
-
* rulesets: [
|
|
446
|
-
* {
|
|
447
|
-
* action: 'create',
|
|
448
|
-
* condition: (user) => {
|
|
449
|
-
* return user.role === 'admin'
|
|
450
|
-
* }
|
|
451
|
-
* }
|
|
452
|
-
* ],
|
|
453
|
-
* user: {
|
|
454
|
-
* role: 'admin'
|
|
455
|
-
* }
|
|
456
|
-
* })
|
|
457
|
-
* auth.can('create') // true
|
|
458
|
-
*/
|
|
459
|
-
useAuth(options) {
|
|
460
|
-
/**@type {Array}**/
|
|
461
|
-
let rules = options.rulesets;
|
|
462
|
-
if (!rules) {
|
|
463
|
-
throw new Error("No rulesets provided");
|
|
464
404
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
string = string.replaceAll(/\$\{\/\*.*\*\/\}/gs, "");
|
|
409
|
+
|
|
410
|
+
string = string.replaceAll('../src', './src')
|
|
411
|
+
|
|
412
|
+
function parseComponents(body, isChild) {
|
|
413
|
+
let componentRegex = /<([A-Z][A-Za-z0-9_-]+)([^>]*)>(.*?)<\/\1>|<([A-Z][A-Za-z0-9_-]+)([^]*?)\/>/gs;
|
|
414
|
+
|
|
415
|
+
let componentMatch = body.match(componentRegex);
|
|
416
|
+
let topComponent = "";
|
|
417
|
+
componentMatch?.forEach(async (component) => {
|
|
418
|
+
|
|
419
|
+
let [, element, attributes] = component;
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
!isChild ? (topComponent = component) : null;
|
|
423
|
+
let before = component;
|
|
424
|
+
|
|
425
|
+
let myChildrens = [];
|
|
426
|
+
|
|
427
|
+
let name = component.split("<")[1].split(">")[0].split(" ")[0].replace("/", "");
|
|
428
|
+
// some components will have props that have html inside of them we need to only get the props ex: <Header title={<h1>hello</h1>}></Header> -> title={<h1>hello</h1>} // also spread props ex: <Header {...props}></Header> -> {...props} or {...props, title: 'hello'} or {...props, color:{color: 'red'}}
|
|
429
|
+
// grab ...( spread props )
|
|
430
|
+
const dynamicAttributesRegex = /(\w+)(?:="([^"]*)")?(?:='([^']*)')?(?:=\{([^}]*)\})?(?:=\{(.*?)\})?(?:={([^}]*)})?(?:{([^}]*)})?|(?:{(?:[^{}]+|\{(?:[^{}]+|\{[^}]*\})*\})*\})|(\.{3}\{(?:[^{}]+|\{(?:[^{}]+|\{[^}]*\})*\})*\})/gs;
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
let props = component.match(dynamicAttributesRegex)
|
|
438
|
+
|
|
439
|
+
let filteredProps = [];
|
|
440
|
+
let isWithinComponent = false;
|
|
441
|
+
let componentName = name
|
|
442
|
+
|
|
443
|
+
for (let prop of props) {
|
|
444
|
+
|
|
445
|
+
if (prop === componentName) {
|
|
446
|
+
|
|
447
|
+
// If the component is encountered, start collecting props
|
|
448
|
+
isWithinComponent = true;
|
|
449
|
+
filteredProps.push(prop);
|
|
450
|
+
} else if (isWithinComponent && prop.includes('=')) {
|
|
451
|
+
|
|
452
|
+
if (prop.includes('${')) {
|
|
453
|
+
// if it has an object inside of it then we should just do soemting:object else we should do something: `${object}`
|
|
454
|
+
|
|
455
|
+
prop = prop.replace('="', ':').replace('}"', '}')
|
|
456
|
+
if (prop.includes('${')) {
|
|
457
|
+
prop = prop.replace('="', ':')
|
|
458
|
+
prop = prop.replace('${', '')
|
|
459
|
+
prop = prop.replace('}', '')
|
|
460
|
+
|
|
474
461
|
}
|
|
462
|
+
if (prop.includes('="${{')) {
|
|
463
|
+
prop = prop.replace('${{', '{')
|
|
464
|
+
prop = prop.replace('}}', '}')
|
|
465
|
+
prop = prop.replace('="', ':')
|
|
466
|
+
prop = prop.replace('}"', '}')
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
}
|
|
470
|
+
if (prop.startsWith('={')) {
|
|
471
|
+
prop = prop.replace('={', ':`${')
|
|
472
|
+
prop.replace('} ', '}`')
|
|
475
473
|
}
|
|
476
|
-
});
|
|
477
|
-
return can;
|
|
478
|
-
},
|
|
479
|
-
/**
|
|
480
|
-
* @function hasRole
|
|
481
|
-
* @description Allows you to check if user has a role
|
|
482
|
-
* @param {String} role
|
|
483
|
-
* @returns {Boolean}
|
|
484
|
-
*/
|
|
485
|
-
hasRole: (role) => {
|
|
486
|
-
return user.role && user.role.includes(role);
|
|
487
|
-
},
|
|
488
|
-
/**
|
|
489
|
-
* @function canWithRole
|
|
490
|
-
* @param {String} action
|
|
491
|
-
* @param {String} role
|
|
492
|
-
* @returns
|
|
493
|
-
*/
|
|
494
|
-
canWithRole: (action, role) => {
|
|
495
|
-
return auth.can(action) && auth.hasRole(role);
|
|
496
|
-
},
|
|
497
|
-
assignRule: (rule) => {
|
|
498
|
-
if (
|
|
499
|
-
!rules.some((existingRule) => existingRule.action === rule.action)
|
|
500
|
-
) {
|
|
501
|
-
rules.push(rule);
|
|
502
|
-
}
|
|
503
|
-
},
|
|
504
|
-
revokeRule: (action) => {
|
|
505
|
-
rules = rules.filter((rule) => rule.action !== action);
|
|
506
|
-
},
|
|
507
|
-
canAnyOf: (actions) => {
|
|
508
|
-
return actions.some((action) => auth.can(action));
|
|
509
|
-
},
|
|
510
|
-
canAllOf: (actions) => {
|
|
511
|
-
return actions.every((action) => auth.can(action));
|
|
512
|
-
},
|
|
513
|
-
canGroup: (actions, logicalOperator = "any") => {
|
|
514
|
-
return logicalOperator === "any"
|
|
515
|
-
? auth.canAnyOf(actions)
|
|
516
|
-
: auth.canAllOf(actions);
|
|
517
|
-
}
|
|
518
|
-
};
|
|
519
|
-
return auth;
|
|
520
|
-
}
|
|
521
|
-
/**
|
|
522
|
-
* @method useReducer
|
|
523
|
-
* @description Allows you to create a reducer
|
|
524
|
-
* @param {*} key
|
|
525
|
-
* @param {*} reducer
|
|
526
|
-
* @param {*} initialState
|
|
527
|
-
* @url - useReducer works similarly to - https://react.dev/reference/react/useReducer
|
|
528
|
-
* @returns {Array} [state, dispatch]
|
|
529
|
-
* @example
|
|
530
|
-
* let [count, setCount] = this.useReducer('count', (state, action) => {
|
|
531
|
-
* switch (action.type) {
|
|
532
|
-
* case 'increment':
|
|
533
|
-
* return state + 1
|
|
534
|
-
* case 'decrement':
|
|
535
|
-
* return state - 1
|
|
536
|
-
* default:
|
|
537
|
-
* throw new Error()
|
|
538
|
-
* }
|
|
539
|
-
* }, 0)
|
|
540
|
-
* setCount({type: 'increment'})
|
|
541
|
-
*/
|
|
542
|
-
useReducer(key, reducer, initialState) {
|
|
543
|
-
if (!this.states[key]) {
|
|
544
|
-
this.states[key] = initialState;
|
|
545
|
-
}
|
|
546
|
-
return [
|
|
547
|
-
this.states[key],
|
|
548
|
-
/**
|
|
549
|
-
* @function dispatch
|
|
550
|
-
* @description Allows you to dispatch a reducer
|
|
551
|
-
* @param {*} action
|
|
552
|
-
* @returns {void}
|
|
553
|
-
*/
|
|
554
|
-
(action) => {
|
|
555
|
-
this.states[key] = reducer(this.states[key], action);
|
|
556
|
-
this.updateComponent();
|
|
557
|
-
}
|
|
558
|
-
];
|
|
559
|
-
}
|
|
560
474
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
if (!this.executedEffects[effect]) {
|
|
565
|
-
effect();
|
|
566
|
-
this.executedEffects[effect] = true;
|
|
567
|
-
}
|
|
568
|
-
});
|
|
569
|
-
});
|
|
570
|
-
}
|
|
475
|
+
if (prop.includes('function')) {
|
|
476
|
+
// parse 'function' to function
|
|
477
|
+
prop = prop.replace("'", '')
|
|
571
478
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
* @description Allows you to create a store
|
|
575
|
-
* @param {String} storeName
|
|
576
|
-
* @param {*} initialState
|
|
577
|
-
* @returns {Object} {getField, setField, subscribe, clear}
|
|
578
|
-
* @example
|
|
579
|
-
* let store = this.useSyncStore('store', {count: 0})
|
|
580
|
-
* store.setField('count', 1)
|
|
581
|
-
* store.getField('count') // 1
|
|
582
|
-
*
|
|
583
|
-
*/
|
|
584
|
-
useSyncStore(storeName, initialState) {
|
|
585
|
-
let [storedState, setStoredState] = this.useState(
|
|
586
|
-
storeName,
|
|
587
|
-
initialState ||
|
|
588
|
-
// @ts-ignore
|
|
589
|
-
localStorage.getItem(`$_vader_${storeName}`, (s) => {
|
|
590
|
-
localStorage.setItem(`$_vader_${storeName}`, JSON.stringify(s));
|
|
591
|
-
this.$_useStore_subscribers.forEach((subscriber) => {
|
|
592
|
-
subscriber(s);
|
|
593
|
-
});
|
|
594
|
-
}) ||
|
|
595
|
-
{}
|
|
596
|
-
);
|
|
479
|
+
if (prop.endsWith("}'")) {
|
|
480
|
+
prop = prop.replace("}'", '}')
|
|
597
481
|
|
|
598
|
-
|
|
599
|
-
return storedState[fieldName];
|
|
600
|
-
};
|
|
601
|
-
const setField = (fieldName, value) => {
|
|
602
|
-
const newState = { ...storedState, [fieldName]: value };
|
|
603
|
-
setStoredState(newState);
|
|
604
|
-
};
|
|
605
|
-
const subscribe = (subscriber) => {
|
|
606
|
-
return this.$_useStore_subscribers.push(subscriber);
|
|
607
|
-
};
|
|
482
|
+
}
|
|
608
483
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
delete newState[fieldName];
|
|
612
|
-
setStoredState(newState);
|
|
613
|
-
};
|
|
614
|
-
return {
|
|
615
|
-
getField,
|
|
616
|
-
setField,
|
|
617
|
-
subscribe,
|
|
618
|
-
clear
|
|
619
|
-
};
|
|
620
|
-
}
|
|
621
|
-
/**
|
|
622
|
-
* @method useState
|
|
623
|
-
* @description Allows you to create a state
|
|
624
|
-
* @param {String} key
|
|
625
|
-
* @param {*} initialValue
|
|
626
|
-
* @param {*} callback
|
|
627
|
-
* @url - useState works similarly to - https://react.dev/reference/react/useState
|
|
628
|
-
* @returns {Array} [state, setState]
|
|
629
|
-
* @example
|
|
630
|
-
* let [count, setCount] = this.useState('count', 0, () => {
|
|
631
|
-
* console.log('count has been updated')
|
|
632
|
-
* })
|
|
633
|
-
*
|
|
634
|
-
* setCount(count + 1)
|
|
635
|
-
*/
|
|
636
|
-
useState(key, initialValue, callback = null) {
|
|
637
|
-
if (!this.states[key]) {
|
|
638
|
-
this.states[key] = initialValue;
|
|
639
|
-
}
|
|
484
|
+
prop = prop.replace('=function', ':function')
|
|
485
|
+
}
|
|
640
486
|
|
|
641
|
-
|
|
642
|
-
this.states[key],
|
|
643
|
-
/**
|
|
644
|
-
* @function setState
|
|
645
|
-
* @description Allows you to set state
|
|
646
|
-
* @param {*} value
|
|
647
|
-
* @returns {void}
|
|
648
|
-
*/
|
|
649
|
-
(value) => {
|
|
650
|
-
this.states[key] = value;
|
|
651
|
-
this.updateComponent();
|
|
652
|
-
// @ts-ignore
|
|
653
|
-
typeof callback === "function" ? callback() : null;
|
|
654
|
-
}
|
|
655
|
-
];
|
|
656
|
-
}
|
|
657
|
-
/**
|
|
658
|
-
* @method useRef
|
|
659
|
-
* @memberof Component
|
|
660
|
-
* @param {string} ref
|
|
661
|
-
* @description Allows you to get reference to DOM elements from the dom array
|
|
662
|
-
* @returns {Object} {current, update}
|
|
663
|
-
* @example
|
|
664
|
-
* let ref = this.useRef('ref')
|
|
665
|
-
* ref.current // returns the DOM element
|
|
666
|
-
|
|
667
|
-
*/
|
|
487
|
+
filteredProps.push(prop);
|
|
668
488
|
|
|
669
|
-
useRef(ref) {
|
|
670
|
-
// get ref from array
|
|
671
|
-
const element = this.dom[ref];
|
|
672
489
|
|
|
673
|
-
|
|
490
|
+
}
|
|
491
|
+
else if (isWithinComponent && prop.includes('...')) {
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
// Check if spread props are within curly braces
|
|
496
|
+
if (prop.startsWith('{') && prop.endsWith('}')) {
|
|
497
|
+
const spreadObject = prop
|
|
498
|
+
const hasOtherObjects = spreadObject.split(',').filter((e) => e.includes(':')).length > 0;
|
|
499
|
+
|
|
500
|
+
const isValidSpread = spreadObject.includes('...');
|
|
501
|
+
|
|
502
|
+
let processedSpreadObject = '';
|
|
503
|
+
if (isValidSpread) {
|
|
504
|
+
// Split the spreadObject by commas and process each part individually
|
|
505
|
+
const parts = spreadObject.split(',').map((part) => {
|
|
506
|
+
if (part.trim().startsWith('{') && part.trim().endsWith('}')) {
|
|
507
|
+
const nestedParts = part
|
|
508
|
+
.trim()
|
|
509
|
+
.slice(1, -1) // Remove outer {}
|
|
510
|
+
.split(',')
|
|
511
|
+
.map((nestedPart) => {
|
|
512
|
+
return nestedPart.includes('...') ? nestedPart.trim().replace(/\.\.\./, '') : `...${nestedPart.trim()}`;
|
|
513
|
+
});
|
|
514
|
+
return `{${nestedParts.join(',')}}`;
|
|
515
|
+
} else {
|
|
516
|
+
return part.includes('...') ? part.trim() : part.trim().startsWith('{') ? `...${part.trim()}` : `${part.trim()}`;
|
|
517
|
+
}
|
|
518
|
+
});
|
|
519
|
+
if (!parts.join(',').includes('{(')) {
|
|
520
|
+
|
|
521
|
+
processedSpreadObject = `${parts.join(',')}`
|
|
674
522
|
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
523
|
+
} else {
|
|
524
|
+
let prop = parts.join(',')
|
|
525
|
+
prop = prop.replaceAll('{(', '(')
|
|
526
|
+
prop = prop.replaceAll(')}', ')')
|
|
527
|
+
processedSpreadObject = prop
|
|
528
|
+
}
|
|
529
|
+
if (prop.includes('{{')) {
|
|
530
|
+
let prop = parts.join(',')
|
|
531
|
+
prop = prop.replaceAll('{{', '{')
|
|
532
|
+
prop = prop.replaceAll('}}', '}')
|
|
533
|
+
processedSpreadObject = prop
|
|
534
|
+
}
|
|
678
535
|
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
536
|
+
|
|
537
|
+
} else {
|
|
538
|
+
// Process nested structures within the object
|
|
539
|
+
processedSpreadObject = `{...${spreadObject}}`;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
const $propsKey = `$props_${Math.random().toString(36).substring(2)}`;
|
|
543
|
+
filteredProps.push(`${$propsKey}:${processedSpreadObject}`);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
else {
|
|
548
|
+
isWithinComponent = false;
|
|
685
549
|
}
|
|
686
550
|
}
|
|
687
|
-
};
|
|
688
551
|
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
};
|
|
696
|
-
}
|
|
552
|
+
// get inner content of <Component>inner content</Component>
|
|
553
|
+
let children = new RegExp(`<${name}[^>]*>(.*?)<\/${name}>`, "gs").exec(component) ? new RegExp(`<${name}[^>]*>(.*?)<\/${name}>`, "gs").exec(component)[1] : null;
|
|
554
|
+
|
|
555
|
+
props = filteredProps.join(',')
|
|
556
|
+
|
|
557
|
+
let savedname = name;
|
|
697
558
|
|
|
698
|
-
/**
|
|
699
|
-
*
|
|
700
|
-
* @function useEffect
|
|
701
|
-
* @param {*} effectFn
|
|
702
|
-
* @param {*} dependencies
|
|
703
|
-
* @description Allows you to run side effects
|
|
704
|
-
* @deprecated - this is no longer suggested please use vader signals instead
|
|
705
|
-
* @returns {Object} {cleanup}
|
|
706
|
-
*/
|
|
707
|
-
useEffect(effectFn, dependencies) {
|
|
708
|
-
if (!this.effects[this.name]) {
|
|
709
|
-
this.effects[this.name] = [];
|
|
710
|
-
}
|
|
711
|
-
this.effects[this.name].push(effectFn);
|
|
712
559
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
560
|
+
|
|
561
|
+
name = name + Math.random().toString(36).substring(2);
|
|
562
|
+
if (children && children.match(componentRegex)) {
|
|
563
|
+
children = parseComponents(children, true);
|
|
564
|
+
childs.push({ parent: name, children: children });
|
|
565
|
+
} else {
|
|
566
|
+
|
|
567
|
+
children ? childs.push({ parent: name, children: children }) : null;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
childs.forEach((child) => {
|
|
571
|
+
if (child.parent == name) {
|
|
572
|
+
let html = child.children.match(
|
|
573
|
+
/<([A-Z][A-Za-z0-9_-]+)([^>]*)>(.*?)<\/\1>|<([A-Z][A-Za-z0-9_-]+)([^]*?)\/>/gs
|
|
718
574
|
);
|
|
575
|
+
if (html) {
|
|
576
|
+
html = html.map((h) => h.trim().replace(/\s+/g, " ")).join(" ");
|
|
577
|
+
child.children = child.children.replaceAll(html, `${html}`);
|
|
578
|
+
// remove duplicate quotes
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
myChildrens.push(child.children);
|
|
719
582
|
}
|
|
720
583
|
});
|
|
721
|
-
} else if (!this.hasMounted) {
|
|
722
|
-
effectFn();
|
|
723
|
-
this.hasMounted = true;
|
|
724
|
-
}
|
|
725
584
|
|
|
726
|
-
return {
|
|
727
|
-
cleanup: () => {
|
|
728
|
-
this.effects[this.name] = this.effects[this.name].filter(
|
|
729
|
-
(effect) => effect !== effectFn
|
|
730
|
-
);
|
|
731
|
-
}
|
|
732
|
-
};
|
|
733
|
-
}
|
|
734
|
-
/**
|
|
735
|
-
* @method $Function
|
|
736
|
-
* @description Allows you to create a function in global scope
|
|
737
|
-
* @returns {Function}
|
|
738
|
-
* @example
|
|
739
|
-
* let func = this.$Function(function add(e, a){
|
|
740
|
-
* return e + a
|
|
741
|
-
* })
|
|
742
|
-
* @param {*} fn
|
|
743
|
-
*/
|
|
744
|
-
$Function(fn) {
|
|
745
|
-
// @ts-ignore
|
|
746
|
-
if (!typeof fn === "function") {
|
|
747
|
-
throw new Error("fn must be a function");
|
|
748
|
-
}
|
|
749
|
-
let name = fn.name;
|
|
750
|
-
if (!name) {
|
|
751
|
-
name = "anonymous" + Math.floor(Math.random() * 100000000000000000);
|
|
752
|
-
}
|
|
753
|
-
window[name] = fn;
|
|
754
|
-
// @ts-ignore
|
|
755
|
-
return `window.${name}()`;
|
|
756
|
-
}
|
|
757
585
|
|
|
758
|
-
// Add other methods like render, useEffect, useReducer, useAuth, etc.
|
|
759
586
|
|
|
760
|
-
updateComponent() {
|
|
761
|
-
const fragment = document.createDocumentFragment();
|
|
762
|
-
Object.keys(components).forEach(async (component) => {
|
|
763
|
-
const { name } = components[component];
|
|
764
587
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
588
|
+
props = props.replaceAll(`,${savedname}`, '').replaceAll(savedname, '')
|
|
589
|
+
if (props.startsWith(',')) {
|
|
590
|
+
props = props.replace(',', '')
|
|
591
|
+
}
|
|
592
|
+
props = props.replaceAll("='", ":'")
|
|
593
|
+
.replaceAll('=`', ':`')
|
|
594
|
+
.replaceAll('="', ':"')
|
|
595
|
+
.replaceAll('={', ':')
|
|
596
|
+
|
|
597
|
+
|
|
769
598
|
/**
|
|
770
|
-
* @
|
|
771
|
-
* @description Allows you to keep track of component snapshots
|
|
772
|
-
* @private
|
|
773
|
-
* @returns {Object} {name, time, prev_state, prev_props, content}
|
|
599
|
+
* @memoize - memoize a component to be remembered on each render and replace the old jsx
|
|
774
600
|
*/
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
// @ts-ignore
|
|
781
|
-
content: componentContainer.innerHTML
|
|
782
|
-
};
|
|
783
|
-
|
|
784
|
-
if (!componentContainer) return;
|
|
785
|
-
const newHtml = await new Function(
|
|
786
|
-
"useState",
|
|
787
|
-
"useEffect",
|
|
788
|
-
"useAuth",
|
|
789
|
-
"useReducer",
|
|
790
|
-
"useSyncStore",
|
|
791
|
-
"signal",
|
|
792
|
-
"rf",
|
|
793
|
-
"props",
|
|
794
|
-
"render",
|
|
795
|
-
"return `" + (await this.render()) + "`;"
|
|
796
|
-
)(
|
|
797
|
-
this.useState,
|
|
798
|
-
this.useEffect,
|
|
799
|
-
this.useAuth,
|
|
800
|
-
this.useReducer,
|
|
801
|
-
this.useSyncStore,
|
|
802
|
-
this.signal,
|
|
803
|
-
this.render
|
|
804
|
-
);
|
|
805
|
-
|
|
806
|
-
if (newHtml !== componentContainer.innerHTML) {
|
|
807
|
-
if (this.snapshots.length > 0) {
|
|
808
|
-
let lastSnapshot = this.snapshots[this.snapshots.length - 1];
|
|
809
|
-
if (lastSnapshot !== snapshot) {
|
|
810
|
-
this.snapshots.push(snapshot);
|
|
811
|
-
}
|
|
812
|
-
} else {
|
|
813
|
-
this.snapshots.push(snapshot);
|
|
814
|
-
}
|
|
815
|
-
this.componentUpdate(
|
|
816
|
-
snapshot.prev_state,
|
|
817
|
-
snapshot.prev_props,
|
|
818
|
-
snapshot.content
|
|
819
|
-
);
|
|
820
|
-
// batch updates
|
|
821
|
-
fragment.appendChild(
|
|
822
|
-
document.createRange().createContextualFragment(newHtml)
|
|
823
|
-
);
|
|
824
|
-
componentContainer.innerHTML = "";
|
|
825
|
-
componentContainer.appendChild(fragment);
|
|
826
|
-
this.runEffects();
|
|
827
|
-
}
|
|
601
|
+
|
|
602
|
+
let replace = "";
|
|
603
|
+
replace = `\${this.memoize(this.createComponent(${savedname}, {${props}}, [\`${myChildrens.join(" ")}\`]))}`;
|
|
604
|
+
|
|
605
|
+
body = body.replace(before, replace);
|
|
828
606
|
});
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
* @method validateClassName
|
|
832
|
-
* @param {String} className
|
|
833
|
-
* @private
|
|
834
|
-
* @returns {Boolean}
|
|
835
|
-
*/
|
|
836
|
-
validateClassName(className) {
|
|
837
|
-
// validate classNames ensure they are camelCase but also allow for - and _
|
|
838
|
-
return /^[a-zA-Z0-9-_]+$/.test(className);
|
|
607
|
+
|
|
608
|
+
return body;
|
|
839
609
|
}
|
|
840
610
|
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
element.getAttribute("alt").length < 1 &&
|
|
861
|
-
!document.documentElement.outerHTML
|
|
862
|
-
.trim()
|
|
863
|
-
.includes("<!-- #vader-disable_accessibility -->")
|
|
864
|
-
) {
|
|
865
|
-
throw new SyntaxError(
|
|
866
|
-
`Image: ${element.outerHTML} alt attribute cannot be empty`
|
|
867
|
-
);
|
|
868
|
-
} else if (
|
|
869
|
-
(element.hasAttribute("src") &&
|
|
870
|
-
!element.getAttribute("src")?.includes("http")) ||
|
|
871
|
-
(!element.getAttribute("src")?.includes("https") &&
|
|
872
|
-
!document.documentElement.outerHTML
|
|
873
|
-
.trim()
|
|
874
|
-
.includes("<!-- #vader-disable_accessibility -->"))
|
|
875
|
-
) {
|
|
876
|
-
let prevurl = element.getAttribute("src");
|
|
877
|
-
element.setAttribute("aria-hidden", "true");
|
|
878
|
-
element.setAttribute("hidden", "true");
|
|
879
|
-
// if window.lcoation.pathname includes a html file remove it and only use the path
|
|
880
|
-
let url =
|
|
881
|
-
window.location.origin +
|
|
882
|
-
window.location.pathname.replace(/\/[^\/]*$/, "") +
|
|
883
|
-
"/public/" +
|
|
884
|
-
element.getAttribute("src");
|
|
885
|
-
let image = new Image();
|
|
886
|
-
image.src = url;
|
|
887
|
-
image.onerror = () => {
|
|
888
|
-
// @ts-ignore
|
|
889
|
-
element.setAttribute("src", prevurl);
|
|
890
|
-
throw new Error(`Image: ${element.outerHTML} not found`);
|
|
891
|
-
};
|
|
892
|
-
element.setAttribute("src", url);
|
|
893
|
-
|
|
894
|
-
image.onload = () => {
|
|
895
|
-
document.querySelectorAll(`img[src="${url}"]`).forEach((img) => {
|
|
896
|
-
img.setAttribute("src", url);
|
|
897
|
-
img.removeAttribute("aria-hidden");
|
|
898
|
-
img.removeAttribute("hidden");
|
|
899
|
-
});
|
|
900
|
-
};
|
|
611
|
+
string = string.replaceAll('vaderjs/client', '/vader.js')
|
|
612
|
+
|
|
613
|
+
const importRegex = /import\s*([^\s,]+|\{[^}]+\})\s*from\s*(['"])(.*?)\2/g;
|
|
614
|
+
const imports = string.match(importRegex);
|
|
615
|
+
let replaceMents = [];
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
for (let match of imports) {
|
|
619
|
+
let path = match.split('from')[1].trim().replace(/'/g, '').replace(/"/g, '').trim()
|
|
620
|
+
switch (true) {
|
|
621
|
+
case path && !path.includes('./') && !path.includes('/vader.js') && !path.includes('/vaderjs/client') && !path.startsWith('src') && !path.startsWith('public') && !path.includes('http') && !path.includes('https'):
|
|
622
|
+
let componentFolder = fs.existsSync(process.cwd() + '/node_modules/' + path) ? process.cwd() + '/node_modules/' + path : process.cwd() + '/node_modules/' + path.split('/')[0]
|
|
623
|
+
componentFolder = componentFolder.split(process.cwd())[1]
|
|
624
|
+
if(!fs.existsSync(process.cwd() + componentFolder)){
|
|
625
|
+
throw new Error('Could not find ' + path + ' at ' + match + ' in file ' + file)
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
if(!fs.existsSync(process.cwd() + '/dist/src/' + componentFolder.split('/').slice(2).join('/'))){
|
|
629
|
+
fs.mkdirSync(process.cwd() + '/dist/src/' + componentFolder.split('/').slice(2).join('/'), { recursive: true })
|
|
901
630
|
}
|
|
902
|
-
|
|
631
|
+
|
|
632
|
+
let baseFolder = componentFolder.split('node_modules')[1].split('/')[1]
|
|
633
|
+
let glp = globSync('**/**/**/**.{jsx,js}', {
|
|
634
|
+
cwd: process.cwd() + '/node_modules/' + baseFolder + '/',
|
|
635
|
+
absolute: true,
|
|
636
|
+
recursive: true
|
|
637
|
+
})
|
|
638
|
+
for (let file of glp) {
|
|
639
|
+
let text = fs.readFileSync(file, "utf8");
|
|
640
|
+
if(!file.endsWith('.js') && file.endsWith('.jsx')){
|
|
641
|
+
text = Compiler(text, file);
|
|
642
|
+
}
|
|
643
|
+
let dest = file.split('node_modules')[1]
|
|
644
|
+
dest = dest.split(baseFolder)[1]
|
|
645
|
+
// write to dist
|
|
646
|
+
writer(process.cwd() + '/dist/src/' + baseFolder + dest, text)
|
|
647
|
+
let importname = match.split('import')[1].split('from')[0].trim()
|
|
648
|
+
let oldImportstring = match.split('from')[1].trim().replace(/'/g, '').replace(/"/g, '').trim()
|
|
649
|
+
let newImport = `/src/${baseFolder + dest}`
|
|
650
|
+
newImport = newImport.replaceAll('.jsx', '.js').replaceAll('\\', '/')
|
|
651
|
+
replaceMents.push({ match: oldImportstring, replace: newImport })
|
|
652
|
+
console.log(`📦 imported Node Package ${baseFolder} `)
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
break;
|
|
657
|
+
default:
|
|
658
|
+
break;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
for(let replace of replaceMents){
|
|
663
|
+
string = string.replaceAll(replace.match, replace.replace)
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
string = string.replaceAll(/\$\{[^{]*\.{3}/gs, (match) => {
|
|
667
|
+
if (match.includes('...')) {
|
|
668
|
+
// Your logic for replacement goes here
|
|
669
|
+
// For example, you can replace '...' with some other string
|
|
670
|
+
return match.replace('...', '');
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
return match;
|
|
674
|
+
});
|
|
903
675
|
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
676
|
+
string = string.replaceAll(/\$\{\/\*.*\*\/\}/gs, "");
|
|
677
|
+
string = string.replaceAll("<>", "`").replaceAll("</>", "`");
|
|
678
|
+
string = string.replaceAll(".jsx", ".js");
|
|
679
|
+
string = parseComponents(string);
|
|
680
|
+
|
|
681
|
+
string = string
|
|
682
|
+
.replaceAll("className", "class")
|
|
683
|
+
.replaceAll("classname", "class");
|
|
684
|
+
|
|
685
|
+
string = string.replaceAll('../src', './src')
|
|
686
|
+
string += `\n\n //wascompiled`;
|
|
687
|
+
|
|
688
|
+
|
|
689
|
+
string = string.replaceAll("undefined", "");
|
|
690
|
+
const parse = (css) => {
|
|
691
|
+
let styles = {};
|
|
692
|
+
let currentSelector = '';
|
|
693
|
+
|
|
694
|
+
css.split('\n').forEach(line => {
|
|
695
|
+
line = line.trim();
|
|
696
|
+
|
|
697
|
+
if (line.endsWith('{')) {
|
|
698
|
+
// Start of a block, extract the selector
|
|
699
|
+
currentSelector = line.slice(0, -1).trim();
|
|
700
|
+
styles[currentSelector] = {};
|
|
701
|
+
} else if (line.endsWith('}')) {
|
|
702
|
+
// End of a block
|
|
703
|
+
currentSelector = '';
|
|
704
|
+
} else if (line.includes(':') && currentSelector) {
|
|
705
|
+
// Inside a block and contains key-value pair
|
|
706
|
+
let [key, value] = line.split(':').map(part => part.trim());
|
|
707
|
+
styles[currentSelector][key] = value;
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
|
|
711
|
+
return styles;
|
|
712
|
+
};
|
|
713
|
+
string.split('\n').forEach(line => {
|
|
714
|
+
if (line.includes('import')) {
|
|
715
|
+
// Regular expression for matching import() statements
|
|
716
|
+
let asyncimportMatch = line.match(/import\s*\((.*)\)/gs);
|
|
717
|
+
// handle import { Component } from 'vaderjs/runtime/vader.js'
|
|
718
|
+
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);
|
|
719
|
+
|
|
720
|
+
if (asyncimportMatch) {
|
|
721
|
+
asyncimportMatch.forEach(async (match) => {
|
|
722
|
+
let beforeimport = match
|
|
723
|
+
let path = match.split('(')[1].split(')')[0].trim()
|
|
724
|
+
let newImport = ''
|
|
725
|
+
let name = match.split('import')[1].split('from')[0].trim()
|
|
726
|
+
switch (true) {
|
|
727
|
+
case path && path.includes('json'):
|
|
728
|
+
path = path.replace(';', '')
|
|
729
|
+
newImport = `let ${name} = await fetch('${path}').then(res => res.json())`
|
|
730
|
+
|
|
731
|
+
break;
|
|
732
|
+
case path && path.includes('module.css'):
|
|
733
|
+
let css = await fs.readFileSync(process.cwd() + path, 'utf8')
|
|
734
|
+
css = css.replaceAll('.', '')
|
|
735
|
+
|
|
736
|
+
if (!name) {
|
|
737
|
+
throw new Error('Could not find name for css module ' + path + ' at' + beforeimport + ' file' + file)
|
|
738
|
+
}
|
|
739
|
+
newImport = `let ${name} = ${JSON.stringify(parse(css.replaceAll('.', '').replace(/\s+/g, " ")))}`
|
|
740
|
+
|
|
741
|
+
break;
|
|
742
|
+
default:
|
|
743
|
+
let deep = path.split('/').length - 1
|
|
744
|
+
for (let i = 0; i < deep; i++) {
|
|
745
|
+
path = path.split('../').join('')
|
|
746
|
+
path = path.split('./').join('')
|
|
747
|
+
}
|
|
748
|
+
path = path.replace(/'/g, '').trim().replace(/"/g, '').trim()
|
|
749
|
+
// remove double / from path
|
|
750
|
+
path = path.split('//').join('/')
|
|
751
|
+
if (!path.startsWith('./') && !path.includes('/vader.js') && !path.startsWith('src')
|
|
752
|
+
&& !path.startsWith('/public')
|
|
753
|
+
) {
|
|
754
|
+
path = '/src/' + path
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
path = path.replaceAll('.jsx', '.js');
|
|
758
|
+
newImport = `await import(${path})`
|
|
908
759
|
}
|
|
909
|
-
if (
|
|
910
|
-
|
|
911
|
-
element.innerHTML.replace(/\\n/g, "\n").trim()
|
|
912
|
-
);
|
|
760
|
+
if (newImport) {
|
|
761
|
+
string = string.replace(beforeimport, newImport)
|
|
913
762
|
}
|
|
763
|
+
})
|
|
764
|
+
}
|
|
914
765
|
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
766
|
+
if (regularimportMatch) {
|
|
767
|
+
for (let match of regularimportMatch) {
|
|
768
|
+
let beforeimport = match
|
|
769
|
+
let path = match.split('from')[1] ? match.split('from')[1].trim() : match.split('import')[1].trim()
|
|
770
|
+
|
|
771
|
+
let newImport = ''
|
|
772
|
+
let name = match.split('import')[1].split('from')[0].trim()
|
|
773
|
+
|
|
774
|
+
|
|
775
|
+
switch (true) {
|
|
776
|
+
case path && path.includes('json'):
|
|
777
|
+
path = path.replace(';', '')
|
|
778
|
+
newImport = `let ${name} = await fetch('${path}').then(res => res.json())`
|
|
779
|
+
|
|
780
|
+
break;
|
|
781
|
+
case path && path.includes('module.css'):
|
|
782
|
+
|
|
783
|
+
path = path.replace(';', '')
|
|
784
|
+
path = path.replace(/'/g, '').trim().replace(/"/g, '').trim()
|
|
785
|
+
path = path.replaceAll('.jsx', '.js');
|
|
786
|
+
path = path.replaceAll('../', '');
|
|
787
|
+
|
|
788
|
+
let css = fs.readFileSync(process.cwd() + '/' + path, 'utf8')
|
|
789
|
+
|
|
790
|
+
css = css.replaceAll('.', '')
|
|
791
|
+
newImport = `let ${name} = ${JSON.stringify(parse(css))}`
|
|
792
|
+
string = string.replace(beforeimport, newImport)
|
|
793
|
+
break;
|
|
794
|
+
case path && path.includes('.css'):
|
|
795
|
+
string = string.replace(beforeimport, '')
|
|
796
|
+
newImport = ``
|
|
797
|
+
break;
|
|
798
|
+
case path && !path.startsWith('./') && !path.includes('/vader.js') && !path.startsWith('src') && !path.startsWith('public') &&
|
|
799
|
+
path.match(/^[A-Za-z0-9_-]+$/gs) && !path.includes('http') && !path.includes('https'):
|
|
800
|
+
console.log(path)
|
|
801
|
+
break;
|
|
802
|
+
default:
|
|
803
|
+
let beforePath = path
|
|
804
|
+
let deep = path.split('/').length - 1
|
|
805
|
+
for (let i = 0; i < deep; i++) {
|
|
806
|
+
path = path.split('../').join('')
|
|
807
|
+
path = path.split('./').join('')
|
|
808
|
+
}
|
|
809
|
+
path = path.replace(/'/g, '').trim().replace(/"/g, '').trim()
|
|
810
|
+
// remove double / from path
|
|
811
|
+
path = path.split('//').join('/')
|
|
812
|
+
if (!path.startsWith('./') && !path.includes('/vader.js') && !path.startsWith('src') && !path.startsWith('public')) {
|
|
813
|
+
path.includes('src') ? path.split('src')[1] : null
|
|
814
|
+
path = '/src/' + path
|
|
815
|
+
} else if (path.startsWith('src') || path.startsWith('public')) {
|
|
816
|
+
path = '/' + path
|
|
817
|
+
}
|
|
818
|
+
path = path.replaceAll('.jsx', '.js');
|
|
819
|
+
|
|
820
|
+
|
|
821
|
+
string = string.replace(beforePath, "'" + path + "'")
|
|
822
|
+
break;
|
|
932
823
|
|
|
933
|
-
if (
|
|
934
|
-
element.hasAttribute("href") &&
|
|
935
|
-
// @ts-ignore
|
|
936
|
-
element.getAttribute("href").startsWith("/") &&
|
|
937
|
-
!document.documentElement.outerHTML
|
|
938
|
-
.trim()
|
|
939
|
-
.includes("<!-- #vader-disable_relative-paths -->")
|
|
940
|
-
) {
|
|
941
|
-
element.setAttribute(
|
|
942
|
-
"href",
|
|
943
|
-
// @ts-ignore
|
|
944
|
-
`#/${element.getAttribute("href").replace("/", "")}`
|
|
945
|
-
);
|
|
946
824
|
}
|
|
947
825
|
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
!element.getAttribute("src").includes("http") &&
|
|
952
|
-
// @ts-ignore
|
|
953
|
-
!element.getAttribute("src").includes("https") &&
|
|
954
|
-
!document.documentElement.outerHTML.includes(
|
|
955
|
-
`<!-- #vader-disable_relative-paths -->`
|
|
956
|
-
)
|
|
957
|
-
) {
|
|
958
|
-
element.setAttribute(
|
|
959
|
-
"src",
|
|
960
|
-
// @ts-ignore
|
|
961
|
-
`./public/${element.getAttribute("src")}`
|
|
962
|
-
);
|
|
826
|
+
|
|
827
|
+
if (newImport) {
|
|
828
|
+
string = string.replace(beforeimport, newImport)
|
|
963
829
|
}
|
|
964
|
-
break;
|
|
965
|
-
}
|
|
966
|
-
});
|
|
967
830
|
|
|
968
|
-
|
|
831
|
+
}
|
|
969
832
|
|
|
970
|
-
this.Componentcontent = result;
|
|
971
833
|
|
|
972
|
-
|
|
973
|
-
result = `<div data-component="${this.name}">${result}</div>`;
|
|
834
|
+
}
|
|
974
835
|
}
|
|
975
|
-
return markdown(result.replace(/\\n/g, "\n").trim());
|
|
976
|
-
}
|
|
977
836
|
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
* 4. **Custom Component Attributes**: It supports adding a 'data-component' attribute to the root element.
|
|
1016
|
-
* - Ensures that the 'data-component' attribute is present for component identification.
|
|
1017
|
-
*
|
|
1018
|
-
* 5. **Lifecycle Method Invocation**: It invokes the `componentDidMount` method if called from a 'render' context.
|
|
1019
|
-
* - Executes `componentDidMount` to handle component initialization once the DOM is ready.
|
|
1020
|
-
*
|
|
1021
|
-
* @see {@link Component}
|
|
1022
|
-
* @see {@link Component#componentDidMount}
|
|
1023
|
-
*/
|
|
1024
|
-
|
|
1025
|
-
html(strings, ...args) {
|
|
1026
|
-
// @ts-ignore
|
|
1027
|
-
let tiemr = setInterval(() => {
|
|
1028
|
-
if (document.querySelector(`[data-component="${this.name}"]`)) {
|
|
1029
|
-
clearInterval(tiemr);
|
|
1030
|
-
this.componentMounted = true;
|
|
1031
|
-
|
|
1032
|
-
document
|
|
1033
|
-
.querySelector(`[data-component="${this.name}"]`)
|
|
1034
|
-
?.querySelectorAll("*")
|
|
1035
|
-
.forEach((element) => {
|
|
1036
|
-
if (element.hasAttribute("ref")) {
|
|
1037
|
-
// @ts-ignore
|
|
1038
|
-
this.dom[element.getAttribute("ref")] = element;
|
|
1039
|
-
}
|
|
1040
|
-
});
|
|
1041
|
-
this.componentDidMount();
|
|
837
|
+
|
|
838
|
+
})
|
|
839
|
+
|
|
840
|
+
return string
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
globalThis.isBuilding = false
|
|
844
|
+
globalThis.isWriting = null
|
|
845
|
+
const glb = await glob("**/**/**/**.{jsx,js}", {
|
|
846
|
+
ignore: ["node_modules/**/*", "dist/**/*"],
|
|
847
|
+
cwd: process.cwd() + '/pages/',
|
|
848
|
+
absolute: true,
|
|
849
|
+
recursive: true
|
|
850
|
+
});
|
|
851
|
+
async function Build() {
|
|
852
|
+
globalThis.isBuilding = true
|
|
853
|
+
console.log('Compiling......')
|
|
854
|
+
let reader = async (file) => {
|
|
855
|
+
let text = await fs.readFileSync(file, "utf8");
|
|
856
|
+
return text;
|
|
857
|
+
};
|
|
858
|
+
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
|
|
862
|
+
|
|
863
|
+
|
|
864
|
+
// Process files in the 'pages' directory
|
|
865
|
+
let appjs = '';
|
|
866
|
+
let hasWritten = []
|
|
867
|
+
function ssg(routes = []) {
|
|
868
|
+
globalThis.isBuilding = true
|
|
869
|
+
console.log(`Generating html files for ${routes.length} routes`)
|
|
870
|
+
routes.forEach(async (route) => {
|
|
871
|
+
if (route.url.includes(':')) {
|
|
872
|
+
console.log('Route ' + route.url + ' is a dynamic route and will not be generated')
|
|
873
|
+
return
|
|
1042
874
|
}
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
worker.postMessage({
|
|
1052
|
-
strings,
|
|
1053
|
-
args,
|
|
1054
|
-
location:
|
|
1055
|
-
window.location.origin +
|
|
1056
|
-
window.location.pathname.replace(/\/[^\/]*$/, "") +
|
|
1057
|
-
"/public/",
|
|
1058
|
-
name: this.name
|
|
1059
|
-
});
|
|
1060
|
-
let promise = new Promise((resolve, reject) => {
|
|
1061
|
-
worker.onmessage = (e) => {
|
|
1062
|
-
if (e.data.error) {
|
|
1063
|
-
throw new Error(e.data.error);
|
|
875
|
+
let equalparamroute = routes.map((e) => {
|
|
876
|
+
if (e.url.includes(':')) {
|
|
877
|
+
let url = e.url.split('/:')[0]
|
|
878
|
+
if (url && route.url === url) {
|
|
879
|
+
return e
|
|
880
|
+
} else {
|
|
881
|
+
return null
|
|
882
|
+
|
|
1064
883
|
}
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
884
|
+
}
|
|
885
|
+
return null
|
|
886
|
+
}).filter(Boolean)
|
|
887
|
+
let document = `
|
|
888
|
+
<!DOCTYPE html>
|
|
889
|
+
<html lang="en">
|
|
890
|
+
<head>
|
|
891
|
+
<script>
|
|
892
|
+
window.routes = JSON.parse('${JSON.stringify(routes)}')
|
|
893
|
+
</script>
|
|
894
|
+
<script id="isServer">
|
|
895
|
+
window.isServer = true
|
|
896
|
+
</script>
|
|
897
|
+
<meta charset="UTF-8">
|
|
898
|
+
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
899
|
+
<script type="module" id="meta">
|
|
900
|
+
window.history.pushState({}, '', '${route.url}')
|
|
901
|
+
window.module = await import('/${route.fileName.replace('.jsx', '.js')}')
|
|
902
|
+
let metadata = await module.$metadata
|
|
903
|
+
if(metadata && metadata.title){
|
|
904
|
+
document.head.innerHTML += '<title>' + metadata.title + '</title>'
|
|
905
|
+
}
|
|
906
|
+
if(metadata && metadata.description){
|
|
907
|
+
document.head.innerHTML += '<meta name="description" content="' + metadata.description + '">'
|
|
908
|
+
}
|
|
909
|
+
if(metadata && metadata.keywords){
|
|
910
|
+
document.head.innerHTML += '<meta name="keywords" content="' + metadata.keywords + '">'
|
|
911
|
+
}
|
|
912
|
+
if(metadata && metadata.author){
|
|
913
|
+
document.head.innerHTML += '<meta name="author" content="' + metadata.author + '">'
|
|
914
|
+
}
|
|
915
|
+
if(metadata && metadata.image){
|
|
916
|
+
let image = metadata.image.file
|
|
917
|
+
let type = metadata.image.type
|
|
918
|
+
|
|
919
|
+
document.head.innerHTML += '<meta property="og:image" content="' + image + '">'
|
|
920
|
+
document.head.innerHTML += '<meta property="og:image:type" content="' + type + '">'
|
|
921
|
+
}
|
|
922
|
+
if(metadata && metadata.url){
|
|
923
|
+
document.head.innerHTML += '<meta property="og:url" content="' + metadata.url + '">'
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
if(metadata && metadata.robot){
|
|
927
|
+
document.head.innerHTML += '<meta name="robots" content="' + metadata.robot + '">'
|
|
928
|
+
}
|
|
929
|
+
if(metadata && metadata.manifest){
|
|
930
|
+
document.head.innerHTML += '<link rel="manifest" href="' + metadata.manifest + '">'
|
|
931
|
+
}
|
|
932
|
+
if(metadata && metadata.tags){
|
|
933
|
+
metadata.tags.forEach(tag => {
|
|
934
|
+
document.head.innerHTML += tag
|
|
935
|
+
})
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
if(metadata && metadata.styles){
|
|
939
|
+
metadata.styles.forEach(style => {
|
|
940
|
+
style = style.replaceAll('./', '/')
|
|
941
|
+
style = style.replaceAll('../', '/')
|
|
942
|
+
style = style.replace("'", '')
|
|
943
|
+
document.head.innerHTML += '<link rel="stylesheet" href="' + style + '">'
|
|
944
|
+
})
|
|
945
|
+
}
|
|
946
|
+
if(metadata && metadata.icon){
|
|
947
|
+
document.head.innerHTML += '<link rel="icon" href="' + metadata.icon + '">'
|
|
948
|
+
}
|
|
949
|
+
</script>
|
|
950
|
+
<script type="module" id="router">
|
|
951
|
+
import VaderRouter from '/router.js'
|
|
952
|
+
const router = new VaderRouter('${route.url}', 3000)
|
|
953
|
+
router.get('${route.url}', async (req, res) => {
|
|
954
|
+
let module = await import('/${route.fileName.replace('.jsx', '.js')}')
|
|
955
|
+
if(Object.keys(module).includes('$prerender') && !module.$prerender){
|
|
956
|
+
document.head.setAttribute('prerender', 'false')
|
|
957
|
+
}
|
|
958
|
+
res.render(module, req, res, module.$metadata)
|
|
959
|
+
})
|
|
960
|
+
${equalparamroute.length > 0 ? equalparamroute.map((e) => {
|
|
961
|
+
|
|
962
|
+
|
|
963
|
+
|
|
964
|
+
return `router.get('${e.url}', async (req, res) => {
|
|
965
|
+
let module = await import('/${e.fileName.replace('.jsx', '.js')}')
|
|
966
|
+
res.render(module, req, res, module.$metadata)
|
|
967
|
+
})\n`
|
|
968
|
+
}) : ''}
|
|
969
|
+
router.listen(3000)
|
|
970
|
+
|
|
971
|
+
</script>
|
|
972
|
+
</head>
|
|
973
|
+
<body>
|
|
974
|
+
<div id="root"></div>
|
|
975
|
+
</body>
|
|
976
|
+
|
|
977
|
+
|
|
978
|
+
</html>
|
|
979
|
+
`;
|
|
1105
980
|
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
981
|
+
// generate random but common ports
|
|
982
|
+
let port = Math.floor(Math.random() * (65535 - 49152 + 1) + 49152)
|
|
983
|
+
|
|
984
|
+
const server = http.createServer((req, res) => {
|
|
985
|
+
|
|
986
|
+
if (req.url === '/') {
|
|
987
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
988
|
+
res.end(document);
|
|
989
|
+
} else {
|
|
990
|
+
// Serve static files (adjust the file paths based on your project structure)
|
|
991
|
+
const filePath = process.cwd() + '/dist/' + req.url
|
|
992
|
+
|
|
993
|
+
fs.readFile(filePath, (err, data) => {
|
|
994
|
+
if (err) {
|
|
995
|
+
res.writeHead(404, { 'Content-Type': filePath.includes('js') ? 'text/javascript' : 'text/html' });
|
|
996
|
+
res.end('File not found');
|
|
997
|
+
} else {
|
|
998
|
+
res.writeHead(200, { 'Content-Type': filePath.includes('js') ? 'text/javascript' : 'text/html' });
|
|
999
|
+
res.end(data);
|
|
1000
|
+
}
|
|
1001
|
+
});
|
|
1002
|
+
}
|
|
1116
1003
|
});
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1004
|
+
|
|
1005
|
+
server.listen(port)
|
|
1006
|
+
server.on('error', (err) => {
|
|
1007
|
+
if (err.code === 'EADDRINUSE') {
|
|
1008
|
+
console.log(`Port ${port} is in use, trying another port...`);
|
|
1009
|
+
setTimeout(() => {
|
|
1010
|
+
server.close();
|
|
1011
|
+
server.listen(++port);
|
|
1012
|
+
}, 1000);
|
|
1125
1013
|
}
|
|
1126
|
-
}
|
|
1127
|
-
result = new Function("useRef", `return \`${result}\``)(useRef);
|
|
1014
|
+
})
|
|
1128
1015
|
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1016
|
+
globalThis.listen = true;
|
|
1017
|
+
|
|
1018
|
+
const browser = await puppeteer.launch({
|
|
1019
|
+
headless: "new", args: ['--no-sandbox', '--disable-setuid-sandbox'],
|
|
1020
|
+
warning: false,
|
|
1021
|
+
})
|
|
1022
|
+
|
|
1023
|
+
const browserPID = browser.process().pid
|
|
1024
|
+
try {
|
|
1025
|
+
|
|
1026
|
+
route.url = route.url.replaceAll(/\/:[a-zA-Z0-9_-]+/gs, '')
|
|
1027
|
+
let page = await browser.newPage();
|
|
1028
|
+
await page.goto(`http://localhost:${port}/`, { waitUntil: 'networkidle2' });
|
|
1029
|
+
await page.waitForSelector('#root', { timeout: 10000 })
|
|
1030
|
+
await page.evaluate(() => {
|
|
1031
|
+
document.getElementById('meta').remove()
|
|
1032
|
+
document.querySelector('#isServer').innerHTML = 'window.isServer = false'
|
|
1033
|
+
if (document.head.getAttribute('prerender') === 'false') {
|
|
1034
|
+
document.querySelector('#root').innerHTML = ''
|
|
1035
|
+
}
|
|
1036
|
+
})
|
|
1037
|
+
const html = await page.content();
|
|
1038
|
+
|
|
1039
|
+
await page.close();
|
|
1040
|
+
await writer(process.cwd() + '/dist/' + (route.url === '/' ? 'index.html' : `${route.url}/` + 'index.html'), html)
|
|
1041
|
+
await browser.close();
|
|
1042
|
+
server.close()
|
|
1043
|
+
|
|
1044
|
+
} catch (error) {
|
|
1045
|
+
server.close()
|
|
1046
|
+
await browser.close();
|
|
1047
|
+
}
|
|
1048
|
+
finally {
|
|
1049
|
+
await browser.close();
|
|
1050
|
+
server.close()
|
|
1051
|
+
}
|
|
1052
|
+
try {
|
|
1053
|
+
process.kill(browserPID )
|
|
1054
|
+
} catch (error) {
|
|
1133
1055
|
}
|
|
1134
1056
|
|
|
1135
|
-
|
|
1136
|
-
}
|
|
1057
|
+
|
|
1058
|
+
})
|
|
1059
|
+
|
|
1060
|
+
let timeout = setTimeout(() => {
|
|
1061
|
+
globalThis.isBuilding = false
|
|
1062
|
+
clearTimeout(timeout)
|
|
1063
|
+
}, 1000)
|
|
1064
|
+
console.log(`Generated ${routes.length} html files for ${routes.length} routes`)
|
|
1137
1065
|
}
|
|
1138
|
-
// write types to ensure it returns a string
|
|
1139
|
-
/**
|
|
1140
|
-
* @method render
|
|
1141
|
-
* @description Allows you to render html
|
|
1142
|
-
* @returns {Promise <any>}
|
|
1143
|
-
* @example
|
|
1144
|
-
* async render() {
|
|
1145
|
-
* return this.html(`
|
|
1146
|
-
* <div className="hero p-5">
|
|
1147
|
-
* <h1>Home</h1>
|
|
1148
|
-
* </div>
|
|
1149
|
-
* `);
|
|
1150
|
-
*/
|
|
1151
|
-
async render(props) {}
|
|
1152
|
-
}
|
|
1153
1066
|
|
|
1154
|
-
|
|
1155
|
-
* @object Vader
|
|
1156
|
-
* @property {class} Component
|
|
1157
|
-
* @property {function} useRef
|
|
1158
|
-
* @description Allows you to create a component
|
|
1159
|
-
* @example
|
|
1160
|
-
* import { Vader } from "../../dist/vader/vader.js";
|
|
1161
|
-
* export class Home extends Vader.Component {
|
|
1162
|
-
* constructor() {
|
|
1163
|
-
* super('Home');
|
|
1164
|
-
* }
|
|
1165
|
-
* async render() {
|
|
1166
|
-
* return this.html(`
|
|
1167
|
-
* <div className="hero p-5">
|
|
1168
|
-
* <h1>Home</h1>
|
|
1169
|
-
* </div>
|
|
1170
|
-
* `);
|
|
1171
|
-
* }
|
|
1172
|
-
*/
|
|
1173
|
-
const Vader = {
|
|
1174
|
-
/**
|
|
1175
|
-
* @class Component
|
|
1176
|
-
* @description Allows you to create a component
|
|
1177
|
-
* @returns {void}
|
|
1178
|
-
* @memberof {Vader}
|
|
1179
|
-
* @example
|
|
1180
|
-
* import { Vader } from "../../dist/vader/index.js";
|
|
1181
|
-
* export class Home extends Vader.Component {
|
|
1182
|
-
* constructor() {
|
|
1183
|
-
* super();
|
|
1184
|
-
* }
|
|
1185
|
-
* async render() {
|
|
1186
|
-
* return this.html(`
|
|
1187
|
-
* <div className="hero p-5">
|
|
1188
|
-
* <h1>Home</h1>
|
|
1189
|
-
* </div>
|
|
1190
|
-
* `);
|
|
1191
|
-
* }
|
|
1192
|
-
* }
|
|
1193
|
-
*/
|
|
1194
|
-
Component: Component,
|
|
1195
|
-
useRef: useRef
|
|
1196
|
-
};
|
|
1197
|
-
/**
|
|
1198
|
-
* @function component
|
|
1199
|
-
* @description Allows you to create a component
|
|
1200
|
-
* @returns {Component}
|
|
1201
|
-
*/
|
|
1202
|
-
export const component = () => {
|
|
1203
|
-
return new Component()
|
|
1204
|
-
};
|
|
1067
|
+
globalThis.routes = []
|
|
1205
1068
|
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
* @description Allows you to register function in global scope
|
|
1213
|
-
*/
|
|
1214
|
-
export const rf = (name, fn) => {
|
|
1215
|
-
window[name] = fn;
|
|
1216
|
-
};
|
|
1217
|
-
let cache = {};
|
|
1218
|
-
async function handletemplate(data) {
|
|
1219
|
-
let dom = new DOMParser().parseFromString(data, "text/html");
|
|
1220
|
-
let elements = dom.documentElement.querySelectorAll("*");
|
|
1221
|
-
|
|
1222
|
-
if (elements.length > 0) {
|
|
1223
|
-
for (var i = 0; i < elements.length; i++) {
|
|
1224
|
-
if (elements[i].nodeName === "INCLUDE") {
|
|
1225
|
-
if (
|
|
1226
|
-
!elements[i].getAttribute("src") ||
|
|
1227
|
-
elements[i].getAttribute("src") === ""
|
|
1228
|
-
) {
|
|
1229
|
-
throw new Error("Include tag must have src attribute");
|
|
1230
|
-
}
|
|
1069
|
+
for await (let file of glb) {
|
|
1070
|
+
// Normalize file paths
|
|
1071
|
+
let origin = file.replace(/\\/g, '/');
|
|
1072
|
+
let fileName = origin.split('/pages/')[1].split('.jsx')[0].replace('.jsx', '') + '.jsx';
|
|
1073
|
+
let isBasePath = fileName === 'index.jsx';
|
|
1074
|
+
let isParamRoute = fileName.includes('[') && fileName.includes(']') ? true : false
|
|
1231
1075
|
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
?.split("/")
|
|
1235
|
-
.pop()
|
|
1236
|
-
?.split(".")[0];
|
|
1237
|
-
// @ts-ignore
|
|
1238
|
-
let filedata = await include(elements[i].getAttribute("src"));
|
|
1239
|
-
// replace ` with \`\` to allow for template literals
|
|
1240
|
-
filedata = filedata.replace(/`/g, "\\`");
|
|
1241
|
-
cache[elements[i].getAttribute("src")] = filedata;
|
|
1242
|
-
filedata = new Function(`return \`${filedata}\`;`)();
|
|
1243
|
-
let newdom = new DOMParser().parseFromString(filedata, "text/html");
|
|
1076
|
+
// Extract all dynamic parameters from the file path [param1]/[param2]/[param3
|
|
1077
|
+
let aburl = origin.split('/pages')[1].split('.jsx')[0].replace('.jsx', '').split('[').join(':').split(']').join('');
|
|
1244
1078
|
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1079
|
+
if (aburl.includes('...')) {
|
|
1080
|
+
// this is a catch all route
|
|
1081
|
+
// it should be /pages/[...]/index.jsx or /pages/[...].jsx
|
|
1082
|
+
aburl = aburl.split('...').join('*').split(':*').join('*')
|
|
1083
|
+
aburl = aburl.replaceAll('./index', '')
|
|
1084
|
+
|
|
1085
|
+
}
|
|
1086
|
+
// Create an object with URL and pathname properties
|
|
1087
|
+
let obj = {
|
|
1088
|
+
url: isBasePath ? '/' : aburl.replaceAll('/index', ''),
|
|
1089
|
+
pathname: `/pages/${origin.split('pages/')[1].split('.jsx')[0].replace('.jsx', '')}.jsx`,
|
|
1090
|
+
fullpath: origin,
|
|
1091
|
+
};
|
|
1092
|
+
|
|
1093
|
+
|
|
1094
|
+
|
|
1095
|
+
let data = await fs.readFileSync(origin, "utf8");
|
|
1096
|
+
data = Compiler(data, origin);
|
|
1097
|
+
|
|
1098
|
+
|
|
1099
|
+
|
|
1100
|
+
await writer(process.cwd() + "/dist/" + fileName.replace('.jsx', '.js'), data).then(async () => {
|
|
1101
|
+
|
|
1102
|
+
|
|
1103
|
+
|
|
1104
|
+
await writer(process.cwd() + "/dist/" + fileName.replace('.jsx', '.js'), data)
|
|
1105
|
+
|
|
1106
|
+
})
|
|
1107
|
+
|
|
1108
|
+
// configure routing for each page
|
|
1109
|
+
|
|
1110
|
+
obj.compiledPath = process.cwd() + "/dist/pages/" + fileName.replace('.jsx', '.js')
|
|
1111
|
+
let providerRedirects = { cloudflare: '_redirects', vercel: 'vercel.json', netlify: '_redirects' }
|
|
1112
|
+
switch (true) {
|
|
1113
|
+
case config && config.host && !config.host['_redirect']:
|
|
1114
|
+
let host = config.host.provider
|
|
1115
|
+
|
|
1116
|
+
let provider = providerRedirects[host]
|
|
1117
|
+
if (provider) {
|
|
1118
|
+
|
|
1119
|
+
let redirectFile = null
|
|
1120
|
+
switch (true) {
|
|
1121
|
+
case provider === '_redirects':
|
|
1122
|
+
redirectFile = fs.existsSync(process.cwd() + '/dist/' + provider) ? fs.readFileSync(process.cwd() + '/dist/' + provider, 'utf8') : ''
|
|
1123
|
+
break;
|
|
1124
|
+
case provider === 'vercel.json':
|
|
1125
|
+
redirectFile = fs.existsSync(process.cwd() + '/' + provider) ? fs.readFileSync(process.cwd() + '/' + provider, 'utf8') : ''
|
|
1126
|
+
break;
|
|
1127
|
+
default:
|
|
1128
|
+
break;
|
|
1262
1129
|
}
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
})
|
|
1275
|
-
|
|
1130
|
+
let type = provider === '_redirects' ? 'text/plain' : 'application/json'
|
|
1131
|
+
|
|
1132
|
+
let root = obj.url.includes(':') ? obj.url.split('/:')[0] : obj.url
|
|
1133
|
+
switch (true) {
|
|
1134
|
+
case root === '/':
|
|
1135
|
+
break;
|
|
1136
|
+
case type === 'text/plain' && !redirectFile.includes(obj.url) && obj.url.includes(':'):
|
|
1137
|
+
let page = obj.pathname.split('/pages/')[1].replace('.jsx', '.js')
|
|
1138
|
+
redirectFile += `\n/${page} /${page} 200\n${obj.url} ${root} 200\n`
|
|
1139
|
+
!redirectFile.includes('/404') ? redirectFile += `\n/404 /404 404` : null
|
|
1140
|
+
fs.writeFileSync(process.cwd() + '/dist/' + provider, redirectFile)
|
|
1141
|
+
console.log(`Added ${obj.url} ${obj.url} 200 to ${provider}`)
|
|
1142
|
+
break;
|
|
1143
|
+
case type === 'application/json' && !redirectFile?.includes(`${obj.url}`):
|
|
1144
|
+
let json = redirectFile ? JSON.parse(redirectFile) : {}
|
|
1145
|
+
let isVercel = provider === 'vercel.json' ? true : false
|
|
1146
|
+
if (isVercel) {
|
|
1147
|
+
json['rewrites'] = json['rewrites'] || []
|
|
1148
|
+
json['rewrites'].push({ "source": obj.url, "destination": `${root}/index.html` })
|
|
1149
|
+
fs.writeFileSync(process.cwd() + '/' + provider, JSON.stringify(json, null, 2))
|
|
1150
|
+
console.log(`Added ${obj.url} ${root}/index.html to ${provider}`)
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1276
1153
|
}
|
|
1154
|
+
}
|
|
1155
|
+
break;
|
|
1156
|
+
case config && config.host && config.host['_redirect']:
|
|
1157
|
+
let file = config.host['_redirect']
|
|
1158
|
+
file = file.split('./').join('')
|
|
1159
|
+
let redirectFile = fs.existsSync(process.cwd() + '/' + file) ? fs.readFileSync(process.cwd() + '/' + file, 'utf8') : ''
|
|
1160
|
+
fs.writeFileSync(process.cwd() + '/dist/' + file, redirectFile)
|
|
1161
|
+
console.log(`Using ${file} for redirects`)
|
|
1162
|
+
default:
|
|
1163
|
+
break;
|
|
1277
1164
|
|
|
1278
|
-
dom.body.querySelectorAll("include").forEach((el) => {
|
|
1279
|
-
el.remove();
|
|
1280
|
-
});
|
|
1281
|
-
// replace ` with \`\` to allow for template literals
|
|
1282
|
-
dom.body.outerHTML = dom.body.outerHTML.replace(/`/g, "\\`");
|
|
1283
|
-
dom.body.outerHTML = dom.body.outerHTML.replace(
|
|
1284
|
-
el.outerHTML,
|
|
1285
|
-
new Function(`return \`${newdom.body.outerHTML}\`;`)()
|
|
1286
|
-
);
|
|
1287
|
-
});
|
|
1288
|
-
}
|
|
1289
1165
|
}
|
|
1166
|
+
|
|
1167
|
+
|
|
1168
|
+
globalThis.routes.push({ fileName: fileName, url: obj.url, html: '/' + (isBasePath ? 'index.html' : `${obj.url}/` + 'index.html') })
|
|
1169
|
+
|
|
1170
|
+
|
|
1171
|
+
|
|
1290
1172
|
}
|
|
1291
1173
|
|
|
1292
|
-
|
|
1293
|
-
dom.body.outerHTML = dom.body.outerHTML.replace(/`/g, "\\`");
|
|
1294
|
-
data = new Function(`return \`${dom.body.outerHTML}\`;`)();
|
|
1174
|
+
ssg(globalThis.routes)
|
|
1295
1175
|
|
|
1296
|
-
return data;
|
|
1297
|
-
}
|
|
1298
|
-
/**
|
|
1299
|
-
* @function include
|
|
1300
|
-
* @description Allows you to include html file
|
|
1301
|
-
* @returns {Promise} - modified string with html content
|
|
1302
|
-
* @param {string} path
|
|
1303
|
-
*/
|
|
1304
1176
|
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1177
|
+
const scannedSourceFiles = await glob("**/**.{jsx,js,json}", {
|
|
1178
|
+
ignore: ["node_modules/**/*", "dist/**/*"],
|
|
1179
|
+
cwd: process.cwd() + '/src/',
|
|
1180
|
+
absolute: true,
|
|
1181
|
+
});
|
|
1182
|
+
const scannedVaderFiles = await glob("**/**.{html,js,json}", {
|
|
1183
|
+
cwd: process.cwd() + '/node_modules/vaderjs/runtime',
|
|
1184
|
+
absolute: true,
|
|
1185
|
+
});
|
|
1186
|
+
|
|
1187
|
+
scannedVaderFiles.forEach(async (file) => {
|
|
1188
|
+
file = file.replace(/\\/g, '/');
|
|
1189
|
+
|
|
1190
|
+
|
|
1191
|
+
let name = file.split('/node_modules/vaderjs/runtime/')[1]
|
|
1192
|
+
if (file.includes('index.html') && fs.existsSync(process.cwd() + "/dist/" + name)) {
|
|
1193
|
+
return
|
|
1194
|
+
}
|
|
1195
|
+
let data = await reader(file)
|
|
1196
|
+
bundleSize += fs.statSync(file).size;
|
|
1197
|
+
await writer(process.cwd() + "/dist/" + name, data);
|
|
1198
|
+
})
|
|
1199
|
+
scannedSourceFiles.forEach(async (file) => {
|
|
1200
|
+
file = file.replace(/\\/g, '/');
|
|
1201
|
+
let name = file.split('/src/')[1]
|
|
1202
|
+
//parse jsx
|
|
1203
|
+
|
|
1204
|
+
let data = await reader(process.cwd() + "/src/" + name)
|
|
1205
|
+
if (name.includes('.jsx')) {
|
|
1206
|
+
data = Compiler(data, process.cwd() + "/src/" + name);
|
|
1207
|
+
|
|
1208
|
+
await writer(process.cwd() + "/dist/src/" + name.split('.jsx').join('.js'), data).then(async () => {
|
|
1209
|
+
await writer(process.cwd() + "/dist/src/" + name.replace('.jsx', '.js'), data)
|
|
1210
|
+
|
|
1211
|
+
})
|
|
1212
|
+
return
|
|
1213
|
+
}
|
|
1214
|
+
bundleSize += fs.statSync(process.cwd() + "/src/" + name).size;
|
|
1215
|
+
await writer(process.cwd() + "/dist/src/" + name, data);
|
|
1216
|
+
})
|
|
1217
|
+
|
|
1218
|
+
const scannedPublicFiles = await glob("**/**.{css,js,html,mjs,cjs}", {
|
|
1219
|
+
ignore: ["node_modules/**/*", "dist/**/*"],
|
|
1220
|
+
cwd: process.cwd() + '/public/',
|
|
1221
|
+
absolute: true,
|
|
1222
|
+
});
|
|
1223
|
+
scannedPublicFiles.forEach(async (file) => {
|
|
1224
|
+
file = file.replace(/\\/g, '/');
|
|
1225
|
+
file = file.split('/public/')[1]
|
|
1226
|
+
let data = await reader(process.cwd() + "/public/" + file)
|
|
1227
|
+
bundleSize += fs.statSync(process.cwd() + "/public/" + file).size;
|
|
1228
|
+
await writer(process.cwd() + "/dist/public/" + file, data);
|
|
1229
|
+
})
|
|
1230
|
+
const scannedFiles = await glob("**/**.{css,js,html}", {
|
|
1231
|
+
ignore: ["node_modules/**/*", "dist/**/*"],
|
|
1232
|
+
cwd: process.cwd() + "/runtime/",
|
|
1233
|
+
absolute: true,
|
|
1234
|
+
})
|
|
1235
|
+
|
|
1236
|
+
|
|
1237
|
+
if (!fs.existsSync(process.cwd() + "/dist/index.html")) {
|
|
1238
|
+
|
|
1239
|
+
scannedFiles.forEach(async (file) => {
|
|
1240
|
+
file = file.split(process.cwd() + '/runtime/')[1]
|
|
1241
|
+
|
|
1242
|
+
let objCase = {
|
|
1243
|
+
...file == "app.js" ? { exit: true } : null,
|
|
1244
|
+
...file.includes("index.html") && fs.existsSync(process.cwd() + "/dist/" + file) ? { exit: true } : null,
|
|
1245
|
+
|
|
1246
|
+
}
|
|
1247
|
+
if (objCase.exit) {
|
|
1248
|
+
console.log('exiting')
|
|
1249
|
+
return true
|
|
1250
|
+
}
|
|
1251
|
+
bundleSize += fs.statSync(process.cwd() + "/node_modules/vaderjs/runtime/" + file).size;
|
|
1252
|
+
let data = await reader(process.cwd() + "/node_modules/vaderjs/runtime/" + file)
|
|
1253
|
+
await writer(process.cwd() + "/dist/" + file, data);
|
|
1254
|
+
});
|
|
1255
|
+
|
|
1314
1256
|
}
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1257
|
+
|
|
1258
|
+
globalThis.isBuilding = false
|
|
1259
|
+
console.log(`📦 Build completed: Build Size -> ${Math.round(bundleSize / 1000)}kb`)
|
|
1260
|
+
|
|
1261
|
+
bundleSize = 0;
|
|
1262
|
+
|
|
1263
|
+
return true
|
|
1264
|
+
}
|
|
1265
|
+
const s = () => {
|
|
1266
|
+
|
|
1267
|
+
const server = http.createServer((req, res) => {
|
|
1268
|
+
|
|
1269
|
+
const validExtensions = ['.js', '.css', '.mjs', '.cjs', '.html', '.json', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.mp4', '.webm', '.ogg'];
|
|
1270
|
+
|
|
1271
|
+
if (!validExtensions.some(ext => req.url.endsWith(ext))) {
|
|
1272
|
+
req.url = req.url !== '/' ? req.url.split('/')[1] : req.url;
|
|
1273
|
+
req.url = path.join(process.cwd(), 'dist', req.url, 'index.html');
|
|
1274
|
+
} else {
|
|
1275
|
+
req.url = path.join(process.cwd(), 'dist', req.url);
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
const filePath = req.url
|
|
1279
|
+
|
|
1280
|
+
fs.readFile(filePath, (err, data) => {
|
|
1281
|
+
if (err) {
|
|
1282
|
+
res.writeHead(404, { 'Content-Type': 'text/html' });
|
|
1283
|
+
res.end(fs.existsSync(process.cwd() + '/dist/404') ? fs.readFileSync(process.cwd() + '/dist/404/index.html') : '404');
|
|
1284
|
+
} else {
|
|
1285
|
+
const contentType = getContentType(filePath);
|
|
1286
|
+
switch (true) {
|
|
1287
|
+
case contentType === 'text/html' && globalThis.devMode:
|
|
1288
|
+
data = data.toString() + `<script type="module">
|
|
1289
|
+
let ws = new WebSocket('ws://localhost:${process.env.PORT || 3000}')
|
|
1290
|
+
ws.onmessage = (e) => {
|
|
1291
|
+
if(e.data === 'reload'){
|
|
1292
|
+
window.location.reload()
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
</script>
|
|
1296
|
+
`
|
|
1322
1297
|
}
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1298
|
+
res.writeHead(200, { 'Content-Type': contentType });
|
|
1299
|
+
res.end(data);
|
|
1300
|
+
}
|
|
1301
|
+
});
|
|
1302
|
+
});
|
|
1327
1303
|
|
|
1328
|
-
data = await handletemplate(new Function(`return \`${data}\`;`)());
|
|
1329
1304
|
|
|
1330
|
-
|
|
1331
|
-
|
|
1305
|
+
const ws = new WebSocketServer({ server });
|
|
1306
|
+
ws.on('connection', (socket) => {
|
|
1307
|
+
console.log('WebSocket Hydration Client connected');
|
|
1308
|
+
socket.on('close', () => console.log('WebSocket Hydration Client disconnected'));
|
|
1309
|
+
});
|
|
1310
|
+
|
|
1311
|
+
|
|
1312
|
+
function getContentType(filePath) {
|
|
1313
|
+
let ext = ['.js', '.css', '.mjs', '.cjs', '.html', '.json', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.mp4', '.webm', '.ogg'].includes(path.extname(filePath)) ? path.extname(filePath) : '.html'
|
|
1314
|
+
switch (ext) {
|
|
1315
|
+
case '.js':
|
|
1316
|
+
return 'text/javascript';
|
|
1317
|
+
case '.css':
|
|
1318
|
+
return 'text/css';
|
|
1319
|
+
case '.mjs':
|
|
1320
|
+
return 'text/javascript';
|
|
1321
|
+
case '.cjs':
|
|
1322
|
+
return 'text/javascript';
|
|
1323
|
+
case '.html':
|
|
1324
|
+
return 'text/html';
|
|
1325
|
+
case '.json':
|
|
1326
|
+
return 'application/json';
|
|
1327
|
+
case '.png':
|
|
1328
|
+
return 'image/png';
|
|
1329
|
+
case '.jpg':
|
|
1330
|
+
return 'image/jpg';
|
|
1331
|
+
case '.jpeg':
|
|
1332
|
+
return 'image/jpeg';
|
|
1333
|
+
case '.gif':
|
|
1334
|
+
return 'image/gif';
|
|
1335
|
+
case '.svg':
|
|
1336
|
+
return 'image/svg+xml';
|
|
1337
|
+
case '.mp4':
|
|
1338
|
+
return 'video/mp4';
|
|
1339
|
+
case '.webm':
|
|
1340
|
+
return 'video/webm';
|
|
1341
|
+
case '.ogg':
|
|
1342
|
+
return 'video/ogg';
|
|
1343
|
+
default:
|
|
1344
|
+
return 'application/octet-stream';
|
|
1345
|
+
}
|
|
1332
1346
|
}
|
|
1333
|
-
};
|
|
1334
1347
|
|
|
1335
|
-
|
|
1348
|
+
const PORT = process.env.PORT || 3000;
|
|
1349
|
+
server.listen(PORT, () => {
|
|
1350
|
+
console.log(`Server is running on port ${PORT}`);
|
|
1351
|
+
});
|
|
1352
|
+
let i =
|
|
1353
|
+
setInterval(() => {
|
|
1354
|
+
if (globalThis.isBuilding && globalThis.devMode) {
|
|
1355
|
+
|
|
1356
|
+
ws.clients.forEach((client) => {
|
|
1357
|
+
client.send('reload')
|
|
1358
|
+
})
|
|
1359
|
+
} else {
|
|
1360
|
+
clearInterval(i)
|
|
1361
|
+
}
|
|
1362
|
+
}, 120)
|
|
1363
|
+
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
|
|
1367
|
+
switch (true) {
|
|
1368
|
+
case process.argv.includes('--watch') && !process.argv.includes('--build') && !process.argv.includes('--serve'):
|
|
1369
|
+
|
|
1370
|
+
globalThis.devMode = true
|
|
1371
|
+
console.log(`
|
|
1372
|
+
Vader.js v1.3.3
|
|
1373
|
+
- Watching for changes in ./pages
|
|
1374
|
+
- Watching for changes in ./src
|
|
1375
|
+
- Watching for changes in ./public
|
|
1376
|
+
`)
|
|
1377
|
+
!globalThis.isBuilding ? Build() : null
|
|
1378
|
+
|
|
1379
|
+
|
|
1380
|
+
Array.from(Array(3).keys()).forEach((i) => {
|
|
1381
|
+
let p = `${process.cwd()}${i == 0 ? '/pages/' : i == 1 ? '/src/' : '/public/'}`
|
|
1382
|
+
watch(p
|
|
1383
|
+
, { recursive: true }, (event, filename) => {
|
|
1384
|
+
if (event == 'change'
|
|
1385
|
+
&& !globalThis.isBuilding
|
|
1386
|
+
) {
|
|
1387
|
+
|
|
1388
|
+
Build()
|
|
1389
|
+
}
|
|
1390
|
+
}).on('error', (err) => console.log(err))
|
|
1391
|
+
})
|
|
1392
|
+
let p = process.argv[process.argv.indexOf('--watch') + 1] || process.env.PORT || 3000
|
|
1393
|
+
|
|
1394
|
+
process.env.PORT = p
|
|
1395
|
+
s()
|
|
1396
|
+
|
|
1397
|
+
globalThis.listen = true;
|
|
1398
|
+
|
|
1399
|
+
break;
|
|
1400
|
+
case process.argv.includes('--build') && !process.argv.includes('--watch') && !process.argv.includes('--serve'):
|
|
1401
|
+
globalThis.devMode = false
|
|
1402
|
+
console.log(`
|
|
1403
|
+
Vader.js v1.3.3
|
|
1404
|
+
Building to ./dist
|
|
1405
|
+
`)
|
|
1406
|
+
Build()
|
|
1407
|
+
|
|
1408
|
+
break;
|
|
1409
|
+
case process.argv.includes('--serve') && !process.argv.includes('--watch') && !process.argv.includes('--build'):
|
|
1410
|
+
let port = process.argv[process.argv.indexOf('--serve') + 1] || 3000
|
|
1411
|
+
process.env.PORT = port
|
|
1412
|
+
globalThis.devMode = false
|
|
1413
|
+
console.log(`
|
|
1414
|
+
Vader.js v1.3.3
|
|
1415
|
+
Serving ./dist on port ${port}
|
|
1416
|
+
url: http://localhost:${port}
|
|
1417
|
+
`)
|
|
1418
|
+
s()
|
|
1419
|
+
break;
|
|
1420
|
+
default:
|
|
1421
|
+
console.log(`
|
|
1422
|
+
Vader.js is a reactive framework for building interactive applications for the web built ontop of bun.js!
|
|
1423
|
+
|
|
1424
|
+
Usage: vader <command>
|
|
1425
|
+
|
|
1426
|
+
Commands:
|
|
1427
|
+
--watch (port) Watch the pages folder for changes with hot reloading
|
|
1428
|
+
|
|
1429
|
+
--build Build the project to ./dist
|
|
1430
|
+
|
|
1431
|
+
--serve (400) Serve the project on a port (default 3000 or process.env.PORT)
|
|
1432
|
+
|
|
1433
|
+
Learn more about vader: https://vader-js.pages.dev/
|
|
1434
|
+
|
|
1435
|
+
`)
|
|
1436
|
+
break;
|
|
1437
|
+
|
|
1438
|
+
}
|