@torpor/build 0.1.34 → 0.3.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/CHANGELOG.md +48 -0
- package/dist/RouteType-g8Ce5gOd.js +107 -0
- package/dist/RouteType-g8Ce5gOd.js.map +1 -0
- package/dist/Server-CSpY_-Ba.d.ts +78 -0
- package/dist/Server-CSpY_-Ba.d.ts.map +1 -0
- package/dist/ServerEvent-2-CnAy1W.js +74 -0
- package/dist/ServerEvent-2-CnAy1W.js.map +1 -0
- package/dist/Site-D4x1l0p5.d.ts +67 -0
- package/dist/Site-D4x1l0p5.d.ts.map +1 -0
- package/dist/_page-CsdPubw4.js +33 -0
- package/dist/_page-CsdPubw4.js.map +1 -0
- package/dist/bin/index.d.ts +1 -1
- package/dist/bin/index.js +14 -19
- package/dist/bin/index.js.map +1 -1
- package/dist/connectMiddleware-DbLj0St1.js +252 -0
- package/dist/connectMiddleware-DbLj0St1.js.map +1 -0
- package/dist/index.d.ts +191 -182
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +109 -145
- package/dist/index.js.map +1 -1
- package/dist/nav.d.ts +14 -0
- package/dist/nav.d.ts.map +1 -0
- package/dist/nav.js +184 -0
- package/dist/nav.js.map +1 -0
- package/dist/pathToRegex-CTgx7hQP.js +11 -0
- package/dist/pathToRegex-CTgx7hQP.js.map +1 -0
- package/dist/response-D-XpIuMH.js +307 -0
- package/dist/response-D-XpIuMH.js.map +1 -0
- package/dist/response.d.ts +336 -151
- package/dist/response.d.ts.map +1 -0
- package/dist/response.js +4 -37
- package/dist/run-CNdaKSPR.js +331 -0
- package/dist/run-CNdaKSPR.js.map +1 -0
- package/dist/run.d.ts +11 -8
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +8 -18
- package/dist/seeOther-BmehiI4C.js +110 -0
- package/dist/seeOther-BmehiI4C.js.map +1 -0
- package/dist/server.d.ts +12 -11
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +5 -18
- package/dist/state.d.ts +14 -10
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +3 -7
- package/dist/test.d.ts +12 -11
- package/dist/test.d.ts.map +1 -0
- package/dist/test.js +152 -225
- package/dist/test.js.map +1 -1
- package/package.json +25 -29
- package/src/bin/index.ts +9 -11
- package/src/index.ts +3 -0
- package/src/nav/load.ts +9 -0
- package/src/nav/loadData.ts +121 -0
- package/src/nav/navigate.ts +154 -0
- package/src/nav/reload.ts +9 -0
- package/src/nav.ts +4 -0
- package/src/response/badRequest.ts +9 -4
- package/src/response/created.ts +10 -3
- package/src/response/forbidden.ts +11 -4
- package/src/response/found.ts +30 -0
- package/src/response/methodNotAllowed.ts +8 -4
- package/src/response/movedPermanently.ts +25 -0
- package/src/response/notFound.ts +14 -7
- package/src/response/notModified.ts +24 -4
- package/src/response/ok.ts +19 -10
- package/src/response/permanentRedirect.ts +30 -0
- package/src/response/seeOther.ts +9 -3
- package/src/response/serverError.ts +14 -2
- package/src/response/temporaryRedirect.ts +31 -0
- package/src/response/unauthorized.ts +11 -4
- package/src/response/unprocessable.ts +8 -2
- package/src/response.ts +8 -4
- package/src/run/prepareTemplate.ts +32 -0
- package/src/{site → run}/run.ts +1 -1
- package/src/{site → run}/runBuild.ts +2 -2
- package/src/{site → run}/runDev.ts +2 -2
- package/src/{site → run}/runPreview.ts +12 -2
- package/src/run.ts +4 -4
- package/src/server/Routerx.ts +3 -3
- package/src/server/Server.ts +3 -3
- package/src/server/ServerEvent.ts +1 -1
- package/src/server/connect/bufferToArrayBuffer.ts +8 -0
- package/src/server/connect/connectMiddleware.ts +4 -2
- package/src/server/connect/nodeMessageToNodeResponse.ts +2 -2
- package/src/server/types/ServerFunction.ts +3 -1
- package/src/site/Router.ts +3 -3
- package/src/site/clientEntry.ts +40 -273
- package/src/site/defaultAdapter.ts +1 -1
- package/src/site/serverEntry.ts +86 -50
- package/src/state/$page.ts +3 -12
- package/src/state/client.ts +6 -0
- package/src/state/internal.ts +45 -0
- package/src/test/runTest.ts +4 -4
- package/src/types/Adapter.ts +2 -4
- package/src/types/ClientState.ts +8 -0
- package/src/types/InternalState.ts +7 -0
- package/src/types/LayoutHandler.ts +2 -4
- package/src/types/LayoutPath.ts +10 -0
- package/src/types/ManifestRoute.ts +2 -4
- package/src/types/PageEndPoint.ts +5 -5
- package/src/types/PageLoadEvent.ts +2 -4
- package/src/types/PageServerAction.ts +1 -1
- package/src/types/PageServerEndPoint.ts +2 -4
- package/src/types/PageServerLoad.ts +1 -1
- package/src/types/PageState.ts +8 -0
- package/src/types/RouteHandler.ts +2 -4
- package/src/types/RouteLayoutHandler.ts +2 -4
- package/src/types/RouteMatchResult.ts +2 -4
- package/src/types/ServerHook.ts +3 -7
- package/src/types/ServerLoadEvent.ts +2 -4
- package/src/types/ServerRequest.ts +1 -1
- package/src/{site → utils}/pathToRegex.ts +1 -1
- package/{tsup.config.ts → tsdown.config.ts} +3 -4
- package/dist/Server-BC_dixZQ.d.cts +0 -71
- package/dist/Server-BC_dixZQ.d.ts +0 -71
- package/dist/Site-4tGiw2-I.d.ts +0 -63
- package/dist/Site-BXX-S541.d.cts +0 -63
- package/dist/bin/index.cjs +0 -755
- package/dist/bin/index.cjs.map +0 -1
- package/dist/bin/index.d.cts +0 -1
- package/dist/chunk-565UOT3F.js +0 -18
- package/dist/chunk-565UOT3F.js.map +0 -1
- package/dist/chunk-B2UNTYN5.js +0 -68
- package/dist/chunk-B2UNTYN5.js.map +0 -1
- package/dist/chunk-KKFND4HK.js +0 -85
- package/dist/chunk-KKFND4HK.js.map +0 -1
- package/dist/chunk-LO7P2LJE.js +0 -278
- package/dist/chunk-LO7P2LJE.js.map +0 -1
- package/dist/chunk-PTVHEJZ5.js +0 -152
- package/dist/chunk-PTVHEJZ5.js.map +0 -1
- package/dist/chunk-RHDSM5GS.js +0 -357
- package/dist/chunk-RHDSM5GS.js.map +0 -1
- package/dist/chunk-SJVHHGVW.js +0 -13
- package/dist/chunk-SJVHHGVW.js.map +0 -1
- package/dist/chunk-WVXAN4IV.js +0 -50
- package/dist/chunk-WVXAN4IV.js.map +0 -1
- package/dist/index.cjs +0 -322
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -199
- package/dist/metafile-cjs.json +0 -1
- package/dist/metafile-esm.json +0 -1
- package/dist/response.cjs +0 -150
- package/dist/response.cjs.map +0 -1
- package/dist/response.d.cts +0 -166
- package/dist/response.js.map +0 -1
- package/dist/run.cjs +0 -764
- package/dist/run.cjs.map +0 -1
- package/dist/run.d.cts +0 -14
- package/dist/run.js.map +0 -1
- package/dist/server.cjs +0 -390
- package/dist/server.cjs.map +0 -1
- package/dist/server.d.cts +0 -17
- package/dist/server.js.map +0 -1
- package/dist/state.cjs +0 -44
- package/dist/state.cjs.map +0 -1
- package/dist/state.d.cts +0 -11
- package/dist/state.js.map +0 -1
- package/dist/test.cjs +0 -538
- package/dist/test.cjs.map +0 -1
- package/dist/test.d.cts +0 -15
- package/src/response/moved.ts +0 -16
- package/src/response/redirect.ts +0 -17
- package/src/site/prepareTemplate.ts +0 -20
- package/src/state/Page.ts +0 -8
package/dist/index.js
CHANGED
|
@@ -1,152 +1,116 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
LAYOUT_ROUTE,
|
|
6
|
-
LAYOUT_SERVER_ROUTE,
|
|
7
|
-
PAGE_ROUTE,
|
|
8
|
-
PAGE_SERVER_ROUTE,
|
|
9
|
-
Router,
|
|
10
|
-
SERVER_ROUTE
|
|
11
|
-
} from "./chunk-PTVHEJZ5.js";
|
|
12
|
-
import "./chunk-SJVHHGVW.js";
|
|
13
|
-
|
|
14
|
-
// src/site/Site.ts
|
|
15
|
-
import { promises as fs } from "fs";
|
|
16
|
-
import fpath from "path";
|
|
1
|
+
import "./pathToRegex-CTgx7hQP.js";
|
|
2
|
+
import { ERROR_ROUTE, HOOK_ROUTE, HOOK_SERVER_ROUTE, LAYOUT_ROUTE, LAYOUT_SERVER_ROUTE, PAGE_ROUTE, PAGE_SERVER_ROUTE, Router, SERVER_ROUTE } from "./RouteType-g8Ce5gOd.js";
|
|
3
|
+
import { promises } from "node:fs";
|
|
4
|
+
import fpath from "node:path";
|
|
17
5
|
import tsconfigPaths from "vite-tsconfig-paths";
|
|
18
6
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
};
|
|
7
|
+
//#region src/site/defaultAdapter.ts
|
|
8
|
+
const defaultAdapter = { serve: () => {
|
|
9
|
+
console.log("An adapter needs to be set in site.config");
|
|
10
|
+
} };
|
|
25
11
|
var defaultAdapter_default = defaultAdapter;
|
|
26
12
|
|
|
27
|
-
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/site/Site.ts
|
|
15
|
+
/**
|
|
16
|
+
* The Site class contains the information necessary to setup a @torpor/build
|
|
17
|
+
* site, including routes, plugins, and options.
|
|
18
|
+
*/
|
|
28
19
|
var Site = class {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
case "_hook":
|
|
122
|
-
return HOOK_ROUTE;
|
|
123
|
-
case "_hook.server":
|
|
124
|
-
return HOOK_SERVER_ROUTE;
|
|
125
|
-
case "_error":
|
|
126
|
-
return ERROR_ROUTE;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
// TODO: You could make your site in a single file, like e.g. Hono...
|
|
130
|
-
//addPage(path: string, endPoint: PageEndPoint, serverEndPoint?: PageServerEndPoint) {}
|
|
131
|
-
//addEndPoint(path: string, endPoint: ServerEndPoint) {}
|
|
132
|
-
#sortRoutes() {
|
|
133
|
-
this.routes = this.routes.sort((a, b) => {
|
|
134
|
-
for (let i = 0; i < Math.min(a.path.length, b.path.length); i++) {
|
|
135
|
-
if (a.path[i] === "[" && b.path[i] !== "[") {
|
|
136
|
-
return 1;
|
|
137
|
-
} else if (b.path[i] === "[" && a.path[i] !== "[") {
|
|
138
|
-
return -1;
|
|
139
|
-
} else if (a.path[i] === b.path[i]) {
|
|
140
|
-
} else {
|
|
141
|
-
return a.path[i].localeCompare(b.path[i]);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
return a.path.length - b.path.length;
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
};
|
|
148
|
-
export {
|
|
149
|
-
Router,
|
|
150
|
-
Site
|
|
20
|
+
root;
|
|
21
|
+
routes = [];
|
|
22
|
+
plugins = [tsconfigPaths({ loose: true })];
|
|
23
|
+
adapter = defaultAdapter_default;
|
|
24
|
+
/**
|
|
25
|
+
* Extra inputs, as absolute file paths, that will be compiled with the
|
|
26
|
+
* output. What you do with them after that is up to you. File paths ending
|
|
27
|
+
* with server.ts/js will only be compiled with the server output
|
|
28
|
+
*/
|
|
29
|
+
inputs = [];
|
|
30
|
+
/**
|
|
31
|
+
* Vite config options to merge with the standard Torpor build options.
|
|
32
|
+
* `plugins` and `build.rollupOptions.input` will be overridden, so you
|
|
33
|
+
* should set `Site.plugins` and `Site.inputs` instead. Other options may be
|
|
34
|
+
* overridden or incompatible, so experimentation may be required
|
|
35
|
+
*/
|
|
36
|
+
viteConfig;
|
|
37
|
+
constructor() {
|
|
38
|
+
this.root = process.cwd();
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Adds a folder of routes, based on the names of the files in the folder
|
|
42
|
+
* @param folder The folder containing the routes
|
|
43
|
+
*/
|
|
44
|
+
async addRouteFolder(folder) {
|
|
45
|
+
const routeFolder = fpath.join(this.root, folder);
|
|
46
|
+
const routeFiles = await promises.readdir(routeFolder, { recursive: true });
|
|
47
|
+
for (let file of routeFiles) if (/^(\+|_).+(\.js|\.ts)$/.test(fpath.basename(file))) {
|
|
48
|
+
let routePath = this.#routePath(file);
|
|
49
|
+
let type = this.#routeType(file);
|
|
50
|
+
file = fpath.relative(this.root, fpath.resolve(routeFolder, file));
|
|
51
|
+
this.routes.push({
|
|
52
|
+
path: routePath,
|
|
53
|
+
file,
|
|
54
|
+
type
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
this.#sortRoutes();
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Adds a file route, which can have a standard name (e.g. +page.ts) or any
|
|
61
|
+
* name if you pass the type
|
|
62
|
+
* @param path The route path
|
|
63
|
+
* @param file The file
|
|
64
|
+
* @param type The file type (if the file name is non-standard)
|
|
65
|
+
*/
|
|
66
|
+
addRouteFile(path, file, type) {
|
|
67
|
+
let routePath = this.#routePath(fpath.join(path, type ?? fpath.basename(file)));
|
|
68
|
+
let routeType = type ? this.#routeTypeFromString(type) : this.#routeType(file);
|
|
69
|
+
this.routes.push({
|
|
70
|
+
path: routePath,
|
|
71
|
+
file,
|
|
72
|
+
type: routeType
|
|
73
|
+
});
|
|
74
|
+
this.#sortRoutes();
|
|
75
|
+
}
|
|
76
|
+
#routePath(file) {
|
|
77
|
+
let routePath = file.replace(/^\//, "").replace(/(\.ts|\.js)$/, "").replace(/_hook.server$/, "_hook/~server").replace(/_layout.server$/, "_layout/~server").replace(/\+page.server$/, "~server").replace(/\+server$/, "").replace(/\+page$/, "").replace(/\/$/, "");
|
|
78
|
+
return routePath.length > 0 ? `/${routePath}` : "/";
|
|
79
|
+
}
|
|
80
|
+
#routeType(file) {
|
|
81
|
+
let routePath = file.replace(/^\//, "").replace(/(\.ts|\.js)$/, "");
|
|
82
|
+
if (routePath.endsWith("+page")) return PAGE_ROUTE;
|
|
83
|
+
else if (routePath.endsWith("+page.server")) return PAGE_SERVER_ROUTE;
|
|
84
|
+
else if (routePath.endsWith("+server")) return SERVER_ROUTE;
|
|
85
|
+
else if (routePath.endsWith("_layout")) return LAYOUT_ROUTE;
|
|
86
|
+
else if (routePath.endsWith("_layout.server")) return LAYOUT_SERVER_ROUTE;
|
|
87
|
+
else if (routePath.endsWith("_hook")) return HOOK_ROUTE;
|
|
88
|
+
else if (routePath.endsWith("_hook.server")) return HOOK_SERVER_ROUTE;
|
|
89
|
+
else if (routePath.endsWith("_error")) return ERROR_ROUTE;
|
|
90
|
+
return -1;
|
|
91
|
+
}
|
|
92
|
+
#routeTypeFromString(type) {
|
|
93
|
+
switch (type) {
|
|
94
|
+
case "+page": return PAGE_ROUTE;
|
|
95
|
+
case "+page.server": return PAGE_SERVER_ROUTE;
|
|
96
|
+
case "+server": return SERVER_ROUTE;
|
|
97
|
+
case "_layout": return LAYOUT_ROUTE;
|
|
98
|
+
case "_layout.server": return LAYOUT_SERVER_ROUTE;
|
|
99
|
+
case "_hook": return HOOK_ROUTE;
|
|
100
|
+
case "_hook.server": return HOOK_SERVER_ROUTE;
|
|
101
|
+
case "_error": return ERROR_ROUTE;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
#sortRoutes() {
|
|
105
|
+
this.routes = this.routes.sort((a, b) => {
|
|
106
|
+
for (let i = 0; i < Math.min(a.path.length, b.path.length); i++) if (a.path[i] === "[" && b.path[i] !== "[") return 1;
|
|
107
|
+
else if (b.path[i] === "[" && a.path[i] !== "[") return -1;
|
|
108
|
+
else if (a.path[i] === b.path[i]) {} else return a.path[i].localeCompare(b.path[i]);
|
|
109
|
+
return a.path.length - b.path.length;
|
|
110
|
+
});
|
|
111
|
+
}
|
|
151
112
|
};
|
|
113
|
+
|
|
114
|
+
//#endregion
|
|
115
|
+
export { Router, Site };
|
|
152
116
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/site/
|
|
1
|
+
{"version":3,"file":"index.js","names":["defaultAdapter: Adapter","defaultAdapter","fs","#routePath","#routeType","#sortRoutes","#routeTypeFromString"],"sources":["../src/site/defaultAdapter.ts","../src/site/Site.ts"],"sourcesContent":["import type Adapter from \"../types/Adapter\";\n\n// TODO: This should be an adapter-auto package that conditionally loads other packages...\n\nconst defaultAdapter: Adapter = {\n\tserve: () => {\n\t\tconsole.log(\"An adapter needs to be set in site.config\");\n\t},\n};\n\nexport default defaultAdapter;\n","import { promises as fs } from \"node:fs\";\nimport fpath from \"node:path\";\nimport { type Plugin, type UserConfig } from \"vite\";\nimport tsconfigPaths from \"vite-tsconfig-paths\";\nimport type Adapter from \"../types/Adapter\";\nimport {\n\tERROR_ROUTE,\n\tHOOK_ROUTE,\n\tHOOK_SERVER_ROUTE,\n\tLAYOUT_ROUTE,\n\tLAYOUT_SERVER_ROUTE,\n\tPAGE_ROUTE,\n\tPAGE_SERVER_ROUTE,\n\tRouteType,\n\tSERVER_ROUTE,\n} from \"../types/RouteType\";\nimport defaultAdapter from \"./defaultAdapter\";\n\n// 1. The user sets this up\n// 2. It is passed into serverEntry and clientEntry through a Vite plugin\n// (defined in manifest.ts)\n// 3. In those files, it is used to build a Router\n\n/**\n * The Site class contains the information necessary to setup a @torpor/build\n * site, including routes, plugins, and options.\n */\nexport default class Site {\n\troot: string;\n\troutes: { path: string; file: string; type: RouteType }[] = [];\n\t// Is default plugins a bad idea?\n\t// HACK: Set loose because otherwise it uses a list of allowed extensions\n\t// TODO: Should probably just do this ourselves and let the user pass in\n\t// tsconfigPaths themselves if they want to do something funky\n\tplugins: Plugin[] = [tsconfigPaths({ loose: true })];\n\t// Is default adapter a bad idea?\n\tadapter: Adapter = defaultAdapter;\n\t/**\n\t * Extra inputs, as absolute file paths, that will be compiled with the\n\t * output. What you do with them after that is up to you. File paths ending\n\t * with server.ts/js will only be compiled with the server output\n\t */\n\tinputs: string[] = [];\n\t/**\n\t * Vite config options to merge with the standard Torpor build options.\n\t * `plugins` and `build.rollupOptions.input` will be overridden, so you\n\t * should set `Site.plugins` and `Site.inputs` instead. Other options may be\n\t * overridden or incompatible, so experimentation may be required\n\t */\n\tviteConfig?: UserConfig;\n\n\tconstructor() {\n\t\tthis.root = process.cwd();\n\t}\n\n\t/**\n\t * Adds a folder of routes, based on the names of the files in the folder\n\t * @param folder The folder containing the routes\n\t */\n\tasync addRouteFolder(folder: string): Promise<void> {\n\t\tconst routeFolder = fpath.join(this.root, folder);\n\t\tconst routeFiles = await fs.readdir(routeFolder, { recursive: true });\n\t\tfor (let file of routeFiles) {\n\t\t\t// The file must start with `+` or `_` and end with `.js` or `.ts`\n\t\t\tif (/^(\\+|_).+(\\.js|\\.ts)$/.test(fpath.basename(file))) {\n\t\t\t\tlet routePath = this.#routePath(file);\n\t\t\t\tlet type = this.#routeType(file);\n\t\t\t\tfile = fpath.relative(this.root, fpath.resolve(routeFolder, file));\n\t\t\t\tthis.routes.push({ path: routePath, file, type });\n\t\t\t}\n\t\t}\n\t\tthis.#sortRoutes();\n\t}\n\n\t/**\n\t * Adds a file route, which can have a standard name (e.g. +page.ts) or any\n\t * name if you pass the type\n\t * @param path The route path\n\t * @param file The file\n\t * @param type The file type (if the file name is non-standard)\n\t */\n\taddRouteFile(\n\t\tpath: string,\n\t\tfile: string,\n\t\ttype?:\n\t\t\t| \"+page\"\n\t\t\t| \"+page.server\"\n\t\t\t| \"+server\"\n\t\t\t| \"_layout\"\n\t\t\t| \"_layout.server\"\n\t\t\t| \"_hook\"\n\t\t\t| \"_hook.server\"\n\t\t\t| \"_error\",\n\t): void {\n\t\tlet routePath = this.#routePath(fpath.join(path, type ?? fpath.basename(file)));\n\t\tlet routeType = type ? this.#routeTypeFromString(type) : this.#routeType(file);\n\t\tthis.routes.push({ path: routePath, file, type: routeType });\n\t\tthis.#sortRoutes();\n\t}\n\n\t#routePath(file: string): string {\n\t\tlet routePath = file\n\t\t\t.replace(/^\\//, \"\")\n\t\t\t.replace(/(\\.ts|\\.js)$/, \"\")\n\t\t\t.replace(/_hook.server$/, \"_hook/~server\")\n\t\t\t.replace(/_layout.server$/, \"_layout/~server\")\n\t\t\t.replace(/\\+page.server$/, \"~server\")\n\t\t\t.replace(/\\+server$/, \"\")\n\t\t\t.replace(/\\+page$/, \"\")\n\t\t\t.replace(/\\/$/, \"\");\n\t\treturn routePath.length > 0 ? `/${routePath}` : \"/\";\n\t}\n\n\t#routeType(file: string): RouteType {\n\t\tlet routePath = file.replace(/^\\//, \"\").replace(/(\\.ts|\\.js)$/, \"\");\n\t\tif (routePath.endsWith(\"+page\")) {\n\t\t\treturn PAGE_ROUTE;\n\t\t} else if (routePath.endsWith(\"+page.server\")) {\n\t\t\treturn PAGE_SERVER_ROUTE;\n\t\t} else if (routePath.endsWith(\"+server\")) {\n\t\t\treturn SERVER_ROUTE;\n\t\t} else if (routePath.endsWith(\"_layout\")) {\n\t\t\treturn LAYOUT_ROUTE;\n\t\t} else if (routePath.endsWith(\"_layout.server\")) {\n\t\t\treturn LAYOUT_SERVER_ROUTE;\n\t\t} else if (routePath.endsWith(\"_hook\")) {\n\t\t\treturn HOOK_ROUTE;\n\t\t} else if (routePath.endsWith(\"_hook.server\")) {\n\t\t\treturn HOOK_SERVER_ROUTE;\n\t\t} else if (routePath.endsWith(\"_error\")) {\n\t\t\treturn ERROR_ROUTE;\n\t\t}\n\t\treturn -1;\n\t}\n\n\t#routeTypeFromString(\n\t\ttype:\n\t\t\t| \"+page\"\n\t\t\t| \"+page.server\"\n\t\t\t| \"+server\"\n\t\t\t| \"_layout\"\n\t\t\t| \"_layout.server\"\n\t\t\t| \"_hook\"\n\t\t\t| \"_hook.server\"\n\t\t\t| \"_error\",\n\t) {\n\t\tswitch (type) {\n\t\t\tcase \"+page\":\n\t\t\t\treturn PAGE_ROUTE;\n\t\t\tcase \"+page.server\":\n\t\t\t\treturn PAGE_SERVER_ROUTE;\n\t\t\tcase \"+server\":\n\t\t\t\treturn SERVER_ROUTE;\n\t\t\tcase \"_layout\":\n\t\t\t\treturn LAYOUT_ROUTE;\n\t\t\tcase \"_layout.server\":\n\t\t\t\treturn LAYOUT_SERVER_ROUTE;\n\t\t\tcase \"_hook\":\n\t\t\t\treturn HOOK_ROUTE;\n\t\t\tcase \"_hook.server\":\n\t\t\t\treturn HOOK_SERVER_ROUTE;\n\t\t\tcase \"_error\":\n\t\t\t\treturn ERROR_ROUTE;\n\t\t}\n\t}\n\n\t// TODO: You could make your site in a single file, like e.g. Hono...\n\t//addPage(path: string, endPoint: PageEndPoint, serverEndPoint?: PageServerEndPoint) {}\n\t//addEndPoint(path: string, endPoint: ServerEndPoint) {}\n\n\t#sortRoutes() {\n\t\tthis.routes = this.routes.sort((a, b) => {\n\t\t\t// Sort [param]s after paths\n\t\t\t// There might be a quicker/easier way to do this\n\t\t\tfor (let i = 0; i < Math.min(a.path.length, b.path.length); i++) {\n\t\t\t\tif (a.path[i] === \"[\" && b.path[i] !== \"[\") {\n\t\t\t\t\treturn 1;\n\t\t\t\t} else if (b.path[i] === \"[\" && a.path[i] !== \"[\") {\n\t\t\t\t\treturn -1;\n\t\t\t\t} else if (a.path[i] === b.path[i]) {\n\t\t\t\t\t// Keep going...\n\t\t\t\t} else {\n\t\t\t\t\treturn a.path[i].localeCompare(b.path[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn a.path.length - b.path.length;\n\t\t});\n\t}\n}\n"],"mappings":"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"}
|
package/dist/nav.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/nav/load.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Loads and renders the page at the supplied path.
|
|
4
|
+
*/
|
|
5
|
+
declare function load(path: string): Promise<boolean>;
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/nav/reload.d.ts
|
|
8
|
+
/**
|
|
9
|
+
* Reloads data for the currently loaded page and rerenders it.
|
|
10
|
+
*/
|
|
11
|
+
declare function reload(): Promise<boolean>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { load, reload };
|
|
14
|
+
//# sourceMappingURL=nav.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nav.d.ts","names":[],"sources":["../src/nav/load.ts","../src/nav/reload.ts"],"sourcesContent":[],"mappings":";;;;iBAK8B,IAAA,gBAAoB;;;;;;iBCApB,MAAA,CAAA,GAAU"}
|
package/dist/nav.js
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { $page_default, internal } from "./_page-CsdPubw4.js";
|
|
2
|
+
import { clearLayoutSlot, fillLayoutSlot, hydrate, mount } from "@torpor/view";
|
|
3
|
+
|
|
4
|
+
//#region src/state/client.ts
|
|
5
|
+
const client = internal().client;
|
|
6
|
+
var client_default = client;
|
|
7
|
+
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region src/nav/loadData.ts
|
|
10
|
+
async function loadData(handler, params, path, newLayoutStack, clientEndPoint, serverEndPoint, prefetch = false) {
|
|
11
|
+
let data = {};
|
|
12
|
+
if (handler.layouts) {
|
|
13
|
+
let layoutStack = client_default.layoutStack;
|
|
14
|
+
for (let [i, layout] of handler.layouts.entries()) {
|
|
15
|
+
let layoutPath = layout.path;
|
|
16
|
+
for (let key in params) layoutPath = layoutPath.replace(`[${key}]`, params[key]);
|
|
17
|
+
if (layoutStack.at(i)?.path === layoutPath) {
|
|
18
|
+
if (!prefetch) layoutStack[i].reuse = true;
|
|
19
|
+
newLayoutStack[i] = layoutStack[i];
|
|
20
|
+
Object.assign(data, layoutStack[i].data);
|
|
21
|
+
} else {
|
|
22
|
+
const stackLayout = {
|
|
23
|
+
path: layoutPath,
|
|
24
|
+
data: {},
|
|
25
|
+
reuse: false,
|
|
26
|
+
slotRange: null
|
|
27
|
+
};
|
|
28
|
+
const layoutEndPoint = (await layout.endPoint())?.default;
|
|
29
|
+
const layoutServerEndPoint = layout.serverEndPoint && (await layout.serverEndPoint())?.default;
|
|
30
|
+
if ((await loadClientAndServerData(stackLayout.data, document.location.origin + layoutPath, params, layoutEndPoint, layoutServerEndPoint))?.ok === false) return;
|
|
31
|
+
Object.assign(data, stackLayout.data);
|
|
32
|
+
newLayoutStack.push(stackLayout);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if ((await loadClientAndServerData(data, document.location.origin + path, params, clientEndPoint, serverEndPoint))?.ok === false) return;
|
|
37
|
+
return data;
|
|
38
|
+
}
|
|
39
|
+
async function loadClientAndServerData(data, location, params, clientEndPoint, serverEndPoint) {
|
|
40
|
+
let prefetchedData = client_default.prefetchedData;
|
|
41
|
+
if (clientEndPoint?.load) if (prefetchedData[location]) Object.assign(data, prefetchedData[location]);
|
|
42
|
+
else {
|
|
43
|
+
const clientUrl = new URL(document.location.href);
|
|
44
|
+
const clientParams = buildClientParams(clientUrl, params, data);
|
|
45
|
+
const clientResponse = await clientEndPoint.load(clientParams);
|
|
46
|
+
if (clientResponse) if (clientResponse.ok) {
|
|
47
|
+
if (clientResponse.headers.get("Content-Type")?.includes("application/json")) {
|
|
48
|
+
const clientData = await clientResponse.json();
|
|
49
|
+
Object.assign(data, clientData);
|
|
50
|
+
prefetchedData[location] = clientData;
|
|
51
|
+
}
|
|
52
|
+
} else return clientResponse;
|
|
53
|
+
}
|
|
54
|
+
if (serverEndPoint?.load) {
|
|
55
|
+
const serverUrl = location.replace(/\/$/, "") + "/~server";
|
|
56
|
+
if (prefetchedData[serverUrl]) Object.assign(data, prefetchedData[serverUrl]);
|
|
57
|
+
else {
|
|
58
|
+
const serverResponse = await fetch(serverUrl);
|
|
59
|
+
if (serverResponse) if (serverResponse.ok) {
|
|
60
|
+
if (serverResponse.headers.get("Content-Type")?.includes("application/json")) {
|
|
61
|
+
const serverData = await serverResponse.json();
|
|
62
|
+
Object.assign(data, serverData);
|
|
63
|
+
prefetchedData[serverUrl] = serverData;
|
|
64
|
+
}
|
|
65
|
+
} else return serverResponse;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function buildClientParams(url, params, data) {
|
|
70
|
+
return {
|
|
71
|
+
url,
|
|
72
|
+
params,
|
|
73
|
+
data
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region src/nav/navigate.ts
|
|
79
|
+
async function navigate(url, withHydration = false) {
|
|
80
|
+
let parent = document.getElementById("app");
|
|
81
|
+
if (!parent) {
|
|
82
|
+
console.log("500");
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
const path = url.pathname;
|
|
86
|
+
const query = url.searchParams;
|
|
87
|
+
console.log(`navigating to '${path}'${query.size ? ` with ${query}` : ""}`);
|
|
88
|
+
const route = client_default.router.match(path, query);
|
|
89
|
+
if (!route) {
|
|
90
|
+
console.log("404");
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
$page_default.url = url;
|
|
94
|
+
if (path.endsWith("/_error")) {
|
|
95
|
+
$page_default.status = parseInt(query.get("status") ?? "404");
|
|
96
|
+
$page_default.error = { message: query.get("message") ?? "" };
|
|
97
|
+
window.history.replaceState({}, "", url.toString().split("?")[0]);
|
|
98
|
+
} else $page_default.status = 200;
|
|
99
|
+
const handler = route.handler;
|
|
100
|
+
const params = route.params || {};
|
|
101
|
+
const clientEndPoint = (await handler.endPoint()).default;
|
|
102
|
+
if (!clientEndPoint?.component) {
|
|
103
|
+
console.log("404");
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
const serverEndPoint = handler.serverEndPoint && (await handler.serverEndPoint())?.default;
|
|
107
|
+
let newLayoutStack = [];
|
|
108
|
+
const data = await loadData(handler, params, path, newLayoutStack, clientEndPoint, serverEndPoint);
|
|
109
|
+
let formInput = document.getElementById("t-form-data");
|
|
110
|
+
let form;
|
|
111
|
+
if (formInput) {
|
|
112
|
+
form = JSON.parse(formInput.value);
|
|
113
|
+
$page_default.form = form;
|
|
114
|
+
formInput.remove();
|
|
115
|
+
}
|
|
116
|
+
const $props = {
|
|
117
|
+
data,
|
|
118
|
+
form
|
|
119
|
+
};
|
|
120
|
+
client_default.layoutStack.push({
|
|
121
|
+
path: route.handler.path,
|
|
122
|
+
data: {},
|
|
123
|
+
reuse: false,
|
|
124
|
+
slotRange: null
|
|
125
|
+
});
|
|
126
|
+
client_default.layoutStack = newLayoutStack;
|
|
127
|
+
let layoutStack = client_default.layoutStack;
|
|
128
|
+
let component = clientEndPoint.component;
|
|
129
|
+
let slots = void 0;
|
|
130
|
+
if (handler.layouts) {
|
|
131
|
+
let slotFunctions = [];
|
|
132
|
+
slotFunctions[handler.layouts.length] = function clientComponent(parent$1, anchor, _, $context) {
|
|
133
|
+
let i = layoutStack.length - 1;
|
|
134
|
+
layoutStack[i].slotRange = fillLayoutSlot(clientEndPoint.component, slotFunctions[i + 1], parent$1, anchor, $props, $context);
|
|
135
|
+
};
|
|
136
|
+
for (let i = handler.layouts.length - 1; i >= 0; i--) {
|
|
137
|
+
const layoutEndPoint = (await handler.layouts[i].endPoint())?.default;
|
|
138
|
+
if (layoutEndPoint?.component) if (layoutStack[i].reuse) {
|
|
139
|
+
parent = layoutStack[i].slotRange.startNode.parentNode;
|
|
140
|
+
clearLayoutSlot(layoutStack[i].slotRange);
|
|
141
|
+
component = slotFunctions[i + 1];
|
|
142
|
+
break;
|
|
143
|
+
} else if (i === 0) {
|
|
144
|
+
component = layoutEndPoint.component;
|
|
145
|
+
slots = { _: slotFunctions[i + 1] };
|
|
146
|
+
} else slotFunctions[i] = function layoutComponent(parent$1, anchor, _, $context) {
|
|
147
|
+
layoutStack[i - 1].slotRange = fillLayoutSlot(layoutEndPoint.component, slotFunctions[i + 1], parent$1, anchor, $props, $context);
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (withHydration) hydrate(parent, component, $props, slots);
|
|
152
|
+
else try {
|
|
153
|
+
mount(parent, component, $props, slots);
|
|
154
|
+
} catch (error) {
|
|
155
|
+
parent.innerHTML = "<span style=\"color: red\">Script syntax error</span><p>" + error + "</p>";
|
|
156
|
+
console.log(error);
|
|
157
|
+
}
|
|
158
|
+
client_default.prefetchedData = {};
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
//#endregion
|
|
163
|
+
//#region src/nav/load.ts
|
|
164
|
+
/**
|
|
165
|
+
* Loads and renders the page at the supplied path.
|
|
166
|
+
*/
|
|
167
|
+
async function load(path) {
|
|
168
|
+
const url = new URL(path, document.location.href);
|
|
169
|
+
return await navigate(url);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
//#endregion
|
|
173
|
+
//#region src/nav/reload.ts
|
|
174
|
+
/**
|
|
175
|
+
* Reloads data for the currently loaded page and rerenders it.
|
|
176
|
+
*/
|
|
177
|
+
async function reload() {
|
|
178
|
+
const url = new URL(document.location.href);
|
|
179
|
+
return await navigate(url);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
//#endregion
|
|
183
|
+
export { load, reload };
|
|
184
|
+
//# sourceMappingURL=nav.js.map
|
package/dist/nav.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nav.js","names":["client: ClientState","client","layoutEndPoint: PageEndPoint | undefined","layoutServerEndPoint: PageServerEndPoint | undefined","client","clientEndPoint: PageEndPoint | undefined","serverEndPoint: PageServerEndPoint | undefined","newLayoutStack: LayoutPath[]","form: Record<string, string> | undefined","$props: Record<string, any>","slots: Record<string, SlotRender> | undefined","slotFunctions: SlotRender[]","parent","layoutEndPoint: PageEndPoint | undefined"],"sources":["../src/state/client.ts","../src/nav/loadData.ts","../src/nav/navigate.ts","../src/nav/load.ts","../src/nav/reload.ts"],"sourcesContent":["import type ClientState from \"../types/ClientState\";\nimport internal from \"./internal\";\n\nconst client: ClientState = internal().client;\n\nexport default client;\n","import client from \"../state/client\";\nimport type LayoutPath from \"../types/LayoutPath\";\nimport type PageEndPoint from \"../types/PageEndPoint\";\nimport type PageServerEndPoint from \"../types/PageServerEndPoint\";\nimport type RouteHandler from \"../types/RouteHandler\";\n\nexport default async function loadData(\n\thandler: RouteHandler,\n\tparams: Record<string, string>,\n\tpath: string,\n\tnewLayoutStack: LayoutPath[],\n\tclientEndPoint: PageEndPoint | undefined,\n\tserverEndPoint: PageServerEndPoint | undefined,\n\tprefetch = false,\n): Promise<Record<string, string> | void> {\n\tlet data = {};\n\tif (handler.layouts) {\n\t\tlet layoutStack = client.layoutStack;\n\t\tfor (let [i, layout] of handler.layouts.entries()) {\n\t\t\tlet layoutPath = layout.path;\n\t\t\tfor (let key in params) {\n\t\t\t\tlayoutPath = layoutPath.replace(`[${key}]`, params[key]);\n\t\t\t}\n\t\t\tif (layoutStack.at(i)?.path === layoutPath) {\n\t\t\t\t// We've already loaded this layout, we can just re-use its data and UI\n\t\t\t\tif (!prefetch) {\n\t\t\t\t\tlayoutStack[i].reuse = true;\n\t\t\t\t}\n\t\t\t\tnewLayoutStack[i] = layoutStack[i];\n\t\t\t\tObject.assign(data, layoutStack[i].data);\n\t\t\t} else {\n\t\t\t\tconst stackLayout = { path: layoutPath, data: {}, reuse: false, slotRange: null };\n\t\t\t\tconst layoutEndPoint: PageEndPoint | undefined = (await layout.endPoint())?.default;\n\t\t\t\tconst layoutServerEndPoint: PageServerEndPoint | undefined =\n\t\t\t\t\tlayout.serverEndPoint && (await layout.serverEndPoint())?.default;\n\t\t\t\tconst layoutResponse = await loadClientAndServerData(\n\t\t\t\t\tstackLayout.data,\n\t\t\t\t\tdocument.location.origin + layoutPath,\n\t\t\t\t\tparams,\n\t\t\t\t\tlayoutEndPoint,\n\t\t\t\t\tlayoutServerEndPoint,\n\t\t\t\t);\n\t\t\t\tif (layoutResponse?.ok === false) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tObject.assign(data, stackLayout.data);\n\t\t\t\tnewLayoutStack.push(stackLayout);\n\t\t\t}\n\t\t}\n\t}\n\tlet endPointResponse = await loadClientAndServerData(\n\t\tdata,\n\t\tdocument.location.origin + path,\n\t\tparams,\n\t\tclientEndPoint,\n\t\tserverEndPoint,\n\t);\n\tif (endPointResponse?.ok === false) {\n\t\treturn;\n\t}\n\treturn data;\n}\n\nasync function loadClientAndServerData(\n\tdata: Record<string, any>,\n\tlocation: string,\n\tparams: Record<string, string>,\n\tclientEndPoint?: PageEndPoint,\n\tserverEndPoint?: PageServerEndPoint,\n): Promise<Response | undefined | void> {\n\tlet prefetchedData = client.prefetchedData;\n\n\tif (clientEndPoint?.load) {\n\t\tif (prefetchedData[location]) {\n\t\t\tObject.assign(data, prefetchedData[location]);\n\t\t} else {\n\t\t\tconst clientUrl = new URL(document.location.href);\n\t\t\tconst clientParams = buildClientParams(clientUrl, params, data);\n\t\t\tconst clientResponse = await clientEndPoint.load(clientParams);\n\t\t\tif (clientResponse) {\n\t\t\t\tif (clientResponse.ok) {\n\t\t\t\t\tif (clientResponse.headers.get(\"Content-Type\")?.includes(\"application/json\")) {\n\t\t\t\t\t\tconst clientData = await clientResponse.json();\n\t\t\t\t\t\tObject.assign(data, clientData);\n\t\t\t\t\t\tprefetchedData[location] = clientData;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treturn clientResponse;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif (serverEndPoint?.load) {\n\t\tconst serverUrl = location.replace(/\\/$/, \"\") + \"/~server\";\n\n\t\tif (prefetchedData[serverUrl]) {\n\t\t\tObject.assign(data, prefetchedData[serverUrl]);\n\t\t} else {\n\t\t\tconst serverResponse = await fetch(serverUrl);\n\t\t\tif (serverResponse) {\n\t\t\t\tif (serverResponse.ok) {\n\t\t\t\t\tif (serverResponse.headers.get(\"Content-Type\")?.includes(\"application/json\")) {\n\t\t\t\t\t\tconst serverData = await serverResponse.json();\n\t\t\t\t\t\tObject.assign(data, serverData);\n\t\t\t\t\t\tprefetchedData[serverUrl] = serverData;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treturn serverResponse;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction buildClientParams(url: URL, params: Record<string, string>, data: Record<string, any>) {\n\treturn {\n\t\turl,\n\t\tparams,\n\t\tdata,\n\t};\n}\n","import { clearLayoutSlot, fillLayoutSlot, hydrate } from \"@torpor/view\";\nimport { type Component, type SlotRender } from \"@torpor/view\";\nimport { mount } from \"@torpor/view\";\nimport $page from \"../state/$page\";\nimport client from \"../state/client\";\nimport type LayoutPath from \"../types/LayoutPath\";\nimport type PageEndPoint from \"../types/PageEndPoint\";\nimport type PageServerEndPoint from \"../types/PageServerEndPoint\";\nimport loadData from \"./loadData\";\n\n// @ts-ignore\nexport default async function navigate(url: URL, withHydration = false): Promise<boolean> {\n\tlet parent = document.getElementById(\"app\");\n\tif (!parent) {\n\t\t// TODO: 500\n\t\tconsole.log(\"500\");\n\t\treturn false;\n\t}\n\n\tconst path = url.pathname;\n\tconst query = url.searchParams;\n\n\tconsole.log(`navigating to '${path}'${query.size ? ` with ${query}` : \"\"}`);\n\n\tconst route = client.router.match(path, query);\n\tif (!route) {\n\t\t// TODO: 404\n\t\tconsole.log(\"404\");\n\t\treturn false;\n\t}\n\n\t// Update $page before building the components\n\t$page.url = url;\n\tif (path.endsWith(\"/_error\")) {\n\t\t$page.status = parseInt(query.get(\"status\") ?? \"404\");\n\t\t$page.error = { message: query.get(\"message\") ?? \"\" };\n\t\t// Make it look a bit classier by removing the query\n\t\twindow.history.replaceState({}, \"\", url.toString().split(\"?\")[0]);\n\t} else {\n\t\t$page.status = 200;\n\t}\n\n\tconst handler = route.handler;\n\tconst params = route.params || {};\n\n\t// There must be a client endpoint with a component\n\tconst clientEndPoint: PageEndPoint | undefined = (await handler.endPoint()).default;\n\tif (!clientEndPoint?.component) {\n\t\t// TODO: 404\n\t\tconsole.log(\"404\");\n\t\treturn false;\n\t}\n\n\t// There may be a server endpoint\n\tconst serverEndPoint: PageServerEndPoint | undefined =\n\t\thandler.serverEndPoint && (await handler.serverEndPoint())?.default;\n\n\tlet newLayoutStack: LayoutPath[] = [];\n\n\t// Pass the data into $props\n\t// TODO: Don't load if this is the first time -- it should have been passed\n\t// to us, somehow...\n\tconst data = await loadData(\n\t\thandler,\n\t\tparams,\n\t\tpath,\n\t\tnewLayoutStack,\n\t\tclientEndPoint,\n\t\tserverEndPoint,\n\t);\n\t// We may have form data in a hidden input -- not sure if this is the best\n\t// way to do it\n\tlet formInput = document.getElementById(\"t-form-data\") as HTMLInputElement;\n\tlet form: Record<string, string> | undefined;\n\tif (formInput) {\n\t\tform = JSON.parse(formInput.value);\n\t\t$page.form = form;\n\t\tformInput.remove();\n\t}\n\tconst $props: Record<string, any> = { data, form };\n\n\tclient.layoutStack.push({ path: route.handler.path, data: {}, reuse: false, slotRange: null });\n\tclient.layoutStack = newLayoutStack;\n\tlet layoutStack = client.layoutStack;\n\n\t// If there are layouts, work our way upwards, pushing each component into\n\t// the default slot of its parent\n\t// TODO: There's probably a nicer way to do this with reducers or something\n\tlet component = clientEndPoint.component as Component;\n\tlet slots: Record<string, SlotRender> | undefined = undefined;\n\tif (handler.layouts) {\n\t\tlet slotFunctions: SlotRender[] = [];\n\t\t// The last slot function will render the client component\n\t\tslotFunctions[handler.layouts.length] = function clientComponent(parent, anchor, _, $context) {\n\t\t\tlet i = layoutStack.length - 1;\n\t\t\tlayoutStack[i].slotRange = fillLayoutSlot(\n\t\t\t\tclientEndPoint.component!,\n\t\t\t\tslotFunctions[i + 1],\n\t\t\t\tparent,\n\t\t\t\tanchor,\n\t\t\t\t$props,\n\t\t\t\t$context,\n\t\t\t);\n\t\t};\n\n\t\t// Each earlier slot function will render a layout\n\t\tfor (let i = handler.layouts.length - 1; i >= 0; i--) {\n\t\t\tconst layoutEndPoint: PageEndPoint | undefined = (await handler.layouts[i].endPoint())\n\t\t\t\t?.default;\n\t\t\tif (layoutEndPoint?.component) {\n\t\t\t\tif (layoutStack[i].reuse) {\n\t\t\t\t\t// Set the parent to add the new content to (from the old\n\t\t\t\t\t// content), clear the range under this point, and set the\n\t\t\t\t\t// component to the slot function within this layout\n\t\t\t\t\tparent = layoutStack[i].slotRange.startNode.parentNode as HTMLElement;\n\t\t\t\t\tclearLayoutSlot(layoutStack[i].slotRange);\n\t\t\t\t\tcomponent = slotFunctions[i + 1];\n\t\t\t\t\tbreak;\n\t\t\t\t} else if (i === 0) {\n\t\t\t\t\tcomponent = layoutEndPoint.component as Component;\n\t\t\t\t\tslots = { _: slotFunctions[i + 1] };\n\t\t\t\t} else {\n\t\t\t\t\tslotFunctions[i] = function layoutComponent(parent, anchor, _, $context) {\n\t\t\t\t\t\tlayoutStack[i - 1].slotRange = fillLayoutSlot(\n\t\t\t\t\t\t\tlayoutEndPoint.component!,\n\t\t\t\t\t\t\tslotFunctions[i + 1],\n\t\t\t\t\t\t\tparent,\n\t\t\t\t\t\t\tanchor,\n\t\t\t\t\t\t\t$props,\n\t\t\t\t\t\t\t$context,\n\t\t\t\t\t\t);\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (withHydration) {\n\t\thydrate(parent, component, $props, slots);\n\t} else {\n\t\ttry {\n\t\t\tmount(parent, component, $props, slots);\n\t\t} catch (error) {\n\t\t\t// TODO: Show a proper Error component\n\t\t\tparent.innerHTML = '<span style=\"color: red\">Script syntax error</span><p>' + error + \"</p>\";\n\t\t\tconsole.log(error);\n\t\t}\n\t}\n\n\t// Reset prefetched data on each navigation\n\tclient.prefetchedData = {};\n\n\treturn true;\n}\n","import navigate from \"./navigate\";\n\n/**\n * Loads and renders the page at the supplied path.\n */\nexport default async function load(path: string): Promise<boolean> {\n\tconst url = new URL(path, document.location.href);\n\treturn await navigate(url);\n}\n","import navigate from \"./navigate\";\n\n/**\n * Reloads data for the currently loaded page and rerenders it.\n */\nexport default async function reload(): Promise<boolean> {\n\tconst url = new URL(document.location.href);\n\treturn await navigate(url);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/utils/pathToRegex.ts
|
|
2
|
+
function pathToRegex(path) {
|
|
3
|
+
const pattern = path.split("/").map((p) => {
|
|
4
|
+
return p.replace(/\[([^/]+?)\]/, "(?<$1>[^\\/]+?)");
|
|
5
|
+
}).join("\\/").replaceAll("*", ".*") + "/*";
|
|
6
|
+
return /* @__PURE__ */ new RegExp(`^${pattern}/*$`);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
//#endregion
|
|
10
|
+
export { pathToRegex };
|
|
11
|
+
//# sourceMappingURL=pathToRegex-CTgx7hQP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathToRegex-CTgx7hQP.js","names":[],"sources":["../src/utils/pathToRegex.ts"],"sourcesContent":["export default function pathToRegex(path: string): RegExp {\n\tconst pattern =\n\t\tpath\n\t\t\t.split(\"/\")\n\t\t\t// Replace `[slug]` with a grouped match so we can pull out params\n\t\t\t.map((p) => {\n\t\t\t\treturn p.replace(/\\[([^/]+?)\\]/, \"(?<$1>[^\\\\/]+?)\");\n\t\t\t})\n\t\t\t.join(\"\\\\/\")\n\t\t\t// Replace globs with regex syntax\n\t\t\t.replaceAll(\"*\", \".*\") +\n\t\t// Ignore trailing slashes -- `/path` should be treated the same as `/path/`\n\t\t\"/*\";\n\treturn new RegExp(`^${pattern}/*$`);\n}\n"],"mappings":";AAAA,SAAwB,YAAY,MAAsB;CACzD,MAAM,UACL,KACE,MAAM,IAAI,CAEV,KAAK,MAAM;AACX,SAAO,EAAE,QAAQ,gBAAgB,kBAAkB;GAClD,CACD,KAAK,MAAM,CAEX,WAAW,KAAK,KAAK,GAEvB;AACD,wBAAO,IAAI,OAAO,IAAI,QAAQ,KAAK"}
|