@rangojs/router 0.0.0-experimental.10
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/CLAUDE.md +43 -0
- package/README.md +19 -0
- package/dist/bin/rango.js +227 -0
- package/dist/vite/index.js +3039 -0
- package/package.json +171 -0
- package/skills/caching/SKILL.md +191 -0
- package/skills/debug-manifest/SKILL.md +108 -0
- package/skills/document-cache/SKILL.md +180 -0
- package/skills/fonts/SKILL.md +165 -0
- package/skills/hooks/SKILL.md +442 -0
- package/skills/intercept/SKILL.md +190 -0
- package/skills/layout/SKILL.md +213 -0
- package/skills/links/SKILL.md +180 -0
- package/skills/loader/SKILL.md +246 -0
- package/skills/middleware/SKILL.md +202 -0
- package/skills/mime-routes/SKILL.md +124 -0
- package/skills/parallel/SKILL.md +228 -0
- package/skills/prerender/SKILL.md +283 -0
- package/skills/rango/SKILL.md +54 -0
- package/skills/response-routes/SKILL.md +358 -0
- package/skills/route/SKILL.md +173 -0
- package/skills/router-setup/SKILL.md +346 -0
- package/skills/tailwind/SKILL.md +129 -0
- package/skills/theme/SKILL.md +78 -0
- package/skills/typesafety/SKILL.md +394 -0
- package/src/__internal.ts +175 -0
- package/src/bin/rango.ts +24 -0
- package/src/browser/event-controller.ts +876 -0
- package/src/browser/index.ts +18 -0
- package/src/browser/link-interceptor.ts +121 -0
- package/src/browser/lru-cache.ts +69 -0
- package/src/browser/merge-segment-loaders.ts +126 -0
- package/src/browser/navigation-bridge.ts +913 -0
- package/src/browser/navigation-client.ts +165 -0
- package/src/browser/navigation-store.ts +823 -0
- package/src/browser/partial-update.ts +600 -0
- package/src/browser/react/Link.tsx +248 -0
- package/src/browser/react/NavigationProvider.tsx +346 -0
- package/src/browser/react/ScrollRestoration.tsx +94 -0
- package/src/browser/react/context.ts +53 -0
- package/src/browser/react/index.ts +52 -0
- package/src/browser/react/location-state-shared.ts +120 -0
- package/src/browser/react/location-state.ts +62 -0
- package/src/browser/react/mount-context.ts +32 -0
- package/src/browser/react/use-action.ts +240 -0
- package/src/browser/react/use-client-cache.ts +56 -0
- package/src/browser/react/use-handle.ts +203 -0
- package/src/browser/react/use-href.tsx +40 -0
- package/src/browser/react/use-link-status.ts +134 -0
- package/src/browser/react/use-mount.ts +31 -0
- package/src/browser/react/use-navigation.ts +140 -0
- package/src/browser/react/use-segments.ts +188 -0
- package/src/browser/request-controller.ts +164 -0
- package/src/browser/rsc-router.tsx +352 -0
- package/src/browser/scroll-restoration.ts +324 -0
- package/src/browser/segment-structure-assert.ts +67 -0
- package/src/browser/server-action-bridge.ts +762 -0
- package/src/browser/shallow.ts +35 -0
- package/src/browser/types.ts +478 -0
- package/src/build/generate-manifest.ts +377 -0
- package/src/build/generate-route-types.ts +828 -0
- package/src/build/index.ts +36 -0
- package/src/build/route-trie.ts +239 -0
- package/src/cache/cache-scope.ts +563 -0
- package/src/cache/cf/cf-cache-store.ts +428 -0
- package/src/cache/cf/index.ts +19 -0
- package/src/cache/document-cache.ts +340 -0
- package/src/cache/index.ts +58 -0
- package/src/cache/memory-segment-store.ts +150 -0
- package/src/cache/memory-store.ts +253 -0
- package/src/cache/types.ts +392 -0
- package/src/client.rsc.tsx +83 -0
- package/src/client.tsx +643 -0
- package/src/component-utils.ts +76 -0
- package/src/components/DefaultDocument.tsx +23 -0
- package/src/debug.ts +233 -0
- package/src/default-error-boundary.tsx +88 -0
- package/src/deps/browser.ts +8 -0
- package/src/deps/html-stream-client.ts +2 -0
- package/src/deps/html-stream-server.ts +2 -0
- package/src/deps/rsc.ts +10 -0
- package/src/deps/ssr.ts +2 -0
- package/src/errors.ts +295 -0
- package/src/handle.ts +130 -0
- package/src/handles/MetaTags.tsx +193 -0
- package/src/handles/index.ts +6 -0
- package/src/handles/meta.ts +247 -0
- package/src/host/cookie-handler.ts +159 -0
- package/src/host/errors.ts +97 -0
- package/src/host/index.ts +56 -0
- package/src/host/pattern-matcher.ts +214 -0
- package/src/host/router.ts +330 -0
- package/src/host/testing.ts +79 -0
- package/src/host/types.ts +138 -0
- package/src/host/utils.ts +25 -0
- package/src/href-client.ts +202 -0
- package/src/href-context.ts +33 -0
- package/src/index.rsc.ts +121 -0
- package/src/index.ts +165 -0
- package/src/loader.rsc.ts +207 -0
- package/src/loader.ts +47 -0
- package/src/network-error-thrower.tsx +21 -0
- package/src/outlet-context.ts +15 -0
- package/src/prerender/param-hash.ts +35 -0
- package/src/prerender/store.ts +40 -0
- package/src/prerender.ts +156 -0
- package/src/reverse.ts +267 -0
- package/src/root-error-boundary.tsx +277 -0
- package/src/route-content-wrapper.tsx +193 -0
- package/src/route-definition.ts +1431 -0
- package/src/route-map-builder.ts +242 -0
- package/src/route-types.ts +220 -0
- package/src/router/error-handling.ts +287 -0
- package/src/router/handler-context.ts +158 -0
- package/src/router/intercept-resolution.ts +387 -0
- package/src/router/loader-resolution.ts +327 -0
- package/src/router/manifest.ts +216 -0
- package/src/router/match-api.ts +621 -0
- package/src/router/match-context.ts +264 -0
- package/src/router/match-middleware/background-revalidation.ts +236 -0
- package/src/router/match-middleware/cache-lookup.ts +382 -0
- package/src/router/match-middleware/cache-store.ts +276 -0
- package/src/router/match-middleware/index.ts +81 -0
- package/src/router/match-middleware/intercept-resolution.ts +281 -0
- package/src/router/match-middleware/segment-resolution.ts +184 -0
- package/src/router/match-pipelines.ts +214 -0
- package/src/router/match-result.ts +213 -0
- package/src/router/metrics.ts +62 -0
- package/src/router/middleware.ts +791 -0
- package/src/router/pattern-matching.ts +407 -0
- package/src/router/revalidation.ts +190 -0
- package/src/router/router-context.ts +301 -0
- package/src/router/segment-resolution.ts +1315 -0
- package/src/router/trie-matching.ts +172 -0
- package/src/router/types.ts +163 -0
- package/src/router.gen.ts +6 -0
- package/src/router.ts +2423 -0
- package/src/rsc/handler.ts +1443 -0
- package/src/rsc/helpers.ts +64 -0
- package/src/rsc/index.ts +56 -0
- package/src/rsc/nonce.ts +18 -0
- package/src/rsc/types.ts +236 -0
- package/src/segment-system.tsx +442 -0
- package/src/server/context.ts +466 -0
- package/src/server/handle-store.ts +229 -0
- package/src/server/loader-registry.ts +174 -0
- package/src/server/request-context.ts +554 -0
- package/src/server/root-layout.tsx +10 -0
- package/src/server/tsconfig.json +14 -0
- package/src/server.ts +171 -0
- package/src/ssr/index.tsx +296 -0
- package/src/theme/ThemeProvider.tsx +291 -0
- package/src/theme/ThemeScript.tsx +61 -0
- package/src/theme/constants.ts +59 -0
- package/src/theme/index.ts +58 -0
- package/src/theme/theme-context.ts +70 -0
- package/src/theme/theme-script.ts +152 -0
- package/src/theme/types.ts +182 -0
- package/src/theme/use-theme.ts +44 -0
- package/src/types.ts +1757 -0
- package/src/urls.gen.ts +8 -0
- package/src/urls.ts +1282 -0
- package/src/use-loader.tsx +346 -0
- package/src/vite/expose-action-id.ts +344 -0
- package/src/vite/expose-handle-id.ts +209 -0
- package/src/vite/expose-loader-id.ts +426 -0
- package/src/vite/expose-location-state-id.ts +177 -0
- package/src/vite/expose-prerender-handler-id.ts +429 -0
- package/src/vite/index.ts +2068 -0
- package/src/vite/package-resolution.ts +125 -0
- package/src/vite/version.d.ts +12 -0
- package/src/vite/virtual-entries.ts +114 -0
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build-time manifest generation for @rangojs/router
|
|
3
|
+
*
|
|
4
|
+
* Extracts the prefix tree and route manifest from UrlPatterns at build time.
|
|
5
|
+
* This enables:
|
|
6
|
+
* - Pre-computed prefix tree for fast short-circuit checks
|
|
7
|
+
* - Complete route manifest for href() without runtime evaluation
|
|
8
|
+
* - Support for nested includes
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { UrlPatterns } from "../urls.js";
|
|
12
|
+
import type { AllUseItems } from "../route-types.js";
|
|
13
|
+
import { extractStaticPrefix } from "../router/pattern-matching.js";
|
|
14
|
+
import { RSCRouterContext, runWithPrefixes } from "../server/context.js";
|
|
15
|
+
import type { EntryData, TrackedInclude } from "../server/context.js";
|
|
16
|
+
import type { TrailingSlashMode } from "../types.js";
|
|
17
|
+
import { createRouteHelpers } from "../route-definition.js";
|
|
18
|
+
import MapRootLayout from "../server/root-layout.js";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Node in the prefix tree
|
|
22
|
+
*/
|
|
23
|
+
export interface PrefixTreeNode {
|
|
24
|
+
/** The static prefix for this node */
|
|
25
|
+
staticPrefix: string;
|
|
26
|
+
/** The full URL prefix (including parent prefixes) */
|
|
27
|
+
fullPrefix: string;
|
|
28
|
+
/** Name prefix for routes in this include */
|
|
29
|
+
namePrefix?: string;
|
|
30
|
+
/** Child nodes (nested includes) */
|
|
31
|
+
children: Record<string, PrefixTreeNode>;
|
|
32
|
+
/** Route names defined directly in this include (not in children) */
|
|
33
|
+
routes: string[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Generated manifest containing prefix tree and route mappings
|
|
38
|
+
*/
|
|
39
|
+
export interface GeneratedManifest {
|
|
40
|
+
/** Nested prefix tree for short-circuit optimization */
|
|
41
|
+
prefixTree: Record<string, PrefixTreeNode>;
|
|
42
|
+
/** Complete route name → pattern mapping for href() */
|
|
43
|
+
routeManifest: Record<string, string>;
|
|
44
|
+
/** Route name → trailing slash mode for trie redirect handling */
|
|
45
|
+
routeTrailingSlash?: Record<string, string>;
|
|
46
|
+
/** Route names using createPrerenderHandler (for dev-mode Node.js delegation) */
|
|
47
|
+
prerenderRoutes?: string[];
|
|
48
|
+
/** Route names with passthrough: true (handler kept in bundle for live fallback) */
|
|
49
|
+
passthroughRoutes?: string[];
|
|
50
|
+
/** Route name → response type for non-RSC routes */
|
|
51
|
+
responseTypeRoutes?: Record<string, string>;
|
|
52
|
+
/** Generation timestamp */
|
|
53
|
+
generatedAt: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Build prefix tree node by running the patterns with proper context.
|
|
58
|
+
* Uses a visited set to detect circular includes and prevent infinite recursion.
|
|
59
|
+
*/
|
|
60
|
+
function buildPrefixTreeNode(
|
|
61
|
+
urlPrefix: string,
|
|
62
|
+
namePrefix: string | undefined,
|
|
63
|
+
patterns: UrlPatterns<any>,
|
|
64
|
+
routeManifest: Record<string, string>,
|
|
65
|
+
routeAncestry: Record<string, string[]>, // internal: feeds trie building, not exported
|
|
66
|
+
mountIndex: number,
|
|
67
|
+
visited: Set<unknown> = new Set(),
|
|
68
|
+
routeTrailingSlash?: Record<string, string>,
|
|
69
|
+
prerenderRoutes?: string[],
|
|
70
|
+
prerenderDefs?: Record<string, any>,
|
|
71
|
+
passthroughRoutes?: string[],
|
|
72
|
+
responseTypeRoutes?: Record<string, string>,
|
|
73
|
+
): PrefixTreeNode {
|
|
74
|
+
if (visited.has(patterns)) {
|
|
75
|
+
console.warn(
|
|
76
|
+
`[@rangojs/router] Circular include detected at prefix "${urlPrefix}". Skipping.`
|
|
77
|
+
);
|
|
78
|
+
return {
|
|
79
|
+
staticPrefix: extractStaticPrefix(urlPrefix),
|
|
80
|
+
fullPrefix: urlPrefix,
|
|
81
|
+
namePrefix: namePrefix || undefined,
|
|
82
|
+
children: {},
|
|
83
|
+
routes: [],
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
visited.add(patterns);
|
|
87
|
+
// Create context for running patterns with include tracking
|
|
88
|
+
const manifest = new Map<string, EntryData>();
|
|
89
|
+
const patternsMap = new Map<string, string>();
|
|
90
|
+
const patternsByPrefix = new Map<string, Map<string, string>>();
|
|
91
|
+
const trailingSlashMap = new Map<string, TrailingSlashMode>();
|
|
92
|
+
const trackedIncludes: TrackedInclude[] = [];
|
|
93
|
+
|
|
94
|
+
RSCRouterContext.run(
|
|
95
|
+
{
|
|
96
|
+
manifest,
|
|
97
|
+
patterns: patternsMap,
|
|
98
|
+
patternsByPrefix,
|
|
99
|
+
trailingSlash: trailingSlashMap,
|
|
100
|
+
namespace: "build",
|
|
101
|
+
parent: null,
|
|
102
|
+
counters: {},
|
|
103
|
+
mountIndex,
|
|
104
|
+
trackedIncludes, // Enable nested include tracking
|
|
105
|
+
},
|
|
106
|
+
() => {
|
|
107
|
+
const helpers = createRouteHelpers();
|
|
108
|
+
// Wrap in root layout for correct parent hierarchy (matches runtime)
|
|
109
|
+
helpers.layout(MapRootLayout, () => {
|
|
110
|
+
if (urlPrefix || namePrefix) {
|
|
111
|
+
return runWithPrefixes(urlPrefix, namePrefix, () => {
|
|
112
|
+
return patterns.handler() as AllUseItems[];
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return patterns.handler() as AllUseItems[];
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
// Collect route names defined in this include (routes have prefixes applied)
|
|
121
|
+
const routes: string[] = [];
|
|
122
|
+
for (const [name, pattern] of patternsMap.entries()) {
|
|
123
|
+
routes.push(name);
|
|
124
|
+
routeManifest[name] = pattern;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Collect trailing slash config
|
|
128
|
+
if (routeTrailingSlash) {
|
|
129
|
+
for (const [name, mode] of trailingSlashMap.entries()) {
|
|
130
|
+
routeTrailingSlash[name] = mode;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Capture ancestry from manifest entries' parent chains
|
|
135
|
+
captureAncestry(manifest, routeAncestry);
|
|
136
|
+
|
|
137
|
+
// Collect prerender route names and handler definitions from manifest entries
|
|
138
|
+
if (prerenderRoutes) {
|
|
139
|
+
for (const [name, entry] of manifest) {
|
|
140
|
+
if (entry.type === "route" && entry.isPrerender) {
|
|
141
|
+
prerenderRoutes.push(name);
|
|
142
|
+
if (prerenderDefs && entry.prerenderDef) {
|
|
143
|
+
prerenderDefs[name] = entry.prerenderDef;
|
|
144
|
+
}
|
|
145
|
+
if (passthroughRoutes && entry.prerenderDef?.options?.passthrough === true) {
|
|
146
|
+
passthroughRoutes.push(name);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Collect response type routes from manifest entries
|
|
153
|
+
if (responseTypeRoutes) {
|
|
154
|
+
for (const [name, entry] of manifest) {
|
|
155
|
+
if (entry.type === "route" && entry.responseType) {
|
|
156
|
+
responseTypeRoutes[name] = entry.responseType;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Build children from tracked nested includes.
|
|
162
|
+
// Multiple includes can share the same fullPrefix (e.g., include("/", patternsA),
|
|
163
|
+
// include("/", patternsB)). Merge their routes instead of overwriting.
|
|
164
|
+
const children: Record<string, PrefixTreeNode> = {};
|
|
165
|
+
|
|
166
|
+
for (const include of trackedIncludes) {
|
|
167
|
+
const childNode = buildPrefixTreeNode(
|
|
168
|
+
include.fullPrefix,
|
|
169
|
+
include.namePrefix,
|
|
170
|
+
include.patterns as UrlPatterns<any>,
|
|
171
|
+
routeManifest,
|
|
172
|
+
routeAncestry,
|
|
173
|
+
mountIndex,
|
|
174
|
+
visited,
|
|
175
|
+
routeTrailingSlash,
|
|
176
|
+
prerenderRoutes,
|
|
177
|
+
prerenderDefs,
|
|
178
|
+
passthroughRoutes,
|
|
179
|
+
responseTypeRoutes,
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
const existing = children[include.fullPrefix];
|
|
183
|
+
if (existing) {
|
|
184
|
+
existing.routes.push(...childNode.routes);
|
|
185
|
+
Object.assign(existing.children, childNode.children);
|
|
186
|
+
} else {
|
|
187
|
+
children[include.fullPrefix] = childNode;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
staticPrefix: extractStaticPrefix(urlPrefix),
|
|
193
|
+
fullPrefix: urlPrefix,
|
|
194
|
+
namePrefix: namePrefix || undefined,
|
|
195
|
+
children,
|
|
196
|
+
routes,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Walk parent chains of route entries to extract ancestry shortCodes.
|
|
202
|
+
*/
|
|
203
|
+
function captureAncestry(
|
|
204
|
+
manifest: Map<string, EntryData>,
|
|
205
|
+
routeAncestry: Record<string, string[]>,
|
|
206
|
+
): void {
|
|
207
|
+
for (const [routeName, entry] of manifest) {
|
|
208
|
+
if (entry.type === "route") {
|
|
209
|
+
const ancestry: string[] = [];
|
|
210
|
+
let current: EntryData | null = entry;
|
|
211
|
+
while (current) {
|
|
212
|
+
ancestry.unshift(current.shortCode);
|
|
213
|
+
current = current.parent;
|
|
214
|
+
}
|
|
215
|
+
routeAncestry[routeName] = ancestry;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Generate manifest from UrlPatterns
|
|
222
|
+
*
|
|
223
|
+
* This runs all patterns (including lazy ones) at build time to extract:
|
|
224
|
+
* - The complete prefix tree for short-circuit optimization
|
|
225
|
+
* - The complete route manifest for href()
|
|
226
|
+
*
|
|
227
|
+
* @example
|
|
228
|
+
* ```typescript
|
|
229
|
+
* import { generateManifest } from "@rangojs/router/build";
|
|
230
|
+
* import { urlpatterns } from "./urls";
|
|
231
|
+
*
|
|
232
|
+
* const manifest = generateManifest(urlpatterns);
|
|
233
|
+
* // Write to file for runtime use
|
|
234
|
+
* fs.writeFileSync(
|
|
235
|
+
* "src/generated/route-manifest.json",
|
|
236
|
+
* JSON.stringify(manifest, null, 2)
|
|
237
|
+
* );
|
|
238
|
+
* ```
|
|
239
|
+
*/
|
|
240
|
+
export function generateManifest<TEnv>(
|
|
241
|
+
urlpatterns: UrlPatterns<TEnv, any>,
|
|
242
|
+
mountIndex: number = 0,
|
|
243
|
+
): GeneratedManifest & { _routeAncestry: Record<string, string[]>; _prerenderDefs?: Record<string, any> } {
|
|
244
|
+
const routeManifest: Record<string, string> = {};
|
|
245
|
+
const routeAncestry: Record<string, string[]> = {};
|
|
246
|
+
const prefixTree: Record<string, PrefixTreeNode> = {};
|
|
247
|
+
|
|
248
|
+
// Run the root patterns handler with tracking enabled
|
|
249
|
+
const manifest = new Map<string, EntryData>();
|
|
250
|
+
const patternsMap = new Map<string, string>();
|
|
251
|
+
const patternsByPrefix = new Map<string, Map<string, string>>();
|
|
252
|
+
const trailingSlashMap = new Map<string, TrailingSlashMode>();
|
|
253
|
+
const trackedIncludes: TrackedInclude[] = [];
|
|
254
|
+
|
|
255
|
+
RSCRouterContext.run(
|
|
256
|
+
{
|
|
257
|
+
manifest,
|
|
258
|
+
patterns: patternsMap,
|
|
259
|
+
patternsByPrefix,
|
|
260
|
+
trailingSlash: trailingSlashMap,
|
|
261
|
+
namespace: "build",
|
|
262
|
+
parent: null,
|
|
263
|
+
counters: {},
|
|
264
|
+
mountIndex,
|
|
265
|
+
trackedIncludes, // Enable include tracking
|
|
266
|
+
},
|
|
267
|
+
() => {
|
|
268
|
+
const helpers = createRouteHelpers();
|
|
269
|
+
// Wrap in root layout for correct parent hierarchy (matches runtime)
|
|
270
|
+
helpers.layout(MapRootLayout, () => {
|
|
271
|
+
return urlpatterns.handler() as AllUseItems[];
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
// Collect root-level routes and trailing slash config
|
|
277
|
+
const routeTrailingSlash: Record<string, string> = {};
|
|
278
|
+
for (const [name, pattern] of patternsMap.entries()) {
|
|
279
|
+
routeManifest[name] = pattern;
|
|
280
|
+
}
|
|
281
|
+
for (const [name, mode] of trailingSlashMap.entries()) {
|
|
282
|
+
routeTrailingSlash[name] = mode;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Capture ancestry from manifest entries' parent chains
|
|
286
|
+
captureAncestry(manifest, routeAncestry);
|
|
287
|
+
|
|
288
|
+
// Collect prerender route names and handler definitions across all levels
|
|
289
|
+
const prerenderRoutes: string[] = [];
|
|
290
|
+
const prerenderDefs: Record<string, any> = {};
|
|
291
|
+
const passthroughRoutes: string[] = [];
|
|
292
|
+
const responseTypeRoutes: Record<string, string> = {};
|
|
293
|
+
for (const [name, entry] of manifest) {
|
|
294
|
+
if (entry.type === "route" && entry.isPrerender) {
|
|
295
|
+
prerenderRoutes.push(name);
|
|
296
|
+
if (entry.prerenderDef) {
|
|
297
|
+
prerenderDefs[name] = entry.prerenderDef;
|
|
298
|
+
}
|
|
299
|
+
if (entry.prerenderDef?.options?.passthrough === true) {
|
|
300
|
+
passthroughRoutes.push(name);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
if (entry.type === "route" && entry.responseType) {
|
|
304
|
+
responseTypeRoutes[name] = entry.responseType;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Build prefix tree from tracked includes (shared visited set for cycle detection).
|
|
309
|
+
// Multiple includes can share the same fullPrefix (e.g., include("/", patternsA),
|
|
310
|
+
// include("/", patternsB)). Merge their routes instead of overwriting.
|
|
311
|
+
const visited = new Set<unknown>();
|
|
312
|
+
for (const include of trackedIncludes) {
|
|
313
|
+
const node = buildPrefixTreeNode(
|
|
314
|
+
include.fullPrefix,
|
|
315
|
+
include.namePrefix,
|
|
316
|
+
include.patterns as UrlPatterns<any>,
|
|
317
|
+
routeManifest,
|
|
318
|
+
routeAncestry,
|
|
319
|
+
mountIndex,
|
|
320
|
+
visited,
|
|
321
|
+
routeTrailingSlash,
|
|
322
|
+
prerenderRoutes,
|
|
323
|
+
prerenderDefs,
|
|
324
|
+
passthroughRoutes,
|
|
325
|
+
responseTypeRoutes,
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
const existing = prefixTree[include.fullPrefix];
|
|
329
|
+
if (existing) {
|
|
330
|
+
existing.routes.push(...node.routes);
|
|
331
|
+
Object.assign(existing.children, node.children);
|
|
332
|
+
} else {
|
|
333
|
+
prefixTree[include.fullPrefix] = node;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return {
|
|
338
|
+
prefixTree,
|
|
339
|
+
routeManifest,
|
|
340
|
+
routeTrailingSlash: Object.keys(routeTrailingSlash).length > 0 ? routeTrailingSlash : undefined,
|
|
341
|
+
prerenderRoutes: prerenderRoutes.length > 0 ? prerenderRoutes : undefined,
|
|
342
|
+
passthroughRoutes: passthroughRoutes.length > 0 ? passthroughRoutes : undefined,
|
|
343
|
+
responseTypeRoutes: Object.keys(responseTypeRoutes).length > 0 ? responseTypeRoutes : undefined,
|
|
344
|
+
generatedAt: new Date().toISOString(),
|
|
345
|
+
// Internal: routeAncestry is used only for trie building, not exported
|
|
346
|
+
_routeAncestry: routeAncestry,
|
|
347
|
+
// Internal: prerender handler definitions for build-time getParams() access
|
|
348
|
+
_prerenderDefs: Object.keys(prerenderDefs).length > 0 ? prerenderDefs : undefined,
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Generate TypeScript code for the manifest
|
|
354
|
+
*
|
|
355
|
+
* @example
|
|
356
|
+
* ```typescript
|
|
357
|
+
* const code = generateManifestCode(urlpatterns);
|
|
358
|
+
* fs.writeFileSync("src/generated/route-manifest.ts", code);
|
|
359
|
+
* ```
|
|
360
|
+
*/
|
|
361
|
+
export function generateManifestCode<TEnv>(
|
|
362
|
+
urlpatterns: UrlPatterns<TEnv, any>
|
|
363
|
+
): string {
|
|
364
|
+
const manifest = generateManifest(urlpatterns);
|
|
365
|
+
|
|
366
|
+
return `/**
|
|
367
|
+
* Auto-generated route manifest
|
|
368
|
+
* Generated at: ${manifest.generatedAt}
|
|
369
|
+
*
|
|
370
|
+
* DO NOT EDIT - This file is generated by @rangojs/router
|
|
371
|
+
*/
|
|
372
|
+
|
|
373
|
+
export const routeManifest = ${JSON.stringify(manifest.routeManifest, null, 2)} as const;
|
|
374
|
+
|
|
375
|
+
export type RouteNames = keyof typeof routeManifest;
|
|
376
|
+
`;
|
|
377
|
+
}
|