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