revojs 0.0.62 → 0.0.64
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/html/index.d.ts +3 -3
- package/dist/index.js +400 -395
- package/dist/jsx/index.js +5 -0
- package/dist/locale/index.d.ts +11 -15
- package/dist/presets/bun.js +4 -7
- package/dist/presets/cloudflare.js +4 -7
- package/dist/presets/{runtime-plDYfDhw.js → runtime-Daz6s680.js} +1 -3
- package/dist/router/index.d.ts +13 -17
- package/dist/runtime/index.d.ts +5 -0
- package/package.json +1 -1
- package/src/types/index.d.ts +15 -9
package/dist/html/index.d.ts
CHANGED
|
@@ -47,14 +47,14 @@ export interface ComponentOptions<TEvents extends Events, TAttributes extends At
|
|
|
47
47
|
attributes?: TAttributes;
|
|
48
48
|
shadowRoot?: ShadowRootInit;
|
|
49
49
|
styles?: Array<string>;
|
|
50
|
-
setup: (component: Component<TEvents, TAttributes>) => Slot
|
|
50
|
+
setup: (component: Component<TEvents, TAttributes>) => Slot;
|
|
51
51
|
}
|
|
52
52
|
export interface Component<TEvents extends Events, TAttributes extends Attributes> {
|
|
53
53
|
readonly scope: Scope;
|
|
54
54
|
readonly events: EventOutput<TEvents>;
|
|
55
55
|
readonly attributes: State<AttributeOutput<TAttributes>>;
|
|
56
56
|
readonly shadowRoot?: ShadowRootInit;
|
|
57
|
-
setup: () => Slot
|
|
57
|
+
setup: () => Slot;
|
|
58
58
|
}
|
|
59
59
|
export interface ComponentConstructor<TEvents extends Events, TAttributes extends Attributes> {
|
|
60
60
|
$name: string;
|
|
@@ -81,7 +81,7 @@ export declare const toString: (slot: Slot) => string;
|
|
|
81
81
|
export declare const toArray: (hydration: Hydration) => Array<Node>;
|
|
82
82
|
export declare const toRange: (hydration: Hydration) => Range;
|
|
83
83
|
export declare const toFragment: (hydration: Hydration) => DocumentFragment;
|
|
84
|
-
export declare const hydrate: (scope: Scope, parentNode: Node, slot: Slot, index: number, previous?: Hydration) =>
|
|
84
|
+
export declare const hydrate: (scope: Scope, parentNode: Node, slot: Slot, index: number, previous?: Hydration) => Hydration;
|
|
85
85
|
export declare const renderToString: (scope: Scope, slot: Slot) => Promise<string>;
|
|
86
86
|
export declare const defineComponent: <TEvents extends Events, TAttributes extends Attributes>(options: ComponentOptions<TEvents, TAttributes>) => ComponentConstructor<TEvents, TAttributes>;
|
|
87
87
|
export declare const toCustomElement: <TEvents extends Events, TAttributes extends Attributes>(Component: ComponentConstructor<TEvents, TAttributes>) => CustomElementConstructor<TEvents, TAttributes>;
|
package/dist/index.js
CHANGED
|
@@ -99,6 +99,163 @@ const namespace = (tag) => {
|
|
|
99
99
|
return svgElements.has(tag) ? "http://www.w3.org/2000/svg" : "http://www.w3.org/1999/xhtml";
|
|
100
100
|
};
|
|
101
101
|
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region src/http/index.ts
|
|
104
|
+
const sendText = (scope, text) => {
|
|
105
|
+
const { response } = useRuntime(scope);
|
|
106
|
+
response.headers.set("Content-Type", "text/plain");
|
|
107
|
+
return new Response(text, response);
|
|
108
|
+
};
|
|
109
|
+
const sendHtml = (scope, text) => {
|
|
110
|
+
const { response } = useRuntime(scope);
|
|
111
|
+
response.headers.set("Content-Type", "text/html");
|
|
112
|
+
return new Response(text, response);
|
|
113
|
+
};
|
|
114
|
+
const sendJson = (scope, value) => {
|
|
115
|
+
const { response } = useRuntime(scope);
|
|
116
|
+
response.headers.set("Content-Type", "application/json");
|
|
117
|
+
return new Response(JSON.stringify(value), response);
|
|
118
|
+
};
|
|
119
|
+
const sendRedirect = (scope, path) => {
|
|
120
|
+
const { response } = useRuntime(scope);
|
|
121
|
+
response.status = 302;
|
|
122
|
+
response.headers.set("Location", path);
|
|
123
|
+
return new Response(null, response);
|
|
124
|
+
};
|
|
125
|
+
const sendBadRequest = (scope, text) => {
|
|
126
|
+
const { response } = useRuntime(scope);
|
|
127
|
+
response.status = 400;
|
|
128
|
+
return new Response(text, response);
|
|
129
|
+
};
|
|
130
|
+
const sendUnauthorized = (scope) => {
|
|
131
|
+
const { response } = useRuntime(scope);
|
|
132
|
+
response.status = 401;
|
|
133
|
+
return new Response(null, response);
|
|
134
|
+
};
|
|
135
|
+
const useRequestUrl = (scope, base) => {
|
|
136
|
+
const { request } = useRuntime(scope);
|
|
137
|
+
return new URL(request.url, base);
|
|
138
|
+
};
|
|
139
|
+
const useCookies = (scope) => {
|
|
140
|
+
const { request } = useRuntime(scope);
|
|
141
|
+
return (isClient() ? document.cookie : request.headers.get("Cookie") ?? "").split("; ").reduce((result, cookie) => {
|
|
142
|
+
const [name, value] = cookie.split("=");
|
|
143
|
+
if (name && value) result[name] = decodeURIComponent(value);
|
|
144
|
+
return result;
|
|
145
|
+
}, {});
|
|
146
|
+
};
|
|
147
|
+
const useSetCookies = (scope) => {
|
|
148
|
+
const { request } = useRuntime(scope);
|
|
149
|
+
return request.headers.getSetCookie().reduce((result, cookie) => {
|
|
150
|
+
const [name, value] = cookie.split("=");
|
|
151
|
+
if (name && value) result[name] = decodeURIComponent(value);
|
|
152
|
+
return result;
|
|
153
|
+
}, {});
|
|
154
|
+
};
|
|
155
|
+
const setCookie = (scope, name, value, options) => {
|
|
156
|
+
const { response } = useRuntime(scope);
|
|
157
|
+
let cookie = name + "=" + encodeURIComponent(value);
|
|
158
|
+
if (options?.domain) cookie += `; Domain=${options.domain}`;
|
|
159
|
+
if (options?.expires) cookie += `; Expires=${options.expires.toUTCString()}`;
|
|
160
|
+
if (options?.httpOnly) cookie += `; HttpOnly`;
|
|
161
|
+
if (options?.maxAge) cookie += `; Max-Age=${options.maxAge}`;
|
|
162
|
+
if (options?.path) cookie += `; Path=${options.path}`;
|
|
163
|
+
if (options?.priority) cookie += `; Priority=${options.priority}`;
|
|
164
|
+
if (options?.sameSite) cookie += `; SameSite=${options.sameSite}`;
|
|
165
|
+
if (options?.secure) cookie += `; Secure`;
|
|
166
|
+
if (isClient()) document.cookie = cookie;
|
|
167
|
+
else response.headers.append("Set-Cookie", cookie);
|
|
168
|
+
};
|
|
169
|
+
const mimeType = (file) => {
|
|
170
|
+
const extension = /\.([a-zA-Z0-9]+?)$/.exec(file)?.at(1);
|
|
171
|
+
return mimeTypes[extension ?? ""] ?? "text/plain";
|
|
172
|
+
};
|
|
173
|
+
const mimeTypes = {
|
|
174
|
+
txt: "text/plain",
|
|
175
|
+
css: "text/css",
|
|
176
|
+
html: "text/html",
|
|
177
|
+
htm: "text/html",
|
|
178
|
+
js: "text/javascript",
|
|
179
|
+
json: "application/json",
|
|
180
|
+
xml: "application/xml",
|
|
181
|
+
csv: "text/csv",
|
|
182
|
+
jpg: "image/jpeg",
|
|
183
|
+
jpeg: "image/jpeg",
|
|
184
|
+
png: "image/png",
|
|
185
|
+
gif: "image/gif",
|
|
186
|
+
webp: "image/webp",
|
|
187
|
+
svg: "image/svg+xml",
|
|
188
|
+
bmp: "image/bmp",
|
|
189
|
+
ico: "image/x-icon",
|
|
190
|
+
ttf: "font/ttf",
|
|
191
|
+
otf: "font/otf",
|
|
192
|
+
woff: "font/woff",
|
|
193
|
+
woff2: "font/woff2",
|
|
194
|
+
mp3: "audio/mpeg",
|
|
195
|
+
wav: "audio/wav",
|
|
196
|
+
ogg: "audio/ogg",
|
|
197
|
+
m4a: "audio/mp4",
|
|
198
|
+
mp4: "video/mp4",
|
|
199
|
+
webm: "video/webm",
|
|
200
|
+
ogv: "video/ogg",
|
|
201
|
+
mov: "video/quicktime",
|
|
202
|
+
avi: "video/x-msvideo",
|
|
203
|
+
zip: "application/zip",
|
|
204
|
+
rar: "application/vnd.rar",
|
|
205
|
+
tar: "application/x-tar",
|
|
206
|
+
gz: "application/gzip",
|
|
207
|
+
"7z": "application/x-7z-compressed",
|
|
208
|
+
pdf: "application/pdf",
|
|
209
|
+
doc: "application/msword",
|
|
210
|
+
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
211
|
+
xls: "application/vnd.ms-excel",
|
|
212
|
+
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
213
|
+
ppt: "application/vnd.ms-powerpoint",
|
|
214
|
+
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
215
|
+
exe: "application/vnd.microsoft.portable-executable",
|
|
216
|
+
apk: "application/vnd.android.package-archive"
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
//#endregion
|
|
220
|
+
//#region src/radix/index.ts
|
|
221
|
+
var Radix = class Radix {
|
|
222
|
+
value;
|
|
223
|
+
input;
|
|
224
|
+
children;
|
|
225
|
+
constructor(input) {
|
|
226
|
+
this.input = input;
|
|
227
|
+
this.children = {};
|
|
228
|
+
}
|
|
229
|
+
insert = (path, value) => {
|
|
230
|
+
let node = this;
|
|
231
|
+
for (let segment of path.split("/")) {
|
|
232
|
+
let input;
|
|
233
|
+
if (segment.startsWith(":")) {
|
|
234
|
+
input = segment.substring(1);
|
|
235
|
+
segment = ":";
|
|
236
|
+
}
|
|
237
|
+
let childNode = node.children[segment];
|
|
238
|
+
if (childNode === void 0) {
|
|
239
|
+
childNode = new Radix(input);
|
|
240
|
+
node.children[segment] = childNode;
|
|
241
|
+
}
|
|
242
|
+
node = childNode;
|
|
243
|
+
}
|
|
244
|
+
node.value = value;
|
|
245
|
+
return this;
|
|
246
|
+
};
|
|
247
|
+
match = (path) => {
|
|
248
|
+
let node = this;
|
|
249
|
+
const match = { inputs: {} };
|
|
250
|
+
for (const segment of path.split("/")) {
|
|
251
|
+
node = node?.children[segment] ?? node?.children[":"];
|
|
252
|
+
if (node?.input) match.inputs[node.input] = segment;
|
|
253
|
+
}
|
|
254
|
+
match.value = node?.value;
|
|
255
|
+
return match;
|
|
256
|
+
};
|
|
257
|
+
};
|
|
258
|
+
|
|
102
259
|
//#endregion
|
|
103
260
|
//#region src/signals/index.ts
|
|
104
261
|
var StopEvent = class extends Event {
|
|
@@ -117,9 +274,7 @@ var Scope = class extends EventTarget {
|
|
|
117
274
|
}
|
|
118
275
|
getContext(input) {
|
|
119
276
|
let scope = this;
|
|
120
|
-
|
|
121
|
-
while (scope && !seen.has(scope)) {
|
|
122
|
-
seen.add(scope);
|
|
277
|
+
while (scope) {
|
|
123
278
|
if (scope.context.has(input)) return scope.context.get(input);
|
|
124
279
|
scope = scope.parentScope;
|
|
125
280
|
}
|
|
@@ -184,11 +339,10 @@ function createState(value) {
|
|
|
184
339
|
function createCompute(scope, invoke) {
|
|
185
340
|
let previous = activeCompute;
|
|
186
341
|
activeCompute = new Compute(scope, invoke);
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
342
|
+
const result = invoke(activeCompute);
|
|
343
|
+
if (result instanceof Promise) return result.finally(() => activeCompute = previous);
|
|
344
|
+
activeCompute = previous;
|
|
345
|
+
return result;
|
|
192
346
|
}
|
|
193
347
|
function createMemo(scope, invoke) {
|
|
194
348
|
let state;
|
|
@@ -211,71 +365,186 @@ let activeCompute;
|
|
|
211
365
|
const targets = /* @__PURE__ */ new WeakMap();
|
|
212
366
|
|
|
213
367
|
//#endregion
|
|
214
|
-
//#region src/
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
super("mounted");
|
|
218
|
-
}
|
|
368
|
+
//#region src/runtime/index.ts
|
|
369
|
+
const isRoute = (value) => {
|
|
370
|
+
return !!value && typeof value === "object" && "fetch" in value;
|
|
219
371
|
};
|
|
220
|
-
const
|
|
221
|
-
return
|
|
372
|
+
const useRuntime = (scope) => {
|
|
373
|
+
return scope.getContext(RUNTIME_CONTEXT);
|
|
222
374
|
};
|
|
223
|
-
const
|
|
224
|
-
return
|
|
375
|
+
const useRoute = (scope) => {
|
|
376
|
+
return scope.getContext(ROUTE_CONTEXT);
|
|
225
377
|
};
|
|
226
|
-
const
|
|
227
|
-
return
|
|
378
|
+
const defineRoute = (route) => {
|
|
379
|
+
return route;
|
|
228
380
|
};
|
|
229
|
-
const
|
|
230
|
-
return
|
|
381
|
+
const defineMiddleware = (middleware) => {
|
|
382
|
+
return middleware;
|
|
231
383
|
};
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
const template = {
|
|
235
|
-
tag: input.$name,
|
|
236
|
-
attributes: attributes ?? {},
|
|
237
|
-
children
|
|
238
|
-
};
|
|
239
|
-
if (input.$styles.length) {
|
|
240
|
-
const classes = template.attributes["class"];
|
|
241
|
-
template.attributes["class"] = (classes ? [classes, ...input.$styles] : input.$styles).join(" ");
|
|
242
|
-
}
|
|
243
|
-
return template;
|
|
244
|
-
}
|
|
245
|
-
if (typeof input === "string") return {
|
|
246
|
-
tag: input,
|
|
247
|
-
attributes: attributes ?? {},
|
|
248
|
-
children
|
|
249
|
-
};
|
|
250
|
-
return input?.({
|
|
251
|
-
...attributes,
|
|
252
|
-
children
|
|
253
|
-
});
|
|
384
|
+
const fileName = (path) => {
|
|
385
|
+
return path.split("/").pop()?.split(".").slice(0, -1).join(".");
|
|
254
386
|
};
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
case "boolean":
|
|
261
|
-
case "symbol": return slot.toString();
|
|
262
|
-
case "object": return JSON.stringify(slot);
|
|
263
|
-
case "function": return toString(slot());
|
|
264
|
-
default: return "";
|
|
265
|
-
}
|
|
387
|
+
const toPath = (value) => {
|
|
388
|
+
const path = (value.startsWith("/") ? value : "/" + value).replaceAll(/\/index/g, "").replaceAll(/\[(.*?)\]/g, (_, name) => ":" + name);
|
|
389
|
+
const route = path.startsWith("/") ? path : "/" + path;
|
|
390
|
+
const split = route.split(".");
|
|
391
|
+
return split.length === 3 ? [split.at(0), split.at(1)] : [split.at(0)];
|
|
266
392
|
};
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
|
|
393
|
+
const $fetch = async (scope, input, options) => {
|
|
394
|
+
const { request, variables } = useRuntime(scope);
|
|
395
|
+
let response;
|
|
396
|
+
if (request) {
|
|
397
|
+
const next = new Scope();
|
|
398
|
+
const url = new URL(input.toString(), request.url);
|
|
399
|
+
next.setContext(RUNTIME_CONTEXT, {
|
|
400
|
+
tasks: new Array(),
|
|
401
|
+
request: new Request(url, options),
|
|
402
|
+
response: { headers: new Headers() },
|
|
403
|
+
variables
|
|
404
|
+
});
|
|
405
|
+
const previous = new URL(request.url);
|
|
406
|
+
if (url.origin === previous.origin) response = await (await import("#virtual/runtime")).runtime.fetch(next);
|
|
407
|
+
}
|
|
408
|
+
response ??= await fetch(input, options);
|
|
409
|
+
if (response.ok === false) throw response;
|
|
410
|
+
const contentType = response.headers.get("Content-Type")?.split(";").shift() ?? "";
|
|
411
|
+
switch (contentType) {
|
|
412
|
+
case "application/json": return response.json();
|
|
413
|
+
default: return response;
|
|
414
|
+
}
|
|
270
415
|
};
|
|
271
|
-
const
|
|
272
|
-
const
|
|
273
|
-
const
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
416
|
+
const useAsync = (scope, invoke) => {
|
|
417
|
+
const { tasks } = useRuntime(scope);
|
|
418
|
+
const state = createState();
|
|
419
|
+
const isLoading = createState(true);
|
|
420
|
+
const task = invoke().then((value) => state.value = value).finally(() => isLoading.value = false);
|
|
421
|
+
if (isServer()) tasks.push(task);
|
|
422
|
+
return {
|
|
423
|
+
state,
|
|
424
|
+
isLoading
|
|
425
|
+
};
|
|
426
|
+
};
|
|
427
|
+
const createRuntime = async () => {
|
|
428
|
+
const radix = new Radix();
|
|
429
|
+
const middlewares = new Array();
|
|
430
|
+
const routes = await import("#virtual/routes").then((module) => module.default);
|
|
431
|
+
for (const path in routes) {
|
|
432
|
+
const [name, method] = toPath(path);
|
|
433
|
+
radix.insert((method ?? "GET").toUpperCase() + name, defineRoute({ fetch: async (event) => {
|
|
434
|
+
const route = routes[path];
|
|
435
|
+
if (isRoute(route)) return route.fetch(event);
|
|
436
|
+
return sendHtml(event, await renderToString(event, await import("#virtual/client").then((module) => module.client)));
|
|
437
|
+
} }));
|
|
438
|
+
}
|
|
439
|
+
const assets = await import("#virtual/assets").then((module) => module.default);
|
|
440
|
+
for (const path in assets) radix.insert("GET/" + path, defineRoute({ fetch: async (scope) => {
|
|
441
|
+
const { response } = useRuntime(scope);
|
|
442
|
+
let content = assets[path];
|
|
443
|
+
if (content) {
|
|
444
|
+
if (path.endsWith(".png")) {
|
|
445
|
+
const [_, base64] = content.split(",");
|
|
446
|
+
const binary = atob(base64.replace(/-/g, "+").replace(/_/g, "/"));
|
|
447
|
+
const bytes = new Uint8Array(binary.length);
|
|
448
|
+
for (let index = 0; index < binary.length; index++) bytes[index] = binary.charCodeAt(index);
|
|
449
|
+
content = bytes;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
response.headers.set("Content-Type", mimeType(path));
|
|
453
|
+
return new Response(content, response);
|
|
454
|
+
} }));
|
|
455
|
+
const invoke = (scope, route, index) => {
|
|
456
|
+
return middlewares.at(index)?.fetch(scope, () => invoke(scope, route, index + 1)) ?? route.fetch(scope);
|
|
457
|
+
};
|
|
458
|
+
return {
|
|
459
|
+
radix,
|
|
460
|
+
middlewares,
|
|
461
|
+
fetch: async (scope) => {
|
|
462
|
+
const { request } = useRuntime(scope);
|
|
463
|
+
const { pathname } = useRequestUrl(scope);
|
|
464
|
+
const { value: route, inputs } = radix.match(request.method + pathname);
|
|
465
|
+
try {
|
|
466
|
+
scope.setContext(ROUTE_CONTEXT, { inputs: createState(inputs) });
|
|
467
|
+
if (route) {
|
|
468
|
+
const response = await invoke(scope, route, 0);
|
|
469
|
+
if (response) return response;
|
|
470
|
+
}
|
|
471
|
+
return sendText(scope, "NOT_FOUND");
|
|
472
|
+
} catch (exception) {
|
|
473
|
+
if (exception instanceof Response) return exception;
|
|
474
|
+
throw exception;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
};
|
|
479
|
+
const RUNTIME_CONTEXT = defineContext("RUNTIME_CONTEXT");
|
|
480
|
+
const ROUTE_CONTEXT = defineContext("ROUTE_CONTEXT");
|
|
481
|
+
|
|
482
|
+
//#endregion
|
|
483
|
+
//#region src/html/index.ts
|
|
484
|
+
var MountedEvent = class extends Event {
|
|
485
|
+
constructor() {
|
|
486
|
+
super("mounted");
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
const isTemplate = (value) => {
|
|
490
|
+
return !!value && typeof value === "object" && "tag" in value && "attributes" in value && "children" in value;
|
|
491
|
+
};
|
|
492
|
+
const isCustomElement = (value) => {
|
|
493
|
+
return !!value && typeof value === "object" && "component" in value;
|
|
494
|
+
};
|
|
495
|
+
const isComponent = (value) => {
|
|
496
|
+
return !!value && typeof value === "function" && "$name" in value;
|
|
497
|
+
};
|
|
498
|
+
const useHost = (scope) => {
|
|
499
|
+
return scope.getContext(HOST_CONTEXT);
|
|
500
|
+
};
|
|
501
|
+
const createElement = (input, attributes, ...children) => {
|
|
502
|
+
if (isComponent(input)) {
|
|
503
|
+
const template = {
|
|
504
|
+
tag: input.$name,
|
|
505
|
+
attributes: attributes ?? {},
|
|
506
|
+
children
|
|
507
|
+
};
|
|
508
|
+
if (input.$styles.length) {
|
|
509
|
+
const classes = template.attributes["class"];
|
|
510
|
+
template.attributes["class"] = (classes ? [classes, ...input.$styles] : input.$styles).join(" ");
|
|
511
|
+
}
|
|
512
|
+
return template;
|
|
513
|
+
}
|
|
514
|
+
if (typeof input === "string") return {
|
|
515
|
+
tag: input,
|
|
516
|
+
attributes: attributes ?? {},
|
|
517
|
+
children
|
|
518
|
+
};
|
|
519
|
+
return input?.({
|
|
520
|
+
...attributes,
|
|
521
|
+
children
|
|
522
|
+
});
|
|
523
|
+
};
|
|
524
|
+
const toString = (slot) => {
|
|
525
|
+
switch (typeof slot) {
|
|
526
|
+
case "string":
|
|
527
|
+
case "number":
|
|
528
|
+
case "bigint":
|
|
529
|
+
case "boolean":
|
|
530
|
+
case "symbol": return slot.toString();
|
|
531
|
+
case "object": return JSON.stringify(slot);
|
|
532
|
+
case "function": return toString(slot());
|
|
533
|
+
default: return "";
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
const toArray = (hydration) => {
|
|
537
|
+
if (Array.isArray(hydration)) return hydration.reduce((items, child) => items.concat(toArray(child)), new Array());
|
|
538
|
+
else return [hydration];
|
|
539
|
+
};
|
|
540
|
+
const toRange = (hydration) => {
|
|
541
|
+
const items = toArray(hydration);
|
|
542
|
+
const range = document.createRange();
|
|
543
|
+
const firstNode = items.at(0);
|
|
544
|
+
if (firstNode) range.setStartBefore(firstNode);
|
|
545
|
+
const lastNode = items.at(-1);
|
|
546
|
+
if (lastNode) range.setEndAfter(lastNode);
|
|
547
|
+
return range;
|
|
279
548
|
};
|
|
280
549
|
const toFragment = (hydration) => {
|
|
281
550
|
return toArray(hydration).reduce((fragment, node) => {
|
|
@@ -283,20 +552,20 @@ const toFragment = (hydration) => {
|
|
|
283
552
|
return fragment;
|
|
284
553
|
}, document.createDocumentFragment());
|
|
285
554
|
};
|
|
286
|
-
const hydrate =
|
|
555
|
+
const hydrate = (scope, parentNode, slot, index, previous) => {
|
|
287
556
|
let hydration = parentNode.childNodes.item(index);
|
|
288
557
|
if (Array.isArray(slot)) {
|
|
289
558
|
const items = new Array();
|
|
290
|
-
for (const [index$1, childSlot] of slot.entries()) items.push(
|
|
559
|
+
for (const [index$1, childSlot] of slot.entries()) items.push(hydrate(scope, parentNode, childSlot, index$1, previous));
|
|
291
560
|
if (items.length) hydration = items;
|
|
292
561
|
else if (previous || !(hydration instanceof Comment)) hydration = document.createComment("");
|
|
293
562
|
}
|
|
294
563
|
if (typeof slot === "function") {
|
|
295
564
|
let previous$1;
|
|
296
|
-
|
|
565
|
+
createCompute(scope, (scope$1) => {
|
|
297
566
|
let input = slot;
|
|
298
|
-
while (typeof input === "function") input =
|
|
299
|
-
hydration =
|
|
567
|
+
while (typeof input === "function") input = input();
|
|
568
|
+
hydration = hydrate(scope$1, parentNode, input, index, previous$1);
|
|
300
569
|
if (previous$1 && hydration !== previous$1) if (Array.isArray(hydration)) if (Array.isArray(previous$1)) {
|
|
301
570
|
const range = toRange(previous$1);
|
|
302
571
|
range.deleteContents();
|
|
@@ -331,13 +600,14 @@ const hydrate = async (scope, parentNode, slot, index, previous) => {
|
|
|
331
600
|
return target.setAttribute(name, set);
|
|
332
601
|
}
|
|
333
602
|
});
|
|
334
|
-
for (const [index$1, childSlot] of slot.children.entries())
|
|
603
|
+
for (const [index$1, childSlot] of slot.children.entries()) hydrate(scope, hydration, childSlot, index$1, previous);
|
|
335
604
|
}
|
|
336
605
|
hydration ??= document.createComment("");
|
|
337
606
|
if (parentNode.childNodes.item(index) === null) parentNode.appendChild(toFragment(hydration));
|
|
338
607
|
return hydration;
|
|
339
608
|
};
|
|
340
609
|
const renderToString = async (scope, slot) => {
|
|
610
|
+
const { tasks } = useRuntime(scope);
|
|
341
611
|
if (typeof slot === "number" || typeof slot === "bigint" || typeof slot === "boolean" || typeof slot === "string" || typeof slot === "symbol") return slot.toString();
|
|
342
612
|
if (typeof slot === "function") {
|
|
343
613
|
let input = slot;
|
|
@@ -359,7 +629,9 @@ const renderToString = async (scope, slot) => {
|
|
|
359
629
|
let content = `<${prefix}>`;
|
|
360
630
|
if (CustomElement) {
|
|
361
631
|
const element = new CustomElement(slot.attributes, scope);
|
|
362
|
-
const
|
|
632
|
+
const result = element.setup();
|
|
633
|
+
while (tasks.length) await tasks.shift();
|
|
634
|
+
const template = await renderToString(element.scope, result);
|
|
363
635
|
if (element.shadowRoot) {
|
|
364
636
|
const shadow = {
|
|
365
637
|
tag: "template",
|
|
@@ -405,9 +677,16 @@ const defineComponent = (options) => {
|
|
|
405
677
|
const toCustomElement = (Component) => {
|
|
406
678
|
return class extends HTMLElement {
|
|
407
679
|
static formAssociated = true;
|
|
408
|
-
component
|
|
409
|
-
|
|
410
|
-
|
|
680
|
+
component;
|
|
681
|
+
constructor() {
|
|
682
|
+
super();
|
|
683
|
+
this.component = new Component();
|
|
684
|
+
this.component.scope.setContext(HOST_CONTEXT, {
|
|
685
|
+
host: this,
|
|
686
|
+
internals: this.attachInternals()
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
connectedCallback() {
|
|
411
690
|
let rootNode = this;
|
|
412
691
|
const findParentScope = (node) => {
|
|
413
692
|
if (node) {
|
|
@@ -425,11 +704,7 @@ const toCustomElement = (Component) => {
|
|
|
425
704
|
detail: value
|
|
426
705
|
}));
|
|
427
706
|
});
|
|
428
|
-
this.component.scope.
|
|
429
|
-
host: this,
|
|
430
|
-
internals: this.internals
|
|
431
|
-
});
|
|
432
|
-
await hydrate(this.component.scope, rootNode, await this.component.setup(), 0);
|
|
707
|
+
hydrate(this.component.scope, rootNode, this.component.setup(), 0);
|
|
433
708
|
requestAnimationFrame(() => this.dispatchEvent(new MountedEvent()));
|
|
434
709
|
}
|
|
435
710
|
attributeChangedCallback(name, oldValue, value) {
|
|
@@ -498,266 +773,6 @@ const stopImmediatePropagation = (event) => event.stopImmediatePropagation();
|
|
|
498
773
|
const components = /* @__PURE__ */ new Map();
|
|
499
774
|
const HOST_CONTEXT = defineContext("HOST_CONTEXT");
|
|
500
775
|
|
|
501
|
-
//#endregion
|
|
502
|
-
//#region src/radix/index.ts
|
|
503
|
-
var Radix = class Radix {
|
|
504
|
-
value;
|
|
505
|
-
input;
|
|
506
|
-
children;
|
|
507
|
-
constructor(input) {
|
|
508
|
-
this.input = input;
|
|
509
|
-
this.children = {};
|
|
510
|
-
}
|
|
511
|
-
insert = (path, value) => {
|
|
512
|
-
let node = this;
|
|
513
|
-
for (let segment of path.split("/")) {
|
|
514
|
-
let input;
|
|
515
|
-
if (segment.startsWith(":")) {
|
|
516
|
-
input = segment.substring(1);
|
|
517
|
-
segment = ":";
|
|
518
|
-
}
|
|
519
|
-
let childNode = node.children[segment];
|
|
520
|
-
if (childNode === void 0) {
|
|
521
|
-
childNode = new Radix(input);
|
|
522
|
-
node.children[segment] = childNode;
|
|
523
|
-
}
|
|
524
|
-
node = childNode;
|
|
525
|
-
}
|
|
526
|
-
node.value = value;
|
|
527
|
-
return this;
|
|
528
|
-
};
|
|
529
|
-
match = (path) => {
|
|
530
|
-
let node = this;
|
|
531
|
-
const match = { inputs: {} };
|
|
532
|
-
for (const segment of path.split("/")) {
|
|
533
|
-
node = node?.children[segment] ?? node?.children[":"];
|
|
534
|
-
if (node?.input) match.inputs[node.input] = segment;
|
|
535
|
-
}
|
|
536
|
-
match.value = node?.value;
|
|
537
|
-
return match;
|
|
538
|
-
};
|
|
539
|
-
};
|
|
540
|
-
|
|
541
|
-
//#endregion
|
|
542
|
-
//#region src/runtime/index.ts
|
|
543
|
-
const isRoute = (value) => {
|
|
544
|
-
return !!value && typeof value === "object" && "fetch" in value;
|
|
545
|
-
};
|
|
546
|
-
const useRuntime = (scope) => {
|
|
547
|
-
return scope.getContext(RUNTIME_CONTEXT);
|
|
548
|
-
};
|
|
549
|
-
const useRoute = (scope) => {
|
|
550
|
-
return scope.getContext(ROUTE_CONTEXT);
|
|
551
|
-
};
|
|
552
|
-
const defineRoute = (route) => {
|
|
553
|
-
return route;
|
|
554
|
-
};
|
|
555
|
-
const defineMiddleware = (middleware) => {
|
|
556
|
-
return middleware;
|
|
557
|
-
};
|
|
558
|
-
const fileName = (path) => {
|
|
559
|
-
return path.split("/").pop()?.split(".").slice(0, -1).join(".");
|
|
560
|
-
};
|
|
561
|
-
const toPath = (value) => {
|
|
562
|
-
const path = (value.startsWith("/") ? value : "/" + value).replaceAll(/\/index/g, "").replaceAll(/\[(.*?)\]/g, (_, name) => ":" + name);
|
|
563
|
-
const route = path.startsWith("/") ? path : "/" + path;
|
|
564
|
-
const split = route.split(".");
|
|
565
|
-
return split.length === 3 ? [split.at(0), split.at(1)] : [split.at(0)];
|
|
566
|
-
};
|
|
567
|
-
const $fetch = async (scope, input, options) => {
|
|
568
|
-
const { request, variables } = useRuntime(scope);
|
|
569
|
-
let response;
|
|
570
|
-
if (request) {
|
|
571
|
-
const next = new Scope();
|
|
572
|
-
const url = new URL(input.toString(), request.url);
|
|
573
|
-
next.setContext(RUNTIME_CONTEXT, {
|
|
574
|
-
request: new Request(url, options),
|
|
575
|
-
response: { headers: new Headers() },
|
|
576
|
-
variables
|
|
577
|
-
});
|
|
578
|
-
const previous = new URL(request.url);
|
|
579
|
-
if (url.origin === previous.origin) response = await (await import("#virtual/runtime")).runtime.fetch(next);
|
|
580
|
-
}
|
|
581
|
-
response ??= await fetch(input, options);
|
|
582
|
-
if (response.ok === false) throw response;
|
|
583
|
-
const contentType = response.headers.get("Content-Type")?.split(";").shift() ?? "";
|
|
584
|
-
switch (contentType) {
|
|
585
|
-
case "application/json": return response.json();
|
|
586
|
-
default: return response;
|
|
587
|
-
}
|
|
588
|
-
};
|
|
589
|
-
const createRuntime = async () => {
|
|
590
|
-
const radix = new Radix();
|
|
591
|
-
const middlewares = new Array();
|
|
592
|
-
const routes = await import("#virtual/routes").then((module) => module.routes);
|
|
593
|
-
for (const path in routes) {
|
|
594
|
-
const [name, method] = toPath(path);
|
|
595
|
-
radix.insert((method ?? "GET").toUpperCase() + name, defineRoute({ fetch: async (event) => {
|
|
596
|
-
const route = await routes[path]?.();
|
|
597
|
-
if (isRoute(route)) return route.fetch(event);
|
|
598
|
-
return sendHtml(event, await renderToString(event, await import("#virtual/client").then((module) => module.client)));
|
|
599
|
-
} }));
|
|
600
|
-
}
|
|
601
|
-
const assets = await import("#virtual/assets").then((module) => module.assets);
|
|
602
|
-
for (const path in assets) radix.insert("GET/" + path, defineRoute({ fetch: async (scope) => {
|
|
603
|
-
const { response } = useRuntime(scope);
|
|
604
|
-
let content = await assets[path]?.();
|
|
605
|
-
if (content) {
|
|
606
|
-
if (path.endsWith(".png")) {
|
|
607
|
-
const [_, base64] = content.split(",");
|
|
608
|
-
const binary = atob(base64.replace(/-/g, "+").replace(/_/g, "/"));
|
|
609
|
-
const bytes = new Uint8Array(binary.length);
|
|
610
|
-
for (let index = 0; index < binary.length; index++) bytes[index] = binary.charCodeAt(index);
|
|
611
|
-
content = bytes;
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
response.headers.set("Content-Type", mimeType(path));
|
|
615
|
-
return new Response(content, response);
|
|
616
|
-
} }));
|
|
617
|
-
const invoke = (scope, route, index) => {
|
|
618
|
-
return middlewares.at(index)?.fetch(scope, () => invoke(scope, route, index + 1)) ?? route.fetch(scope);
|
|
619
|
-
};
|
|
620
|
-
return {
|
|
621
|
-
radix,
|
|
622
|
-
middlewares,
|
|
623
|
-
fetch: async (scope) => {
|
|
624
|
-
const { request } = useRuntime(scope);
|
|
625
|
-
const { pathname } = useRequestUrl(scope);
|
|
626
|
-
const { value: route, inputs } = radix.match(request.method + pathname);
|
|
627
|
-
try {
|
|
628
|
-
scope.setContext(ROUTE_CONTEXT, { inputs: createState(inputs) });
|
|
629
|
-
if (route) {
|
|
630
|
-
const response = await invoke(scope, route, 0);
|
|
631
|
-
if (response) return response;
|
|
632
|
-
}
|
|
633
|
-
return sendText(scope, "NOT_FOUND");
|
|
634
|
-
} catch (exception) {
|
|
635
|
-
if (exception instanceof Response) return exception;
|
|
636
|
-
throw exception;
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
};
|
|
640
|
-
};
|
|
641
|
-
const RUNTIME_CONTEXT = defineContext("RUNTIME_CONTEXT");
|
|
642
|
-
const ROUTE_CONTEXT = defineContext("ROUTE_CONTEXT");
|
|
643
|
-
|
|
644
|
-
//#endregion
|
|
645
|
-
//#region src/http/index.ts
|
|
646
|
-
const sendText = (scope, text) => {
|
|
647
|
-
const { response } = useRuntime(scope);
|
|
648
|
-
response.headers.set("Content-Type", "text/plain");
|
|
649
|
-
return new Response(text, response);
|
|
650
|
-
};
|
|
651
|
-
const sendHtml = (scope, text) => {
|
|
652
|
-
const { response } = useRuntime(scope);
|
|
653
|
-
response.headers.set("Content-Type", "text/html");
|
|
654
|
-
return new Response(text, response);
|
|
655
|
-
};
|
|
656
|
-
const sendJson = (scope, value) => {
|
|
657
|
-
const { response } = useRuntime(scope);
|
|
658
|
-
response.headers.set("Content-Type", "application/json");
|
|
659
|
-
return new Response(JSON.stringify(value), response);
|
|
660
|
-
};
|
|
661
|
-
const sendRedirect = (scope, path) => {
|
|
662
|
-
const { response } = useRuntime(scope);
|
|
663
|
-
response.status = 302;
|
|
664
|
-
response.headers.set("Location", path);
|
|
665
|
-
return new Response(null, response);
|
|
666
|
-
};
|
|
667
|
-
const sendBadRequest = (scope, text) => {
|
|
668
|
-
const { response } = useRuntime(scope);
|
|
669
|
-
response.status = 400;
|
|
670
|
-
return new Response(text, response);
|
|
671
|
-
};
|
|
672
|
-
const sendUnauthorized = (scope) => {
|
|
673
|
-
const { response } = useRuntime(scope);
|
|
674
|
-
response.status = 401;
|
|
675
|
-
return new Response(null, response);
|
|
676
|
-
};
|
|
677
|
-
const useRequestUrl = (scope, base) => {
|
|
678
|
-
const { request } = useRuntime(scope);
|
|
679
|
-
return new URL(request.url, base);
|
|
680
|
-
};
|
|
681
|
-
const useCookies = (scope) => {
|
|
682
|
-
const { request } = useRuntime(scope);
|
|
683
|
-
return (isClient() ? document.cookie : request.headers.get("Cookie") ?? "").split("; ").reduce((result, cookie) => {
|
|
684
|
-
const [name, value] = cookie.split("=");
|
|
685
|
-
if (name && value) result[name] = decodeURIComponent(value);
|
|
686
|
-
return result;
|
|
687
|
-
}, {});
|
|
688
|
-
};
|
|
689
|
-
const useSetCookies = (scope) => {
|
|
690
|
-
const { request } = useRuntime(scope);
|
|
691
|
-
return request.headers.getSetCookie().reduce((result, cookie) => {
|
|
692
|
-
const [name, value] = cookie.split("=");
|
|
693
|
-
if (name && value) result[name] = decodeURIComponent(value);
|
|
694
|
-
return result;
|
|
695
|
-
}, {});
|
|
696
|
-
};
|
|
697
|
-
const setCookie = (scope, name, value, options) => {
|
|
698
|
-
const { response } = useRuntime(scope);
|
|
699
|
-
let cookie = name + "=" + encodeURIComponent(value);
|
|
700
|
-
if (options?.domain) cookie += `; Domain=${options.domain}`;
|
|
701
|
-
if (options?.expires) cookie += `; Expires=${options.expires.toUTCString()}`;
|
|
702
|
-
if (options?.httpOnly) cookie += `; HttpOnly`;
|
|
703
|
-
if (options?.maxAge) cookie += `; Max-Age=${options.maxAge}`;
|
|
704
|
-
if (options?.path) cookie += `; Path=${options.path}`;
|
|
705
|
-
if (options?.priority) cookie += `; Priority=${options.priority}`;
|
|
706
|
-
if (options?.sameSite) cookie += `; SameSite=${options.sameSite}`;
|
|
707
|
-
if (options?.secure) cookie += `; Secure`;
|
|
708
|
-
if (isClient()) document.cookie = cookie;
|
|
709
|
-
else response.headers.append("Set-Cookie", cookie);
|
|
710
|
-
};
|
|
711
|
-
const mimeType = (file) => {
|
|
712
|
-
const extension = /\.([a-zA-Z0-9]+?)$/.exec(file)?.at(1);
|
|
713
|
-
return mimeTypes[extension ?? ""] ?? "text/plain";
|
|
714
|
-
};
|
|
715
|
-
const mimeTypes = {
|
|
716
|
-
txt: "text/plain",
|
|
717
|
-
css: "text/css",
|
|
718
|
-
html: "text/html",
|
|
719
|
-
htm: "text/html",
|
|
720
|
-
js: "text/javascript",
|
|
721
|
-
json: "application/json",
|
|
722
|
-
xml: "application/xml",
|
|
723
|
-
csv: "text/csv",
|
|
724
|
-
jpg: "image/jpeg",
|
|
725
|
-
jpeg: "image/jpeg",
|
|
726
|
-
png: "image/png",
|
|
727
|
-
gif: "image/gif",
|
|
728
|
-
webp: "image/webp",
|
|
729
|
-
svg: "image/svg+xml",
|
|
730
|
-
bmp: "image/bmp",
|
|
731
|
-
ico: "image/x-icon",
|
|
732
|
-
ttf: "font/ttf",
|
|
733
|
-
otf: "font/otf",
|
|
734
|
-
woff: "font/woff",
|
|
735
|
-
woff2: "font/woff2",
|
|
736
|
-
mp3: "audio/mpeg",
|
|
737
|
-
wav: "audio/wav",
|
|
738
|
-
ogg: "audio/ogg",
|
|
739
|
-
m4a: "audio/mp4",
|
|
740
|
-
mp4: "video/mp4",
|
|
741
|
-
webm: "video/webm",
|
|
742
|
-
ogv: "video/ogg",
|
|
743
|
-
mov: "video/quicktime",
|
|
744
|
-
avi: "video/x-msvideo",
|
|
745
|
-
zip: "application/zip",
|
|
746
|
-
rar: "application/vnd.rar",
|
|
747
|
-
tar: "application/x-tar",
|
|
748
|
-
gz: "application/gzip",
|
|
749
|
-
"7z": "application/x-7z-compressed",
|
|
750
|
-
pdf: "application/pdf",
|
|
751
|
-
doc: "application/msword",
|
|
752
|
-
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
753
|
-
xls: "application/vnd.ms-excel",
|
|
754
|
-
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
755
|
-
ppt: "application/vnd.ms-powerpoint",
|
|
756
|
-
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
757
|
-
exe: "application/vnd.microsoft.portable-executable",
|
|
758
|
-
apk: "application/vnd.android.package-archive"
|
|
759
|
-
};
|
|
760
|
-
|
|
761
776
|
//#endregion
|
|
762
777
|
//#region src/router/index.tsx
|
|
763
778
|
var NavigateEvent = class extends Event {
|
|
@@ -765,12 +780,11 @@ var NavigateEvent = class extends Event {
|
|
|
765
780
|
super("navigate");
|
|
766
781
|
}
|
|
767
782
|
};
|
|
768
|
-
const
|
|
769
|
-
const createRouter = (options) => {
|
|
770
|
-
const navigator = new EventTarget();
|
|
771
|
-
const radix = new Radix();
|
|
783
|
+
const provideRouterContext = (scope, options) => {
|
|
772
784
|
const url = createState();
|
|
773
785
|
const route = createState();
|
|
786
|
+
const radix = new Radix();
|
|
787
|
+
const navigator = new EventTarget();
|
|
774
788
|
for (const path in options.routes) {
|
|
775
789
|
const [name] = toPath(path);
|
|
776
790
|
if (name) {
|
|
@@ -778,31 +792,26 @@ const createRouter = (options) => {
|
|
|
778
792
|
if (value) radix.insert(name, value);
|
|
779
793
|
}
|
|
780
794
|
}
|
|
781
|
-
const
|
|
782
|
-
const
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
await startViewTransition(async () => route.value = await match.value?.());
|
|
789
|
-
};
|
|
790
|
-
if (isClient()) useEvent(scope, window, "popstate", () => navigator.dispatchEvent(new NavigateEvent()));
|
|
791
|
-
scope.setContext(ROUTE_CONTEXT, { inputs: createState() });
|
|
792
|
-
scope.setContext(ROUTER_CONTEXT, {
|
|
793
|
-
options,
|
|
794
|
-
navigator,
|
|
795
|
-
url,
|
|
796
|
-
radix,
|
|
797
|
-
route
|
|
798
|
-
});
|
|
799
|
-
await fetch$1().then(() => useEvent(scope, navigator, "navigate", fetch$1));
|
|
800
|
-
return useRouter(scope);
|
|
801
|
-
};
|
|
802
|
-
return {
|
|
803
|
-
ROUTER_CONTEXT,
|
|
804
|
-
registerRouterContext
|
|
795
|
+
const fetch$1 = () => {
|
|
796
|
+
const { inputs } = useRoute(scope);
|
|
797
|
+
const { request } = useRuntime(scope);
|
|
798
|
+
url.value = new URL(request?.url ?? window?.location.href);
|
|
799
|
+
const match = radix.match(url.value.pathname);
|
|
800
|
+
inputs.value = match.inputs;
|
|
801
|
+
route.value = match.value;
|
|
805
802
|
};
|
|
803
|
+
if (isClient()) useEvent(scope, window, "popstate", () => navigator.dispatchEvent(new NavigateEvent()));
|
|
804
|
+
scope.setContext(ROUTE_CONTEXT, { inputs: createState() });
|
|
805
|
+
scope.setContext(ROUTER_CONTEXT, {
|
|
806
|
+
options,
|
|
807
|
+
navigator,
|
|
808
|
+
url,
|
|
809
|
+
radix,
|
|
810
|
+
route
|
|
811
|
+
});
|
|
812
|
+
fetch$1();
|
|
813
|
+
useEvent(scope, navigator, "navigate", async () => await startViewTransition(fetch$1));
|
|
814
|
+
return useRouter(scope);
|
|
806
815
|
};
|
|
807
816
|
const useRouter = (scope, context) => {
|
|
808
817
|
const { url, route, navigator } = scope.getContext(context ?? ROUTER_CONTEXT);
|
|
@@ -831,38 +840,33 @@ const Page = defineComponent({
|
|
|
831
840
|
return () => route.value;
|
|
832
841
|
}
|
|
833
842
|
});
|
|
843
|
+
const ROUTER_CONTEXT = defineContext("ROUTER_CONTEXT");
|
|
834
844
|
|
|
835
845
|
//#endregion
|
|
836
846
|
//#region src/locale/index.ts
|
|
837
|
-
const
|
|
838
|
-
const
|
|
847
|
+
const provideLocaleContext = (scope, options) => {
|
|
848
|
+
const { inputs } = useRoute(scope);
|
|
849
|
+
const { navigator } = useRouter(scope);
|
|
839
850
|
const locale = createState(options.defaultLocale);
|
|
840
851
|
const messages = createState();
|
|
841
|
-
const
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
const target = options.locales[locale.value];
|
|
851
|
-
messages.value = typeof target === "function" ? await target() : target;
|
|
852
|
-
}
|
|
853
|
-
};
|
|
854
|
-
await fetch$1().then(() => useEvent(scope, navigator, "navigate", fetch$1));
|
|
855
|
-
scope.setContext(LOCALE_CONTEXT, {
|
|
856
|
-
locale,
|
|
857
|
-
messages,
|
|
858
|
-
options
|
|
859
|
-
});
|
|
860
|
-
return useLocale(scope);
|
|
861
|
-
};
|
|
862
|
-
return {
|
|
863
|
-
LOCALE_CONTEXT,
|
|
864
|
-
registerLocaleContext
|
|
852
|
+
const fetch$1 = () => {
|
|
853
|
+
if (options.input) {
|
|
854
|
+
const input = inputs.value[options.input];
|
|
855
|
+
if (input && input in options.locales) locale.value = input;
|
|
856
|
+
}
|
|
857
|
+
if (locale.value) {
|
|
858
|
+
const target = options.locales[locale.value];
|
|
859
|
+
messages.value = target;
|
|
860
|
+
}
|
|
865
861
|
};
|
|
862
|
+
fetch$1();
|
|
863
|
+
useEvent(scope, navigator, "navigate", fetch$1);
|
|
864
|
+
scope.setContext(LOCALE_CONTEXT, {
|
|
865
|
+
locale,
|
|
866
|
+
messages,
|
|
867
|
+
options
|
|
868
|
+
});
|
|
869
|
+
return useLocale(scope);
|
|
866
870
|
};
|
|
867
871
|
const useLocale = (scope, context) => {
|
|
868
872
|
const { locale, messages } = scope.getContext(context ?? LOCALE_CONTEXT);
|
|
@@ -880,6 +884,7 @@ const useLocale = (scope, context) => {
|
|
|
880
884
|
date
|
|
881
885
|
};
|
|
882
886
|
};
|
|
887
|
+
const LOCALE_CONTEXT = defineContext("LOCALE_CONTEXT");
|
|
883
888
|
|
|
884
889
|
//#endregion
|
|
885
|
-
export { $fetch, CLIENT, Compute, HOST_CONTEXT, Handler, LOCALE_CONTEXT, MountedEvent, NavigateEvent, Page, ROUTER_CONTEXT, ROUTE_CONTEXT, RUNTIME_CONTEXT, Radix, SERVER, Scope, StopEvent, activeCompute, components, createApp, createCompute, createElement,
|
|
890
|
+
export { $fetch, CLIENT, Compute, HOST_CONTEXT, Handler, LOCALE_CONTEXT, MountedEvent, NavigateEvent, Page, ROUTER_CONTEXT, ROUTE_CONTEXT, RUNTIME_CONTEXT, Radix, SERVER, Scope, StopEvent, activeCompute, components, createApp, createCompute, createElement, createMemo, createRuntime, createState, defineComponent, defineContext, defineMiddleware, defineRoute, fileName, fromValue, hydrate, isClient, isComponent, isCustomElement, isRoute, isServer, isTemplate, mimeType, onMounted, preventDefault, provideLocaleContext, provideRouterContext, registerComponent, renderToString, sendBadRequest, sendHtml, sendJson, sendRedirect, sendText, sendUnauthorized, setCookie, startViewTransition, stopImmediatePropagation, stopPropagation, targets, toArray, toCustomElement, toFragment, toPath, toRange, toString, useAsync, useCookies, useEvent, useHost, useLocale, useRequestUrl, useRoute, useRouter, useRuntime, useSetCookies };
|
package/dist/jsx/index.js
CHANGED
|
@@ -3,6 +3,11 @@ function defineContext(key) {
|
|
|
3
3
|
return key;
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/runtime/index.ts
|
|
8
|
+
const RUNTIME_CONTEXT = defineContext("RUNTIME_CONTEXT");
|
|
9
|
+
const ROUTE_CONTEXT = defineContext("ROUTE_CONTEXT");
|
|
10
|
+
|
|
6
11
|
//#endregion
|
|
7
12
|
//#region src/html/index.ts
|
|
8
13
|
const isComponent = (value) => {
|
package/dist/locale/index.d.ts
CHANGED
|
@@ -1,24 +1,19 @@
|
|
|
1
1
|
import { type Descriptor, Scope, type State } from "../signals";
|
|
2
|
-
export type
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
defaultLocale?: keyof T;
|
|
2
|
+
export type LocaleOptions = {
|
|
3
|
+
locales: Record<string, Record<string, string>>;
|
|
4
|
+
defaultLocale?: string;
|
|
6
5
|
input?: string;
|
|
7
6
|
};
|
|
8
|
-
export type LocaleContext
|
|
7
|
+
export type LocaleContext = {
|
|
9
8
|
locale: State<string | undefined>;
|
|
10
9
|
messages: State<Record<string, string> | undefined>;
|
|
11
|
-
options:
|
|
10
|
+
options: LocaleOptions;
|
|
12
11
|
};
|
|
13
|
-
export declare const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
messages: State<Record<string, string> | undefined>;
|
|
19
|
-
$: (key: never) => () => string | number | symbol;
|
|
20
|
-
date: (date?: Date, options?: Intl.DateTimeFormatOptions) => string | undefined;
|
|
21
|
-
}>;
|
|
12
|
+
export declare const provideLocaleContext: (scope: Scope, options: LocaleOptions) => {
|
|
13
|
+
locale: State<string | undefined>;
|
|
14
|
+
messages: State<Record<string, string> | undefined>;
|
|
15
|
+
$: (key: string) => () => string | number | symbol;
|
|
16
|
+
date: (date?: Date, options?: Intl.DateTimeFormatOptions) => string | undefined;
|
|
22
17
|
};
|
|
23
18
|
export declare const useLocale: <T extends LocaleContext>(scope: Scope, context?: Descriptor<T>) => {
|
|
24
19
|
locale: State<string | undefined>;
|
|
@@ -26,3 +21,4 @@ export declare const useLocale: <T extends LocaleContext>(scope: Scope, context?
|
|
|
26
21
|
$: (key: keyof T["options"]["locales"][keyof T["options"]["locales"]]) => () => string | number | symbol;
|
|
27
22
|
date: (date?: Date, options?: Intl.DateTimeFormatOptions) => string | undefined;
|
|
28
23
|
};
|
|
24
|
+
export declare const LOCALE_CONTEXT: Descriptor<LocaleContext>;
|
package/dist/presets/bun.js
CHANGED
|
@@ -1,20 +1,17 @@
|
|
|
1
|
-
import { RUNTIME_CONTEXT, Scope } from "./runtime-
|
|
1
|
+
import { RUNTIME_CONTEXT, Scope } from "./runtime-Daz6s680.js";
|
|
2
2
|
import { serve } from "bun";
|
|
3
3
|
import { runtime } from "#virtual/runtime";
|
|
4
4
|
|
|
5
5
|
//#region src/presets/bun.ts
|
|
6
|
-
serve({ fetch: (request) => {
|
|
6
|
+
serve({ fetch: async (request) => {
|
|
7
7
|
const scope = new Scope();
|
|
8
8
|
scope.setContext(RUNTIME_CONTEXT, {
|
|
9
|
+
tasks: new Array(),
|
|
9
10
|
request,
|
|
10
11
|
response: { headers: new Headers() },
|
|
11
12
|
variables: process.env
|
|
12
13
|
});
|
|
13
|
-
|
|
14
|
-
return runtime.fetch(scope);
|
|
15
|
-
} finally {
|
|
16
|
-
scope.stop();
|
|
17
|
-
}
|
|
14
|
+
return await runtime.fetch(scope).finally(() => scope.stop());
|
|
18
15
|
} });
|
|
19
16
|
|
|
20
17
|
//#endregion
|
|
@@ -1,19 +1,16 @@
|
|
|
1
|
-
import { RUNTIME_CONTEXT, Scope } from "./runtime-
|
|
1
|
+
import { RUNTIME_CONTEXT, Scope } from "./runtime-Daz6s680.js";
|
|
2
2
|
import { runtime } from "#virtual/runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/presets/cloudflare.ts
|
|
5
|
-
var cloudflare_default = { fetch: (request, variables) => {
|
|
5
|
+
var cloudflare_default = { fetch: async (request, variables) => {
|
|
6
6
|
const scope = new Scope();
|
|
7
7
|
scope.setContext(RUNTIME_CONTEXT, {
|
|
8
|
+
tasks: new Array(),
|
|
8
9
|
request,
|
|
9
10
|
response: { headers: new Headers() },
|
|
10
11
|
variables
|
|
11
12
|
});
|
|
12
|
-
|
|
13
|
-
return runtime.fetch(scope);
|
|
14
|
-
} finally {
|
|
15
|
-
scope.stop();
|
|
16
|
-
}
|
|
13
|
+
return await runtime.fetch(scope).finally(() => scope.stop());
|
|
17
14
|
} };
|
|
18
15
|
|
|
19
16
|
//#endregion
|
|
@@ -15,9 +15,7 @@ var Scope = class extends EventTarget {
|
|
|
15
15
|
}
|
|
16
16
|
getContext(input) {
|
|
17
17
|
let scope = this;
|
|
18
|
-
|
|
19
|
-
while (scope && !seen.has(scope)) {
|
|
20
|
-
seen.add(scope);
|
|
18
|
+
while (scope) {
|
|
21
19
|
if (scope.context.has(input)) return scope.context.get(input);
|
|
22
20
|
scope = scope.parentScope;
|
|
23
21
|
}
|
package/dist/router/index.d.ts
CHANGED
|
@@ -1,30 +1,25 @@
|
|
|
1
1
|
import { type Slot } from "../html";
|
|
2
2
|
import { Radix } from "../radix";
|
|
3
3
|
import { type Descriptor, Scope, type State } from "../signals";
|
|
4
|
-
export type
|
|
5
|
-
|
|
6
|
-
routes: T;
|
|
4
|
+
export type RouterOptions = {
|
|
5
|
+
routes: Record<string, Slot>;
|
|
7
6
|
};
|
|
8
|
-
export type RouterContext
|
|
9
|
-
options: T;
|
|
10
|
-
navigator: EventTarget;
|
|
7
|
+
export type RouterContext = {
|
|
11
8
|
url: State<URL | undefined>;
|
|
12
|
-
radix: Radix<() => Promise<Slot>>;
|
|
13
9
|
route: State<Slot | undefined>;
|
|
10
|
+
radix: Radix<Slot>;
|
|
11
|
+
navigator: EventTarget;
|
|
12
|
+
options: RouterOptions;
|
|
14
13
|
};
|
|
15
14
|
export declare class NavigateEvent extends Event {
|
|
16
15
|
constructor();
|
|
17
16
|
}
|
|
18
|
-
export declare const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
navigator: EventTarget;
|
|
25
|
-
navigate: (path: string) => void;
|
|
26
|
-
anchorNavigate: (event: Event) => void;
|
|
27
|
-
}>;
|
|
17
|
+
export declare const provideRouterContext: (scope: Scope, options: RouterOptions) => {
|
|
18
|
+
url: State<URL | undefined>;
|
|
19
|
+
route: State<unknown>;
|
|
20
|
+
navigator: EventTarget;
|
|
21
|
+
navigate: (path: string) => void;
|
|
22
|
+
anchorNavigate: (event: Event) => void;
|
|
28
23
|
};
|
|
29
24
|
export declare const useRouter: <T extends RouterContext>(scope: Scope, context?: Descriptor<T>) => {
|
|
30
25
|
url: State<URL | undefined>;
|
|
@@ -34,6 +29,7 @@ export declare const useRouter: <T extends RouterContext>(scope: Scope, context?
|
|
|
34
29
|
anchorNavigate: (event: Event) => void;
|
|
35
30
|
};
|
|
36
31
|
export declare const Page: import("..").ComponentConstructor<import("..").Events, import("..").Attributes>;
|
|
32
|
+
export declare const ROUTER_CONTEXT: Descriptor<RouterContext>;
|
|
37
33
|
declare global {
|
|
38
34
|
interface ElementEventMap {
|
|
39
35
|
navigate: NavigateEvent;
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export type Runtime = {
|
|
|
13
13
|
fetch: (scope: Scope) => Promise<Response>;
|
|
14
14
|
};
|
|
15
15
|
export type RuntimeContext<T = Record<string, unknown>> = {
|
|
16
|
+
tasks: Array<Promise<unknown>>;
|
|
16
17
|
request: Request;
|
|
17
18
|
response: ResponseOptions;
|
|
18
19
|
variables: T;
|
|
@@ -28,6 +29,10 @@ export declare const defineMiddleware: (middleware: Middleware) => Middleware;
|
|
|
28
29
|
export declare const fileName: (path: string) => string | undefined;
|
|
29
30
|
export declare const toPath: (value: string) => (string | undefined)[];
|
|
30
31
|
export declare const $fetch: <T>(scope: Scope, input: string | URL, options?: RequestInit) => Promise<T>;
|
|
32
|
+
export declare const useAsync: <T>(scope: Scope, invoke: () => Promise<T>) => {
|
|
33
|
+
state: State<T | undefined>;
|
|
34
|
+
isLoading: State<boolean>;
|
|
35
|
+
};
|
|
31
36
|
export declare const createRuntime: () => Promise<Runtime>;
|
|
32
37
|
export declare const RUNTIME_CONTEXT: import("..").Descriptor<RuntimeContext<Record<string, unknown>>>;
|
|
33
38
|
export declare const ROUTE_CONTEXT: import("..").Descriptor<RouteContext>;
|
package/package.json
CHANGED
package/src/types/index.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
declare module "#virtual/
|
|
2
|
-
|
|
3
|
-
}
|
|
1
|
+
declare module "#virtual/runtime" {
|
|
2
|
+
import type { Runtime } from "revojs";
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
export const assets: Record<string, () => Promise<string>>;
|
|
4
|
+
export const runtime: Runtime;
|
|
7
5
|
}
|
|
8
6
|
|
|
9
7
|
declare module "#virtual/client" {
|
|
@@ -15,11 +13,19 @@ declare module "#virtual/client" {
|
|
|
15
13
|
declare module "#virtual/routes" {
|
|
16
14
|
import type { Route, Slot } from "revojs";
|
|
17
15
|
|
|
18
|
-
|
|
16
|
+
const routes: Record<string, Route | Slot>;
|
|
17
|
+
|
|
18
|
+
export default routes;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
declare module "#virtual/
|
|
22
|
-
|
|
21
|
+
declare module "#virtual/locales" {
|
|
22
|
+
const locales: Record<string, Record<string, string>>;
|
|
23
23
|
|
|
24
|
-
export
|
|
24
|
+
export default locales;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
declare module "#virtual/assets" {
|
|
28
|
+
const assets: Record<string, string>;
|
|
29
|
+
|
|
30
|
+
export default assets;
|
|
25
31
|
}
|