htmx-router 0.2.0 → 1.0.0-alpha.1

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.
Files changed (55) hide show
  1. package/bin/cli/config.d.ts +10 -0
  2. package/bin/cli/config.js +4 -0
  3. package/bin/cli/index.js +54 -10
  4. package/bin/client/index.d.ts +4 -0
  5. package/bin/client/index.js +100 -0
  6. package/bin/client/mount.d.ts +2 -0
  7. package/bin/client/mount.js +74 -0
  8. package/bin/client/watch.d.ts +1 -0
  9. package/bin/client/watch.js +19 -0
  10. package/bin/helper.d.ts +1 -2
  11. package/bin/helper.js +25 -14
  12. package/bin/index.d.ts +8 -6
  13. package/bin/index.js +7 -16
  14. package/bin/request/http.d.ts +10 -0
  15. package/bin/request/http.js +46 -0
  16. package/bin/request/index.d.ts +16 -0
  17. package/bin/request/index.js +6 -0
  18. package/bin/request/native.d.ts +9 -0
  19. package/bin/request/native.js +56 -0
  20. package/bin/router.d.ts +41 -16
  21. package/bin/router.js +176 -236
  22. package/bin/types.d.ts +10 -0
  23. package/bin/types.js +1 -0
  24. package/bin/util/cookies.d.ts +22 -0
  25. package/bin/util/cookies.js +57 -0
  26. package/bin/util/css.d.ts +9 -0
  27. package/bin/util/css.js +47 -0
  28. package/bin/util/dynamic.d.ts +5 -0
  29. package/bin/util/dynamic.js +26 -0
  30. package/bin/util/endpoint.d.ts +9 -0
  31. package/bin/util/endpoint.js +28 -0
  32. package/bin/util/event-source.d.ts +16 -0
  33. package/bin/util/event-source.js +85 -0
  34. package/bin/util/hash.d.ts +1 -0
  35. package/bin/util/hash.js +7 -0
  36. package/bin/util/index.d.ts +1 -0
  37. package/bin/util/index.js +7 -0
  38. package/bin/util/parameters.d.ts +7 -0
  39. package/bin/util/parameters.js +14 -0
  40. package/bin/util/shell.d.ts +32 -0
  41. package/bin/util/shell.js +1 -0
  42. package/package.json +9 -7
  43. package/readme.md +149 -213
  44. package/bin/404-route.d.ts +0 -2
  45. package/bin/404-route.js +0 -8
  46. package/bin/cli/dynamic.d.ts +0 -2
  47. package/bin/cli/dynamic.js +0 -47
  48. package/bin/cli/static.d.ts +0 -2
  49. package/bin/cli/static.js +0 -49
  50. package/bin/components.d.ts +0 -8
  51. package/bin/components.js +0 -11
  52. package/bin/render-args.d.ts +0 -35
  53. package/bin/render-args.js +0 -120
  54. package/bin/shared.d.ts +0 -28
  55. package/bin/shared.js +0 -28
