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