@markless/router 0.5.0 → 0.6.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.
@@ -1,189 +0,0 @@
1
- import { extname, join, normalize, relative } from "pathe";
2
- import { joinURL, withLeadingSlash, withoutLeadingSlash, withoutTrailingSlash } from "ufo";
3
- //#region src/route-manifest.ts
4
- const PAGES_DIR = "pages";
5
- const PAGE_EXTENSIONS = /* @__PURE__ */ new Set([".tsrx", ".mdx"]);
6
- function buildRouteManifestFromFileIds(fileIds) {
7
- const pages = unique(fileIds.map(normalizeRouteFileId)).filter(isPageModuleFile).toSorted(compareCodeUnits).map(normalizePage);
8
- const routes = pages.flatMap((page) => page.kind === "route" ? [page.route] : []);
9
- assertNoRouteConflicts(routes);
10
- const statusPages = {};
11
- for (const page of pages) if (page.kind === "status") statusPages[page.status] = page.file;
12
- return {
13
- routes: routes.map(toPublicRoute).toSorted(compareRoutes),
14
- statusPages
15
- };
16
- }
17
- function normalizeRequestPathname(pathname) {
18
- const normalizedPathname = withoutTrailingSlash(withLeadingSlash(pathname));
19
- return normalizedPathname === "" ? "/" : normalizedPathname;
20
- }
21
- function normalizeRouteFileId(fileId) {
22
- return withoutLeadingSlash(normalize(fileId));
23
- }
24
- function matchRouteManifest(pathname, manifest) {
25
- const requestPathname = normalizeRequestPathname(pathname);
26
- for (const route of manifest.routes) {
27
- const params = matchRoutePathname(route, requestPathname);
28
- if (params) return {
29
- route,
30
- params
31
- };
32
- }
33
- }
34
- function isPageModuleFile(file) {
35
- const pageFile = pageRelativeFile(file);
36
- return pageFile !== void 0 && PAGE_EXTENSIONS.has(extname(pageFile));
37
- }
38
- function normalizePage(file) {
39
- const relativeFile = file;
40
- const pageFile = pageRelativeFile(file);
41
- const extension = extname(pageFile);
42
- const withoutExtension = pageFile.slice(0, -extension.length);
43
- if (withoutExtension === "api" || withoutExtension.startsWith("api/")) throw new Error(`API routes inside pages/ are not supported. Use top-level api/: ${relativeFile}`);
44
- const routeFile = normalize(join(withoutExtension));
45
- const rawSegments = routeFile === "." ? [] : routeFile.split("/");
46
- if (rawSegments.length === 1 && rawSegments[0] === "404") return {
47
- kind: "status",
48
- status: "notFound",
49
- file: relativeFile
50
- };
51
- if (rawSegments.length === 1 && rawSegments[0] === "500") return {
52
- kind: "status",
53
- status: "error",
54
- file: relativeFile
55
- };
56
- if (rawSegments.length > 1 && ["404", "500"].includes(rawSegments.at(-1))) throw new Error(`Nested status pages are not supported in v0: ${relativeFile}`);
57
- if (rawSegments.at(-1) === "index") rawSegments.pop();
58
- const pattern = routePathname(rawSegments);
59
- const segments = rawSegments.map((segment, index) => normalizeSegment(segment, index, rawSegments, relativeFile));
60
- const pathnameSegments = segments.map((segment) => segment.pathname);
61
- const identitySegments = segments.map((segment) => segment.identity);
62
- const params = segments.flatMap((segment) => segment.params);
63
- return {
64
- kind: "route",
65
- route: {
66
- pathname: routePathname(pathnameSegments),
67
- pattern,
68
- identity: routePathname(identitySegments),
69
- params,
70
- file: relativeFile,
71
- relativeFile
72
- }
73
- };
74
- }
75
- function pageRelativeFile(file) {
76
- if (file === PAGES_DIR || !file.startsWith(`${PAGES_DIR}/`)) return;
77
- return relative(PAGES_DIR, file);
78
- }
79
- function normalizeSegment(segment, index, segments, relativeFile) {
80
- const catchAll = segment.match(/^\[\.\.\.([A-Za-z_$][\w$]*)\]$/);
81
- if (catchAll) {
82
- if (index !== segments.length - 1) throw new Error(`Catch-all route segments must be final: ${relativeFile}`);
83
- return {
84
- pathname: "**",
85
- identity: "**",
86
- params: [{
87
- name: catchAll[1],
88
- kind: "catch-all"
89
- }]
90
- };
91
- }
92
- const dynamic = segment.match(/^\[([A-Za-z_$][\w$]*)\]$/);
93
- if (dynamic) return {
94
- pathname: `:${dynamic[1]}`,
95
- identity: ":param",
96
- params: [{
97
- name: dynamic[1],
98
- kind: "dynamic"
99
- }]
100
- };
101
- if (segment.includes("[") || segment.includes("]")) throw new Error(`Unsupported route segment pattern: ${relativeFile}`);
102
- return {
103
- pathname: segment,
104
- identity: segment,
105
- params: []
106
- };
107
- }
108
- function assertNoRouteConflicts(routes) {
109
- const routesByIdentity = /* @__PURE__ */ new Map();
110
- for (const route of routes) {
111
- const existingRoutes = routesByIdentity.get(route.identity) ?? [];
112
- existingRoutes.push(route);
113
- routesByIdentity.set(route.identity, existingRoutes);
114
- }
115
- for (const [identity, conflictingRoutes] of routesByIdentity) {
116
- if (conflictingRoutes.length < 2) continue;
117
- const files = conflictingRoutes.map((route) => route.relativeFile).toSorted(compareCodeUnits);
118
- throw new Error([`Route conflict: ${identity} is defined by both:`, ...files.map((file) => `- ${file}`)].join("\n"));
119
- }
120
- }
121
- function toPublicRoute(route) {
122
- return {
123
- pathname: route.pathname,
124
- pattern: route.pattern,
125
- params: route.params,
126
- file: route.file
127
- };
128
- }
129
- function compareRoutes(left, right) {
130
- const leftSegments = splitRoutePathname(left.pathname);
131
- const rightSegments = splitRoutePathname(right.pathname);
132
- const length = Math.max(leftSegments.length, rightSegments.length);
133
- for (let index = 0; index < length; index += 1) {
134
- const leftSegment = leftSegments[index];
135
- const rightSegment = rightSegments[index];
136
- if (leftSegment === void 0) return -1;
137
- if (rightSegment === void 0) return 1;
138
- const rankDifference = segmentRank(leftSegment) - segmentRank(rightSegment);
139
- if (rankDifference !== 0) return rankDifference;
140
- if (segmentRank(leftSegment) === 0 && leftSegment !== rightSegment) return compareCodeUnits(leftSegment, rightSegment);
141
- }
142
- return compareCodeUnits(left.pathname, right.pathname);
143
- }
144
- function splitRoutePathname(pathname) {
145
- const route = withoutLeadingSlash(pathname);
146
- return route === "" ? [] : route.split("/");
147
- }
148
- function matchRoutePathname(route, requestPathname) {
149
- const routeSegments = splitRoutePathname(route.pathname);
150
- const requestSegments = splitRoutePathname(requestPathname);
151
- const catchAllIndex = routeSegments.indexOf("**");
152
- if (catchAllIndex === -1 && routeSegments.length !== requestSegments.length) return;
153
- if (catchAllIndex !== -1 && requestSegments.length <= catchAllIndex) return;
154
- const params = {};
155
- for (let index = 0; index < routeSegments.length; index += 1) {
156
- const routeSegment = routeSegments[index];
157
- const requestSegment = requestSegments[index];
158
- if (routeSegment === "**") {
159
- const catchAllParam = route.params.find((param) => param.kind === "catch-all");
160
- if (!catchAllParam) return void 0;
161
- params[catchAllParam.name] = joinURL(requestSegment, ...requestSegments.slice(index + 1));
162
- return params;
163
- }
164
- if (routeSegment.startsWith(":")) {
165
- params[routeSegment.slice(1)] = requestSegment;
166
- continue;
167
- }
168
- if (routeSegment !== requestSegment) return;
169
- }
170
- return params;
171
- }
172
- function segmentRank(segment) {
173
- if (segment === "**") return 2;
174
- if (segment.startsWith(":")) return 1;
175
- return 0;
176
- }
177
- function compareCodeUnits(left, right) {
178
- return left < right ? -1 : left > right ? 1 : 0;
179
- }
180
- function unique(values) {
181
- return [...new Set(values)];
182
- }
183
- function routePathname(segments) {
184
- if (segments.length === 0) return "/";
185
- const [base, ...rest] = segments;
186
- return withLeadingSlash(joinURL(base, ...rest));
187
- }
188
- //#endregion
189
- export { normalizeRouteFileId as a, normalizeRequestPathname as i, isPageModuleFile as n, matchRouteManifest as r, buildRouteManifestFromFileIds as t };