@forgebook/sveltekit 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +145 -2
- package/dist/src/app/env.d.ts +8 -0
- package/dist/src/app/env.js +15 -0
- package/dist/src/app/forms.d.ts +68 -0
- package/dist/src/app/forms.js +125 -0
- package/dist/src/app/manifest.d.ts +21 -0
- package/dist/src/app/manifest.js +17 -0
- package/dist/src/app/navigation.d.ts +97 -0
- package/dist/src/app/navigation.js +147 -0
- package/dist/src/app/paths.d.ts +32 -0
- package/dist/src/app/paths.js +56 -0
- package/dist/src/app/state.d.ts +27 -0
- package/dist/src/app/state.js +60 -0
- package/dist/src/app/stores.d.ts +31 -0
- package/dist/src/app/stores.js +36 -0
- package/dist/src/appSettings.d.ts +44 -0
- package/dist/src/appSettings.js +55 -0
- package/dist/src/kitParameters.d.ts +272 -0
- package/dist/src/kitParameters.js +291 -0
- package/dist/src/kitRenderer.d.ts +3 -0
- package/dist/src/kitRenderer.js +254 -0
- package/dist/src/kitStore.d.ts +90 -0
- package/dist/src/kitStore.js +301 -0
- package/dist/src/mountFrame.d.ts +14 -0
- package/dist/src/mountFrame.js +15 -0
- package/dist/src/routeIds.d.ts +44 -0
- package/dist/src/routeIds.js +150 -0
- package/dist/src/routeOrder.d.ts +18 -0
- package/dist/src/routeOrder.js +187 -0
- package/dist/src/stories.d.ts +48 -0
- package/dist/src/stories.js +11 -0
- package/dist/src/storyCode.d.ts +3 -0
- package/dist/src/storyCode.js +9 -0
- package/dist/src/storyPage.d.ts +35 -0
- package/dist/src/storyPage.js +19 -0
- package/dist/src/vite/envModules.d.ts +67 -0
- package/dist/src/vite/envModules.js +181 -0
- package/dist/src/vite/extractDocs.d.ts +14 -0
- package/dist/src/vite/extractDocs.js +20 -0
- package/dist/src/vite/kitPlugin.d.ts +28 -0
- package/dist/src/vite/kitPlugin.js +241 -0
- package/dist/src/vite/kitProject.d.ts +27 -0
- package/dist/src/vite/kitProject.js +176 -0
- package/dist/src/vite/projectFiles.d.ts +14 -0
- package/dist/src/vite/projectFiles.js +70 -0
- package/dist/src/vite/sveltekit.d.ts +26 -0
- package/dist/src/vite/sveltekit.js +39 -0
- package/package.json +113 -3
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SvelteKit's route ids, read as SvelteKit reads them: which route a path matches and with which params, and the path a
|
|
3
|
+
* route id gives with its params filled in.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* Pure: ids and paths in, matches out, so it is tested without a page. The ids are the project's own, listed from its
|
|
7
|
+
* `src/routes` by the Vite plugin, so a story's links and `goto` calls land on the route SvelteKit would choose:
|
|
8
|
+
* `/blog/[slug]` for `/blog/hello`, with `{ slug: "hello" }`. A param's matcher (`[id=integer]`) is not run, since the
|
|
9
|
+
* catalogue does not load the project's matchers: any value matches it.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
/** A route's params, by name: SvelteKit gives each as one text, a rest param's slashes included. */
|
|
14
|
+
export type RouteParams = Readonly<Record<string, string>>;
|
|
15
|
+
/** A route a path matched: its id and its params. */
|
|
16
|
+
export type RouteMatch = {
|
|
17
|
+
/** The route's id (`/blog/[slug]`). */
|
|
18
|
+
readonly id: string;
|
|
19
|
+
/** The params read from the path. */
|
|
20
|
+
readonly params: RouteParams;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* The route a path matches among a project's routes, and its params.
|
|
24
|
+
*
|
|
25
|
+
* @param routes - the project's route ids.
|
|
26
|
+
* @param pathname - the path, without the base path (`/blog/hello`).
|
|
27
|
+
* @returns the match, or none when no route matches.
|
|
28
|
+
*/
|
|
29
|
+
export declare const matchRoute: (routes: readonly string[], pathname: string) => RouteMatch | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* The path a route id gives with its params filled in, as `resolve` from `$app/paths` writes it: the layout groups
|
|
32
|
+
* left out, an optional or rest param with no value dropped with its slash.
|
|
33
|
+
*
|
|
34
|
+
* @param id - the route's id (`/blog/[slug]`).
|
|
35
|
+
* @param params - the params, by name.
|
|
36
|
+
* @returns the path (`/blog/hello`).
|
|
37
|
+
*/
|
|
38
|
+
export declare const filledRoute: (id: string, params: RouteParams) => string;
|
|
39
|
+
/**
|
|
40
|
+
* Whether a text is a route id rather than a path: it names a param or a layout group.
|
|
41
|
+
*
|
|
42
|
+
* @param text - the text.
|
|
43
|
+
*/
|
|
44
|
+
export declare const isRouteId: (text: string) => boolean;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SvelteKit's route ids, read as SvelteKit reads them: which route a path matches and with which params, and the path a
|
|
3
|
+
* route id gives with its params filled in.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* Pure: ids and paths in, matches out, so it is tested without a page. The ids are the project's own, listed from its
|
|
7
|
+
* `src/routes` by the Vite plugin, so a story's links and `goto` calls land on the route SvelteKit would choose:
|
|
8
|
+
* `/blog/[slug]` for `/blog/hello`, with `{ slug: "hello" }`. A param's matcher (`[id=integer]`) is not run, since the
|
|
9
|
+
* catalogue does not load the project's matchers: any value matches it.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import { byRouteOrder } from "./routeOrder.js";
|
|
14
|
+
/** A param in a route id: `[name]`, `[[name]]`, `[...name]`, each with an optional `=matcher`. */
|
|
15
|
+
const PARAM = /\[(\[)?(\.\.\.)?([A-Za-z_$][\w$]*)(?:=[\w$]+)?\]?\]/g;
|
|
16
|
+
/** A layout group, `(app)`: a folder that is not a segment of the path. */
|
|
17
|
+
const GROUP = /^\(.+\)$/;
|
|
18
|
+
/**
|
|
19
|
+
* The segments of a route id that are in its paths: its layout groups left out.
|
|
20
|
+
*
|
|
21
|
+
* @param id - the route's id (`/(app)/blog/[slug]`).
|
|
22
|
+
*/
|
|
23
|
+
const pathSegments = (id) => id.split("/").filter((segment) => segment !== "" && !GROUP.test(segment));
|
|
24
|
+
/**
|
|
25
|
+
* A segment's parts: its texts and its params.
|
|
26
|
+
*
|
|
27
|
+
* @param segment - a segment of a route id (`[a]-[b]`).
|
|
28
|
+
*/
|
|
29
|
+
const segmentParts = (segment) => {
|
|
30
|
+
const parts = [];
|
|
31
|
+
let index = 0;
|
|
32
|
+
for (const match of segment.matchAll(PARAM)) {
|
|
33
|
+
if (match.index > index)
|
|
34
|
+
parts.push({ kind: "text", text: segment.slice(index, match.index) });
|
|
35
|
+
parts.push({
|
|
36
|
+
kind: "param",
|
|
37
|
+
name: match[3] ?? "",
|
|
38
|
+
isRest: match[2] !== undefined,
|
|
39
|
+
isOptional: match[1] !== undefined
|
|
40
|
+
});
|
|
41
|
+
index = match.index + match[0].length;
|
|
42
|
+
}
|
|
43
|
+
if (index < segment.length)
|
|
44
|
+
parts.push({ kind: "text", text: segment.slice(index) });
|
|
45
|
+
return parts;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* A text written so a regular expression reads it as itself.
|
|
49
|
+
*
|
|
50
|
+
* @param text - the text.
|
|
51
|
+
*/
|
|
52
|
+
const escaped = (text) => text.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&");
|
|
53
|
+
/**
|
|
54
|
+
* The regular expression one segment of a route id matches, its slash included.
|
|
55
|
+
*
|
|
56
|
+
* @param parts - the segment's parts.
|
|
57
|
+
* @param names - where its params' names are added, in order.
|
|
58
|
+
*/
|
|
59
|
+
const segmentSource = (parts, names) => {
|
|
60
|
+
const only = parts.length === 1 ? parts[0] : undefined;
|
|
61
|
+
// a segment that is a rest or optional param alone may be absent from the path, its slash with it
|
|
62
|
+
if (only?.kind === "param" && (only.isRest || only.isOptional)) {
|
|
63
|
+
names.push(only.name);
|
|
64
|
+
return only.isRest ? "(?:/(.*))?" : "(?:/([^/]+))?";
|
|
65
|
+
}
|
|
66
|
+
const written = parts.map((part) => {
|
|
67
|
+
if (part.kind === "text")
|
|
68
|
+
return escaped(part.text);
|
|
69
|
+
names.push(part.name);
|
|
70
|
+
return part.isRest ? "(.*?)" : "([^/]+?)";
|
|
71
|
+
});
|
|
72
|
+
return `/${written.join("")}`;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* The regular expression a route id matches paths with, and its params' names in order.
|
|
76
|
+
*
|
|
77
|
+
* @param id - the route's id.
|
|
78
|
+
*/
|
|
79
|
+
const routePattern = (id) => {
|
|
80
|
+
const names = [];
|
|
81
|
+
const source = pathSegments(id)
|
|
82
|
+
.map((segment) => segmentSource(segmentParts(segment), names))
|
|
83
|
+
.join("");
|
|
84
|
+
return { pattern: new RegExp(`^${source}/?$`), names };
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* A path's parts decoded, as SvelteKit decodes a param: a malformed escape left as it is.
|
|
88
|
+
*
|
|
89
|
+
* @param value - the text.
|
|
90
|
+
*/
|
|
91
|
+
const decoded = (value) => {
|
|
92
|
+
try {
|
|
93
|
+
return decodeURIComponent(value);
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return value;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* The route a path matches among a project's routes, and its params.
|
|
101
|
+
*
|
|
102
|
+
* @param routes - the project's route ids.
|
|
103
|
+
* @param pathname - the path, without the base path (`/blog/hello`).
|
|
104
|
+
* @returns the match, or none when no route matches.
|
|
105
|
+
*/
|
|
106
|
+
export const matchRoute = (routes, pathname) => {
|
|
107
|
+
for (const id of [...routes].sort(byRouteOrder)) {
|
|
108
|
+
const { pattern, names } = routePattern(id);
|
|
109
|
+
const found = pattern.exec(pathname);
|
|
110
|
+
if (found === null)
|
|
111
|
+
continue;
|
|
112
|
+
const params = {};
|
|
113
|
+
names.forEach((name, index) => {
|
|
114
|
+
params[name] = decoded(found[index + 1] ?? "");
|
|
115
|
+
});
|
|
116
|
+
return { id, params };
|
|
117
|
+
}
|
|
118
|
+
return undefined;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* The path a route id gives with its params filled in, as `resolve` from `$app/paths` writes it: the layout groups
|
|
122
|
+
* left out, an optional or rest param with no value dropped with its slash.
|
|
123
|
+
*
|
|
124
|
+
* @param id - the route's id (`/blog/[slug]`).
|
|
125
|
+
* @param params - the params, by name.
|
|
126
|
+
* @returns the path (`/blog/hello`).
|
|
127
|
+
*/
|
|
128
|
+
export const filledRoute = (id, params) => {
|
|
129
|
+
const segments = pathSegments(id).flatMap((segment) => {
|
|
130
|
+
const parts = segmentParts(segment);
|
|
131
|
+
const text = parts
|
|
132
|
+
.map((part) => {
|
|
133
|
+
if (part.kind === "text")
|
|
134
|
+
return part.text;
|
|
135
|
+
// inserted as given, as SvelteKit's `resolve` does: the address the page builds from it encodes what it must
|
|
136
|
+
return params[part.name] ?? "";
|
|
137
|
+
})
|
|
138
|
+
.join("");
|
|
139
|
+
return text === "" ? [] : [text];
|
|
140
|
+
});
|
|
141
|
+
return `/${segments.join("/")}`;
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* Whether a text is a route id rather than a path: it names a param or a layout group.
|
|
145
|
+
*
|
|
146
|
+
* @param text - the text.
|
|
147
|
+
*/
|
|
148
|
+
export const isRouteId = (text) => text
|
|
149
|
+
.split("/")
|
|
150
|
+
.some((segment) => GROUP.test(segment) || segmentParts(segment).some((part) => part.kind === "param"));
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The order SvelteKit tries its routes in, so a path two routes match lands on the one SvelteKit would choose.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* SvelteKit's own `sort_routes` (MIT), written again in this package's TypeScript: the rules are SvelteKit's to the
|
|
6
|
+
* letter, since a route chosen otherwise gives a component other params than the app would. A text segment outranks a
|
|
7
|
+
* param, a param with a matcher one without, a required param an optional one, `[...rest]/x` a plain param; a shallower
|
|
8
|
+
* path a deeper one; an optional param that is not last is left out of the comparison.
|
|
9
|
+
*
|
|
10
|
+
* @module
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Orders two routes, the one SvelteKit tries first first.
|
|
14
|
+
*
|
|
15
|
+
* @param first - a route id.
|
|
16
|
+
* @param second - another.
|
|
17
|
+
*/
|
|
18
|
+
export declare const byRouteOrder: (first: string, second: string) => number;
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The order SvelteKit tries its routes in, so a path two routes match lands on the one SvelteKit would choose.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* SvelteKit's own `sort_routes` (MIT), written again in this package's TypeScript: the rules are SvelteKit's to the
|
|
6
|
+
* letter, since a route chosen otherwise gives a component other params than the app would. A text segment outranks a
|
|
7
|
+
* param, a param with a matcher one without, a required param an optional one, `[...rest]/x` a plain param; a shallower
|
|
8
|
+
* path a deeper one; an optional param that is not last is left out of the comparison.
|
|
9
|
+
*
|
|
10
|
+
* @module
|
|
11
|
+
*/
|
|
12
|
+
/** The part a segment past a route's end compares as. */
|
|
13
|
+
const EMPTY = { type: "static", content: "", isMatched: false };
|
|
14
|
+
/** A param's type, by the character after its `[`: `[[optional]]`, `[...rest]`, any other `[required]`. */
|
|
15
|
+
const PARAM_TYPES = { "[": "optional", ".": "rest" };
|
|
16
|
+
/** A layout group, `(app)`: a folder that is not a segment of the path. */
|
|
17
|
+
const GROUP = /^\(.+\)$/;
|
|
18
|
+
/**
|
|
19
|
+
* A segment's parts: a text first (empty when the segment opens with a param), then params and texts in turn.
|
|
20
|
+
*
|
|
21
|
+
* @param segment - the segment.
|
|
22
|
+
*/
|
|
23
|
+
const partsOf = (segment) => {
|
|
24
|
+
const parts = [];
|
|
25
|
+
let index = 0;
|
|
26
|
+
while (index <= segment.length) {
|
|
27
|
+
const start = segment.indexOf("[", index);
|
|
28
|
+
if (start === -1) {
|
|
29
|
+
parts.push({ type: "static", content: segment.slice(index), isMatched: false });
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
parts.push({ type: "static", content: segment.slice(index, start), isMatched: false });
|
|
33
|
+
const type = PARAM_TYPES[segment[start + 1] ?? ""] ?? "required";
|
|
34
|
+
const delimiter = type === "optional" ? "]]" : "]";
|
|
35
|
+
const end = segment.indexOf(delimiter, start);
|
|
36
|
+
if (end === -1)
|
|
37
|
+
return [{ type: "static", content: segment, isMatched: false }];
|
|
38
|
+
index = end + delimiter.length;
|
|
39
|
+
const content = segment.slice(start, index);
|
|
40
|
+
parts.push({ type, content, isMatched: content.includes("=") });
|
|
41
|
+
}
|
|
42
|
+
return parts;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* A route id's segments as the sort compares them: an optional param that is not at the end left out, groups too.
|
|
46
|
+
*
|
|
47
|
+
* @param id - the route id.
|
|
48
|
+
*/
|
|
49
|
+
const sortedSegments = (id) => id
|
|
50
|
+
.replace(/\[\[[^\]]+\]\](?!(?:\/\([^/]+\))*$)/g, "")
|
|
51
|
+
.slice(1)
|
|
52
|
+
.split("/")
|
|
53
|
+
.filter((segment) => segment !== "" && !GROUP.test(segment))
|
|
54
|
+
.map(partsOf);
|
|
55
|
+
/**
|
|
56
|
+
* Orders two texts as SvelteKit does: by their characters, except that `foobar` outranks `foo`.
|
|
57
|
+
*
|
|
58
|
+
* @param first - a text.
|
|
59
|
+
* @param second - another.
|
|
60
|
+
*/
|
|
61
|
+
const byText = (first, second) => {
|
|
62
|
+
for (let index = 0;; index += 1) {
|
|
63
|
+
const a = first[index];
|
|
64
|
+
const b = second[index];
|
|
65
|
+
if (a === b) {
|
|
66
|
+
if (a === undefined)
|
|
67
|
+
return 0;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (a === undefined)
|
|
71
|
+
return 1;
|
|
72
|
+
if (b === undefined)
|
|
73
|
+
return -1;
|
|
74
|
+
return a < b ? -1 : 1;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Orders two params at the same place of two routes, or none when they rank the same.
|
|
79
|
+
*
|
|
80
|
+
* @param a - the first route's param.
|
|
81
|
+
* @param b - the second's.
|
|
82
|
+
* @param nextA - the text after the first's, in its segment or the next.
|
|
83
|
+
* @param nextB - the text after the second's.
|
|
84
|
+
*/
|
|
85
|
+
const byParam = (a, b, nextA, nextB) => {
|
|
86
|
+
if (a.type === "rest" || b.type === "rest")
|
|
87
|
+
return byRest(a, b, nextA, nextB);
|
|
88
|
+
if (a.isMatched !== b.isMatched)
|
|
89
|
+
return a.isMatched ? -1 : 1;
|
|
90
|
+
if (a.type !== b.type) {
|
|
91
|
+
if (a.type === "required")
|
|
92
|
+
return -1;
|
|
93
|
+
if (b.type === "required")
|
|
94
|
+
return 1;
|
|
95
|
+
}
|
|
96
|
+
return undefined;
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Orders two params at the same place when one is a rest param: `[...rest]/x` outranks a plain param, which outranks
|
|
100
|
+
* a bare `[...rest]`.
|
|
101
|
+
*
|
|
102
|
+
* @param a - the first route's param.
|
|
103
|
+
* @param b - the second's.
|
|
104
|
+
* @param nextA - the text after the first's.
|
|
105
|
+
* @param nextB - the text after the second's.
|
|
106
|
+
*/
|
|
107
|
+
const byRest = (a, b, nextA, nextB) => {
|
|
108
|
+
if (a.type === "rest" && b.type === "rest") {
|
|
109
|
+
if (nextA !== "" && nextB !== "")
|
|
110
|
+
return undefined;
|
|
111
|
+
if (nextA !== "")
|
|
112
|
+
return -1;
|
|
113
|
+
return nextB !== "" ? 1 : undefined;
|
|
114
|
+
}
|
|
115
|
+
if (a.type === "rest")
|
|
116
|
+
return nextA !== "" && nextB === "" ? -1 : 1;
|
|
117
|
+
return nextB !== "" && nextA === "" ? 1 : -1;
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* The text that follows a part: the next part of its segment, or the first of the next segment.
|
|
121
|
+
*
|
|
122
|
+
* @param segments - the route's segments.
|
|
123
|
+
* @param segment - the part's segment.
|
|
124
|
+
* @param part - the part.
|
|
125
|
+
*/
|
|
126
|
+
const nextText = (segments, segment, part) => segments[segment]?.[part + 1]?.content || segments[segment + 1]?.[0]?.content || "";
|
|
127
|
+
/**
|
|
128
|
+
* Orders two segments at the same place of two routes, or none when they rank the same.
|
|
129
|
+
*
|
|
130
|
+
* @param segmentsA - the first route's segments.
|
|
131
|
+
* @param segmentsB - the second's.
|
|
132
|
+
* @param index - the segments' place.
|
|
133
|
+
*/
|
|
134
|
+
const bySegment = (segmentsA, segmentsB, index) => {
|
|
135
|
+
const segmentA = segmentsA[index] ?? [EMPTY];
|
|
136
|
+
const segmentB = segmentsB[index] ?? [EMPTY];
|
|
137
|
+
for (let part = 0; part < Math.max(segmentA.length, segmentB.length); part += 1) {
|
|
138
|
+
const order = byPart(segmentA[part], segmentB[part], part % 2 === 1, () => [
|
|
139
|
+
nextText(segmentsA, index, part),
|
|
140
|
+
nextText(segmentsB, index, part)
|
|
141
|
+
]);
|
|
142
|
+
if (order !== undefined)
|
|
143
|
+
return order;
|
|
144
|
+
}
|
|
145
|
+
return undefined;
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* Orders two parts at the same place of two segments, or none when they rank the same.
|
|
149
|
+
*
|
|
150
|
+
* @param a - the first segment's part, or none past its end.
|
|
151
|
+
* @param b - the second's.
|
|
152
|
+
* @param isParam - whether the place holds params: a segment starts with a text, maybe empty, then alternates.
|
|
153
|
+
* @param nextTexts - the texts after each param.
|
|
154
|
+
*/
|
|
155
|
+
const byPart = (a, b, isParam, nextTexts) => {
|
|
156
|
+
if (isParam) {
|
|
157
|
+
if (a === undefined)
|
|
158
|
+
return -1;
|
|
159
|
+
if (b === undefined)
|
|
160
|
+
return 1;
|
|
161
|
+
const [nextA, nextB] = nextTexts();
|
|
162
|
+
return byParam(a, b, nextA, nextB);
|
|
163
|
+
}
|
|
164
|
+
if (a?.content === b?.content)
|
|
165
|
+
return undefined;
|
|
166
|
+
if (a === undefined || a === EMPTY)
|
|
167
|
+
return -1;
|
|
168
|
+
if (b === undefined || b === EMPTY)
|
|
169
|
+
return 1;
|
|
170
|
+
return byText(a.content, b.content);
|
|
171
|
+
};
|
|
172
|
+
/**
|
|
173
|
+
* Orders two routes, the one SvelteKit tries first first.
|
|
174
|
+
*
|
|
175
|
+
* @param first - a route id.
|
|
176
|
+
* @param second - another.
|
|
177
|
+
*/
|
|
178
|
+
export const byRouteOrder = (first, second) => {
|
|
179
|
+
const segmentsA = sortedSegments(first);
|
|
180
|
+
const segmentsB = sortedSegments(second);
|
|
181
|
+
for (let index = 0; index < Math.max(segmentsA.length, segmentsB.length); index += 1) {
|
|
182
|
+
const order = bySegment(segmentsA, segmentsB, index);
|
|
183
|
+
if (order !== undefined)
|
|
184
|
+
return order;
|
|
185
|
+
}
|
|
186
|
+
return first < second ? 1 : -1;
|
|
187
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The story types for a SvelteKit project: Svelte's, with the `parameters.sveltekit` a story sets its page, its data
|
|
3
|
+
* and its navigation with (`import type { Meta, Story } from "@forgebook/sveltekit"`).
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* `navigation`, `forms` and `hrefs` are written as Storybook's SvelteKit framework writes them under
|
|
7
|
+
* `sveltekit_experimental`, which is read too, so a story moved from Storybook keeps its page; `page`, `load` and
|
|
8
|
+
* `serverData` are Forgebook's. Types only.
|
|
9
|
+
*
|
|
10
|
+
* @module
|
|
11
|
+
*/
|
|
12
|
+
import type { StoryParameters } from "@forgebook/story-format/csf";
|
|
13
|
+
import type { AnyComponent, NoComponent, Meta as SvelteMeta, Preview as SveltePreview, Story as SvelteStory } from "@forgebook/svelte";
|
|
14
|
+
import type { HrefParameter, KitActionResult, KitLoadEvent, KitPage, PageParameters, StoryLoad, SveltekitParameters } from "./kitParameters.ts";
|
|
15
|
+
/** A story's SvelteKit settings (`parameters.sveltekit`). */
|
|
16
|
+
export type StorySveltekit = SveltekitParameters;
|
|
17
|
+
/** The page a story starts on (`parameters.sveltekit.page`). */
|
|
18
|
+
export type StoryPageParameters = PageParameters;
|
|
19
|
+
/** The page a story's components read, as `page` from `$app/state` gives it. */
|
|
20
|
+
export type StoryKitPage = KitPage;
|
|
21
|
+
/** A universal `load` a story runs (`parameters.sveltekit.load`). */
|
|
22
|
+
export type StoryKitLoad = StoryLoad;
|
|
23
|
+
/** What a story's `load` receives. */
|
|
24
|
+
export type StoryKitLoadEvent = KitLoadEvent;
|
|
25
|
+
/** An action's result, as `parameters.sveltekit.forms.result` gives it. */
|
|
26
|
+
export type StoryActionResult = KitActionResult;
|
|
27
|
+
/** An `hrefs` entry: a callback, or one with whether its key is a regular expression. */
|
|
28
|
+
export type StoryHref = HrefParameter;
|
|
29
|
+
/** A story's parameters: the catalogue's settings, and its SvelteKit ones. */
|
|
30
|
+
export type SveltekitStoryParameters = StoryParameters & {
|
|
31
|
+
/** The story's page, its data and what its navigation, forms and links do. */
|
|
32
|
+
readonly sveltekit?: StorySveltekit;
|
|
33
|
+
};
|
|
34
|
+
/** A story file's default export: `{ title, component, parameters: { sveltekit } } satisfies Meta<typeof Nav>`. */
|
|
35
|
+
export type Meta<TComponent extends AnyComponent = NoComponent> = Omit<SvelteMeta<TComponent>, "parameters"> & {
|
|
36
|
+
/** Settings for every story of the file, its page among them. */
|
|
37
|
+
readonly parameters?: SveltekitStoryParameters;
|
|
38
|
+
};
|
|
39
|
+
/** A story: a named export of a story file. */
|
|
40
|
+
export type Story<TComponent extends AnyComponent = NoComponent> = Omit<SvelteStory<TComponent>, "parameters"> & {
|
|
41
|
+
/** Settings over the meta's, its page among them. */
|
|
42
|
+
readonly parameters?: SveltekitStoryParameters;
|
|
43
|
+
};
|
|
44
|
+
/** A SvelteKit catalogue's preview (`forgebook.preview.ts`): Svelte's, with a page every story starts from. */
|
|
45
|
+
export type Preview = Omit<SveltePreview, "parameters"> & {
|
|
46
|
+
/** Settings every story starts from, a page among them. */
|
|
47
|
+
readonly parameters?: SveltekitStoryParameters;
|
|
48
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The story types for a SvelteKit project: Svelte's, with the `parameters.sveltekit` a story sets its page, its data
|
|
3
|
+
* and its navigation with (`import type { Meta, Story } from "@forgebook/sveltekit"`).
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* `navigation`, `forms` and `hrefs` are written as Storybook's SvelteKit framework writes them under
|
|
7
|
+
* `sveltekit_experimental`, which is read too, so a story moved from Storybook keeps its page; `page`, `load` and
|
|
8
|
+
* `serverData` are Forgebook's. Types only.
|
|
9
|
+
*
|
|
10
|
+
* @module
|
|
11
|
+
*/
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The code writer of a SvelteKit catalogue: a story drawn from its args written as Svelte markup, as Svelte's catalogue
|
|
3
|
+
* writes it, under this package's name, so a catalogue needs no other Forgebook package of its own.
|
|
4
|
+
*
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
7
|
+
import { codeOf as svelteCodeOf } from "@forgebook/svelte/code";
|
|
8
|
+
/** Writes a story drawn from its args as Svelte markup. */
|
|
9
|
+
export const codeOf = svelteCodeOf;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a play function reads of a SvelteKit story's page: where its links and `goto` calls took it, its data and form,
|
|
3
|
+
* and the calls it made (`goto`, `invalidateAll`, `enhance`), to assert on.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { storyPage } from "@forgebook/sveltekit/page";
|
|
8
|
+
*
|
|
9
|
+
* export const GoesToAbout: Story<typeof Nav> = {
|
|
10
|
+
* play: async ({ canvasElement }) => {
|
|
11
|
+
* await userEvent.click(within(canvasElement).getByRole("link", { name: "About" }));
|
|
12
|
+
* expect(storyPage().pathname).toBe("/about");
|
|
13
|
+
* }
|
|
14
|
+
* };
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
import type { KitPage } from "./kitParameters.ts";
|
|
20
|
+
import { type KitCall } from "./kitStore.ts";
|
|
21
|
+
/** A story's page as a play function reads it. */
|
|
22
|
+
export type StoryPageState = Pick<KitPage, "params" | "data" | "form" | "state" | "status" | "error"> & {
|
|
23
|
+
/** The page's path, its base path included (`/blog/hello`). */
|
|
24
|
+
readonly pathname: string;
|
|
25
|
+
/** The search params, by name: the last value of a name given twice. */
|
|
26
|
+
readonly query: Readonly<Record<string, string>>;
|
|
27
|
+
/** The hash, with its `#`, or empty. */
|
|
28
|
+
readonly hash: string;
|
|
29
|
+
/** The route's id, or `null` when no route of the project matches. */
|
|
30
|
+
readonly routeId: string | null;
|
|
31
|
+
/** The calls the story made to SvelteKit, in order. */
|
|
32
|
+
readonly calls: readonly KitCall[];
|
|
33
|
+
};
|
|
34
|
+
/** The page of the story drawn now, and the calls it made. */
|
|
35
|
+
export declare const storyPage: () => StoryPageState;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { currentStore } from "./kitStore.js";
|
|
2
|
+
/** The page of the story drawn now, and the calls it made. */
|
|
3
|
+
export const storyPage = () => {
|
|
4
|
+
const store = currentStore();
|
|
5
|
+
const page = store.page();
|
|
6
|
+
return {
|
|
7
|
+
pathname: page.url.pathname,
|
|
8
|
+
query: Object.fromEntries(page.url.searchParams),
|
|
9
|
+
hash: page.url.hash,
|
|
10
|
+
routeId: page.route.id,
|
|
11
|
+
params: page.params,
|
|
12
|
+
data: page.data,
|
|
13
|
+
form: page.form,
|
|
14
|
+
state: page.state,
|
|
15
|
+
status: page.status,
|
|
16
|
+
error: page.error,
|
|
17
|
+
calls: store.calls()
|
|
18
|
+
};
|
|
19
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { type Alias } from "vite";
|
|
2
|
+
/** The modules only a server may load, with what each is. */
|
|
3
|
+
export declare const SERVER_ONLY: Readonly<Record<string, string>>;
|
|
4
|
+
/** The public environment modules, by the name a component imports. */
|
|
5
|
+
export declare const PUBLIC_ENV: readonly ["$env/static/public", "$env/dynamic/public", "$app/env/public"];
|
|
6
|
+
/** A public environment module's name. */
|
|
7
|
+
export type PublicEnvModule = (typeof PUBLIC_ENV)[number];
|
|
8
|
+
/**
|
|
9
|
+
* A module that refuses to load in a story: it declares the names its importer asked for, so the browser links it and
|
|
10
|
+
* runs it, and its error, which says why, is the one the frame shows.
|
|
11
|
+
*
|
|
12
|
+
* @param id - the module's name, with the names it is imported with (`$app/env/private?names=TOKEN`).
|
|
13
|
+
* @param reason - the error's message.
|
|
14
|
+
*/
|
|
15
|
+
export declare const refusedModule: (id: string, reason: string) => string;
|
|
16
|
+
/**
|
|
17
|
+
* A server-only module, refusing to load with why.
|
|
18
|
+
*
|
|
19
|
+
* @param id - the module's name, with the names it is imported with.
|
|
20
|
+
*/
|
|
21
|
+
export declare const serverOnlyModule: (id: string) => string;
|
|
22
|
+
/**
|
|
23
|
+
* A module's code with its named imports of SvelteKit's environment and server modules naming what they import, so a
|
|
24
|
+
* module that refuses to load (`refusedModule`) can declare them.
|
|
25
|
+
*
|
|
26
|
+
* @param code - the module's code.
|
|
27
|
+
* @returns the code, or none when it imports none of those modules by name.
|
|
28
|
+
*/
|
|
29
|
+
export declare const namedServerImports: (code: string) => string | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* The environment or server module of SvelteKit a name stands for, its query left out; none for another module.
|
|
32
|
+
*
|
|
33
|
+
* @param source - an import's module.
|
|
34
|
+
*/
|
|
35
|
+
export declare const kitModuleName: (source: string) => string | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Whether a name is a server-only module, its query left out.
|
|
38
|
+
*
|
|
39
|
+
* @param source - an import's module.
|
|
40
|
+
*/
|
|
41
|
+
export declare const isServerOnly: (source: string) => boolean;
|
|
42
|
+
/**
|
|
43
|
+
* The variables SvelteKit 2 gives the browser: those with the public prefix, and not the private one.
|
|
44
|
+
*
|
|
45
|
+
* @param env - every variable, by name.
|
|
46
|
+
* @param publicPrefix - `env.publicPrefix` (`PUBLIC_`).
|
|
47
|
+
* @param privatePrefix - `env.privatePrefix` (empty by default).
|
|
48
|
+
*/
|
|
49
|
+
export declare const publicVariables: (env: Readonly<Record<string, string>>, publicPrefix: string, privatePrefix: string) => Record<string, string>;
|
|
50
|
+
/**
|
|
51
|
+
* A module of named exports, one per variable: what a name JavaScript cannot export is left out.
|
|
52
|
+
*
|
|
53
|
+
* @param values - the values, by name.
|
|
54
|
+
*/
|
|
55
|
+
export declare const namedExports: (values: Readonly<Record<string, unknown>>) => string;
|
|
56
|
+
/**
|
|
57
|
+
* The public variables a SvelteKit 3 project declares in `src/env.ts`, checked by their schemas.
|
|
58
|
+
*
|
|
59
|
+
* @param srcDir - the project's source folder (`src`).
|
|
60
|
+
* @param env - every variable, by name.
|
|
61
|
+
* @param aliases - the project's aliases.
|
|
62
|
+
* @returns the values by name, and the files read; none without an env file.
|
|
63
|
+
*/
|
|
64
|
+
export declare const declaredPublicVariables: (srcDir: string, env: Readonly<Record<string, string>>, aliases?: readonly Alias[]) => Promise<{
|
|
65
|
+
readonly values: Record<string, unknown>;
|
|
66
|
+
readonly file: string;
|
|
67
|
+
} | undefined>;
|