htmx-router 0.1.3 → 1.0.0-alpha.0
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/cli/config.d.ts +10 -0
- package/bin/cli/config.js +4 -0
- package/bin/cli/index.js +54 -10
- package/bin/client/index.d.ts +4 -0
- package/bin/client/index.js +100 -0
- package/bin/client/mount.d.ts +2 -0
- package/bin/client/mount.js +75 -0
- package/bin/client/watch.d.ts +1 -0
- package/bin/client/watch.js +19 -0
- package/bin/helper.d.ts +1 -2
- package/bin/helper.js +25 -14
- package/bin/index.d.ts +8 -6
- package/bin/index.js +7 -16
- package/bin/request/http.d.ts +10 -0
- package/bin/request/http.js +46 -0
- package/bin/request/index.d.ts +16 -0
- package/bin/request/index.js +6 -0
- package/bin/request/native.d.ts +9 -0
- package/bin/request/native.js +56 -0
- package/bin/router.d.ts +41 -16
- package/bin/router.js +176 -236
- package/bin/types.d.ts +10 -0
- package/bin/types.js +1 -0
- package/bin/util/cookies.d.ts +22 -0
- package/bin/util/cookies.js +57 -0
- package/bin/util/css.d.ts +9 -0
- package/bin/util/css.js +47 -0
- package/bin/util/dynamic.d.ts +5 -0
- package/bin/util/dynamic.js +26 -0
- package/bin/util/endpoint.d.ts +9 -0
- package/bin/util/endpoint.js +28 -0
- package/bin/util/event-source.d.ts +16 -0
- package/bin/util/event-source.js +85 -0
- package/bin/util/hash.d.ts +1 -0
- package/bin/util/hash.js +7 -0
- package/bin/util/index.d.ts +1 -0
- package/bin/util/index.js +7 -0
- package/bin/util/parameters.d.ts +7 -0
- package/bin/util/parameters.js +14 -0
- package/bin/util/shell.d.ts +32 -0
- package/bin/util/shell.js +1 -0
- package/package.json +9 -7
- package/readme.md +149 -211
- package/bin/404-route.d.ts +0 -2
- package/bin/404-route.js +0 -8
- package/bin/cli/dynamic.d.ts +0 -2
- package/bin/cli/dynamic.js +0 -47
- package/bin/cli/static.d.ts +0 -2
- package/bin/cli/static.js +0 -49
- package/bin/components.d.ts +0 -6
- package/bin/components.js +0 -31
- package/bin/render-args.d.ts +0 -35
- package/bin/render-args.js +0 -140
- package/bin/shared.d.ts +0 -28
- package/bin/shared.js +0 -28
package/readme.md
CHANGED
|
@@ -1,279 +1,217 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
# htmx Router
|
|
2
|
+
|
|
3
|
+
A simple file based router with support for dynamic + client islands, route-less endpoints, and built in CSS sheet generation.
|
|
4
|
+
|
|
5
|
+
- [htmx Router](#htmx-router)
|
|
6
|
+
- [Setup](#setup)
|
|
7
|
+
- [Routing](#routing)
|
|
8
|
+
- [Route Module](#route-module)
|
|
9
|
+
- [Nested Route Rendering](#nested-route-rendering)
|
|
10
|
+
- [JSX Rendering](#jsx-rendering)
|
|
11
|
+
- [Route Contexts](#route-contexts)
|
|
12
|
+
- [Params](#params)
|
|
13
|
+
- [Cookies](#cookies)
|
|
14
|
+
- [Headers](#headers)
|
|
15
|
+
- [Request](#request)
|
|
16
|
+
- [URL](#url)
|
|
17
|
+
- [Style Sheets](#style-sheets)
|
|
18
|
+
- [Route-less Endpoint](#route-less-endpoint)
|
|
19
|
+
- [Islands](#islands)
|
|
20
|
+
- [Dynamic](#dynamic)
|
|
21
|
+
- [Client](#client)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
## Setup
|
|
25
|
+
|
|
26
|
+
Create a `htmx-router.json` in the root of your project defining where you want your router file to be placed, and where your routes are.
|
|
27
|
+
You can also define where you want to create your client component bindings, and for what target framework.
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"router": {
|
|
31
|
+
"folder": "./source/routes",
|
|
32
|
+
"output": "./source/router.tsx"
|
|
33
|
+
},
|
|
34
|
+
"client": {
|
|
35
|
+
"adapter": "react",
|
|
36
|
+
"source": "./source/client.tsx"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
8
40
|
|
|
9
|
-
|
|
41
|
+
Once you have done this, run `npx htmx-router` to generate the artifacts to start development.
|
|
42
|
+
We recommand you copy the setup from `examples/react` for your `server.js`, `entry.server.ts`, and `entry.client.ts`.
|
|
10
43
|
|
|
11
|
-
|
|
12
|
-
- [Routes](#routes)
|
|
13
|
-
- [Module Layout](#module-layout)
|
|
14
|
-
- [Auth Function](#auth-function)
|
|
15
|
-
- [Render Function](#render-function)
|
|
16
|
-
- [CatchError Function](#catcherror-function)
|
|
17
|
-
- [Router](#router)
|
|
18
|
-
- [Types](#types)
|
|
19
|
-
- [RenderArgs](#renderargs)
|
|
20
|
-
- [Outlet](#outlet)
|
|
21
|
-
- [setTitle](#settitle)
|
|
22
|
-
- [addMeta](#addmeta)
|
|
23
|
-
- [addLinks](#addlinks)
|
|
24
|
-
- [renderHeadHTML](#renderheadhtml)
|
|
25
|
-
- [shared](#shared)
|
|
26
|
-
- [ErrorResponse](#errorresponse)
|
|
27
|
-
- [Override](#override)
|
|
28
|
-
- [Redirect](#redirect)
|
|
29
|
-
- [Components](#components)
|
|
30
|
-
- [Link](#link)
|
|
31
|
-
- [StyleCSS](#stylecss)
|
|
44
|
+
Don't forget that in all rendered routes you must include the `<RouterHeader/>` component in your head for hydration and `StyleClass`s to apply affectively.
|
|
32
45
|
|
|
33
|
-
## Routes
|
|
34
46
|
|
|
35
|
-
|
|
47
|
+
## Routing
|
|
36
48
|
|
|
37
|
-
|
|
49
|
+
Routing applies in a depth first order, where it will match in order:
|
|
50
|
+
1. The `_index`
|
|
51
|
+
2. Static sub-routes
|
|
52
|
+
3. Url path-param wildcards
|
|
53
|
+
4. Catchall slug
|
|
38
54
|
|
|
39
|
-
|
|
55
|
+
This allows for easy overriding and fallback behaviour. For instance with the routes.
|
|
40
56
|
```
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
├── user.tsx
|
|
45
|
-
├── user.static-path.tsx
|
|
46
|
-
└── user.$userID.tsx
|
|
57
|
+
/user/$id.tsx
|
|
58
|
+
/user/me.tsx
|
|
59
|
+
/user/$.tsx
|
|
47
60
|
```
|
|
48
61
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
Since there is no `user.$userID.history.tsx` file, if `user.$userID.tsx` calls [Outlet](#outlet) it will trigger a 404 error, which is actually generated by an internal hidden route placed at the end of an Outlet chain when it is not able to match the rest of a given URL.
|
|
52
|
-
|
|
53
|
-
If we request `/user`, the root route will render, and the `user.tsx` route will render, with `user.tsx`'s [Outlet](#outlet) function actually returning a blank string. If we instead want this request to throw an error we should add a `user._index.tsx` file which on render always throws a `ErrorResponse`.
|
|
54
|
-
|
|
55
|
-
### Module Layout
|
|
62
|
+
It will match on the `/user/me` route if applicable, and otherwise will fallback to attempt to match on `/user/$id`, and if the wildcard route fails, it will try the generic slug route `/user/$.tsx`.
|
|
56
63
|
|
|
57
|
-
|
|
64
|
+
If a route returns `null` the router will continue the depth first search, allowing for dynamic flow through of the routes.
|
|
58
65
|
|
|
59
|
-
|
|
66
|
+
### Route Module
|
|
60
67
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
68
|
+
A route module must define a `parameters` export, which defines how the url path params should be parsed when attempting to match the route.
|
|
69
|
+
You can use any function which takes a string, and returns something as the parser. You can also simply use JS-Builtin functions for this, and there is a special case with the `Number` function so it will reject on `NaN` values.
|
|
70
|
+
```js
|
|
71
|
+
export const parameters = { id: Number };
|
|
66
72
|
```
|
|
67
73
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
#### Render Function
|
|
71
|
-
|
|
74
|
+
A route can additionally define a loader, which is called on `GET` and `HEAD` requests
|
|
72
75
|
```ts
|
|
73
|
-
export async function
|
|
76
|
+
export async function loader({}: RouteContext<typeof parameters>);
|
|
74
77
|
```
|
|
75
78
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
> **Note** that a render function may not always run for a given request, and may sometimes be ommited when the router determines the client already has this information in their DOM, and instead only response with the new data and where it should be inserted.
|
|
79
|
-
>
|
|
80
|
-
> For authorisation checks which must always run for a given URL, please use the [Auth](#auth) function
|
|
81
|
-
|
|
82
|
-
Optionally this function can also `throw`, in this case the thrown value will boil up until it hits a [CatchError](#catcherror), unless it throws certain types from this library such as `Redirect` or `Override` which will boil all the way to the top without triggering any [CatchError](#catcherror) functions.
|
|
83
|
-
|
|
84
|
-
This allows a given route to return an arbitrary response without being nested within it's parent routes.
|
|
85
|
-
|
|
86
|
-
#### CatchError Function
|
|
87
|
-
|
|
79
|
+
With the `action` function being called for all other methods
|
|
88
80
|
```ts
|
|
89
|
-
export async function
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
This function behaves almost identically to [Render](#render) in the way that it's results will be embed within it's parents unless an `Override` is thrown, and it takes a `routeName` which must be used in the root `HTML` element as the id. And it is given [RenderArgs](#renderargs).
|
|
93
|
-
|
|
94
|
-
However this function **must not** call the [Outlet](#outlet) function within the [RenderArgs](#renderargs), as that will attempt to consume a failed child route as it's result.
|
|
95
|
-
|
|
96
|
-
## Router
|
|
97
|
-
|
|
98
|
-
The router itself can be generated via two different ways through the CLI from this library, dynamically or statically.
|
|
99
|
-
|
|
100
|
-
```bash
|
|
101
|
-
npx htmx-router ./source/website --dynamic
|
|
81
|
+
export async function action({}: RouteContext<typeof parameters>);
|
|
102
82
|
```
|
|
103
83
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
- **Static**: The static build will read your directories and statically import all of your routes into itself, allowing for easy bundling with tools such as `esbuild`
|
|
107
|
-
- **Dynamic**: Will instead generate a file will on startup will read your directory every time, and dynamically import your routes, which will make it unsuitable for use with webpackers, but allows for quick revisions and working well with tools such as `nodemon`.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
Once your router is generated you can simply import it and use it like the example below:
|
|
84
|
+
If any value is thrown by the parameter parsing, or the render functions (`loader`/`action`) it will boil up, attempting first to call an error function is supplied in the route, and otherwise boiling up to the nearest slug route's `error` function.
|
|
111
85
|
```ts
|
|
112
|
-
|
|
113
|
-
const out = await Router.render(req, res, url);
|
|
114
|
-
if (out instanceof Redirect) {
|
|
115
|
-
res.statusCode = 302;
|
|
116
|
-
res.setHeader('Location', out.location);
|
|
117
|
-
return res.end();
|
|
118
|
-
} else if (out instanceof Override) {
|
|
119
|
-
res.end(out.data);
|
|
120
|
-
} else {
|
|
121
|
-
res.setHeader('Content-Type', 'text/html; charset=UTF-8');
|
|
122
|
-
res.end("<!DOCTYPE html>"+out);
|
|
123
|
-
}
|
|
86
|
+
export async function error(ctx: GenericContext, error: unknown);
|
|
124
87
|
```
|
|
125
88
|
|
|
126
|
-
|
|
89
|
+
### Nested Route Rendering
|
|
127
90
|
|
|
128
|
-
|
|
91
|
+
The router will not do nested layouts, if that behaviour is required we recommend using the slug-shell pattern.
|
|
92
|
+
Where you define a slug route, and export a `shell` function which takes the `JSX` rendered result from the sub route, and renders the upper route around it.
|
|
129
93
|
|
|
130
|
-
|
|
94
|
+
This allows flexibility at runtime on how nested route rendering behaves, and can also allow you to ensure you are not reloading data from the db which is already loaded by a sub-route based on how you parse up data through your slug shells.
|
|
131
95
|
|
|
132
|
-
|
|
96
|
+
We recommend you look at [Predictable Bot](https://github.com/AjaniBilby/predictable) as an example of this pattern performed simply.
|
|
133
97
|
|
|
134
|
-
```ts
|
|
135
|
-
export async function Render(rn: string, {req, res}: RenderArgs) {
|
|
136
|
-
return "Hello World";
|
|
137
|
-
}
|
|
138
|
-
```
|
|
139
98
|
|
|
140
|
-
|
|
99
|
+
### JSX Rendering
|
|
141
100
|
|
|
142
|
-
|
|
101
|
+
htmx-router is jsx templating agnostic for SSR, instead only requiring a definition provided when creating your request handler, allowing you to BYO JSX templating.
|
|
102
|
+
```js
|
|
103
|
+
// @kitajs/html
|
|
104
|
+
app.use('*', createRequestHandler.http({
|
|
105
|
+
build,
|
|
106
|
+
viteDevServer,
|
|
107
|
+
render: (res) => {
|
|
108
|
+
const headers = new Headers();
|
|
109
|
+
headers.set("Content-Type", "text/html; charset=UTF-8");
|
|
110
|
+
return new Response(String(res), { headers });
|
|
111
|
+
}
|
|
112
|
+
}));
|
|
143
113
|
|
|
144
|
-
|
|
114
|
+
// React
|
|
115
|
+
app.use('*', createRequestHandler.http({
|
|
116
|
+
build,
|
|
117
|
+
viteDevServer,
|
|
118
|
+
render: (res) => {
|
|
119
|
+
const headers = new Headers();
|
|
120
|
+
headers.set("Content-Type", "text/html; charset=UTF-8");
|
|
121
|
+
return new Response(renderToString(res), { headers });
|
|
122
|
+
}
|
|
123
|
+
}));
|
|
124
|
+
```
|
|
145
125
|
|
|
146
|
-
|
|
126
|
+
## Route Contexts
|
|
147
127
|
|
|
148
|
-
|
|
128
|
+
There are two kinds of route context, the `RouteContext<T>` which is the resolved route with parameterization, and the `GenericContext` which is used by error functions, and dynamic loads.
|
|
149
129
|
|
|
150
|
-
|
|
130
|
+
### Params
|
|
151
131
|
|
|
152
|
-
|
|
153
|
-
export async function Render(rn: string, {setTitle, Outlet}: RenderArgs) {
|
|
154
|
-
setTitle("Admin Panel");
|
|
155
|
-
|
|
156
|
-
return <div id={rn}>
|
|
157
|
-
<h1><Link to="/admin" style="color: inherit">
|
|
158
|
-
Admin Panel
|
|
159
|
-
</Link></h1>
|
|
160
|
-
{await Outlet()}
|
|
161
|
-
</div>;
|
|
162
|
-
}
|
|
163
|
-
```
|
|
132
|
+
In the `GenericContext` this will simply be an object with string key value pairs for the parameters, and only the `RouteContext<T>` for `loader` and `action` will have the parameters pre-parsed by your `parameters` definition.
|
|
164
133
|
|
|
165
|
-
|
|
134
|
+
### Cookies
|
|
166
135
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
addMeta([
|
|
170
|
-
{ property: "og:title", content: `${guild.name} - Predictions` },
|
|
171
|
-
{ property: "og:image", content: banner }
|
|
172
|
-
], true);
|
|
173
|
-
```
|
|
136
|
+
The `RouteContext` and `GenericContext`s both provide a `cookie` object, with the cookie's pre-parsed from the request headers.
|
|
137
|
+
It also has a built in `set(name, value, options)` function which will add the appropriate headers to the response for the cookie changes.
|
|
174
138
|
|
|
175
|
-
|
|
139
|
+
### Headers
|
|
176
140
|
|
|
177
|
-
|
|
141
|
+
This is a header object useful for adding response headers when you haven't fully finished generating your response yet.
|
|
142
|
+
These headers will merge with the response object created by the provided `render` function, with response headers overriding any conflicting `ctx.headers` values.
|
|
178
143
|
|
|
179
|
-
|
|
144
|
+
### Request
|
|
180
145
|
|
|
181
|
-
|
|
146
|
+
This is the original request object, including request headers.
|
|
182
147
|
|
|
183
|
-
|
|
148
|
+
### URL
|
|
184
149
|
|
|
185
|
-
|
|
150
|
+
The parsed `URL` object of the incoming request.
|
|
186
151
|
|
|
187
|
-
|
|
152
|
+
## Style Sheets
|
|
188
153
|
|
|
189
|
-
|
|
154
|
+
htmx-router includes a `StyleClass` object, which can be used to define CSS classes without needing a unique name.
|
|
155
|
+
StyleClasses should only be defined at the top level of a file, and not created within a function, or dynamically during runtime.
|
|
190
156
|
|
|
191
|
-
Such an example would look like this
|
|
192
157
|
```ts
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
export function GetCookies(req: IncomingMessage, shared: any): Record<string, string> {
|
|
197
|
-
if (shared.cookie) return shared.cookie;
|
|
198
|
-
|
|
199
|
-
shared.cookies = cookie.parse(req.headers.cookie || "");
|
|
200
|
-
return shared.cookies;
|
|
158
|
+
const myClass = new StyleClass(`myClass`, `
|
|
159
|
+
.this:hover {
|
|
160
|
+
background-color: red;
|
|
201
161
|
}
|
|
162
|
+
`).name;
|
|
202
163
|
```
|
|
203
164
|
|
|
204
|
-
|
|
205
|
-
import type { GetCookies } from "../shared/cookie.ts";
|
|
165
|
+
## Route-less Endpoint
|
|
206
166
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
167
|
+
This should be defined at the top level of your file, these endpoints can optionally be given an name which will help for debugging network requests, but they do not need to be unique.
|
|
168
|
+
```ts
|
|
169
|
+
const endpoint_url = new Endpoint((ctx: GenericContext) => {
|
|
170
|
+
return new Response("Hello World");
|
|
171
|
+
}, "hello-world").url;
|
|
211
172
|
```
|
|
212
173
|
|
|
213
|
-
|
|
174
|
+
## Islands
|
|
214
175
|
|
|
215
|
-
|
|
176
|
+
> Tip: Don't forget to wrap your islands in a hx-preserve to prevent losing state. And use `display: contents;` to make that wrapping div transparent for grid and other layout features.
|
|
216
177
|
|
|
217
|
-
|
|
218
|
-
export class ErrorResponse {
|
|
219
|
-
code : number;
|
|
220
|
-
status : string;
|
|
221
|
-
data : any;
|
|
222
|
-
}
|
|
223
|
-
```
|
|
178
|
+
### Dynamic
|
|
224
179
|
|
|
225
|
-
|
|
180
|
+
A dynamic component takes params which will be converted into the props of the loader function, these props may only be string key string value pairs as they are encoded the the query string to allow for browser side caching.
|
|
226
181
|
|
|
227
|
-
|
|
182
|
+
The body of a dynamic component is the pre-rendered infill that will display while the client is loading the dynamic content.
|
|
228
183
|
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
184
|
+
```tsx
|
|
185
|
+
async function MyProfile(params: {}, ctx: GenericContext): Promise<JSX.Element> {
|
|
186
|
+
ctx.headers.set('Cache-Control', "private, max-age=120");
|
|
187
|
+
const userID = ctx.cookie.get('userID');
|
|
188
|
+
if (!userID) return <></>;
|
|
234
189
|
|
|
235
|
-
|
|
190
|
+
const user = await GetUser(userID);
|
|
191
|
+
if (!user) return <></>;
|
|
236
192
|
|
|
237
|
-
|
|
193
|
+
return <a href={`/user/${userID}`}>
|
|
194
|
+
<div safe>{user.name}</div>
|
|
195
|
+
</a>
|
|
196
|
+
}
|
|
238
197
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
198
|
+
export async function loader({ params }: RouteContext<typeof parameters>) {
|
|
199
|
+
return <Dynamic params={{}} loader={MyProfile}>
|
|
200
|
+
put your ssr pre-rendered skeleton here
|
|
201
|
+
</Dynamic>
|
|
242
202
|
}
|
|
243
203
|
```
|
|
244
204
|
|
|
245
|
-
|
|
205
|
+
### Client
|
|
246
206
|
|
|
247
|
-
|
|
207
|
+
Import all of the components you want to be able to use on the client side into your `client.tsx`, if you are running a dev server this file will automatically generate the clientized version, otherwise use the `npx htmx-router` command to regenerate these artifacts.
|
|
208
|
+
|
|
209
|
+
Once a component has been clientized you can import it as use it like normal, however the body is now overwritten to it will render immediately on the server, and then all props will parsed to the client for it to be rendered properly in the browser.
|
|
248
210
|
|
|
249
|
-
```ts
|
|
250
|
-
export function Link(props: {
|
|
251
|
-
to: string,
|
|
252
|
-
target?: string,
|
|
253
|
-
style?: string
|
|
254
|
-
}, contents: string[])
|
|
255
|
-
```
|
|
256
211
|
```tsx
|
|
257
|
-
<
|
|
212
|
+
<Client.Counter>
|
|
213
|
+
<button>No yet hydrated...</button> {/* this will be overwritten in the browser once hydrated */}
|
|
214
|
+
</Client.Counter>
|
|
258
215
|
```
|
|
259
216
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
Sending it back to the client telling htmX where to insert the new content.
|
|
263
|
-
|
|
264
|
-
This element will encode as a standard `<a>` with some extra html attributes, meaning it won't affect SEO and bots attempting to scrape your website.
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
## StyleCSS
|
|
268
|
-
|
|
269
|
-
This is a helper function allowing you to give it a [CSS.Properties](https://www.npmjs.com/package/csstype) type, and render it into a string for [typed-html](https://www.npmjs.com/package/typed-html) to use.
|
|
270
|
-
```tsx
|
|
271
|
-
<div style={StyleCSS({
|
|
272
|
-
height: "100%",
|
|
273
|
-
width: "100%",
|
|
274
|
-
fontWeight: "bold",
|
|
275
|
-
fontSize: "5em",
|
|
276
|
-
})}>
|
|
277
|
-
I AM BIG
|
|
278
|
-
</div>
|
|
279
|
-
```
|
|
217
|
+
It is very important that you ensure your `Client` component has a single child element, if there are multiple child components the browser will only mount to the last child causing artifacting.
|
package/bin/404-route.d.ts
DELETED
package/bin/404-route.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Render = void 0;
|
|
4
|
-
const shared_1 = require("./shared");
|
|
5
|
-
async function Render(rn, { req }) {
|
|
6
|
-
throw new shared_1.ErrorResponse(404, "Resource Not Found", req.url || "/");
|
|
7
|
-
}
|
|
8
|
-
exports.Render = Render;
|
package/bin/cli/dynamic.d.ts
DELETED
package/bin/cli/dynamic.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.BuildDynamic = void 0;
|
|
5
|
-
const fs_1 = require("fs");
|
|
6
|
-
function BuildDynamic(cwd) {
|
|
7
|
-
const rootMatcher = new RegExp(/^root\.(j|t)sx?$/);
|
|
8
|
-
const root = (0, fs_1.readdirSync)(cwd)
|
|
9
|
-
.filter(x => rootMatcher.test(x))[0];
|
|
10
|
-
if (!root) {
|
|
11
|
-
console.log(`Missing root.jsx/tsx`);
|
|
12
|
-
process.exit(1);
|
|
13
|
-
}
|
|
14
|
-
let script = `import { RouteTree, IsAllowedExt } from "htmx-router";\n`;
|
|
15
|
-
script +=
|
|
16
|
-
`import { readdirSync } from "fs";
|
|
17
|
-
import { extname, join, relative, resolve } from "path";
|
|
18
|
-
|
|
19
|
-
function readDirRecursively(dir: string) {
|
|
20
|
-
const files = readdirSync(dir, { withFileTypes: true });
|
|
21
|
-
|
|
22
|
-
let filePaths: string[] = [];
|
|
23
|
-
for (const file of files) {
|
|
24
|
-
if (file.isDirectory()) {
|
|
25
|
-
filePaths = [...filePaths, ...readDirRecursively(join(dir, file.name))];
|
|
26
|
-
} else {
|
|
27
|
-
filePaths.push(join(dir, file.name));
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return filePaths;
|
|
32
|
-
}\n`;
|
|
33
|
-
script += `\nexport const Router = new RouteTree();\n`;
|
|
34
|
-
script += `import * as RootRoute from "./root";\n`;
|
|
35
|
-
script += `Router.assignRoot(RootRoute);\n\n`;
|
|
36
|
-
script += "const ctx = resolve(`${__dirname}/routes`);\n";
|
|
37
|
-
script += "const files = readDirRecursively(ctx);\n";
|
|
38
|
-
script += "for (const file of files){\n";
|
|
39
|
-
script += "\tconst ext = extname(file);\n";
|
|
40
|
-
script += "\tif (!IsAllowedExt(ext)) continue;\n";
|
|
41
|
-
script += "\tconst url = relative(ctx, file.slice(0, file.lastIndexOf(\".\")).replace(/\\\\/g, \"/\"));\n";
|
|
42
|
-
script += `\timport(file).then((mod) => Router.ingest(url, mod, [false]));\n`;
|
|
43
|
-
script += "}\n";
|
|
44
|
-
(0, fs_1.writeFileSync)(`${cwd}/router.ts`, script);
|
|
45
|
-
console.log(`Finished Building`);
|
|
46
|
-
}
|
|
47
|
-
exports.BuildDynamic = BuildDynamic;
|
package/bin/cli/static.d.ts
DELETED
package/bin/cli/static.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.BuildStatic = void 0;
|
|
5
|
-
const fs_1 = require("fs");
|
|
6
|
-
const path_1 = require("path");
|
|
7
|
-
const router_1 = require("../router");
|
|
8
|
-
function readDirRecursively(dir) {
|
|
9
|
-
const files = (0, fs_1.readdirSync)(dir, { withFileTypes: true });
|
|
10
|
-
let filePaths = [];
|
|
11
|
-
for (const file of files) {
|
|
12
|
-
if (file.isDirectory()) {
|
|
13
|
-
filePaths = [...filePaths, ...readDirRecursively((0, path_1.join)(dir, file.name))];
|
|
14
|
-
}
|
|
15
|
-
else {
|
|
16
|
-
filePaths.push((0, path_1.join)(dir, file.name));
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
return filePaths;
|
|
20
|
-
}
|
|
21
|
-
function BuildStatic(cwd) {
|
|
22
|
-
const rootMatcher = new RegExp(/^root\.(j|t)sx?$/);
|
|
23
|
-
const root = (0, fs_1.readdirSync)(cwd)
|
|
24
|
-
.filter(x => rootMatcher.test(x))[0];
|
|
25
|
-
if (!root) {
|
|
26
|
-
console.log(`Missing root.jsx/tsx`);
|
|
27
|
-
process.exit(1);
|
|
28
|
-
}
|
|
29
|
-
const DIR = './routes';
|
|
30
|
-
const files = readDirRecursively(`${cwd}/routes`)
|
|
31
|
-
.filter(x => (0, router_1.IsAllowedExt)((0, path_1.extname)(x)))
|
|
32
|
-
.map(x => (0, path_1.relative)(cwd, x.slice(0, x.lastIndexOf("."))).replace(/\\/g, "/"))
|
|
33
|
-
.sort();
|
|
34
|
-
let script = `import { RouteTree } from "htmx-router";\n`;
|
|
35
|
-
for (let i = 0; i < files.length; i++) {
|
|
36
|
-
const file = files[i];
|
|
37
|
-
script += `import * as Route${i} from "./${file}";\n`;
|
|
38
|
-
}
|
|
39
|
-
script += `import * as RootRoute from "./root";\n`;
|
|
40
|
-
script += `\nexport const Router = new RouteTree();\n`;
|
|
41
|
-
for (let i = 0; i < files.length; i++) {
|
|
42
|
-
const file = files[i];
|
|
43
|
-
script += `Router.ingest("${file.slice(DIR.length - 1)}", Route${i}, [false]);\n`;
|
|
44
|
-
}
|
|
45
|
-
script += `Router.assignRoot(RootRoute);\n`;
|
|
46
|
-
(0, fs_1.writeFileSync)(`${cwd}/router.ts`, script);
|
|
47
|
-
console.log(`Build with routes;\n` + files.map(x => ` - ${x}`).join("\n"));
|
|
48
|
-
}
|
|
49
|
-
exports.BuildStatic = BuildStatic;
|
package/bin/components.d.ts
DELETED
package/bin/components.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.Link = void 0;
|
|
27
|
-
const elements = __importStar(require("typed-html"));
|
|
28
|
-
function Link(props, contents) {
|
|
29
|
-
return elements.createElement("a", { target: props.target || "", class: props.class || "", style: props.style || "", href: props.to, "hx-get": props.to, "hx-headers": '{"Cache-Control": "no-cache"}' }, contents);
|
|
30
|
-
}
|
|
31
|
-
exports.Link = Link;
|
package/bin/render-args.d.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
import type http from "node:http";
|
|
3
|
-
import { RouteLeaf } from "./router";
|
|
4
|
-
type MetaHTML = {
|
|
5
|
-
[key: string]: string;
|
|
6
|
-
};
|
|
7
|
-
export declare enum MaskType {
|
|
8
|
-
show = 0,
|
|
9
|
-
headless = 1,
|
|
10
|
-
hide = 2
|
|
11
|
-
}
|
|
12
|
-
export declare class RenderArgs {
|
|
13
|
-
req: http.IncomingMessage;
|
|
14
|
-
res: http.ServerResponse;
|
|
15
|
-
title: string;
|
|
16
|
-
params: MetaHTML;
|
|
17
|
-
url: URL;
|
|
18
|
-
shared: {
|
|
19
|
-
[key: string]: any;
|
|
20
|
-
};
|
|
21
|
-
links: MetaHTML[];
|
|
22
|
-
meta: MetaHTML[];
|
|
23
|
-
_outletChain: RouteLeaf[];
|
|
24
|
-
_maskChain: MaskType[];
|
|
25
|
-
_maxChain: number;
|
|
26
|
-
constructor(req: http.IncomingMessage, res: http.ServerResponse, url: URL);
|
|
27
|
-
setTitle: (value: string) => void;
|
|
28
|
-
addLinks: (links: MetaHTML[], override?: boolean) => void;
|
|
29
|
-
addMeta: (links: MetaHTML[], override?: boolean) => void;
|
|
30
|
-
Outlet: () => Promise<string>;
|
|
31
|
-
_addOutlet(route: RouteLeaf): void;
|
|
32
|
-
_applyMask(mask: boolean[], depth: number): void;
|
|
33
|
-
renderHeadHTML: () => string;
|
|
34
|
-
}
|
|
35
|
-
export {};
|