@solidjs/router 1.0.0 → 2.0.0-next.12
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/README.md +606 -697
- package/dist/claims.d.ts +21 -0
- package/dist/claims.js +115 -0
- package/dist/data/action.d.ts +40 -11
- package/dist/data/action.js +303 -101
- package/dist/data/events.d.ts +8 -0
- package/dist/data/events.js +24 -23
- package/dist/data/index.d.ts +2 -4
- package/dist/data/index.js +2 -4
- package/dist/data/query.d.ts +1 -3
- package/dist/data/query.js +39 -22
- package/dist/data/serverForms.d.ts +1 -0
- package/dist/data/serverForms.js +5 -0
- package/dist/fs.d.ts +94 -0
- package/dist/fs.js +51 -0
- package/dist/index.d.ts +24 -3
- package/dist/index.js +1890 -1200
- package/dist/index.jsx +2 -2
- package/dist/lifecycle.d.ts +29 -4
- package/dist/lifecycle.js +40 -37
- package/dist/paths.d.ts +117 -0
- package/dist/paths.js +41 -0
- package/dist/routers/components.d.ts +12 -26
- package/dist/routers/components.jsx +68 -54
- package/dist/routers/factory.d.ts +121 -0
- package/dist/routers/factory.jsx +154 -0
- package/dist/routers/history.d.ts +26 -0
- package/dist/routers/history.js +180 -0
- package/dist/routers/index.d.ts +5 -11
- package/dist/routers/index.js +2 -6
- package/dist/routers/scrollRestoration.d.ts +10 -1
- package/dist/routers/scrollRestoration.js +49 -11
- package/dist/routing.d.ts +96 -52
- package/dist/routing.js +399 -167
- package/dist/server.d.ts +47 -0
- package/dist/server.js +156 -0
- package/dist/types.d.ts +148 -44
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +2 -0
- package/package.json +12 -7
- package/dist/components.d.ts +0 -31
- package/dist/components.jsx +0 -40
- package/dist/data/createAsync.d.ts +0 -32
- package/dist/data/createAsync.js +0 -96
- package/dist/data/response.d.ts +0 -4
- package/dist/data/response.js +0 -42
- package/dist/routers/HashRouter.d.ts +0 -9
- package/dist/routers/HashRouter.js +0 -41
- package/dist/routers/MemoryRouter.d.ts +0 -24
- package/dist/routers/MemoryRouter.js +0 -57
- package/dist/routers/Router.d.ts +0 -17
- package/dist/routers/Router.js +0 -59
- package/dist/routers/StaticRouter.d.ts +0 -6
- package/dist/routers/StaticRouter.js +0 -15
- package/dist/routers/createRouter.d.ts +0 -10
- package/dist/routers/createRouter.js +0 -41
package/dist/data/events.d.ts
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import type { RouterContext } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The submit delegation consults this slot instead of importing the action
|
|
4
|
+
* module: the action side installs its handler on first action creation
|
|
5
|
+
* (see data/action.ts), so an app that never creates an action never pulls
|
|
6
|
+
* the data layer into its bundle through the router's event wiring.
|
|
7
|
+
*/
|
|
8
|
+
export type RouterFormHandler = (evt: SubmitEvent, router: RouterContext, actionBase: string) => void;
|
|
9
|
+
export declare function setRouterFormHandler(handler: RouterFormHandler | undefined): void;
|
|
2
10
|
type NativeEventConfig = {
|
|
3
11
|
preload?: boolean;
|
|
4
12
|
explicitLinks?: boolean;
|
package/dist/data/events.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { delegateEvents } from "
|
|
1
|
+
import { delegateEvents } from "@solidjs/web";
|
|
2
2
|
import { onCleanup } from "solid-js";
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
let formHandler;
|
|
4
|
+
export function setRouterFormHandler(handler) {
|
|
5
|
+
formHandler = handler;
|
|
6
|
+
}
|
|
5
7
|
export function setupNativeEvents({ preload = true, explicitLinks = false, actionBase = "/_server", transformUrl } = {}) {
|
|
6
8
|
return (router) => {
|
|
7
9
|
const basePath = router.base.path();
|
|
@@ -76,30 +78,29 @@ export function setupNativeEvents({ preload = true, explicitLinks = false, actio
|
|
|
76
78
|
}, 20);
|
|
77
79
|
}
|
|
78
80
|
function handleFormSubmit(evt) {
|
|
81
|
+
if (formHandler)
|
|
82
|
+
return formHandler(evt, router, actionBase);
|
|
83
|
+
// No form handler means no action module in the client graph at all
|
|
84
|
+
// (e.g. server components binding forms straight to server functions).
|
|
85
|
+
// A POST to a url under actionBase is self-describing, so delegation
|
|
86
|
+
// is still sufficient: intercept synchronously — the no-JS treatment
|
|
87
|
+
// is reserved for clients with no JS — capture the FormData, and load
|
|
88
|
+
// the handler lazily. Apps that never submit one never load it.
|
|
79
89
|
if (evt.defaultPrevented)
|
|
80
90
|
return;
|
|
81
|
-
|
|
91
|
+
const form = evt.target;
|
|
92
|
+
const ref = evt.submitter && evt.submitter.hasAttribute("formaction")
|
|
82
93
|
? evt.submitter.getAttribute("formaction")
|
|
83
|
-
:
|
|
84
|
-
if (!
|
|
94
|
+
: form.getAttribute("action");
|
|
95
|
+
if (!ref || ref.startsWith("https://action/"))
|
|
85
96
|
return;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (evt.target.method.toUpperCase() !== "POST")
|
|
94
|
-
throw new Error("Only POST forms are supported for Actions");
|
|
95
|
-
const handler = actions.get(actionRef);
|
|
96
|
-
if (handler) {
|
|
97
|
-
evt.preventDefault();
|
|
98
|
-
const data = new FormData(evt.target, evt.submitter);
|
|
99
|
-
handler.call({ r: router, f: evt.target }, evt.target.enctype === "multipart/form-data"
|
|
100
|
-
? data
|
|
101
|
-
: new URLSearchParams(data));
|
|
102
|
-
}
|
|
97
|
+
const url = new URL(ref, document.baseURI);
|
|
98
|
+
const path = router.parsePath(url.pathname + url.search);
|
|
99
|
+
if (!path.startsWith(actionBase) || form.method.toUpperCase() !== "POST")
|
|
100
|
+
return;
|
|
101
|
+
evt.preventDefault();
|
|
102
|
+
const data = new FormData(form, evt.submitter);
|
|
103
|
+
import("./serverForms.js").then(m => m.submitServerForm(router, path, form, data));
|
|
103
104
|
}
|
|
104
105
|
// ensure delegated event run first
|
|
105
106
|
delegateEvents(["click", "submit"]);
|
package/dist/data/index.d.ts
CHANGED
|
@@ -1,4 +1,2 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export { query, revalidate, cache, type CachedFunction } from "./query.js";
|
|
4
|
-
export { redirect, reload, json } from "./response.js";
|
|
1
|
+
export { action, useSubmissions, useAction, type Action } from "./action.js";
|
|
2
|
+
export { query, revalidate, type CachedFunction } from "./query.js";
|
package/dist/data/index.js
CHANGED
|
@@ -1,4 +1,2 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export { query, revalidate, cache } from "./query.js";
|
|
4
|
-
export { redirect, reload, json } from "./response.js";
|
|
1
|
+
export { action, useSubmissions, useAction } from "./action.js";
|
|
2
|
+
export { query, revalidate } from "./query.js";
|
package/dist/data/query.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { CacheEntry, NarrowResponse } from "../types.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* Revalidates the given cache entry/entries.
|
|
4
4
|
*/
|
|
5
|
-
export declare function revalidate(key?: string | string[] | void, force?: boolean):
|
|
5
|
+
export declare function revalidate(key?: string | string[] | void, force?: boolean): void;
|
|
6
6
|
export declare function cacheKeyOp(key: string | string[] | void, fn: (cacheEntry: CacheEntry) => void): void;
|
|
7
7
|
export type CachedFunction<T extends (...args: any) => any> = T extends (...args: infer A) => infer R ? ([] extends {
|
|
8
8
|
[K in keyof A]-?: A[K];
|
|
@@ -18,6 +18,4 @@ export declare namespace query {
|
|
|
18
18
|
export var clear: () => void;
|
|
19
19
|
export { _a as delete };
|
|
20
20
|
}
|
|
21
|
-
/** @deprecated use query instead */
|
|
22
|
-
export declare const cache: typeof query;
|
|
23
21
|
export declare function hashKey<T extends Array<any>>(args: T): string;
|
package/dist/data/query.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { createSignal,
|
|
2
|
-
import { getRequestEvent, isServer } from "
|
|
1
|
+
import { createSignal, getObserver, getOwner, onCleanup, sharedConfig } from "solid-js";
|
|
2
|
+
import { getRequestEvent, isResponseEnvelope, isServer } from "@solidjs/web";
|
|
3
|
+
import { GET, decodeResponse, getServerFunctionMetadata, isServerFunction } from "@solidjs/web/server-functions";
|
|
3
4
|
import { useNavigate, getIntent, getInPreloadFn } from "../routing.js";
|
|
4
5
|
const LocationHeader = "Location";
|
|
5
6
|
const PRELOAD_TIMEOUT = 5000;
|
|
@@ -29,11 +30,9 @@ function getCache() {
|
|
|
29
30
|
*/
|
|
30
31
|
export function revalidate(key, force = true) {
|
|
31
32
|
const now = Date.now();
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return startTransition(() => {
|
|
36
|
-
cacheKeyOp(key, entry => entry[4][1](now)); // retrigger live signals
|
|
33
|
+
cacheKeyOp(key, entry => {
|
|
34
|
+
force && (entry[0] = 0); //force cache miss
|
|
35
|
+
entry[4][1](now); // retrigger live signals
|
|
37
36
|
});
|
|
38
37
|
}
|
|
39
38
|
export function cacheKeyOp(key, fn) {
|
|
@@ -44,9 +43,16 @@ export function cacheKeyOp(key, fn) {
|
|
|
44
43
|
}
|
|
45
44
|
}
|
|
46
45
|
export function query(fn, name) {
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
// query implies GET: the router primitive is the declaration site, so a
|
|
47
|
+
// server function handed to query() is wrapped with core `GET(fn)` here,
|
|
48
|
+
// at query-creation (module scope) — the server half records the method
|
|
49
|
+
// declaration for dispatch, the client half swaps in the GET transport.
|
|
50
|
+
// An explicit `GET(fn)` already carries the declaration on the metadata
|
|
51
|
+
// channel (`getServerFunctionMetadata(fn)?.method === "GET"`) and passes
|
|
52
|
+
// through; non-server functions are untouched.
|
|
53
|
+
if (isServerFunction(fn) && !getServerFunctionMetadata(fn)?.method) {
|
|
54
|
+
fn = GET(fn);
|
|
55
|
+
}
|
|
50
56
|
const cachedFn = ((...args) => {
|
|
51
57
|
const cache = getCache();
|
|
52
58
|
const intent = getIntent();
|
|
@@ -72,7 +78,7 @@ export function query(fn, name) {
|
|
|
72
78
|
}
|
|
73
79
|
}
|
|
74
80
|
}
|
|
75
|
-
if (
|
|
81
|
+
if (getObserver() && !isServer) {
|
|
76
82
|
tracking = true;
|
|
77
83
|
onCleanup(() => cached[4].count--);
|
|
78
84
|
}
|
|
@@ -95,7 +101,7 @@ export function query(fn, name) {
|
|
|
95
101
|
"then" in cached[1]
|
|
96
102
|
? cached[1].then(handleResponse(false), handleResponse(true))
|
|
97
103
|
: handleResponse(false)(cached[1]);
|
|
98
|
-
!isServer && intent === "navigate" &&
|
|
104
|
+
!isServer && intent === "navigate" && cached[4][1](cached[0]); // update version
|
|
99
105
|
}
|
|
100
106
|
inPreloadFn && "then" in res && res.catch(() => { });
|
|
101
107
|
return res;
|
|
@@ -112,10 +118,10 @@ export function query(fn, name) {
|
|
|
112
118
|
cached[0] = now;
|
|
113
119
|
cached[1] = res;
|
|
114
120
|
cached[3] = intent;
|
|
115
|
-
!isServer && intent === "navigate" &&
|
|
121
|
+
!isServer && intent === "navigate" && cached[4][1](cached[0]); // update version
|
|
116
122
|
}
|
|
117
123
|
else {
|
|
118
|
-
cache.set(key, (cached = [now, res, , intent, createSignal(now)]));
|
|
124
|
+
cache.set(key, (cached = [now, res, , intent, createSignal(now, { ownedWrite: true })]));
|
|
119
125
|
cached[4].count = 0;
|
|
120
126
|
}
|
|
121
127
|
if (tracking) {
|
|
@@ -145,6 +151,14 @@ export function query(fn, name) {
|
|
|
145
151
|
return res;
|
|
146
152
|
function handleResponse(error) {
|
|
147
153
|
return async (v) => {
|
|
154
|
+
let enveloped;
|
|
155
|
+
let hasEnveloped = false;
|
|
156
|
+
if (isResponseEnvelope(v)) {
|
|
157
|
+
// respond(): the value rides in memory beside the metadata
|
|
158
|
+
enveloped = v.value;
|
|
159
|
+
hasEnveloped = true;
|
|
160
|
+
v = v.response;
|
|
161
|
+
}
|
|
148
162
|
if (v instanceof Response) {
|
|
149
163
|
const e = getRequestEvent();
|
|
150
164
|
if (e) {
|
|
@@ -159,17 +173,22 @@ export function query(fn, name) {
|
|
|
159
173
|
if (url !== null) {
|
|
160
174
|
// client + server relative redirect
|
|
161
175
|
if (navigate && url.startsWith("/"))
|
|
162
|
-
|
|
163
|
-
navigate(url, { replace: true });
|
|
164
|
-
});
|
|
176
|
+
navigate(url, { replace: true });
|
|
165
177
|
else if (!isServer)
|
|
166
178
|
window.location.href = url;
|
|
167
179
|
else if (e)
|
|
168
180
|
e.response.status = 302;
|
|
169
181
|
return;
|
|
170
182
|
}
|
|
171
|
-
if (
|
|
172
|
-
v =
|
|
183
|
+
if (hasEnveloped)
|
|
184
|
+
v = enveloped;
|
|
185
|
+
else if (v.body) {
|
|
186
|
+
// responses the transport hands over whole (revalidation) carry a
|
|
187
|
+
// codec-encoded body; anything else (a raw user Response) stays whole
|
|
188
|
+
const decoded = await decodeResponse(v);
|
|
189
|
+
if (decoded !== undefined)
|
|
190
|
+
v = decoded;
|
|
191
|
+
}
|
|
173
192
|
}
|
|
174
193
|
if (error)
|
|
175
194
|
throw v;
|
|
@@ -197,14 +216,12 @@ query.set = (key, value) => {
|
|
|
197
216
|
cached[3] = "preload";
|
|
198
217
|
}
|
|
199
218
|
else {
|
|
200
|
-
cache.set(key, (cached = [now, Promise.resolve(value), value, "preload", createSignal(now)]));
|
|
219
|
+
cache.set(key, (cached = [now, Promise.resolve(value), value, "preload", createSignal(now, { ownedWrite: true })]));
|
|
201
220
|
cached[4].count = 0;
|
|
202
221
|
}
|
|
203
222
|
};
|
|
204
223
|
query.delete = (key) => getCache().delete(key);
|
|
205
224
|
query.clear = () => getCache().clear();
|
|
206
|
-
/** @deprecated use query instead */
|
|
207
|
-
export const cache = query;
|
|
208
225
|
function matchKey(key, keys) {
|
|
209
226
|
for (let k of keys) {
|
|
210
227
|
if (k && key.startsWith(k))
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { submitServerForm } from "./action.js";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// The delegation fallback's lazy entry (see data/events.ts). Nothing imports
|
|
2
|
+
// this module statically — it exists so the dynamic import has a target that
|
|
3
|
+
// bundlers can keep as a split point: router-only apps never load the action
|
|
4
|
+
// machinery unless a server-action form actually submits.
|
|
5
|
+
export { submitServerForm } from "./action.js";
|
package/dist/fs.d.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { DefinedRouteFilters, RouteParams, RoutePreloadFunc, RoutePreloadFuncArgs, RouteInfo, RouteSectionComponent, StandardSchemaV1, TypedRouteConfig, ValidFilters } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The type `defineFileRoute` hands back: `matchFilters` and `search` stay
|
|
4
|
+
* literal — and only present when provided precisely, which is what the
|
|
5
|
+
* `paths` machinery keys on once the manifest spreads this into the
|
|
6
|
+
* definition — while `preload` widens back to the plain contract. The
|
|
7
|
+
* pattern rides along as a phantom brand so `RouteProps<typeof route>`
|
|
8
|
+
* can type the file's component from the same witness.
|
|
9
|
+
*/
|
|
10
|
+
export type FileRouteConfig<S extends string = string, T = unknown, F = undefined, Sch = undefined> = TypedRouteConfig<S> & ([F] extends [undefined] ? {} : DefinedRouteFilters<S> extends F ? {} : {
|
|
11
|
+
matchFilters: F;
|
|
12
|
+
}) & ([Sch] extends [undefined] ? {} : {
|
|
13
|
+
search: Sch;
|
|
14
|
+
}) & {
|
|
15
|
+
preload?: RoutePreloadFunc<T>;
|
|
16
|
+
info?: RouteInfo;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Identity helper for a route file's `route` export that types `preload`'s
|
|
20
|
+
* `args.params` from a pattern witness — the file's path pattern, which the
|
|
21
|
+
* manifest (not this string) still provides at runtime:
|
|
22
|
+
*
|
|
23
|
+
* ```ts
|
|
24
|
+
* // routes/blog/[id].tsx
|
|
25
|
+
* export const route = defineFileRoute("/blog/:id", {
|
|
26
|
+
* matchFilters: { id: int },
|
|
27
|
+
* preload: ({ params }) => getPost(params.id) // params.id: string
|
|
28
|
+
* });
|
|
29
|
+
*
|
|
30
|
+
* export default function Post(props: RouteProps<typeof route>) {} // params *and* data typed
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* `matchFilters` are validated against the pattern's params, and their
|
|
34
|
+
* types (and any `search` schema) flow through the manifest into `paths`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function defineFileRoute<S extends string, T = unknown, const F = DefinedRouteFilters<S>, Sch extends StandardSchemaV1<any, any> | undefined = undefined>(path: S, config: {
|
|
37
|
+
matchFilters?: F & ValidFilters<F, S>;
|
|
38
|
+
preload?: (args: RoutePreloadFuncArgs<RouteParams<S>>) => T;
|
|
39
|
+
/** Standard Schema validator for this route's search params; its input type flows into the typed path proxy. */
|
|
40
|
+
search?: Sch;
|
|
41
|
+
info?: RouteInfo;
|
|
42
|
+
}): FileRouteConfig<S, T, F, Sch>;
|
|
43
|
+
/** A code-split module ref: delivered as a dynamic import. */
|
|
44
|
+
export interface FileRouteLazyRef<M = Record<string, unknown>> {
|
|
45
|
+
src: string;
|
|
46
|
+
import(): Promise<M>;
|
|
47
|
+
}
|
|
48
|
+
/** An eager module ref: its picked exports are imported statically. */
|
|
49
|
+
export interface FileRouteEagerRef<M = Record<string, unknown>> {
|
|
50
|
+
require(): M;
|
|
51
|
+
}
|
|
52
|
+
/** The shape of a nested route-manifest entry the adapter consumes. */
|
|
53
|
+
export interface FileRouteEntry {
|
|
54
|
+
path: string;
|
|
55
|
+
page?: boolean;
|
|
56
|
+
$component?: FileRouteLazyRef<any> | undefined;
|
|
57
|
+
$$route?: FileRouteEagerRef<any> | undefined;
|
|
58
|
+
children?: readonly FileRouteEntry[] | undefined;
|
|
59
|
+
}
|
|
60
|
+
type RouteConfigOf<E> = E extends {
|
|
61
|
+
$$route: {
|
|
62
|
+
require(): {
|
|
63
|
+
route: infer R;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
} ? R : {};
|
|
67
|
+
/**
|
|
68
|
+
* One manifest entry as a route definition. `children` is a required key on
|
|
69
|
+
* purpose: an optional key infers as `C | undefined`, and that union
|
|
70
|
+
* distributes `RoutePaths` into an uncallable shape.
|
|
71
|
+
*/
|
|
72
|
+
export type FileRouteFrom<E> = RouteConfigOf<E> & {
|
|
73
|
+
path: E extends {
|
|
74
|
+
path: infer P extends string;
|
|
75
|
+
} ? P : never;
|
|
76
|
+
component: E extends {
|
|
77
|
+
$component: object;
|
|
78
|
+
} ? RouteSectionComponent : undefined;
|
|
79
|
+
children: E extends {
|
|
80
|
+
children: infer C extends readonly FileRouteEntry[];
|
|
81
|
+
} ? FileRoutesFrom<C> : undefined;
|
|
82
|
+
};
|
|
83
|
+
export type FileRoutesFrom<T extends readonly FileRouteEntry[]> = {
|
|
84
|
+
[K in keyof T]: FileRouteFrom<T[K]>;
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Converts the nested page entries of a file-system route manifest into
|
|
88
|
+
* route definitions: `$component` refs become code-split `lazy` components
|
|
89
|
+
* (their `src` doubles as the `moduleUrl` core resolves assets and islands
|
|
90
|
+
* against), and each entry's `route` config export is spread into its
|
|
91
|
+
* definition. Pass the result to `createRouter({ routes })`.
|
|
92
|
+
*/
|
|
93
|
+
export declare function fileRoutes<const T extends readonly FileRouteEntry[]>(entries: T): FileRoutesFrom<T>;
|
|
94
|
+
export {};
|
package/dist/fs.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { lazy } from "solid-js";
|
|
2
|
+
/**
|
|
3
|
+
* Identity helper for a route file's `route` export that types `preload`'s
|
|
4
|
+
* `args.params` from a pattern witness — the file's path pattern, which the
|
|
5
|
+
* manifest (not this string) still provides at runtime:
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* // routes/blog/[id].tsx
|
|
9
|
+
* export const route = defineFileRoute("/blog/:id", {
|
|
10
|
+
* matchFilters: { id: int },
|
|
11
|
+
* preload: ({ params }) => getPost(params.id) // params.id: string
|
|
12
|
+
* });
|
|
13
|
+
*
|
|
14
|
+
* export default function Post(props: RouteProps<typeof route>) {} // params *and* data typed
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* `matchFilters` are validated against the pattern's params, and their
|
|
18
|
+
* types (and any `search` schema) flow through the manifest into `paths`.
|
|
19
|
+
*/
|
|
20
|
+
export function defineFileRoute(path, config) {
|
|
21
|
+
return config;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Converts the nested page entries of a file-system route manifest into
|
|
25
|
+
* route definitions: `$component` refs become code-split `lazy` components
|
|
26
|
+
* (their `src` doubles as the `moduleUrl` core resolves assets and islands
|
|
27
|
+
* against), and each entry's `route` config export is spread into its
|
|
28
|
+
* definition. Pass the result to `createRouter({ routes })`.
|
|
29
|
+
*/
|
|
30
|
+
export function fileRoutes(entries) {
|
|
31
|
+
const components = new Map();
|
|
32
|
+
const componentOf = (ref) => {
|
|
33
|
+
let component = components.get(ref.src);
|
|
34
|
+
if (!component) {
|
|
35
|
+
component = lazy(ref.import, ref.src);
|
|
36
|
+
components.set(ref.src, component);
|
|
37
|
+
}
|
|
38
|
+
return component;
|
|
39
|
+
};
|
|
40
|
+
const toRoute = (entry) => {
|
|
41
|
+
const config = (entry.$$route?.require().route ?? {});
|
|
42
|
+
return {
|
|
43
|
+
...config,
|
|
44
|
+
path: entry.path,
|
|
45
|
+
component: entry.$component ? componentOf(entry.$component) : undefined,
|
|
46
|
+
info: { ...config.info, filesystem: true },
|
|
47
|
+
children: entry.children ? entry.children.map(toRoute) : undefined
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
return entries.map(toRoute);
|
|
51
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Arbitrary metadata attached to routes via `info`, surfaced through
|
|
3
|
+
* `useRouteMatches` and the instance's `match()`. Declared here — in the
|
|
4
|
+
* package entry — so apps can augment it for typed, discoverable metadata:
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* declare module "@solidjs/router" {
|
|
8
|
+
* interface RouteInfo {
|
|
9
|
+
* breadcrumb?: string;
|
|
10
|
+
* }
|
|
11
|
+
* }
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Declared keys are type-checked at route definitions and typed on reads;
|
|
15
|
+
* undeclared keys remain freeform.
|
|
16
|
+
*/
|
|
17
|
+
export interface RouteInfo {
|
|
18
|
+
[key: string]: any;
|
|
19
|
+
}
|
|
1
20
|
export * from "./routers/index.js";
|
|
2
|
-
export * from "./components.jsx";
|
|
3
21
|
export * from "./lifecycle.js";
|
|
4
|
-
export { useHref, useIsRouting, useLocation, useMatch,
|
|
22
|
+
export { useHref, useIsRouting, useLinkState, useLocation, useMatch, useNavigate, usePreloadRoute, useParams, useResolvedPath, useRouteMatches, useSearchParams, RouterContextObj as RouterContext } from "./routing.js";
|
|
23
|
+
export type { LinkState } from "./routing.js";
|
|
5
24
|
export { mergeSearchString as _mergeSearchString } from "./utils.js";
|
|
25
|
+
export { int } from "./paths.js";
|
|
26
|
+
export type { RoutePaths, PathParamsOf, PathEnd, TypedMatchFilter, DefaultSearchTypes } from "./paths.js";
|
|
6
27
|
export * from "./data/index.js";
|
|
7
|
-
export type { Location, LocationChange, SearchParams, MatchFilter, MatchFilters, NavigateOptions, Navigator, OutputMatch, Params, PathMatch, RouteSectionProps, RoutePreloadFunc, RoutePreloadFuncArgs, RouteDefinition, RouteDescription, RouteMatch, RouterIntegration, RouterUtils, SetParams, Submission, BeforeLeaveEventArgs,
|
|
28
|
+
export type { Location, LocationChange, SearchParams, MatchFilter, MatchFilters, NavigateOptions, Navigator, OutputMatch, Params, PathMatch, RouteComponent, RouteParams, RouteProps, RouteSectionProps, RoutePreloadFunc, RoutePreloadFuncArgs, RouteDefinition, RouteDescription, RouteMatch, RouterIntegration, RouterUtils, SetParams, SetSearchParams, Submission, BeforeLeaveEventArgs, TypedPath, TypedSearchPath, StandardSchemaV1 } from "./types.js";
|