htmx-router 1.0.0-alpha.4 → 1.0.0-alpha.6
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/{bin/util/css.js → css.js} +1 -1
- package/dynamic.d.ts +5 -0
- package/{bin/util/dynamic.js → dynamic.js} +20 -7
- package/{bin/util/endpoint.d.ts → endpoint.d.ts} +2 -2
- package/{bin/util/endpoint.js → endpoint.js} +3 -1
- package/event-source.d.ts +26 -0
- package/event-source.js +123 -0
- package/example/eventdim-react/package.json +67 -0
- package/example/eventdim-react/server.js +90 -0
- package/example/island-react/global.d.ts +8 -0
- package/example/island-react/package.json +38 -0
- package/example/island-react/server.js +58 -0
- package/global.d.ts +7 -0
- package/index.d.ts +19 -0
- package/index.js +2 -0
- package/internal/cli/config.d.ts +13 -0
- package/internal/cli/config.js +11 -0
- package/internal/cli/index.js +15 -0
- package/internal/client.d.ts +1 -0
- package/{bin/client/entry.js → internal/client.js} +3 -1
- package/internal/compile/manifest.d.ts +1 -0
- package/internal/compile/manifest.js +178 -0
- package/internal/compile/router.d.ts +1 -0
- package/internal/compile/router.js +51 -0
- package/internal/component/dynamic.d.ts +4 -0
- package/internal/component/dynamic.js +18 -0
- package/internal/component/head.d.ts +5 -0
- package/internal/component/head.js +22 -0
- package/internal/component/scripts.d.ts +4 -0
- package/internal/component/scripts.js +23 -0
- package/{bin/client → internal}/mount.js +15 -9
- package/internal/request/http.d.ts +10 -0
- package/internal/request/http.js +61 -0
- package/{bin → internal}/request/index.d.ts +3 -3
- package/internal/request/index.js +8 -0
- package/{bin → internal}/request/native.d.ts +2 -2
- package/{bin → internal}/request/native.js +12 -14
- package/{bin/helper.d.ts → internal/util.d.ts} +2 -0
- package/{bin/helper.js → internal/util.js} +15 -0
- package/package.json +9 -5
- package/readme.md +2 -214
- package/{bin/request → request}/http.d.ts +1 -1
- package/{bin/request → request}/http.js +22 -4
- package/request/index.d.ts +13 -0
- package/request/index.js +3 -0
- package/request/native.d.ts +9 -0
- package/request/native.js +46 -0
- package/response.d.ts +13 -0
- package/{bin/response.js → response.js} +25 -12
- package/{bin/router.d.ts → router.d.ts} +12 -10
- package/{bin/router.js → router.js} +62 -48
- package/shell.d.ts +120 -0
- package/shell.js +253 -0
- package/{bin/util → util}/parameters.d.ts +0 -3
- package/{bin/util → util}/parameters.js +0 -3
- package/{bin/util → util}/path-builder.js +2 -0
- package/util/route.d.ts +2 -0
- package/util/route.js +58 -0
- package/vite/bundle-splitter.d.ts +4 -0
- package/vite/bundle-splitter.js +26 -0
- package/vite/client-island.d.ts +4 -0
- package/vite/client-island.js +14 -0
- package/vite/code-splitting.d.ts +4 -0
- package/vite/code-splitting.js +14 -0
- package/vite/index.d.ts +3 -0
- package/vite/index.js +3 -0
- package/vite/router.d.ts +2 -0
- package/vite/router.js +29 -0
- package/bin/cli/config.d.ts +0 -10
- package/bin/cli/config.js +0 -4
- package/bin/cli/index.js +0 -72
- package/bin/client/entry.d.ts +0 -1
- package/bin/client/index.d.ts +0 -7
- package/bin/client/index.js +0 -126
- package/bin/client/watch.d.ts +0 -1
- package/bin/client/watch.js +0 -11
- package/bin/index.d.ts +0 -9
- package/bin/index.js +0 -8
- package/bin/request/index.js +0 -6
- package/bin/response.d.ts +0 -4
- package/bin/types.d.ts +0 -10
- package/bin/types.js +0 -1
- package/bin/util/dynamic.d.ts +0 -8
- package/bin/util/event-source.d.ts +0 -16
- package/bin/util/event-source.js +0 -85
- package/bin/util/index.d.ts +0 -1
- package/bin/util/index.js +0 -7
- package/bin/util/shell.d.ts +0 -32
- package/bin/util/shell.js +0 -8
- /package/{bin/util/cookies.d.ts → cookies.d.ts} +0 -0
- /package/{bin/util/cookies.js → cookies.js} +0 -0
- /package/{bin/util/css.d.ts → css.d.ts} +0 -0
- /package/{bin → internal}/cli/index.d.ts +0 -0
- /package/{bin/util → internal}/hash.d.ts +0 -0
- /package/{bin/util → internal}/hash.js +0 -0
- /package/{bin/client → internal}/mount.d.ts +0 -0
- /package/{bin/util → util}/path-builder.d.ts +0 -0
package/shell.d.ts
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
export type ShellOptions<D = {}> = D & MetaDescriptor;
|
|
2
|
+
export declare function ApplyMetaDescriptorDefaults(options: ShellOptions, defaults: Readonly<Partial<ShellOptions>>): void;
|
|
3
|
+
export type InferShellOptions<F> = F extends (jsx: any, options: infer U) => any ? U : never;
|
|
4
|
+
export type MetaDescriptor = {
|
|
5
|
+
title?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
meta?: Record<string, string>;
|
|
8
|
+
og?: OpenGraph<string>;
|
|
9
|
+
jsonLD?: LdJsonObject[];
|
|
10
|
+
};
|
|
11
|
+
export declare function RenderMetaDescriptor<T>(options: ShellOptions<T>): string;
|
|
12
|
+
export type LdJsonObject = {
|
|
13
|
+
[Key in string]?: LdJsonValue | undefined;
|
|
14
|
+
};
|
|
15
|
+
type LdJsonArray = LdJsonValue[] | readonly LdJsonValue[];
|
|
16
|
+
type LdJsonPrimitive = string | number | boolean | null;
|
|
17
|
+
type LdJsonValue = LdJsonPrimitive | LdJsonObject | LdJsonArray;
|
|
18
|
+
export type OpenGraphType = "website" | "article" | "book" | "profile" | "music.song" | "music.album" | "music.playlist" | "music.radio_station" | "video.movie" | "video.episode" | "video.tv_show" | "video.other" | string;
|
|
19
|
+
export type OpenGraph<T extends OpenGraphType = string> = {
|
|
20
|
+
type?: T;
|
|
21
|
+
title?: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
determiner?: string;
|
|
24
|
+
url?: string;
|
|
25
|
+
secure_url?: string;
|
|
26
|
+
locale?: string | {
|
|
27
|
+
base: string;
|
|
28
|
+
alternative: string[];
|
|
29
|
+
};
|
|
30
|
+
image?: OpenGraphImage[];
|
|
31
|
+
video?: OpenGraphVideo[];
|
|
32
|
+
audio?: OpenGraphAudio[];
|
|
33
|
+
} & (T extends "music.song" ? OpenGraphSong : T extends "music.album" ? OpenGraphAlbum : T extends "music.playlist" ? OpenGraphPlaylist : T extends "music.radio_station" ? OpenGraphRadioStation : T extends "video.movie" ? OpenGraphMovie : T extends "video.episode" ? OpenGraphEpisode : T extends "video.tv_show" ? OpenGraphTvShow : T extends "video.other" ? OpenGraphVideoOther : T extends "article" ? OpenGraphArticle : T extends "book" ? OpenGraphBook : T extends "profile" ? OpenGraphProfile : {});
|
|
34
|
+
export type OpenGraphImage = {
|
|
35
|
+
url: string;
|
|
36
|
+
secure_url?: string;
|
|
37
|
+
type?: string;
|
|
38
|
+
width?: number;
|
|
39
|
+
height?: number;
|
|
40
|
+
alt?: string;
|
|
41
|
+
};
|
|
42
|
+
export type OpenGraphVideo = {
|
|
43
|
+
url: string;
|
|
44
|
+
type?: string;
|
|
45
|
+
secure_url?: string;
|
|
46
|
+
width?: number;
|
|
47
|
+
height?: number;
|
|
48
|
+
alt?: string;
|
|
49
|
+
};
|
|
50
|
+
export type OpenGraphAudio = {
|
|
51
|
+
url: string;
|
|
52
|
+
type?: string;
|
|
53
|
+
secure_url?: string;
|
|
54
|
+
};
|
|
55
|
+
type OpenGraphSong = {
|
|
56
|
+
duration?: number;
|
|
57
|
+
album?: Array<string | {
|
|
58
|
+
url: string;
|
|
59
|
+
disc?: number;
|
|
60
|
+
track?: number;
|
|
61
|
+
}>;
|
|
62
|
+
musician?: string[];
|
|
63
|
+
};
|
|
64
|
+
type OpenGraphAlbum = {
|
|
65
|
+
songs?: Array<string | {
|
|
66
|
+
url: string;
|
|
67
|
+
disc?: number;
|
|
68
|
+
track?: number;
|
|
69
|
+
}>;
|
|
70
|
+
musician?: string[];
|
|
71
|
+
release_date?: Date;
|
|
72
|
+
};
|
|
73
|
+
type OpenGraphPlaylist = {
|
|
74
|
+
songs?: Array<string | {
|
|
75
|
+
url: string;
|
|
76
|
+
disc?: number;
|
|
77
|
+
track?: number;
|
|
78
|
+
}>;
|
|
79
|
+
creator?: string[];
|
|
80
|
+
};
|
|
81
|
+
type OpenGraphRadioStation = {
|
|
82
|
+
creator?: string[];
|
|
83
|
+
};
|
|
84
|
+
type OpenGraphMovie = {
|
|
85
|
+
actors?: Array<string | {
|
|
86
|
+
url: string;
|
|
87
|
+
role: string;
|
|
88
|
+
}>;
|
|
89
|
+
directors?: string[];
|
|
90
|
+
writers?: string[];
|
|
91
|
+
duration?: number;
|
|
92
|
+
release_date?: Date;
|
|
93
|
+
tag: string[];
|
|
94
|
+
};
|
|
95
|
+
type OpenGraphEpisode = OpenGraphMovie & {
|
|
96
|
+
series?: string;
|
|
97
|
+
};
|
|
98
|
+
type OpenGraphTvShow = OpenGraphMovie;
|
|
99
|
+
type OpenGraphVideoOther = OpenGraphMovie;
|
|
100
|
+
type OpenGraphArticle = {
|
|
101
|
+
published_time?: Date;
|
|
102
|
+
modified_time?: Date;
|
|
103
|
+
expiration_time?: Date;
|
|
104
|
+
authors?: string[];
|
|
105
|
+
section?: string;
|
|
106
|
+
tag?: string;
|
|
107
|
+
};
|
|
108
|
+
type OpenGraphBook = {
|
|
109
|
+
authors?: string[];
|
|
110
|
+
isbn?: string;
|
|
111
|
+
release_date?: Date;
|
|
112
|
+
tag?: string;
|
|
113
|
+
};
|
|
114
|
+
type OpenGraphProfile = {
|
|
115
|
+
first_name?: string;
|
|
116
|
+
last_name?: string;
|
|
117
|
+
username?: string;
|
|
118
|
+
gender?: "male" | "female";
|
|
119
|
+
};
|
|
120
|
+
export {};
|
package/shell.js
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { ServerOnlyWarning } from "./internal/util.js";
|
|
2
|
+
ServerOnlyWarning("shell");
|
|
3
|
+
export function ApplyMetaDescriptorDefaults(options, defaults) {
|
|
4
|
+
if (defaults.title && !options.title)
|
|
5
|
+
options.title = defaults.title;
|
|
6
|
+
if (defaults.description && !options.description)
|
|
7
|
+
options.description = defaults.description;
|
|
8
|
+
if (defaults.meta && !options.meta)
|
|
9
|
+
options.meta = defaults.meta;
|
|
10
|
+
if (defaults.og && !options.og)
|
|
11
|
+
options.og = defaults.og;
|
|
12
|
+
if (defaults.jsonLD && !options.jsonLD)
|
|
13
|
+
options.jsonLD = defaults.jsonLD;
|
|
14
|
+
}
|
|
15
|
+
export function RenderMetaDescriptor(options) {
|
|
16
|
+
let out = "";
|
|
17
|
+
if (options.title)
|
|
18
|
+
out += `<title>${EscapeHTML(options.title)}</title>`;
|
|
19
|
+
if (options.description)
|
|
20
|
+
out += `<meta name="description" content="${EscapeHTML(options.description)}">\n`;
|
|
21
|
+
if (options.meta)
|
|
22
|
+
for (const key in options.meta) {
|
|
23
|
+
out += `<meta name="${EscapeHTML(key)}" content="${EscapeHTML(options.meta[key])}">\n`;
|
|
24
|
+
}
|
|
25
|
+
if (options.jsonLD)
|
|
26
|
+
for (const json of options.jsonLD) {
|
|
27
|
+
out += `<script type="application/ld+json">${JSON.stringify(json)}</script>\n`;
|
|
28
|
+
}
|
|
29
|
+
// Auto apply og:title + og:description if not present
|
|
30
|
+
if (options.title && !options.og?.title)
|
|
31
|
+
out += `<meta property="og:title" content="${EscapeHTML(options.title)}">\n`;
|
|
32
|
+
if (options.description && !options.og?.description)
|
|
33
|
+
out += `<meta property="og:description" content="${EscapeHTML(options.description)}">\n`;
|
|
34
|
+
// Apply open graphs
|
|
35
|
+
if (options.og)
|
|
36
|
+
out += RenderOpenGraph(options.og);
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
function RenderOpenGraph(og) {
|
|
40
|
+
// Manually encoding everything rather than using a loop to ensure they are in the correct order
|
|
41
|
+
// And to ensure extra values can't leak in creating unsafe og tags
|
|
42
|
+
const type = og.type || "website";
|
|
43
|
+
let out = RenderProperty("og:type", type);
|
|
44
|
+
if (og.title)
|
|
45
|
+
out += RenderProperty("og:title", og.title);
|
|
46
|
+
if (og.description)
|
|
47
|
+
out += RenderProperty("og:description", og.description);
|
|
48
|
+
if (og.determiner)
|
|
49
|
+
out += RenderProperty("og:determiner", og.determiner);
|
|
50
|
+
if (og.url)
|
|
51
|
+
out += RenderProperty("og:url", og.url);
|
|
52
|
+
if (og.secure_url)
|
|
53
|
+
out += RenderProperty("og:secure_url", og.secure_url);
|
|
54
|
+
if (og.locale) {
|
|
55
|
+
if (typeof og.locale === "string")
|
|
56
|
+
out += RenderProperty("og:locale", og.locale);
|
|
57
|
+
else {
|
|
58
|
+
out += RenderProperty("og:locale", og.locale.base);
|
|
59
|
+
for (const l of og.locale.alternative)
|
|
60
|
+
out += RenderProperty("og:locale:alternative", l);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (og.image)
|
|
64
|
+
for (const img of og.image) {
|
|
65
|
+
out += RenderProperty("og:image", img.url);
|
|
66
|
+
if (img.secure_url)
|
|
67
|
+
out += RenderProperty("og:image:secure_url", img.secure_url);
|
|
68
|
+
if (img.type)
|
|
69
|
+
out += RenderProperty("og:image:type", img.type);
|
|
70
|
+
if (img.width)
|
|
71
|
+
out += RenderProperty("og:image:width", img.width.toString());
|
|
72
|
+
if (img.height)
|
|
73
|
+
out += RenderProperty("og:image:height", img.height.toString());
|
|
74
|
+
if (img.alt)
|
|
75
|
+
out += RenderProperty("og:image:alt", img.alt);
|
|
76
|
+
}
|
|
77
|
+
if (og.video)
|
|
78
|
+
for (const vid of og.video) {
|
|
79
|
+
out += RenderProperty("og:video", vid.url);
|
|
80
|
+
if (vid.secure_url)
|
|
81
|
+
out += RenderProperty("og:video:secure_url", vid.secure_url);
|
|
82
|
+
if (vid.type)
|
|
83
|
+
out += RenderProperty("og:video:type", vid.type);
|
|
84
|
+
if (vid.width)
|
|
85
|
+
out += RenderProperty("og:video:width", vid.width.toString());
|
|
86
|
+
if (vid.height)
|
|
87
|
+
out += RenderProperty("og:video:height", vid.height.toString());
|
|
88
|
+
if (vid.alt)
|
|
89
|
+
out += RenderProperty("og:video:alt", vid.alt);
|
|
90
|
+
}
|
|
91
|
+
if (og.audio)
|
|
92
|
+
for (const audio of og.audio) {
|
|
93
|
+
out += RenderProperty("og:audio", audio.url);
|
|
94
|
+
if (audio.secure_url)
|
|
95
|
+
out += RenderProperty("og:audio:secure_url", audio.secure_url);
|
|
96
|
+
if (audio.type)
|
|
97
|
+
out += RenderProperty("og:audio:type", audio.type);
|
|
98
|
+
}
|
|
99
|
+
return out + RenderOpenGraphExtras(og);
|
|
100
|
+
}
|
|
101
|
+
function RenderProperty(name, value) {
|
|
102
|
+
return `<meta property="${name}" content="${EscapeHTML(value)}">\n`;
|
|
103
|
+
}
|
|
104
|
+
function RenderOpenGraphExtras(og) {
|
|
105
|
+
let out = "";
|
|
106
|
+
if (og.type === "music.song") {
|
|
107
|
+
const g = og;
|
|
108
|
+
if (g.duration)
|
|
109
|
+
out += RenderProperty("og:music:duration", g.duration.toString());
|
|
110
|
+
if (g.album)
|
|
111
|
+
for (const album of g.album) {
|
|
112
|
+
if (typeof album === "string")
|
|
113
|
+
out += RenderProperty("og:music:album", album);
|
|
114
|
+
else {
|
|
115
|
+
out += RenderProperty("og:music:album", album.url);
|
|
116
|
+
if (album.disc)
|
|
117
|
+
out += RenderProperty("og:music:album:disc", album.disc.toString());
|
|
118
|
+
if (album.track)
|
|
119
|
+
out += RenderProperty("og:music:album:track", album.track.toString());
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (g.musician)
|
|
123
|
+
for (const profile of g.musician)
|
|
124
|
+
out += RenderProperty("og:music:musician", profile);
|
|
125
|
+
return out;
|
|
126
|
+
}
|
|
127
|
+
if (og.type === "music.album") {
|
|
128
|
+
const g = og;
|
|
129
|
+
if (g.songs)
|
|
130
|
+
for (const song of g.songs) {
|
|
131
|
+
if (typeof song === "string")
|
|
132
|
+
out += RenderProperty("og:music:song", song);
|
|
133
|
+
else {
|
|
134
|
+
out += RenderProperty("og:music:song", song.url);
|
|
135
|
+
if (song.disc)
|
|
136
|
+
out += RenderProperty("og:music:song:disc", song.disc.toString());
|
|
137
|
+
if (song.track)
|
|
138
|
+
out += RenderProperty("og:music:song:track", song.track.toString());
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (g.musician)
|
|
142
|
+
for (const profile of g.musician)
|
|
143
|
+
out += RenderProperty("og:music:musician", profile);
|
|
144
|
+
if (g.release_date)
|
|
145
|
+
out += RenderProperty("og:music:release_date", g.release_date.toISOString());
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
148
|
+
if (og.type === "music.playlist") {
|
|
149
|
+
const g = og;
|
|
150
|
+
if (g.songs)
|
|
151
|
+
for (const song of g.songs) {
|
|
152
|
+
if (typeof song === "string")
|
|
153
|
+
out += RenderProperty("og:music:song", song);
|
|
154
|
+
else {
|
|
155
|
+
out += RenderProperty("og:music:song", song.url);
|
|
156
|
+
if (song.disc)
|
|
157
|
+
out += RenderProperty("og:music:song:disc", song.disc.toString());
|
|
158
|
+
if (song.track)
|
|
159
|
+
out += RenderProperty("og:music:song:track", song.track.toString());
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (g.creator)
|
|
163
|
+
for (const profile of g.creator)
|
|
164
|
+
out += RenderProperty("og:music:creator", profile);
|
|
165
|
+
return out;
|
|
166
|
+
}
|
|
167
|
+
if (og.type === "music.radio_station") {
|
|
168
|
+
const g = og;
|
|
169
|
+
if (g.creator)
|
|
170
|
+
for (const profile of g.creator)
|
|
171
|
+
out += RenderProperty("og:music:creator", profile);
|
|
172
|
+
return out;
|
|
173
|
+
}
|
|
174
|
+
if (og.type === "video.movie" || og.type === "video.episode" || og.type === "video.tv_show" || og.type === "video.other") {
|
|
175
|
+
const g = og;
|
|
176
|
+
if (g.actors)
|
|
177
|
+
for (const actor of g.actors) {
|
|
178
|
+
if (typeof actor === "string")
|
|
179
|
+
out += RenderProperty("og:video:actor", actor);
|
|
180
|
+
else {
|
|
181
|
+
out += RenderProperty("og:video:actor", actor.url);
|
|
182
|
+
out += RenderProperty("og:video:actor:role", actor.role);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (g.directors)
|
|
186
|
+
for (const profile of g.directors)
|
|
187
|
+
out += RenderProperty("og:video:director", profile);
|
|
188
|
+
if (g.writers)
|
|
189
|
+
for (const profile of g.writers)
|
|
190
|
+
out += RenderProperty("og:video:writer", profile);
|
|
191
|
+
if (g.duration)
|
|
192
|
+
out += RenderProperty("og:video:duration", g.duration.toString());
|
|
193
|
+
if (g.release_date)
|
|
194
|
+
out += RenderProperty("og:video:release_date", g.release_date.toISOString());
|
|
195
|
+
if (g.tag)
|
|
196
|
+
for (const tag of g.tag)
|
|
197
|
+
out += RenderProperty("og:video:tag", tag);
|
|
198
|
+
if (g.series)
|
|
199
|
+
out += RenderProperty("og:video:series", g.series);
|
|
200
|
+
}
|
|
201
|
+
if (og.type === "article") {
|
|
202
|
+
const g = og;
|
|
203
|
+
if (g.published_time)
|
|
204
|
+
out += RenderProperty("og:article:published_time", g.published_time.toISOString());
|
|
205
|
+
if (g.modified_time)
|
|
206
|
+
out += RenderProperty("og:article:modified_time", g.modified_time.toISOString());
|
|
207
|
+
if (g.expiration_time)
|
|
208
|
+
out += RenderProperty("og:article:expiration_time", g.expiration_time.toISOString());
|
|
209
|
+
if (g.authors)
|
|
210
|
+
for (const profile of g.authors)
|
|
211
|
+
out += RenderProperty("og:article:author", profile);
|
|
212
|
+
if (g.section)
|
|
213
|
+
out += RenderProperty("og:article:section", g.section);
|
|
214
|
+
if (g.tag)
|
|
215
|
+
for (const tag of g.tag)
|
|
216
|
+
out += RenderProperty("og:video:tag", tag);
|
|
217
|
+
}
|
|
218
|
+
if (og.type === "book") {
|
|
219
|
+
const g = og;
|
|
220
|
+
if (g.authors)
|
|
221
|
+
for (const profile of g.authors)
|
|
222
|
+
out += RenderProperty("og:article:author", profile);
|
|
223
|
+
if (g.isbn)
|
|
224
|
+
out += RenderProperty("og:book:isbn", g.isbn);
|
|
225
|
+
if (g.release_date)
|
|
226
|
+
out += RenderProperty("og:book:release_date", g.release_date.toISOString());
|
|
227
|
+
if (g.tag)
|
|
228
|
+
for (const tag of g.tag)
|
|
229
|
+
out += RenderProperty("og:video:tag", tag);
|
|
230
|
+
}
|
|
231
|
+
if (og.type === "profile") {
|
|
232
|
+
const g = og;
|
|
233
|
+
if (g.first_name)
|
|
234
|
+
out += RenderProperty("og:profile:first_name", g.first_name);
|
|
235
|
+
if (g.last_name)
|
|
236
|
+
out += RenderProperty("og:profile:last_name", g.last_name);
|
|
237
|
+
if (g.username)
|
|
238
|
+
out += RenderProperty("og:profile:username", g.username);
|
|
239
|
+
if (g.gender)
|
|
240
|
+
out += RenderProperty("og:profile:gender", g.gender);
|
|
241
|
+
}
|
|
242
|
+
return "";
|
|
243
|
+
}
|
|
244
|
+
const escapeTo = {
|
|
245
|
+
"&": "&",
|
|
246
|
+
"<": "<",
|
|
247
|
+
">": ">",
|
|
248
|
+
"\"": """,
|
|
249
|
+
"'": "'",
|
|
250
|
+
};
|
|
251
|
+
function EscapeHTML(str) {
|
|
252
|
+
return str.replace(/[&<>"']/g, (match) => escapeTo[match] || match);
|
|
253
|
+
}
|
package/util/route.d.ts
ADDED
package/util/route.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ServerOnlyWarning } from "../internal/util.js";
|
|
2
|
+
ServerOnlyWarning("route-path");
|
|
3
|
+
export function RoutePath() {
|
|
4
|
+
const frags = new Array();
|
|
5
|
+
return (params) => {
|
|
6
|
+
const t = params;
|
|
7
|
+
if (typeof t === "string") {
|
|
8
|
+
Compile("/" + t, frags);
|
|
9
|
+
return "";
|
|
10
|
+
}
|
|
11
|
+
return Parse(frags, params);
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
const indexRoute = "/_index";
|
|
15
|
+
function Compile(url, into) {
|
|
16
|
+
let cursor = 0;
|
|
17
|
+
let i = 1;
|
|
18
|
+
for (; i < url.length; i++) {
|
|
19
|
+
if (url[i] !== "$")
|
|
20
|
+
continue;
|
|
21
|
+
if (url[i - 1] !== "/")
|
|
22
|
+
continue;
|
|
23
|
+
let e = url.indexOf("/", i + 1);
|
|
24
|
+
if (e === -1)
|
|
25
|
+
e = url.length;
|
|
26
|
+
into.push(url.slice(cursor, i));
|
|
27
|
+
into.push(url.slice(i, e));
|
|
28
|
+
cursor = e;
|
|
29
|
+
i = e - 1;
|
|
30
|
+
}
|
|
31
|
+
// remainder
|
|
32
|
+
if (cursor != i)
|
|
33
|
+
into.push(url.slice(cursor));
|
|
34
|
+
// remove _index from end if present
|
|
35
|
+
const lastI = into.length - 1;
|
|
36
|
+
const last = into[lastI];
|
|
37
|
+
if (last && last.endsWith(indexRoute)) {
|
|
38
|
+
if (last.length === indexRoute.length)
|
|
39
|
+
into.length--;
|
|
40
|
+
else
|
|
41
|
+
into[lastI] = last.slice(0, -indexRoute.length);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function Parse(fragments, params) {
|
|
45
|
+
let out = "";
|
|
46
|
+
for (const frag of fragments) {
|
|
47
|
+
if (!frag.startsWith("$")) {
|
|
48
|
+
out += frag;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const key = frag.slice(1);
|
|
52
|
+
const param = params[key];
|
|
53
|
+
if (!param)
|
|
54
|
+
throw new Error(`Missing ${key} parameter required for route`);
|
|
55
|
+
out += param;
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ServerOnlyWarning } from "../internal/util.js";
|
|
2
|
+
ServerOnlyWarning("bundle-splitter");
|
|
3
|
+
const serverPattern = /\.server\.[tj]s(x)?/;
|
|
4
|
+
const clientPattern = /\.client\.[tj]s(x)?/;
|
|
5
|
+
const BLANK_MODULE = "export {};";
|
|
6
|
+
export function BundleSplitter() {
|
|
7
|
+
return {
|
|
8
|
+
name: "htmx-bundle-splitter",
|
|
9
|
+
enforce: "pre",
|
|
10
|
+
transform: (code, id, options) => {
|
|
11
|
+
const ssr = options?.ssr || false;
|
|
12
|
+
const pattern = ssr ? clientPattern : serverPattern;
|
|
13
|
+
if (pattern.test(id))
|
|
14
|
+
return BLANK_MODULE;
|
|
15
|
+
if (ssr) {
|
|
16
|
+
if (code.startsWith('"use client"'))
|
|
17
|
+
return BLANK_MODULE;
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
if (code.startsWith('"use server"'))
|
|
21
|
+
return BLANK_MODULE;
|
|
22
|
+
}
|
|
23
|
+
return code;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { resolve } from "path";
|
|
2
|
+
import { CompileManifest } from "../internal/compile/manifest.js";
|
|
3
|
+
export function ClientIsland(framework) {
|
|
4
|
+
const file = resolve("./app/manifest.tsx").replaceAll("\\", "/");
|
|
5
|
+
return {
|
|
6
|
+
name: "vite-plugin-htmx-client-island",
|
|
7
|
+
enforce: "pre",
|
|
8
|
+
transform: (code, id, options) => {
|
|
9
|
+
if (id !== file)
|
|
10
|
+
return code;
|
|
11
|
+
return CompileManifest(framework, code, options?.ssr || false);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const serverPattern = /\.server\.[tj]s(x)?/;
|
|
2
|
+
const clientPattern = /\.client\.[tj]s(x)?/;
|
|
3
|
+
export function BundleSplitting() {
|
|
4
|
+
return {
|
|
5
|
+
name: "htmx-bundle-splitter",
|
|
6
|
+
enforce: "pre",
|
|
7
|
+
transform: (code, id, options) => {
|
|
8
|
+
const pattern = options?.ssr ? clientPattern : serverPattern;
|
|
9
|
+
if (pattern.test(id))
|
|
10
|
+
return "export {};";
|
|
11
|
+
return code;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
}
|
package/vite/index.d.ts
ADDED
package/vite/index.js
ADDED
package/vite/router.d.ts
ADDED
package/vite/router.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export function Router() {
|
|
2
|
+
const virtualModuleId = "virtual:htmx-router/dynamic.tsx";
|
|
3
|
+
const resolvedVirtualModuleId = '\0' + virtualModuleId;
|
|
4
|
+
return {
|
|
5
|
+
name: "vite-plugin-htmx-router",
|
|
6
|
+
resolveId(id) {
|
|
7
|
+
if (id === virtualModuleId)
|
|
8
|
+
return resolvedVirtualModuleId;
|
|
9
|
+
},
|
|
10
|
+
load(id) {
|
|
11
|
+
if (id !== resolvedVirtualModuleId)
|
|
12
|
+
return;
|
|
13
|
+
return source;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
const source = `export function Scripts() {
|
|
18
|
+
if (headCache) return headCache;
|
|
19
|
+
|
|
20
|
+
const res = <>
|
|
21
|
+
<link href={GetSheetUrl()} rel="stylesheet"></link>
|
|
22
|
+
{ isProduction ? "" : <script type="module" src="/@vite/client"></script> }
|
|
23
|
+
<script type="module" src={clientEntry}></script>
|
|
24
|
+
<script src={GetMountUrl()}></script>
|
|
25
|
+
</>;
|
|
26
|
+
|
|
27
|
+
if (isProduction) headCache = res;
|
|
28
|
+
return res;
|
|
29
|
+
}`;
|
package/bin/cli/config.d.ts
DELETED
package/bin/cli/config.js
DELETED
package/bin/cli/index.js
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
import { writeFile } from "fs/promises";
|
|
4
|
-
import { relative } from "path";
|
|
5
|
-
import { GenerateClient } from "../client/index.js";
|
|
6
|
-
import { ReadConfig } from "../cli/config.js";
|
|
7
|
-
const config = await ReadConfig();
|
|
8
|
-
console.info("Building router");
|
|
9
|
-
const routes = relative(config.router.output, config.router.folder).replaceAll("\\", "/").slice(1);
|
|
10
|
-
await writeFile(config.router.output, `/*------------------------------------------
|
|
11
|
-
* Generated by htmx-router *
|
|
12
|
-
* Warn: Any changes will be overwritten *
|
|
13
|
-
-------------------------------------------*/
|
|
14
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
15
|
-
|
|
16
|
-
import { GenericContext, RouteTree } from "htmx-router/bin/router";
|
|
17
|
-
import { RegisterDynamic } from "htmx-router/bin/util/dynamic";
|
|
18
|
-
import { GetClientEntryURL } from 'htmx-router/bin/client/entry';
|
|
19
|
-
import { GetMountUrl } from 'htmx-router/bin/client/mount';
|
|
20
|
-
import { GetSheetUrl } from 'htmx-router/bin/util/css';
|
|
21
|
-
import { RouteModule } from "htmx-router";
|
|
22
|
-
import { resolve } from "path";
|
|
23
|
-
|
|
24
|
-
(globalThis as any).HTMX_ROUTER_ROOT = resolve('${config.router.folder.replaceAll("\\", "/")}');
|
|
25
|
-
const modules = import.meta.glob('${routes}/**/*.{ts,tsx}', { eager: true });
|
|
26
|
-
|
|
27
|
-
export const tree = new RouteTree();
|
|
28
|
-
for (const path in modules) {
|
|
29
|
-
const tail = path.lastIndexOf(".");
|
|
30
|
-
const url = path.slice(${routes.length + 1}, tail);
|
|
31
|
-
tree.ingest(url, modules[path] as RouteModule<any>);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function Dynamic<T extends Record<string, string>>(props: {
|
|
35
|
-
params: T,
|
|
36
|
-
loader: (params: T, ctx: GenericContext) => Promise<JSX.Element>
|
|
37
|
-
children?: JSX.Element
|
|
38
|
-
}): JSX.Element {
|
|
39
|
-
const path = RegisterDynamic(props.loader);
|
|
40
|
-
|
|
41
|
-
const query = new URLSearchParams();
|
|
42
|
-
for (const key in props.params) query.set(key, props.params[key]);
|
|
43
|
-
const url = path + query.toString();
|
|
44
|
-
|
|
45
|
-
return <div
|
|
46
|
-
hx-get={url}
|
|
47
|
-
hx-trigger="load"
|
|
48
|
-
hx-swap="outerHTML transition:true"
|
|
49
|
-
style={{ display: "contents" }}
|
|
50
|
-
>{props.children ? props.children : ""}</div>
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
let headCache: JSX.Element | null = null;
|
|
54
|
-
const isProduction = process.env.NODE_ENV === "production";
|
|
55
|
-
const clientEntry = await GetClientEntryURL();
|
|
56
|
-
export function Scripts() {
|
|
57
|
-
if (headCache) return headCache;
|
|
58
|
-
|
|
59
|
-
const res = <>
|
|
60
|
-
<link href={GetSheetUrl()} rel="stylesheet"></link>
|
|
61
|
-
{ isProduction ? "" : <script type="module" src="/@vite/client"></script> }
|
|
62
|
-
<script type="module" src={clientEntry}></script>
|
|
63
|
-
<script src={GetMountUrl()}></script>
|
|
64
|
-
</>;
|
|
65
|
-
|
|
66
|
-
if (isProduction) headCache = res;
|
|
67
|
-
return res;
|
|
68
|
-
}`);
|
|
69
|
-
if (config.client) {
|
|
70
|
-
console.info("Building client islands");
|
|
71
|
-
await GenerateClient(config.client, true);
|
|
72
|
-
}
|
package/bin/client/entry.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function GetClientEntryURL(): Promise<any>;
|