revojs 0.0.2 → 0.0.4
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/dist/app/index.d.ts +18 -22
- package/dist/hooks/index.d.ts +9 -0
- package/dist/html/index.d.ts +30 -15
- package/dist/http/index.d.ts +37 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +476 -202
- package/dist/jsx/index.d.ts +361 -2
- package/dist/jsx/index.js +90 -1
- package/dist/markdown/index.d.ts +2 -2
- package/dist/presets/bun.js +6 -1
- package/dist/presets/cloudflare.d.ts +1 -1
- package/dist/presets/cloudflare.js +6 -1
- package/dist/router/index.d.ts +1 -1
- package/dist/runtime/index.d.ts +16 -15
- package/dist/signals/index.d.ts +21 -15
- package/dist/types/index.d.ts +4 -0
- package/package.json +3 -3
- package/dist/event/index.d.ts +0 -19
package/dist/index.js
CHANGED
|
@@ -1,118 +1,226 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { defu } from "defu";
|
|
2
2
|
import { h } from "revojs/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/app/index.ts
|
|
5
|
-
const
|
|
6
|
-
return await import("#virtual/
|
|
5
|
+
const getRoutes = async () => {
|
|
6
|
+
return await import("#virtual/routes").then((module) => module.index);
|
|
7
|
+
};
|
|
8
|
+
const getAssets = async () => {
|
|
9
|
+
return await import("#virtual/assets").then((module) => module.index);
|
|
7
10
|
};
|
|
8
11
|
const createApp = (config) => {
|
|
9
12
|
return {
|
|
10
|
-
config: defu
|
|
13
|
+
config: defu(config, {
|
|
11
14
|
client: { entry: "./index.html" },
|
|
12
15
|
server: { entry: "revojs/presets/node" },
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
type: "static",
|
|
16
|
-
source: "./dist/client",
|
|
17
|
-
include: ["**/*.*"]
|
|
18
|
-
},
|
|
19
|
-
routes: {
|
|
20
|
-
type: "asset",
|
|
21
|
-
source: "./routes",
|
|
22
|
-
include: [
|
|
23
|
-
"**/*.js",
|
|
24
|
-
"**/*.ts",
|
|
25
|
-
"**/*.jsx",
|
|
26
|
-
"**/*.tsx"
|
|
27
|
-
]
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
markdown: {}
|
|
16
|
+
markdown: {},
|
|
17
|
+
dev: { middleware: [] }
|
|
31
18
|
}),
|
|
32
19
|
virtuals: {}
|
|
33
20
|
};
|
|
34
21
|
};
|
|
35
22
|
|
|
36
23
|
//#endregion
|
|
37
|
-
//#region src/
|
|
38
|
-
const
|
|
39
|
-
return
|
|
40
|
-
request,
|
|
41
|
-
response: { headers: new Headers() },
|
|
42
|
-
context
|
|
43
|
-
};
|
|
24
|
+
//#region src/types/index.ts
|
|
25
|
+
const descriptor = (descriptor$1) => {
|
|
26
|
+
return (typeof descriptor$1 === "object" ? descriptor$1.key : descriptor$1).toString();
|
|
44
27
|
};
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
28
|
+
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/hooks/index.ts
|
|
31
|
+
var Hooks = class {
|
|
32
|
+
hooks;
|
|
33
|
+
constructor() {
|
|
34
|
+
this.hooks = new Map();
|
|
35
|
+
}
|
|
36
|
+
on = (scope, input, invoke) => {
|
|
37
|
+
const key = descriptor(input);
|
|
38
|
+
const invokes = this.hooks.get(key) ?? new Set();
|
|
39
|
+
invokes.add(invoke);
|
|
40
|
+
this.hooks.set(key, invokes);
|
|
41
|
+
return scope.dispose.push(() => invokes.delete(invoke));
|
|
42
|
+
};
|
|
43
|
+
dispatch = (input, value) => {
|
|
44
|
+
const invokes = this.hooks.get(descriptor(input));
|
|
45
|
+
if (invokes) for (const invoke of invokes) invoke(value);
|
|
46
|
+
};
|
|
51
47
|
};
|
|
52
|
-
const
|
|
53
|
-
return
|
|
48
|
+
const defineHook = (description) => {
|
|
49
|
+
return { key: Symbol(description) };
|
|
54
50
|
};
|
|
55
|
-
|
|
56
|
-
|
|
51
|
+
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region src/jsx/index.ts
|
|
54
|
+
const svgElements = new Set([
|
|
55
|
+
"altGlyph",
|
|
56
|
+
"altGlyphDef",
|
|
57
|
+
"altGlyphItem",
|
|
58
|
+
"animate",
|
|
59
|
+
"animateColor",
|
|
60
|
+
"animateMotion",
|
|
61
|
+
"animateTransform",
|
|
62
|
+
"circle",
|
|
63
|
+
"clipPath",
|
|
64
|
+
"color-profile",
|
|
65
|
+
"cursor",
|
|
66
|
+
"defs",
|
|
67
|
+
"desc",
|
|
68
|
+
"ellipse",
|
|
69
|
+
"feBlend",
|
|
70
|
+
"feColorMatrix",
|
|
71
|
+
"feComponentTransfer",
|
|
72
|
+
"feComposite",
|
|
73
|
+
"feConvolveMatrix",
|
|
74
|
+
"feDiffuseLighting",
|
|
75
|
+
"feDisplacementMap",
|
|
76
|
+
"feDistantLight",
|
|
77
|
+
"feDropShadow",
|
|
78
|
+
"feFlood",
|
|
79
|
+
"feFuncA",
|
|
80
|
+
"feFuncB",
|
|
81
|
+
"feFuncG",
|
|
82
|
+
"feFuncR",
|
|
83
|
+
"feGaussianBlur",
|
|
84
|
+
"feImage",
|
|
85
|
+
"feMerge",
|
|
86
|
+
"feMergeNode",
|
|
87
|
+
"feMorphology",
|
|
88
|
+
"feOffset",
|
|
89
|
+
"fePointLight",
|
|
90
|
+
"feSpecularLighting",
|
|
91
|
+
"feSpotLight",
|
|
92
|
+
"feTile",
|
|
93
|
+
"feTurbulence",
|
|
94
|
+
"filter",
|
|
95
|
+
"font",
|
|
96
|
+
"font-face",
|
|
97
|
+
"font-face-format",
|
|
98
|
+
"font-face-name",
|
|
99
|
+
"font-face-src",
|
|
100
|
+
"font-face-uri",
|
|
101
|
+
"foreignObject",
|
|
102
|
+
"g",
|
|
103
|
+
"glyph",
|
|
104
|
+
"glyphRef",
|
|
105
|
+
"hkern",
|
|
106
|
+
"image",
|
|
107
|
+
"line",
|
|
108
|
+
"linearGradient",
|
|
109
|
+
"marker",
|
|
110
|
+
"mask",
|
|
111
|
+
"metadata",
|
|
112
|
+
"missing-glyph",
|
|
113
|
+
"mpath",
|
|
114
|
+
"path",
|
|
115
|
+
"pattern",
|
|
116
|
+
"polygon",
|
|
117
|
+
"polyline",
|
|
118
|
+
"radialGradient",
|
|
119
|
+
"rect",
|
|
120
|
+
"set",
|
|
121
|
+
"stop",
|
|
122
|
+
"svg",
|
|
123
|
+
"switch",
|
|
124
|
+
"symbol",
|
|
125
|
+
"text",
|
|
126
|
+
"textPath",
|
|
127
|
+
"tref",
|
|
128
|
+
"tspan",
|
|
129
|
+
"use",
|
|
130
|
+
"view",
|
|
131
|
+
"vkern"
|
|
132
|
+
]);
|
|
133
|
+
const namespace = (tag) => {
|
|
134
|
+
return svgElements.has(tag) ? "http://www.w3.org/2000/svg" : "http://www.w3.org/1999/xhtml";
|
|
57
135
|
};
|
|
58
136
|
|
|
59
137
|
//#endregion
|
|
60
138
|
//#region src/signals/index.ts
|
|
139
|
+
var Scope = class {
|
|
140
|
+
dispose;
|
|
141
|
+
constructor() {
|
|
142
|
+
this.dispose = new Array();
|
|
143
|
+
}
|
|
144
|
+
stop() {
|
|
145
|
+
while (this.dispose.length) this.dispose.pop()?.(this);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
var Compute = class extends Scope {
|
|
149
|
+
scope;
|
|
150
|
+
invoke;
|
|
151
|
+
constructor(scope, invoke) {
|
|
152
|
+
super();
|
|
153
|
+
this.scope = scope;
|
|
154
|
+
this.invoke = invoke;
|
|
155
|
+
}
|
|
156
|
+
run() {
|
|
157
|
+
this.stop();
|
|
158
|
+
return this.invoke(this);
|
|
159
|
+
}
|
|
160
|
+
};
|
|
61
161
|
var Handler = class Handler {
|
|
62
|
-
get
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
162
|
+
get(target, key) {
|
|
163
|
+
const compute = activeCompute;
|
|
164
|
+
if (compute) {
|
|
165
|
+
const computes = targets.get(target) ?? new Map();
|
|
166
|
+
const set = computes.get(key) ?? new Set();
|
|
167
|
+
computes.set(key, set.add(compute));
|
|
168
|
+
targets.set(target, computes);
|
|
169
|
+
compute.scope.dispose.push(() => {
|
|
170
|
+
compute.stop();
|
|
171
|
+
set.delete(compute);
|
|
172
|
+
});
|
|
69
173
|
}
|
|
70
|
-
const value = Reflect.get(target,
|
|
71
|
-
if (value
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
set = (target, path, value) => {
|
|
75
|
-
const result = Reflect.set(target, path, value);
|
|
76
|
-
for (const effect of targets.get(target)?.get(path) ?? []) {
|
|
77
|
-
while (effect.cleanUps.length) effect.cleanUps.pop()?.(effect);
|
|
78
|
-
effect.invoke();
|
|
174
|
+
const value = Reflect.get(target, key);
|
|
175
|
+
if (value) {
|
|
176
|
+
if (typeof value === "function") return value.bind(target);
|
|
177
|
+
if (typeof value === "object") return new Proxy(value, new Handler());
|
|
79
178
|
}
|
|
179
|
+
return value;
|
|
180
|
+
}
|
|
181
|
+
set(target, key, value) {
|
|
182
|
+
const result = Reflect.set(target, key, value);
|
|
183
|
+
for (const compute of targets.get(target)?.get(key) ?? []) compute.run();
|
|
80
184
|
return result;
|
|
81
|
-
}
|
|
185
|
+
}
|
|
82
186
|
};
|
|
83
|
-
|
|
187
|
+
function createState(value) {
|
|
84
188
|
return new Proxy({ value }, new Handler());
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
cleanUps: []
|
|
90
|
-
});
|
|
91
|
-
};
|
|
92
|
-
const runCompute = (compute) => {
|
|
93
|
-
compute.previous = runningCompute;
|
|
94
|
-
runningCompute = compute;
|
|
189
|
+
}
|
|
190
|
+
function createCompute(scope, invoke) {
|
|
191
|
+
let previous = activeCompute;
|
|
192
|
+
activeCompute = new Compute(scope, invoke);
|
|
95
193
|
try {
|
|
96
|
-
return
|
|
194
|
+
return invoke(activeCompute);
|
|
97
195
|
} finally {
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
const fromValue = (value) => {
|
|
102
|
-
if (value) {
|
|
103
|
-
if (value instanceof Function) return fromValue(value());
|
|
104
|
-
if (value instanceof Object) return value.value;
|
|
196
|
+
activeCompute = previous;
|
|
105
197
|
}
|
|
198
|
+
}
|
|
199
|
+
function createMemo(scope, invoke) {
|
|
200
|
+
let state;
|
|
201
|
+
const compute = createCompute(scope, () => {
|
|
202
|
+
const value = invoke();
|
|
203
|
+
if (typeof state === "object") state.value = value;
|
|
204
|
+
return value;
|
|
205
|
+
});
|
|
206
|
+
state = createState(compute);
|
|
207
|
+
return state;
|
|
208
|
+
}
|
|
209
|
+
function fromValue(value) {
|
|
210
|
+
if (value instanceof Function) return fromValue(value());
|
|
106
211
|
return value;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
runningCompute?.cleanUps.push(cleanUp);
|
|
110
|
-
};
|
|
212
|
+
}
|
|
213
|
+
let activeCompute;
|
|
111
214
|
const targets = new WeakMap();
|
|
112
|
-
let runningCompute;
|
|
113
215
|
|
|
114
216
|
//#endregion
|
|
115
217
|
//#region src/html/index.ts
|
|
218
|
+
const isTemplate = (value) => {
|
|
219
|
+
return "tag" in value && "attributes" in value && "children" in value;
|
|
220
|
+
};
|
|
221
|
+
const defineContext = (description) => {
|
|
222
|
+
return { key: Symbol(description) };
|
|
223
|
+
};
|
|
116
224
|
const createElement = (input, attributes, ...children) => {
|
|
117
225
|
return {
|
|
118
226
|
tag: typeof input === "function" ? input.$name : input,
|
|
@@ -132,58 +240,107 @@ const toString = (slot) => {
|
|
|
132
240
|
default: return "";
|
|
133
241
|
}
|
|
134
242
|
};
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if (
|
|
147
|
-
const
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
243
|
+
const toFragment = (nodes) => {
|
|
244
|
+
const fragment = document.createDocumentFragment();
|
|
245
|
+
fragment.replaceChildren(...nodes);
|
|
246
|
+
return fragment;
|
|
247
|
+
};
|
|
248
|
+
const renderToString = async (slot, context) => {
|
|
249
|
+
if (slot) {
|
|
250
|
+
if (typeof slot === "number" || typeof slot === "bigint" || typeof slot === "boolean" || typeof slot === "string" || typeof slot === "symbol") return slot.toString();
|
|
251
|
+
if (typeof slot === "function") return await renderToString(await slot(), context);
|
|
252
|
+
if (typeof slot === "object") {
|
|
253
|
+
if (Array.isArray(slot)) return await Promise.all(slot.map((slot$1) => renderToString(slot$1, context))).then((chunks) => chunks.join(""));
|
|
254
|
+
if (isTemplate(slot)) {
|
|
255
|
+
const customElement = components.get(slot.tag);
|
|
256
|
+
const prefix = Object.entries(slot.attributes).reduce((chunks, [name, value]) => {
|
|
257
|
+
if (!name.startsWith("on")) chunks.push(`${name}='${toString(value)}'`);
|
|
258
|
+
return chunks;
|
|
259
|
+
}, [slot.tag]).join(" ");
|
|
260
|
+
const children = await renderToString(slot.children, context);
|
|
261
|
+
if (customElement) {
|
|
262
|
+
const element = new customElement(slot.attributes, context);
|
|
263
|
+
const template = await renderToString(await element.setup(), context);
|
|
264
|
+
if (element.shadowRoot) {
|
|
265
|
+
const shadow = await renderToString({
|
|
266
|
+
tag: "template",
|
|
267
|
+
attributes: { shadowRootMode: element.shadowRoot.mode },
|
|
268
|
+
children: [template]
|
|
269
|
+
}, context);
|
|
270
|
+
return `<${prefix}>` + shadow + children + `</${slot.tag}>`;
|
|
271
|
+
}
|
|
272
|
+
return `<${prefix}>` + template + children + `</${slot.tag}>`;
|
|
273
|
+
}
|
|
274
|
+
return `<${prefix}>` + children + `</${slot.tag}>`;
|
|
151
275
|
}
|
|
152
|
-
return
|
|
276
|
+
return JSON.stringify(slot);
|
|
153
277
|
}
|
|
154
|
-
return toString(slot);
|
|
155
278
|
}
|
|
156
|
-
return "";
|
|
157
|
-
};
|
|
158
|
-
const
|
|
159
|
-
if (
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
279
|
+
return "<!---->";
|
|
280
|
+
};
|
|
281
|
+
const renderToNode = async (scope, slot) => {
|
|
282
|
+
if (slot) {
|
|
283
|
+
if (typeof slot === "number" || typeof slot === "bigint" || typeof slot === "boolean" || typeof slot === "string" || typeof slot === "symbol") return document.createTextNode(slot.toString());
|
|
284
|
+
if (typeof slot === "function") {
|
|
285
|
+
let node;
|
|
286
|
+
await createCompute(scope, async (scope$1) => {
|
|
287
|
+
let next;
|
|
288
|
+
let input = slot;
|
|
289
|
+
let parentNode = Array.isArray(node) ? node.at(0)?.parentNode : node?.parentNode;
|
|
290
|
+
while (typeof input === "function") input = await input();
|
|
291
|
+
if (Array.isArray(input)) if (input.length) next = await Promise.all(input.map((child) => renderToNode(scope$1, child)));
|
|
292
|
+
else next = document.createComment("");
|
|
293
|
+
else next = await renderToNode(scope$1, input);
|
|
294
|
+
if (Array.isArray(next)) if (Array.isArray(node)) {
|
|
295
|
+
if (parentNode) {
|
|
296
|
+
const range = document.createRange();
|
|
297
|
+
const firstNode = node.at(0);
|
|
298
|
+
if (firstNode) range.setStartBefore(firstNode);
|
|
299
|
+
const lastNode = node.at(-1);
|
|
300
|
+
if (lastNode) range.setEndAfter(lastNode);
|
|
301
|
+
range.deleteContents();
|
|
302
|
+
for (const child of next) parentNode?.appendChild(child);
|
|
303
|
+
}
|
|
304
|
+
} else node?.parentNode?.replaceChild(toFragment(next), node);
|
|
305
|
+
else if (Array.isArray(node)) {
|
|
306
|
+
if (parentNode) {
|
|
307
|
+
const range = document.createRange();
|
|
308
|
+
const firstNode = node.at(0);
|
|
309
|
+
if (firstNode) range.setStartBefore(firstNode);
|
|
310
|
+
const lastNode = node.at(-1);
|
|
311
|
+
if (lastNode) range.setEndAfter(lastNode);
|
|
312
|
+
range.deleteContents();
|
|
313
|
+
parentNode?.appendChild(next);
|
|
314
|
+
}
|
|
315
|
+
} else node?.parentNode?.replaceChild(next, node);
|
|
316
|
+
node = next;
|
|
317
|
+
});
|
|
318
|
+
if (Array.isArray(node)) return toFragment(node);
|
|
319
|
+
return node ?? document.createComment("");
|
|
320
|
+
}
|
|
321
|
+
if (typeof slot === "object") {
|
|
322
|
+
if (Array.isArray(slot)) {
|
|
323
|
+
if (slot.length) {
|
|
324
|
+
const children = await Promise.all(slot.map((child) => renderToNode(scope, child)));
|
|
325
|
+
return toFragment(children);
|
|
326
|
+
}
|
|
327
|
+
return document.createComment("");
|
|
328
|
+
}
|
|
329
|
+
if (isTemplate(slot)) {
|
|
330
|
+
const element = document.createElementNS(namespace(slot.tag), slot.tag);
|
|
331
|
+
for (const name in slot.attributes) {
|
|
332
|
+
const value = slot.attributes[name];
|
|
333
|
+
if (value) if (name.startsWith("on") && typeof value === "function") {
|
|
334
|
+
const event = name.substring(2).toLowerCase();
|
|
335
|
+
const controller = new AbortController();
|
|
336
|
+
element.addEventListener(event, value, { signal: controller.signal });
|
|
337
|
+
scope.dispose.push(() => controller.abort());
|
|
338
|
+
} else createCompute(scope, () => element.setAttribute(name, toString(value)));
|
|
339
|
+
}
|
|
340
|
+
element.replaceChildren(await renderToNode(scope, slot.children));
|
|
341
|
+
return element;
|
|
184
342
|
}
|
|
185
|
-
|
|
186
|
-
return node;
|
|
343
|
+
return document.createTextNode(JSON.stringify(slot));
|
|
187
344
|
}
|
|
188
345
|
}
|
|
189
346
|
return document.createComment("");
|
|
@@ -193,47 +350,64 @@ const defineComponent = (options) => {
|
|
|
193
350
|
static $name = options.name;
|
|
194
351
|
static $events = options.events ?? {};
|
|
195
352
|
static $attributes = options.attributes ?? {};
|
|
353
|
+
scope;
|
|
354
|
+
hooks;
|
|
196
355
|
events;
|
|
197
356
|
attributes;
|
|
198
357
|
shadowRoot;
|
|
199
|
-
|
|
358
|
+
context;
|
|
359
|
+
host;
|
|
360
|
+
constructor(input, context, host) {
|
|
361
|
+
this.scope = new Scope();
|
|
362
|
+
this.hooks = new Hooks();
|
|
200
363
|
this.events = Object.keys(options.events ?? {}).reduce((output, name) => {
|
|
201
364
|
Reflect.set(output, name, input?.[name], output);
|
|
202
365
|
return output;
|
|
203
366
|
}, {});
|
|
204
|
-
this.attributes = Object.entries(options.attributes ?? {}).reduce((
|
|
205
|
-
Reflect.set(
|
|
206
|
-
return
|
|
367
|
+
this.attributes = Object.entries(options.attributes ?? {}).reduce((attributes, [name, attribute]) => {
|
|
368
|
+
Reflect.set(attributes.value, name, fromValue(input?.[name]) ?? attribute.default, attributes.value);
|
|
369
|
+
return attributes;
|
|
207
370
|
}, createState({}));
|
|
208
371
|
this.shadowRoot = options.shadowRoot ?? { mode: "open" };
|
|
372
|
+
this.context = context ?? {};
|
|
373
|
+
this.host = host;
|
|
209
374
|
}
|
|
375
|
+
getContext = (input) => {
|
|
376
|
+
return this.context[descriptor(input)] ?? {};
|
|
377
|
+
};
|
|
378
|
+
setContext = (input, value) => {
|
|
379
|
+
this.context[descriptor(input)] = value;
|
|
380
|
+
};
|
|
381
|
+
onMounted = (invoke) => {
|
|
382
|
+
return this.hooks.on(this.scope, MOUNTED_HOOK, invoke);
|
|
383
|
+
};
|
|
210
384
|
setup = () => options.setup(this);
|
|
211
385
|
});
|
|
212
386
|
};
|
|
213
387
|
const toCustomElement = (component) => {
|
|
214
388
|
return class extends HTMLElement {
|
|
389
|
+
static formAssociated = true;
|
|
215
390
|
component;
|
|
216
391
|
constructor() {
|
|
217
392
|
super();
|
|
218
|
-
this.component = new component();
|
|
393
|
+
this.component = new component(undefined, undefined, this);
|
|
219
394
|
}
|
|
220
395
|
async connectedCallback() {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
activeElement = previous;
|
|
234
|
-
}
|
|
396
|
+
const shadow = this.component.shadowRoot ? this.attachShadow(this.component.shadowRoot) : this;
|
|
397
|
+
const parentNode = getCustomElement(this.parentNode);
|
|
398
|
+
for (const [name, event] of Object.entries(component.$events)) Reflect.set(this.component.events, name, (value) => {
|
|
399
|
+
if (value instanceof Event) return;
|
|
400
|
+
this.dispatchEvent(new CustomEvent(name.substring(2).toLowerCase(), {
|
|
401
|
+
...event,
|
|
402
|
+
detail: value
|
|
403
|
+
}));
|
|
404
|
+
}, this.component.events);
|
|
405
|
+
if (parentNode) for (const key in parentNode.component.context) this.component.setContext(key, parentNode.component.context[key]);
|
|
406
|
+
shadow.replaceChildren(await renderToNode(this.component.scope, await this.component.setup()));
|
|
407
|
+
this.component.hooks.dispatch(MOUNTED_HOOK, this);
|
|
235
408
|
}
|
|
236
|
-
attributeChangedCallback(name,
|
|
409
|
+
attributeChangedCallback(name, oldValue, value) {
|
|
410
|
+
if (value === oldValue) return;
|
|
237
411
|
const attribute = component.$attributes?.[name];
|
|
238
412
|
if (attribute) {
|
|
239
413
|
let convertedValue;
|
|
@@ -245,7 +419,7 @@ const toCustomElement = (component) => {
|
|
|
245
419
|
convertedValue = Number(value);
|
|
246
420
|
break;
|
|
247
421
|
case Boolean:
|
|
248
|
-
convertedValue =
|
|
422
|
+
convertedValue = value.toLowerCase() === "true";
|
|
249
423
|
break;
|
|
250
424
|
case Object:
|
|
251
425
|
convertedValue = JSON.parse(value);
|
|
@@ -254,25 +428,19 @@ const toCustomElement = (component) => {
|
|
|
254
428
|
Reflect.set(this.component.attributes.value, name, convertedValue ?? attribute.default, this.component.attributes.value);
|
|
255
429
|
}
|
|
256
430
|
}
|
|
431
|
+
disconnectedCallback() {
|
|
432
|
+
this.component.scope.stop();
|
|
433
|
+
}
|
|
257
434
|
static get observedAttributes() {
|
|
258
435
|
return Object.keys(component.$attributes ?? {});
|
|
259
436
|
}
|
|
260
437
|
};
|
|
261
438
|
};
|
|
262
439
|
const registerComponent = (component) => {
|
|
263
|
-
components.set(component.$name, component);
|
|
440
|
+
if (isServer()) components.set(component.$name, component);
|
|
264
441
|
if (isClient()) customElements.define(component.$name, toCustomElement(component));
|
|
265
442
|
return component;
|
|
266
443
|
};
|
|
267
|
-
const isClient = () => {
|
|
268
|
-
return typeof window !== "undefined";
|
|
269
|
-
};
|
|
270
|
-
const isServer = () => {
|
|
271
|
-
return typeof window === "undefined";
|
|
272
|
-
};
|
|
273
|
-
const addStyles = (...styles) => {
|
|
274
|
-
activeElement?.shadowRoot?.adoptedStyleSheets.push(...styles);
|
|
275
|
-
};
|
|
276
444
|
const getGlobalStyles = () => {
|
|
277
445
|
return Array.from(isServer() ? [] : document.styleSheets).map((style) => {
|
|
278
446
|
const sheet = new CSSStyleSheet();
|
|
@@ -281,21 +449,94 @@ const getGlobalStyles = () => {
|
|
|
281
449
|
return sheet;
|
|
282
450
|
});
|
|
283
451
|
};
|
|
284
|
-
|
|
285
|
-
|
|
452
|
+
const getCustomElement = (node) => {
|
|
453
|
+
if (node) {
|
|
454
|
+
if ("component" in node) return node;
|
|
455
|
+
return getCustomElement(node.parentNode);
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
const isClient = () => typeof window !== "undefined";
|
|
459
|
+
const isServer = () => typeof window === "undefined";
|
|
460
|
+
const preventDefault = (event) => event.preventDefault();
|
|
461
|
+
const stopPropagation = (event) => event.stopPropagation();
|
|
462
|
+
const stopImmediatePropagation = (event) => event.stopImmediatePropagation();
|
|
463
|
+
const MOUNTED_HOOK = defineHook("MOUNTED_HOOK");
|
|
286
464
|
const components = new Map();
|
|
287
465
|
|
|
288
466
|
//#endregion
|
|
289
467
|
//#region src/http/index.ts
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
468
|
+
const createEvent = (request, context) => {
|
|
469
|
+
return {
|
|
470
|
+
request,
|
|
471
|
+
response: { headers: new Headers() },
|
|
472
|
+
context
|
|
473
|
+
};
|
|
474
|
+
};
|
|
475
|
+
const sendText = (event, text) => {
|
|
476
|
+
event.response.headers.set("Content-Type", "text/plain");
|
|
477
|
+
return new Response(text, event.response);
|
|
478
|
+
};
|
|
479
|
+
const sendHtml = (event, text) => {
|
|
480
|
+
event.response.headers.set("Content-Type", "text/html");
|
|
481
|
+
return new Response(text, event.response);
|
|
482
|
+
};
|
|
483
|
+
const sendJson = (event, value) => {
|
|
484
|
+
event.response.headers.set("Content-Type", "application/json");
|
|
485
|
+
return new Response(JSON.stringify(value), event.response);
|
|
486
|
+
};
|
|
487
|
+
const sendRedirect = (event, path) => {
|
|
488
|
+
event.response.status = 302;
|
|
489
|
+
event.response.headers.set("Location", path);
|
|
490
|
+
return new Response(null, event.response);
|
|
491
|
+
};
|
|
492
|
+
const sendBadRequest = (event, text) => {
|
|
493
|
+
event.response.status = 400;
|
|
494
|
+
return new Response(text, event.response);
|
|
495
|
+
};
|
|
496
|
+
const sendUnauthorized = (event) => {
|
|
497
|
+
event.response.status = 401;
|
|
498
|
+
return new Response(null, event.response);
|
|
499
|
+
};
|
|
500
|
+
const getRequestUrl = (event) => {
|
|
501
|
+
return new URL(event instanceof Request ? event.url : event.request.url);
|
|
502
|
+
};
|
|
503
|
+
const getCookies = (event) => {
|
|
504
|
+
const cookies = event.request.headers.get("Cookie")?.split("; ") ?? [];
|
|
505
|
+
return cookies.reduce((result, cookie) => {
|
|
506
|
+
const [name, value] = cookie.split("=");
|
|
507
|
+
if (name && value) result[name] = decodeURIComponent(value);
|
|
508
|
+
return result;
|
|
509
|
+
}, {});
|
|
510
|
+
};
|
|
511
|
+
const getSetCookies = (event) => {
|
|
512
|
+
const cookies = event.request.headers.getSetCookie();
|
|
513
|
+
return cookies.reduce((result, cookie) => {
|
|
514
|
+
const [name, value] = cookie.split("=");
|
|
515
|
+
if (name && value) result[name] = decodeURIComponent(value);
|
|
516
|
+
return result;
|
|
517
|
+
}, {});
|
|
518
|
+
};
|
|
519
|
+
const setCookie = (event, name, value, options) => {
|
|
520
|
+
let cookie = name + "=" + encodeURIComponent(value);
|
|
521
|
+
if (options?.domain) cookie += `; Domain=${options.domain}`;
|
|
522
|
+
if (options?.expires) cookie += `; Expires=${options.expires.toUTCString()}`;
|
|
523
|
+
if (options?.httpOnly) cookie += `; HttpOnly`;
|
|
524
|
+
if (options?.maxAge) cookie += `; Max-Age=${options.maxAge}`;
|
|
525
|
+
if (options?.path) cookie += `; Path=${options.path}`;
|
|
526
|
+
if (options?.priority) cookie += `; Priority=${options.priority}`;
|
|
527
|
+
if (options?.sameSite) cookie += `; SameSite=${options.sameSite}`;
|
|
528
|
+
if (options?.secure) cookie += `; Secure`;
|
|
529
|
+
event.response.headers.append("Set-Cookie", cookie);
|
|
294
530
|
};
|
|
295
531
|
const getMimeType = (file) => {
|
|
296
532
|
const extension = /\.([a-zA-Z0-9]+?)$/.exec(file)?.at(1);
|
|
297
533
|
return mimeTypes[extension ?? ""] ?? "text/plain";
|
|
298
534
|
};
|
|
535
|
+
const mimeTypes = {
|
|
536
|
+
css: "text/css",
|
|
537
|
+
js: "text/javascript",
|
|
538
|
+
txt: "text/plain"
|
|
539
|
+
};
|
|
299
540
|
|
|
300
541
|
//#endregion
|
|
301
542
|
//#region src/markdown/index.ts
|
|
@@ -435,63 +676,96 @@ var Radix = class Radix {
|
|
|
435
676
|
const defineRoute = (route) => {
|
|
436
677
|
return route;
|
|
437
678
|
};
|
|
438
|
-
const defineSocket = (socket) => {
|
|
439
|
-
return socket;
|
|
440
|
-
};
|
|
441
679
|
const fileName = (path) => {
|
|
442
680
|
return path.split("/").pop()?.split(".").slice(0, -1).join(".");
|
|
443
681
|
};
|
|
444
682
|
const toPath = (value) => {
|
|
445
|
-
|
|
683
|
+
const path = (value.startsWith("/") ? value : "/" + value).replaceAll(/\/index/g, "").replaceAll(/\[(.*)\]/g, (_, name) => ":" + name);
|
|
684
|
+
const route = path.startsWith("/") ? path : "/" + path;
|
|
685
|
+
const split = route.split(".");
|
|
686
|
+
return split.length === 3 ? [split.at(0), split.at(1)] : [split.at(0)];
|
|
687
|
+
};
|
|
688
|
+
const $fetch = async (event, input, init) => {
|
|
689
|
+
let response;
|
|
690
|
+
if (event) {
|
|
691
|
+
const url = new URL(input.toString(), event.request.url);
|
|
692
|
+
response = await (await import("#virtual/runtime")).runtime.fetch(new Request(url, init), event.context);
|
|
693
|
+
} else response = await fetch(input, init);
|
|
694
|
+
if (response.ok === false) throw response;
|
|
695
|
+
switch (response.headers.get("Content-Type")) {
|
|
696
|
+
case "application/json": return response.json();
|
|
697
|
+
default: return response;
|
|
698
|
+
}
|
|
699
|
+
};
|
|
700
|
+
const getVariables = (event) => {
|
|
701
|
+
return event ? event.context.variables : import.meta.env;
|
|
446
702
|
};
|
|
447
703
|
const createRuntime = async () => {
|
|
448
704
|
const radix = new Radix();
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
if (route) {
|
|
458
|
-
if ("message" in route) return sendText(event, "WebSocket");
|
|
459
|
-
if ("$name" in route) {
|
|
705
|
+
const middlewares = new Array();
|
|
706
|
+
const routes = await getRoutes();
|
|
707
|
+
for (const path in routes) {
|
|
708
|
+
const [name, method] = toPath(path);
|
|
709
|
+
radix.insert((method ?? "GET").toUpperCase() + name, defineRoute({ fetch: async (event) => {
|
|
710
|
+
const route = await routes[path]?.();
|
|
711
|
+
if (typeof route === "object") return route.fetch(event);
|
|
712
|
+
if (route) {
|
|
460
713
|
const slot = await import("#virtual/client").then((module) => module.index);
|
|
461
|
-
return sendHtml(event, await
|
|
714
|
+
return sendHtml(event, await renderToString(slot, { [descriptor(RUNTIME_CONTEXT)]: { event } }));
|
|
462
715
|
}
|
|
463
|
-
|
|
464
|
-
|
|
716
|
+
} }));
|
|
717
|
+
}
|
|
718
|
+
const assets = await getAssets();
|
|
719
|
+
for (const path in assets) radix.insert("GET/" + path, defineRoute({ fetch: async (event) => {
|
|
720
|
+
event.response.headers.set("Content-Type", getMimeType(path));
|
|
721
|
+
return new Response(await assets[path]?.(), event.response);
|
|
465
722
|
} }));
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
723
|
+
const invoke = (event, next, index) => {
|
|
724
|
+
return middlewares.at(index)?.(event, () => invoke(event, next, index + 1)) ?? next(event);
|
|
725
|
+
};
|
|
726
|
+
return {
|
|
727
|
+
radix,
|
|
728
|
+
middlewares,
|
|
729
|
+
fetch: async (request, context) => {
|
|
730
|
+
const url = getRequestUrl(request);
|
|
731
|
+
const { value: route, inputs } = radix.match(request.method + url.pathname);
|
|
732
|
+
const event = createEvent(request, {
|
|
733
|
+
...context,
|
|
734
|
+
inputs
|
|
735
|
+
});
|
|
736
|
+
try {
|
|
737
|
+
if (route) {
|
|
738
|
+
const response = await invoke(event, route.fetch, 0);
|
|
739
|
+
if (response) return response;
|
|
740
|
+
}
|
|
741
|
+
return sendText(event, "Not found");
|
|
742
|
+
} catch (response) {
|
|
743
|
+
if (response instanceof Response) return response;
|
|
744
|
+
throw response;
|
|
745
|
+
}
|
|
477
746
|
}
|
|
478
|
-
}
|
|
747
|
+
};
|
|
479
748
|
};
|
|
480
|
-
|
|
749
|
+
const RUNTIME_CONTEXT = defineContext("RUNTIME_CONTEXT");
|
|
481
750
|
|
|
482
751
|
//#endregion
|
|
483
752
|
//#region src/router/index.tsx
|
|
484
753
|
const Outlet = defineComponent({
|
|
485
754
|
name: "x-outlet",
|
|
486
|
-
|
|
755
|
+
shadowRoot: false,
|
|
756
|
+
setup: async ({ scope, getContext }) => {
|
|
757
|
+
const { event } = getContext(RUNTIME_CONTEXT);
|
|
487
758
|
const radix = new Radix();
|
|
488
|
-
const routes = await
|
|
489
|
-
for (const path in routes)
|
|
490
|
-
|
|
759
|
+
const routes = await getRoutes();
|
|
760
|
+
for (const path in routes) {
|
|
761
|
+
const [name] = toPath(path);
|
|
762
|
+
if (name) radix.insert(name, routes[path]);
|
|
763
|
+
}
|
|
764
|
+
const url = createState(new URL(event ? event.request.url : window.location.href));
|
|
491
765
|
if (isClient()) {
|
|
492
766
|
const controller = new AbortController();
|
|
493
767
|
window.addEventListener("popstate", () => url.value = new URL(window.location.href), { signal: controller.signal });
|
|
494
|
-
|
|
768
|
+
scope.dispose.push(() => controller.abort());
|
|
495
769
|
}
|
|
496
770
|
return async () => {
|
|
497
771
|
const { value, inputs } = radix.match(url.value.pathname);
|
|
@@ -513,4 +787,4 @@ const anchorNavigate = (event) => {
|
|
|
513
787
|
};
|
|
514
788
|
|
|
515
789
|
//#endregion
|
|
516
|
-
export { Handler, Outlet,
|
|
790
|
+
export { $fetch, Compute, Handler, Hooks, MOUNTED_HOOK, Outlet, RUNTIME_CONTEXT, Radix, Scope, activeCompute, anchorNavigate, components, createApp, createCompute, createElement, createEvent, createMemo, createRuntime, createState, defineComponent, defineContext, defineHook, defineRoute, descriptor, fileName, fromValue, getAssets, getCookies, getCustomElement, getGlobalStyles, getMimeType, getRequestUrl, getRoutes, getSetCookies, getVariables, isClient, isServer, isTemplate, markdownToSlot, navigate, preventDefault, registerComponent, renderToNode, renderToString, sendBadRequest, sendHtml, sendJson, sendRedirect, sendText, sendUnauthorized, setCookie, stopImmediatePropagation, stopPropagation, targets, toCustomElement, toFragment, toPath, toString };
|