package/readme.md CHANGED
@@ -1,281 +1,217 @@
1
- # htmX Router
2
-
3
- > A [remix.js](https://remix.run/docs/en/main/guides/routing) style file path router for htmX websites
4
-
5
- This library attempts to be as unopinionated as possible allowing for multiple escape hatches in-case there are certain times you want a different style of behaviour.
6
-
7
- This library does not rely on any heavy weight dependencies such as react, instead opting to be built on the lighter weight [kitajs/html](https://kitajs.github.io/html/) library for it's JSX rendering, and using [csstype](https://www.npmjs.com/package/csstype), just as a type interface to improve developer ergonomics.
8
-
9
- You can also see an example site running this library [here](https://github.com/AjaniBilby/predictable) with source code as an extra helpful example. Please be mindful the slow loading of this site is actually due to Discord APIs, and the rendering is taking less than 2ms on a raspberry pi on my floor.
10
-
11
- - [htmX Router](#htmx-router)
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)
32
-
33
- ## Routes
34
-
35
- There are two requirements for this package behave correctly, you need a `root.jsx`/`.tsx`, in the same folder as a `routes` sub-folder. Plus any given route **must** have use the `route name` provided as the top element's `id` - which will be explained more in later.
36
-
37
- URLs are resolved based on the file structure of yur `routes` folder, you can choose to use nested folders or `.`s to have all of your files in a single folder if you choose - all examples will use the `.` layout for simplicity.
38
-
39
- If the url path `/user/1234/history` is requested, the router will create an outlet chain to your file tree (*this chain is actually just an array of modules, and the library works based on stack operations to reduce recursion and increase response times*).
40
- ```
41
- root.tsx
42
- routes
43
- ├── _index.tsx
44
- ├── user.tsx
45
- ├── user.static-path.tsx
46
- └── user.$userID.tsx
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
+ }
47
39
  ```
48
40
 
49
- Given the file tree above, when the root function calls it's [Outlet](#outlet) function, that will trigger `user` to render, and when user calls it's [Outlet](#outlet) function, that will trigger `user.$userID.tsx` to render as this sub route didn't match with any of the static options available, so instead it matched with the wild card route.
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.
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`.
52
43
 
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`.
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.
54
45
 
55
- ### Module Layout
56
46
 
57
- The router will look for three functions when reading a module, [Render](#render), [CatchError](#catcherror), and [Auth](#auth). Any combination of all or none of these functions are allowed, with the only exception being your `root.tsx` which must have a [Render](#render) and a [CatchError](#catcherror) function.
47
+ ## Routing
58
48
 
59
- #### Auth Function
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
60
54
 
61
- ```ts
62
- export async function Auth({shared}: RenderArgs) {
63
- if (!shared.auth?.isAdmin) throw new ErrorResponse(401, 'Unauthorised', "Unauthorised Access");
64
- return;
65
- }
55
+ This allows for easy overriding and fallback behaviour. For instance with the routes.
66
56
  ```
67
-
68
- This function is ran on all routes resolved by this file, and it's child routes - no matter if the route itself is masked or not rendered. This function must return nothing, and instead signals failure via throwing an error. With the successful case being nothing was thrown.
69
-
70
- #### Render Function
71
-
72
- ```ts
73
- export async function Render(routeName: string, {}: RenderArgs): Promise<string>
57
+ /user/$id.tsx
58
+ /user/me.tsx
59
+ /user/$.tsx
74
60
  ```
75
61
 
76
- The render function should follow the above function signature, the routeName string must be consumed if you're rendering a valid output, with the top most HTML element having the id assigned to this value. This helps the router dynamically insert new routes when using the [Link](#link) component.
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
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`.
81
63
 
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.
64
+ If a route returns `null` the router will continue the depth first search, allowing for dynamic flow through of the routes.
83
65
 
84
- This allows a given route to return an arbitrary response without being nested within it's parent routes.
66
+ ### Route Module
85
67
 
86
- #### CatchError Function
87
-
88
- ```ts
89
- export async function CatchError(rn: string, {}: RenderArgs, e: ErrorResponse): Promise<string>
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 };
90
72
  ```
91
73
 
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
74
+ A route can additionally define a loader, which is called on `GET` and `HEAD` requests
75
+ ```ts
76
+ export async function loader({}: RouteContext<typeof parameters>);
102
77
  ```
103
78
 
104
- When the command is ran it will generate a router based on the directory provided which should contain your root file and routes folder. This command will generate a `router.ts` which we recommend you git ignore from your project.
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:
79
+ With the `action` function being called for all other methods
111
80
  ```ts
112
- const url = new URL(req.url || "/", "http://localhost");
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
- }
81
+ export async function action({}: RouteContext<typeof parameters>);
124
82
  ```
125
83
 
126
- The `Router.render` function may output three possible types [Redirect](#redirect), [Override](#override), or a simple string. These two non-string types are to allow the boil up of overrides within routes, and allows you do handle them specific to your server environment.
127
-
128
- ## Types
129
-
130
- ### RenderArgs
131
-
132
- This class has been designed to work well with object unpacking for ease of use, typically it's used in a style like this for routes that only need information about the `req` and `res` objects.
133
-
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.
134
85
  ```ts
135
- export async function Render(rn: string, {req, res}: RenderArgs) {
136
- return "Hello World";
137
- }
86
+ export async function error(ctx: GenericContext, error: unknown);
138
87
  ```
139
88
 
140
- However it also includes a bunch of functions to help with higher order features.
89
+ ### Nested Route Rendering
141
90
 
142
- #### Outlet
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.
143
93
 
144
- The outlet function will call the child route to render, this function is asynchronous and will always return a string, or else it will throw. If there is nothing left in the outlet chain, it will return an empty string.
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.
145
95
 
146
- #### setTitle
96
+ We recommend you look at [Predictable Bot](https://github.com/AjaniBilby/predictable) as an example of this pattern performed simply.
147
97
 
148
- This function will update the title that will be generated by the [renderHeadHTML](#renderheadhtml) function, as well as the trigger value for the title updater when using the [Link](#link) component.
149
98
 
150
- You should consider when you call this function in conjunction to your [Outlet](#outlet) function, because if you run setTitle, after the outlet has been called it will override the title set by the child.
99
+ ### JSX Rendering
151
100
 
152
- ```tsx
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
- ```
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
+ }));
164
113
 
165
- #### addMeta
166
-
167
- This function allows you to add meta tags which will be rendered by the [renderHeadHTML](#renderheadhtml) function.
168
- ```ts
169
- addMeta([
170
- { property: "og:title", content: `${guild.name} - Predictions` },
171
- { property: "og:image", content: banner }
172
- ], true);
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
+ }));
173
124
  ```
174
125
 
175
- If the second argument of this function is set to `true` this function will override any meta tags currently set, replacing them with the inputted tags instead.
126
+ ## Route Contexts
176
127
 
177
- #### addLinks
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.
178
129
 
179
- This function behaves identically to [addMeta](#addmeta) but instead designed for link tags.
130
+ ### Params
180
131
 
181
- #### renderHeadHTML
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.
182
133
 
183
- This renders out the set meta and link tags for use in the `root.tsx` module, it also includes an embed script for updating the title for dynamic loads from the [Link](#link) component.
134
+ ### Cookies
184
135
 
185
- #### shared
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.
186
138
 
187
- There is also a blank object attached to all [RenderArgs](#renderargs) for sharing information between routes.
139
+ ### Headers
188
140
 
189
- This can be used for various purposes, but one example is to hold onto decoded cookie values so that each session doesn't need to recompute them if they already have.
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.
190
143
 
191
- Such an example would look like this
192
- ```ts
193
- import type { IncomingMessage } from "node:http";
194
- import * as cookie from "cookie";
144
+ ### Request
195
145
 
196
- export function GetCookies(req: IncomingMessage, shared: any): Record<string, string> {
197
- if (shared.cookie) return shared.cookie;
146
+ This is the original request object, including request headers.
198
147
 
199
- shared.cookies = cookie.parse(req.headers.cookie || "");
200
- return shared.cookies;
201
- }
202
- ```
203
-
204
- ```ts
205
- import type { GetCookies } from "../shared/cookie.ts";
148
+ ### URL
206
149
 
207
- export function GetCookies(rn: string, {shared}: RenderArgs) {
208
- const cookies = GetCookies(shared);
209
- // do stuff....
210
- }
211
- ```
150
+ The parsed `URL` object of the incoming request.
212
151
 
213
- ### ErrorResponse
152
+ ## Style Sheets
214
153
 
215
- This class is a way of HTTP-ifying error objects, and other error states, if an error is thrown by a [Render](#render) or an [Auth](#auth) function that isn't already wrapped by this type, the error will then become wrapped by this type.
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.
216
156
 
217
157
  ```ts
218
- export class ErrorResponse {
219
- code : number;
220
- status : string;
221
- data : any;
158
+ const myClass = new StyleClass(`myClass`, `
159
+ .this:hover {
160
+ background-color: red;
222
161
  }
162
+ `).name;
223
163
  ```
224
164
 
225
- ### Override
226
-
227
- If a render function throws a value of this type, it will boil all the way up to the original render call allowing it to bypass any parent manipulation.
165
+ ## Route-less Endpoint
228
166
 
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.
229
168
  ```ts
230
- export class Override {
231
- data : string | Buffer | Uint8Array;
232
- }
169
+ const endpoint_url = new Endpoint((ctx: GenericContext) => {
170
+ return new Response("Hello World");
171
+ }, "hello-world").url;
233
172
  ```
234
173
 
235
- ### Redirect
174
+ ## Islands
236
175
 
237
- This type behaves identically to override by is intended for boiling up specifically http redirect responses.
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.
238
177
 
239
- ```ts
240
- export class Redirect {
241
- location: string;
242
- }
243
- ```
178
+ ### Dynamic
244
179
 
245
- ## Components
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.
246
181
 
247
- ### Link
182
+ The body of a dynamic component is the pre-rendered infill that will display while the client is loading the dynamic content.
248
183
 
249
- ```ts
250
- export function Link(props: {
251
- to: string,
252
- target?: string,
253
- style?: string
254
- }, contents: string[])
255
- ```
256
184
  ```tsx
257
- <Link to={`/user/${id}`}>View Profile</Link>
258
- ```
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 <></>;
259
189
 
260
- This component overrides a normal `<a>`, adding extra headers telling the server route it is coming from, based on this information the server can determine the minimal route that needs to be rendered to send back to the client and calculates just that sub route.
190
+ const user = await GetUser(userID);
191
+ if (!user) return <></>;
261
192
 
262
- Sending it back to the client telling htmX where to insert the new content.
193
+ return <a href={`/user/${userID}`}>
194
+ <div safe>{user.name}</div>
195
+ </a>
196
+ }
263
197
 
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.
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>
202
+ }
203
+ ```
265
204
 
205
+ ### Client
266
206
 
267
- ## StyleCSS
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.
268
208
 
269
- > **DEPRECATED**: If you utilize `@kitajs/html` instead of `typed-html` this function is no longer needed
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.
270
210
 
271
- 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 [kitajs/html](https://kitajs.github.io/html/) to use.
272
211
  ```tsx
273
- <div style={StyleCSS({
274
- height: "100%",
275
- width: "100%",
276
- fontWeight: "bold",
277
- fontSize: "5em",
278
- })}>
279
- I AM BIG
280
- </div>
281
- ```
212
+ <Client.Counter>
213
+ <button>No yet hydrated...</button> {/* this will be overwritten in the browser once hydrated */}
214
+ </Client.Counter>
215
+ ```
216
+
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.
@@ -1,2 +0,0 @@
1
- import { RenderArgs } from "./render-args";
2
- export declare function Render(rn: string, { req }: RenderArgs): Promise<string>;
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;
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export declare function BuildDynamic(cwd: string): void;
@@ -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;
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export declare function BuildStatic(cwd: string): void;
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;
@@ -1,8 +0,0 @@
1
- import type * as CSS from 'csstype';
2
- import html from '@kitajs/html';
3
- export declare function Link(props: html.PropsWithChildren<{
4
- to: string;
5
- class?: string;
6
- style?: string | CSS.Properties<0 | (string & {}), string & {}>;
7
- target?: string;
8
- }>): string;
package/bin/components.js DELETED
@@ -1,11 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.Link = void 0;
7
- const html_1 = __importDefault(require("@kitajs/html"));
8
- function Link(props) {
9
- return html_1.default.createElement("a", { target: props.target || "", class: props.class || "", style: props.style || "", href: props.to, "hx-get": props.to, "hx-headers": '{"Cache-Control": "no-cache"}' }, props.children);
10
- }
11
- exports.Link = Link;
@@ -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 {};