@rangojs/router 0.0.0-experimental.0f44aca1
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/AGENTS.md +5 -0
- package/README.md +899 -0
- package/dist/bin/rango.js +1601 -0
- package/dist/vite/index.js +5214 -0
- package/package.json +176 -0
- package/skills/breadcrumbs/SKILL.md +250 -0
- package/skills/cache-guide/SKILL.md +262 -0
- package/skills/caching/SKILL.md +220 -0
- package/skills/composability/SKILL.md +172 -0
- package/skills/debug-manifest/SKILL.md +112 -0
- package/skills/document-cache/SKILL.md +182 -0
- package/skills/fonts/SKILL.md +167 -0
- package/skills/hooks/SKILL.md +704 -0
- package/skills/host-router/SKILL.md +218 -0
- package/skills/intercept/SKILL.md +313 -0
- package/skills/layout/SKILL.md +310 -0
- package/skills/links/SKILL.md +239 -0
- package/skills/loader/SKILL.md +596 -0
- package/skills/middleware/SKILL.md +339 -0
- package/skills/mime-routes/SKILL.md +128 -0
- package/skills/parallel/SKILL.md +305 -0
- package/skills/prerender/SKILL.md +643 -0
- package/skills/rango/SKILL.md +118 -0
- package/skills/response-routes/SKILL.md +411 -0
- package/skills/route/SKILL.md +385 -0
- package/skills/router-setup/SKILL.md +439 -0
- package/skills/tailwind/SKILL.md +129 -0
- package/skills/theme/SKILL.md +79 -0
- package/skills/typesafety/SKILL.md +623 -0
- package/skills/use-cache/SKILL.md +324 -0
- package/src/__internal.ts +273 -0
- package/src/bin/rango.ts +321 -0
- package/src/browser/action-coordinator.ts +97 -0
- package/src/browser/action-response-classifier.ts +99 -0
- package/src/browser/event-controller.ts +899 -0
- package/src/browser/history-state.ts +80 -0
- package/src/browser/index.ts +18 -0
- package/src/browser/intercept-utils.ts +52 -0
- package/src/browser/link-interceptor.ts +141 -0
- package/src/browser/logging.ts +55 -0
- package/src/browser/merge-segment-loaders.ts +134 -0
- package/src/browser/navigation-bridge.ts +645 -0
- package/src/browser/navigation-client.ts +215 -0
- package/src/browser/navigation-store.ts +806 -0
- package/src/browser/navigation-transaction.ts +295 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +550 -0
- package/src/browser/prefetch/cache.ts +146 -0
- package/src/browser/prefetch/fetch.ts +135 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +42 -0
- package/src/browser/prefetch/queue.ts +88 -0
- package/src/browser/rango-state.ts +112 -0
- package/src/browser/react/Link.tsx +360 -0
- package/src/browser/react/NavigationProvider.tsx +386 -0
- package/src/browser/react/ScrollRestoration.tsx +94 -0
- package/src/browser/react/context.ts +59 -0
- package/src/browser/react/filter-segment-order.ts +11 -0
- package/src/browser/react/index.ts +52 -0
- package/src/browser/react/location-state-shared.ts +162 -0
- package/src/browser/react/location-state.ts +107 -0
- package/src/browser/react/mount-context.ts +37 -0
- package/src/browser/react/nonce-context.ts +23 -0
- package/src/browser/react/shallow-equal.ts +27 -0
- package/src/browser/react/use-action.ts +218 -0
- package/src/browser/react/use-client-cache.ts +58 -0
- package/src/browser/react/use-handle.ts +162 -0
- package/src/browser/react/use-href.tsx +40 -0
- package/src/browser/react/use-link-status.ts +135 -0
- package/src/browser/react/use-mount.ts +31 -0
- package/src/browser/react/use-navigation.ts +99 -0
- package/src/browser/react/use-params.ts +65 -0
- package/src/browser/react/use-pathname.ts +47 -0
- package/src/browser/react/use-router.ts +63 -0
- package/src/browser/react/use-search-params.ts +56 -0
- package/src/browser/react/use-segments.ts +171 -0
- package/src/browser/response-adapter.ts +73 -0
- package/src/browser/rsc-router.tsx +431 -0
- package/src/browser/scroll-restoration.ts +400 -0
- package/src/browser/segment-reconciler.ts +216 -0
- package/src/browser/segment-structure-assert.ts +83 -0
- package/src/browser/server-action-bridge.ts +667 -0
- package/src/browser/shallow.ts +40 -0
- package/src/browser/types.ts +538 -0
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/generate-manifest.ts +438 -0
- package/src/build/generate-route-types.ts +36 -0
- package/src/build/index.ts +35 -0
- package/src/build/route-trie.ts +265 -0
- package/src/build/route-types/ast-helpers.ts +25 -0
- package/src/build/route-types/ast-route-extraction.ts +98 -0
- package/src/build/route-types/codegen.ts +102 -0
- package/src/build/route-types/include-resolution.ts +411 -0
- package/src/build/route-types/param-extraction.ts +48 -0
- package/src/build/route-types/per-module-writer.ts +128 -0
- package/src/build/route-types/router-processing.ts +469 -0
- package/src/build/route-types/scan-filter.ts +78 -0
- package/src/build/runtime-discovery.ts +231 -0
- package/src/cache/background-task.ts +34 -0
- package/src/cache/cache-key-utils.ts +44 -0
- package/src/cache/cache-policy.ts +125 -0
- package/src/cache/cache-runtime.ts +338 -0
- package/src/cache/cache-scope.ts +382 -0
- package/src/cache/cf/cf-cache-store.ts +540 -0
- package/src/cache/cf/index.ts +25 -0
- package/src/cache/document-cache.ts +369 -0
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +41 -0
- package/src/cache/index.ts +43 -0
- package/src/cache/memory-segment-store.ts +328 -0
- package/src/cache/profile-registry.ts +73 -0
- package/src/cache/read-through-swr.ts +134 -0
- package/src/cache/segment-codec.ts +256 -0
- package/src/cache/taint.ts +98 -0
- package/src/cache/types.ts +342 -0
- package/src/client.rsc.tsx +85 -0
- package/src/client.tsx +601 -0
- package/src/component-utils.ts +76 -0
- package/src/components/DefaultDocument.tsx +27 -0
- package/src/context-var.ts +86 -0
- package/src/debug.ts +243 -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 +365 -0
- package/src/handle.ts +135 -0
- package/src/handles/MetaTags.tsx +246 -0
- package/src/handles/breadcrumbs.ts +66 -0
- package/src/handles/index.ts +7 -0
- package/src/handles/meta.ts +264 -0
- package/src/host/cookie-handler.ts +165 -0
- package/src/host/errors.ts +97 -0
- package/src/host/index.ts +53 -0
- package/src/host/pattern-matcher.ts +214 -0
- package/src/host/router.ts +352 -0
- package/src/host/testing.ts +79 -0
- package/src/host/types.ts +146 -0
- package/src/host/utils.ts +25 -0
- package/src/href-client.ts +222 -0
- package/src/index.rsc.ts +233 -0
- package/src/index.ts +277 -0
- package/src/internal-debug.ts +11 -0
- package/src/loader.rsc.ts +89 -0
- package/src/loader.ts +64 -0
- package/src/network-error-thrower.tsx +23 -0
- package/src/outlet-context.ts +15 -0
- package/src/outlet-provider.tsx +45 -0
- package/src/prerender/param-hash.ts +37 -0
- package/src/prerender/store.ts +185 -0
- package/src/prerender.ts +463 -0
- package/src/reverse.ts +330 -0
- package/src/root-error-boundary.tsx +289 -0
- package/src/route-content-wrapper.tsx +196 -0
- package/src/route-definition/dsl-helpers.ts +934 -0
- package/src/route-definition/helper-factories.ts +200 -0
- package/src/route-definition/helpers-types.ts +430 -0
- package/src/route-definition/index.ts +52 -0
- package/src/route-definition/redirect.ts +93 -0
- package/src/route-definition.ts +1 -0
- package/src/route-map-builder.ts +275 -0
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +259 -0
- package/src/router/content-negotiation.ts +116 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +287 -0
- package/src/router/find-match.ts +158 -0
- package/src/router/handler-context.ts +451 -0
- package/src/router/intercept-resolution.ts +395 -0
- package/src/router/lazy-includes.ts +234 -0
- package/src/router/loader-resolution.ts +420 -0
- package/src/router/logging.ts +248 -0
- package/src/router/manifest.ts +267 -0
- package/src/router/match-api.ts +620 -0
- package/src/router/match-context.ts +266 -0
- package/src/router/match-handlers.ts +440 -0
- package/src/router/match-middleware/background-revalidation.ts +223 -0
- package/src/router/match-middleware/cache-lookup.ts +634 -0
- package/src/router/match-middleware/cache-store.ts +295 -0
- package/src/router/match-middleware/index.ts +81 -0
- package/src/router/match-middleware/intercept-resolution.ts +306 -0
- package/src/router/match-middleware/segment-resolution.ts +192 -0
- package/src/router/match-pipelines.ts +179 -0
- package/src/router/match-result.ts +219 -0
- package/src/router/metrics.ts +282 -0
- package/src/router/middleware-cookies.ts +55 -0
- package/src/router/middleware-types.ts +222 -0
- package/src/router/middleware.ts +748 -0
- package/src/router/pattern-matching.ts +563 -0
- package/src/router/prerender-match.ts +402 -0
- package/src/router/preview-match.ts +170 -0
- package/src/router/revalidation.ts +289 -0
- package/src/router/router-context.ts +316 -0
- package/src/router/router-interfaces.ts +452 -0
- package/src/router/router-options.ts +592 -0
- package/src/router/router-registry.ts +24 -0
- package/src/router/segment-resolution/fresh.ts +570 -0
- package/src/router/segment-resolution/helpers.ts +263 -0
- package/src/router/segment-resolution/loader-cache.ts +198 -0
- package/src/router/segment-resolution/revalidation.ts +1239 -0
- package/src/router/segment-resolution/static-store.ts +67 -0
- package/src/router/segment-resolution.ts +21 -0
- package/src/router/segment-wrappers.ts +289 -0
- package/src/router/telemetry-otel.ts +299 -0
- package/src/router/telemetry.ts +300 -0
- package/src/router/timeout.ts +148 -0
- package/src/router/trie-matching.ts +239 -0
- package/src/router/types.ts +170 -0
- package/src/router.ts +1002 -0
- package/src/rsc/handler-context.ts +45 -0
- package/src/rsc/handler.ts +1089 -0
- package/src/rsc/helpers.ts +198 -0
- package/src/rsc/index.ts +36 -0
- package/src/rsc/loader-fetch.ts +209 -0
- package/src/rsc/manifest-init.ts +86 -0
- package/src/rsc/nonce.ts +32 -0
- package/src/rsc/origin-guard.ts +141 -0
- package/src/rsc/progressive-enhancement.ts +379 -0
- package/src/rsc/response-error.ts +37 -0
- package/src/rsc/response-route-handler.ts +347 -0
- package/src/rsc/rsc-rendering.ts +235 -0
- package/src/rsc/runtime-warnings.ts +42 -0
- package/src/rsc/server-action.ts +348 -0
- package/src/rsc/ssr-setup.ts +128 -0
- package/src/rsc/types.ts +263 -0
- package/src/search-params.ts +230 -0
- package/src/segment-system.tsx +454 -0
- package/src/server/context.ts +591 -0
- package/src/server/cookie-store.ts +190 -0
- package/src/server/fetchable-loader-store.ts +37 -0
- package/src/server/handle-store.ts +308 -0
- package/src/server/loader-registry.ts +133 -0
- package/src/server/request-context.ts +914 -0
- package/src/server/root-layout.tsx +10 -0
- package/src/server/tsconfig.json +14 -0
- package/src/server.ts +51 -0
- package/src/ssr/index.tsx +365 -0
- package/src/static-handler.ts +114 -0
- package/src/theme/ThemeProvider.tsx +297 -0
- package/src/theme/ThemeScript.tsx +61 -0
- package/src/theme/constants.ts +62 -0
- package/src/theme/index.ts +48 -0
- package/src/theme/theme-context.ts +44 -0
- package/src/theme/theme-script.ts +155 -0
- package/src/theme/types.ts +182 -0
- package/src/theme/use-theme.ts +44 -0
- package/src/types/boundaries.ts +158 -0
- package/src/types/cache-types.ts +198 -0
- package/src/types/error-types.ts +192 -0
- package/src/types/global-namespace.ts +100 -0
- package/src/types/handler-context.ts +687 -0
- package/src/types/index.ts +88 -0
- package/src/types/loader-types.ts +183 -0
- package/src/types/route-config.ts +170 -0
- package/src/types/route-entry.ts +102 -0
- package/src/types/segments.ts +148 -0
- package/src/types.ts +1 -0
- package/src/urls/include-helper.ts +197 -0
- package/src/urls/index.ts +53 -0
- package/src/urls/path-helper-types.ts +339 -0
- package/src/urls/path-helper.ts +329 -0
- package/src/urls/pattern-types.ts +95 -0
- package/src/urls/response-types.ts +106 -0
- package/src/urls/type-extraction.ts +372 -0
- package/src/urls/urls-function.ts +98 -0
- package/src/urls.ts +1 -0
- package/src/use-loader.tsx +354 -0
- package/src/vite/discovery/bundle-postprocess.ts +184 -0
- package/src/vite/discovery/discover-routers.ts +344 -0
- package/src/vite/discovery/prerender-collection.ts +385 -0
- package/src/vite/discovery/route-types-writer.ts +258 -0
- package/src/vite/discovery/self-gen-tracking.ts +47 -0
- package/src/vite/discovery/state.ts +110 -0
- package/src/vite/discovery/virtual-module-codegen.ts +203 -0
- package/src/vite/index.ts +16 -0
- package/src/vite/plugin-types.ts +131 -0
- package/src/vite/plugins/cjs-to-esm.ts +93 -0
- package/src/vite/plugins/client-ref-dedup.ts +115 -0
- package/src/vite/plugins/client-ref-hashing.ts +105 -0
- package/src/vite/plugins/expose-action-id.ts +365 -0
- package/src/vite/plugins/expose-id-utils.ts +287 -0
- package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +179 -0
- package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
- package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
- package/src/vite/plugins/expose-ids/types.ts +45 -0
- package/src/vite/plugins/expose-internal-ids.ts +569 -0
- package/src/vite/plugins/refresh-cmd.ts +65 -0
- package/src/vite/plugins/use-cache-transform.ts +323 -0
- package/src/vite/plugins/version-injector.ts +83 -0
- package/src/vite/plugins/version-plugin.ts +254 -0
- package/src/vite/plugins/version.d.ts +12 -0
- package/src/vite/plugins/virtual-entries.ts +123 -0
- package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
- package/src/vite/rango.ts +510 -0
- package/src/vite/router-discovery.ts +785 -0
- package/src/vite/utils/ast-handler-extract.ts +517 -0
- package/src/vite/utils/banner.ts +36 -0
- package/src/vite/utils/bundle-analysis.ts +137 -0
- package/src/vite/utils/manifest-utils.ts +70 -0
- package/src/vite/utils/package-resolution.ts +121 -0
- package/src/vite/utils/prerender-utils.ts +189 -0
- package/src/vite/utils/shared-utils.ts +169 -0
|
@@ -0,0 +1,438 @@
|
|
|
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 Prerender (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
|
+
/** Route name -> search schema descriptor for typed URL helpers */
|
|
53
|
+
routeSearchSchemas?: Record<string, Record<string, 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
|
+
routeSearchSchemas?: Record<string, Record<string, string>>,
|
|
74
|
+
): PrefixTreeNode {
|
|
75
|
+
if (visited.has(patterns)) {
|
|
76
|
+
console.warn(
|
|
77
|
+
`[@rangojs/router] Circular include detected at prefix "${urlPrefix}". Skipping.`,
|
|
78
|
+
);
|
|
79
|
+
return {
|
|
80
|
+
staticPrefix: extractStaticPrefix(urlPrefix),
|
|
81
|
+
fullPrefix: urlPrefix,
|
|
82
|
+
namePrefix: namePrefix || undefined,
|
|
83
|
+
children: {},
|
|
84
|
+
routes: [],
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
visited.add(patterns);
|
|
88
|
+
// Create context for running patterns with include tracking
|
|
89
|
+
const manifest = new Map<string, EntryData>();
|
|
90
|
+
const patternsMap = new Map<string, string>();
|
|
91
|
+
const patternsByPrefix = new Map<string, Map<string, string>>();
|
|
92
|
+
const trailingSlashMap = new Map<string, TrailingSlashMode>();
|
|
93
|
+
const searchSchemasMap = new Map<string, Record<string, string>>();
|
|
94
|
+
const trackedIncludes: TrackedInclude[] = [];
|
|
95
|
+
|
|
96
|
+
RSCRouterContext.run(
|
|
97
|
+
{
|
|
98
|
+
manifest,
|
|
99
|
+
patterns: patternsMap,
|
|
100
|
+
patternsByPrefix,
|
|
101
|
+
trailingSlash: trailingSlashMap,
|
|
102
|
+
searchSchemas: searchSchemasMap,
|
|
103
|
+
namespace: "build",
|
|
104
|
+
parent: null,
|
|
105
|
+
counters: {},
|
|
106
|
+
mountIndex,
|
|
107
|
+
trackedIncludes, // Enable nested include tracking
|
|
108
|
+
},
|
|
109
|
+
() => {
|
|
110
|
+
const helpers = createRouteHelpers();
|
|
111
|
+
// Wrap in root layout for correct parent hierarchy (matches runtime)
|
|
112
|
+
helpers.layout(MapRootLayout, () => {
|
|
113
|
+
if (urlPrefix || namePrefix) {
|
|
114
|
+
return runWithPrefixes(urlPrefix, namePrefix, () => {
|
|
115
|
+
return patterns.handler() as AllUseItems[];
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return patterns.handler() as AllUseItems[];
|
|
119
|
+
});
|
|
120
|
+
},
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
// Collect route names defined in this include (routes have prefixes applied)
|
|
124
|
+
const routes: string[] = [];
|
|
125
|
+
for (const [name, pattern] of patternsMap.entries()) {
|
|
126
|
+
routes.push(name);
|
|
127
|
+
routeManifest[name] = pattern;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Collect trailing slash config
|
|
131
|
+
if (routeTrailingSlash) {
|
|
132
|
+
for (const [name, mode] of trailingSlashMap.entries()) {
|
|
133
|
+
routeTrailingSlash[name] = mode;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (routeSearchSchemas) {
|
|
137
|
+
for (const [name, schema] of searchSchemasMap.entries()) {
|
|
138
|
+
routeSearchSchemas[name] = schema;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Capture ancestry from manifest entries' parent chains
|
|
143
|
+
captureAncestry(manifest, routeAncestry);
|
|
144
|
+
|
|
145
|
+
// Collect prerender route names and handler definitions from manifest entries
|
|
146
|
+
if (prerenderRoutes) {
|
|
147
|
+
for (const [name, entry] of manifest) {
|
|
148
|
+
if (entry.type === "route" && entry.isPrerender) {
|
|
149
|
+
prerenderRoutes.push(name);
|
|
150
|
+
if (prerenderDefs && entry.prerenderDef) {
|
|
151
|
+
prerenderDefs[name] = entry.prerenderDef;
|
|
152
|
+
}
|
|
153
|
+
if (
|
|
154
|
+
passthroughRoutes &&
|
|
155
|
+
entry.prerenderDef?.options?.passthrough === true
|
|
156
|
+
) {
|
|
157
|
+
passthroughRoutes.push(name);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Collect response type routes from manifest entries
|
|
164
|
+
if (responseTypeRoutes) {
|
|
165
|
+
for (const [name, entry] of manifest) {
|
|
166
|
+
if (entry.type === "route" && entry.responseType) {
|
|
167
|
+
responseTypeRoutes[name] = entry.responseType;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Build children from tracked nested includes.
|
|
173
|
+
// Multiple includes can share the same fullPrefix (e.g., include("/", patternsA),
|
|
174
|
+
// include("/", patternsB)). Merge their routes instead of overwriting.
|
|
175
|
+
const children: Record<string, PrefixTreeNode> = {};
|
|
176
|
+
|
|
177
|
+
for (const include of trackedIncludes) {
|
|
178
|
+
const childNode = buildPrefixTreeNode(
|
|
179
|
+
include.fullPrefix,
|
|
180
|
+
include.namePrefix,
|
|
181
|
+
include.patterns as UrlPatterns<any>,
|
|
182
|
+
routeManifest,
|
|
183
|
+
routeAncestry,
|
|
184
|
+
mountIndex,
|
|
185
|
+
visited,
|
|
186
|
+
routeTrailingSlash,
|
|
187
|
+
prerenderRoutes,
|
|
188
|
+
prerenderDefs,
|
|
189
|
+
passthroughRoutes,
|
|
190
|
+
responseTypeRoutes,
|
|
191
|
+
routeSearchSchemas,
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
const existing = children[include.fullPrefix];
|
|
195
|
+
if (existing) {
|
|
196
|
+
existing.routes.push(...childNode.routes);
|
|
197
|
+
Object.assign(existing.children, childNode.children);
|
|
198
|
+
} else {
|
|
199
|
+
children[include.fullPrefix] = childNode;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Remove from visited so sibling branches can reuse the same patterns
|
|
204
|
+
// without false circular-include detection. Only ancestors in the current
|
|
205
|
+
// recursion path should trigger the cycle guard.
|
|
206
|
+
visited.delete(patterns);
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
staticPrefix: extractStaticPrefix(urlPrefix),
|
|
210
|
+
fullPrefix: urlPrefix,
|
|
211
|
+
namePrefix: namePrefix || undefined,
|
|
212
|
+
children,
|
|
213
|
+
routes,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Walk parent chains of route entries to extract ancestry shortCodes.
|
|
219
|
+
*/
|
|
220
|
+
function captureAncestry(
|
|
221
|
+
manifest: Map<string, EntryData>,
|
|
222
|
+
routeAncestry: Record<string, string[]>,
|
|
223
|
+
): void {
|
|
224
|
+
for (const [routeName, entry] of manifest) {
|
|
225
|
+
if (entry.type === "route") {
|
|
226
|
+
const ancestry: string[] = [];
|
|
227
|
+
let current: EntryData | null = entry;
|
|
228
|
+
while (current) {
|
|
229
|
+
ancestry.unshift(current.shortCode);
|
|
230
|
+
current = current.parent;
|
|
231
|
+
}
|
|
232
|
+
routeAncestry[routeName] = ancestry;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Internal manifest result including build-pipeline-only fields.
|
|
239
|
+
* Not part of the public API — use generateManifest() for the public surface.
|
|
240
|
+
*/
|
|
241
|
+
export interface FullManifest extends GeneratedManifest {
|
|
242
|
+
_routeAncestry: Record<string, string[]>;
|
|
243
|
+
_prerenderDefs?: Record<string, any>;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Generate manifest from UrlPatterns (public API).
|
|
248
|
+
*
|
|
249
|
+
* Returns only the public GeneratedManifest fields. Internal build pipeline
|
|
250
|
+
* consumers that need _routeAncestry or _prerenderDefs should use
|
|
251
|
+
* generateManifestFull() instead.
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* ```typescript
|
|
255
|
+
* import { generateManifest } from "@rangojs/router/build";
|
|
256
|
+
* import { urlpatterns } from "./urls";
|
|
257
|
+
*
|
|
258
|
+
* const manifest = generateManifest(urlpatterns);
|
|
259
|
+
* // Write to file for runtime use
|
|
260
|
+
* fs.writeFileSync(
|
|
261
|
+
* "src/generated/route-manifest.json",
|
|
262
|
+
* JSON.stringify(manifest, null, 2)
|
|
263
|
+
* );
|
|
264
|
+
* ```
|
|
265
|
+
*/
|
|
266
|
+
export function generateManifest<TEnv>(
|
|
267
|
+
urlpatterns: UrlPatterns<TEnv, any>,
|
|
268
|
+
mountIndex: number = 0,
|
|
269
|
+
): GeneratedManifest {
|
|
270
|
+
const {
|
|
271
|
+
_routeAncestry: _,
|
|
272
|
+
_prerenderDefs: __,
|
|
273
|
+
...publicManifest
|
|
274
|
+
} = generateManifestFull(urlpatterns, mountIndex);
|
|
275
|
+
return publicManifest;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Generate manifest with internal build-pipeline fields.
|
|
280
|
+
*
|
|
281
|
+
* Used by the Vite plugin (discover-routers via dynamic import through
|
|
282
|
+
* @rangojs/router/build), manifest-init (direct import), and trie
|
|
283
|
+
* building. Not intended for external use.
|
|
284
|
+
*/
|
|
285
|
+
export function generateManifestFull<TEnv>(
|
|
286
|
+
urlpatterns: UrlPatterns<TEnv, any>,
|
|
287
|
+
mountIndex: number = 0,
|
|
288
|
+
): FullManifest {
|
|
289
|
+
const routeManifest: Record<string, string> = {};
|
|
290
|
+
const routeAncestry: Record<string, string[]> = {};
|
|
291
|
+
const prefixTree: Record<string, PrefixTreeNode> = {};
|
|
292
|
+
|
|
293
|
+
// Run the root patterns handler with tracking enabled
|
|
294
|
+
const manifest = new Map<string, EntryData>();
|
|
295
|
+
const patternsMap = new Map<string, string>();
|
|
296
|
+
const patternsByPrefix = new Map<string, Map<string, string>>();
|
|
297
|
+
const trailingSlashMap = new Map<string, TrailingSlashMode>();
|
|
298
|
+
const searchSchemasMap = new Map<string, Record<string, string>>();
|
|
299
|
+
const trackedIncludes: TrackedInclude[] = [];
|
|
300
|
+
|
|
301
|
+
RSCRouterContext.run(
|
|
302
|
+
{
|
|
303
|
+
manifest,
|
|
304
|
+
patterns: patternsMap,
|
|
305
|
+
patternsByPrefix,
|
|
306
|
+
trailingSlash: trailingSlashMap,
|
|
307
|
+
searchSchemas: searchSchemasMap,
|
|
308
|
+
namespace: "build",
|
|
309
|
+
parent: null,
|
|
310
|
+
counters: {},
|
|
311
|
+
mountIndex,
|
|
312
|
+
trackedIncludes, // Enable include tracking
|
|
313
|
+
},
|
|
314
|
+
() => {
|
|
315
|
+
const helpers = createRouteHelpers();
|
|
316
|
+
// Wrap in root layout for correct parent hierarchy (matches runtime)
|
|
317
|
+
helpers.layout(MapRootLayout, () => {
|
|
318
|
+
return urlpatterns.handler() as AllUseItems[];
|
|
319
|
+
});
|
|
320
|
+
},
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
// Collect root-level routes and trailing slash config
|
|
324
|
+
const routeTrailingSlash: Record<string, string> = {};
|
|
325
|
+
for (const [name, pattern] of patternsMap.entries()) {
|
|
326
|
+
routeManifest[name] = pattern;
|
|
327
|
+
}
|
|
328
|
+
for (const [name, mode] of trailingSlashMap.entries()) {
|
|
329
|
+
routeTrailingSlash[name] = mode;
|
|
330
|
+
}
|
|
331
|
+
const routeSearchSchemas: Record<string, Record<string, string>> = {};
|
|
332
|
+
for (const [name, schema] of searchSchemasMap.entries()) {
|
|
333
|
+
routeSearchSchemas[name] = schema;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Capture ancestry from manifest entries' parent chains
|
|
337
|
+
captureAncestry(manifest, routeAncestry);
|
|
338
|
+
|
|
339
|
+
// Collect prerender route names and handler definitions across all levels
|
|
340
|
+
const prerenderRoutes: string[] = [];
|
|
341
|
+
const prerenderDefs: Record<string, any> = {};
|
|
342
|
+
const passthroughRoutes: string[] = [];
|
|
343
|
+
const responseTypeRoutes: Record<string, string> = {};
|
|
344
|
+
for (const [name, entry] of manifest) {
|
|
345
|
+
if (entry.type === "route" && entry.isPrerender) {
|
|
346
|
+
prerenderRoutes.push(name);
|
|
347
|
+
if (entry.prerenderDef) {
|
|
348
|
+
prerenderDefs[name] = entry.prerenderDef;
|
|
349
|
+
}
|
|
350
|
+
if (entry.prerenderDef?.options?.passthrough === true) {
|
|
351
|
+
passthroughRoutes.push(name);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
if (entry.type === "route" && entry.responseType) {
|
|
355
|
+
responseTypeRoutes[name] = entry.responseType;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Build prefix tree from tracked includes (shared visited set for cycle detection).
|
|
360
|
+
// Multiple includes can share the same fullPrefix (e.g., include("/", patternsA),
|
|
361
|
+
// include("/", patternsB)). Merge their routes instead of overwriting.
|
|
362
|
+
const visited = new Set<unknown>();
|
|
363
|
+
for (const include of trackedIncludes) {
|
|
364
|
+
const node = buildPrefixTreeNode(
|
|
365
|
+
include.fullPrefix,
|
|
366
|
+
include.namePrefix,
|
|
367
|
+
include.patterns as UrlPatterns<any>,
|
|
368
|
+
routeManifest,
|
|
369
|
+
routeAncestry,
|
|
370
|
+
mountIndex,
|
|
371
|
+
visited,
|
|
372
|
+
routeTrailingSlash,
|
|
373
|
+
prerenderRoutes,
|
|
374
|
+
prerenderDefs,
|
|
375
|
+
passthroughRoutes,
|
|
376
|
+
responseTypeRoutes,
|
|
377
|
+
routeSearchSchemas,
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
const existing = prefixTree[include.fullPrefix];
|
|
381
|
+
if (existing) {
|
|
382
|
+
existing.routes.push(...node.routes);
|
|
383
|
+
Object.assign(existing.children, node.children);
|
|
384
|
+
} else {
|
|
385
|
+
prefixTree[include.fullPrefix] = node;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return {
|
|
390
|
+
prefixTree,
|
|
391
|
+
routeManifest,
|
|
392
|
+
routeTrailingSlash:
|
|
393
|
+
Object.keys(routeTrailingSlash).length > 0
|
|
394
|
+
? routeTrailingSlash
|
|
395
|
+
: undefined,
|
|
396
|
+
prerenderRoutes: prerenderRoutes.length > 0 ? prerenderRoutes : undefined,
|
|
397
|
+
passthroughRoutes:
|
|
398
|
+
passthroughRoutes.length > 0 ? passthroughRoutes : undefined,
|
|
399
|
+
responseTypeRoutes:
|
|
400
|
+
Object.keys(responseTypeRoutes).length > 0
|
|
401
|
+
? responseTypeRoutes
|
|
402
|
+
: undefined,
|
|
403
|
+
routeSearchSchemas:
|
|
404
|
+
Object.keys(routeSearchSchemas).length > 0
|
|
405
|
+
? routeSearchSchemas
|
|
406
|
+
: undefined,
|
|
407
|
+
_routeAncestry: routeAncestry,
|
|
408
|
+
// Internal: prerender handler definitions for build-time getParams() access
|
|
409
|
+
_prerenderDefs:
|
|
410
|
+
Object.keys(prerenderDefs).length > 0 ? prerenderDefs : undefined,
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Generate TypeScript code for the manifest
|
|
416
|
+
*
|
|
417
|
+
* @example
|
|
418
|
+
* ```typescript
|
|
419
|
+
* const code = generateManifestCode(urlpatterns);
|
|
420
|
+
* fs.writeFileSync("src/generated/route-manifest.ts", code);
|
|
421
|
+
* ```
|
|
422
|
+
*/
|
|
423
|
+
export function generateManifestCode<TEnv>(
|
|
424
|
+
urlpatterns: UrlPatterns<TEnv, any>,
|
|
425
|
+
): string {
|
|
426
|
+
const manifest = generateManifest(urlpatterns);
|
|
427
|
+
|
|
428
|
+
return `/**
|
|
429
|
+
* Auto-generated route manifest
|
|
430
|
+
*
|
|
431
|
+
* DO NOT EDIT - This file is generated by @rangojs/router
|
|
432
|
+
*/
|
|
433
|
+
|
|
434
|
+
export const routeManifest = ${JSON.stringify(manifest.routeManifest, null, 2)} as const;
|
|
435
|
+
|
|
436
|
+
export type RouteNames = keyof typeof routeManifest;
|
|
437
|
+
`;
|
|
438
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Barrel re-export -- see route-types/ for implementations.
|
|
2
|
+
export {
|
|
3
|
+
extractParamsFromPattern,
|
|
4
|
+
formatRouteEntry,
|
|
5
|
+
} from "./route-types/param-extraction.js";
|
|
6
|
+
export { extractRoutesFromSource } from "./route-types/ast-route-extraction.js";
|
|
7
|
+
export {
|
|
8
|
+
generatePerModuleTypesSource,
|
|
9
|
+
generateRouteTypesSource,
|
|
10
|
+
} from "./route-types/codegen.js";
|
|
11
|
+
export {
|
|
12
|
+
DEFAULT_EXCLUDE_PATTERNS,
|
|
13
|
+
type ScanFilter,
|
|
14
|
+
createScanFilter,
|
|
15
|
+
findTsFiles,
|
|
16
|
+
} from "./route-types/scan-filter.js";
|
|
17
|
+
export {
|
|
18
|
+
writePerModuleRouteTypes,
|
|
19
|
+
writePerModuleRouteTypesForFile,
|
|
20
|
+
} from "./route-types/per-module-writer.js";
|
|
21
|
+
export {
|
|
22
|
+
type UnresolvableReason,
|
|
23
|
+
type UnresolvableInclude,
|
|
24
|
+
extractIncludesWithDiagnostics,
|
|
25
|
+
} from "./route-types/include-resolution.js";
|
|
26
|
+
export {
|
|
27
|
+
extractUrlsVariableFromRouter,
|
|
28
|
+
buildCombinedRouteMapForRouterFile,
|
|
29
|
+
detectUnresolvableIncludes,
|
|
30
|
+
detectUnresolvableIncludesForUrlsFile,
|
|
31
|
+
findNestedRouterConflict,
|
|
32
|
+
formatNestedRouterConflictError,
|
|
33
|
+
findRouterFiles,
|
|
34
|
+
writeCombinedRouteTypes,
|
|
35
|
+
} from "./route-types/router-processing.js";
|
|
36
|
+
export { findUrlsVariableNames } from "./route-types/per-module-writer.js";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build-time utilities for @rangojs/router
|
|
3
|
+
*
|
|
4
|
+
* Note: Route manifest is automatically generated at runtime on first request.
|
|
5
|
+
* These build-time utilities are only needed for advanced use cases like
|
|
6
|
+
* custom tooling or pre-generating manifests.
|
|
7
|
+
*
|
|
8
|
+
* @example Generate manifest programmatically (for custom tooling)
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { generateManifest } from "@rangojs/router/build";
|
|
11
|
+
* import { urlpatterns } from "./urls";
|
|
12
|
+
*
|
|
13
|
+
* const manifest = generateManifest(urlpatterns);
|
|
14
|
+
* console.log(manifest.routeManifest); // { home: "/", about: "/about", ... }
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
generateManifest,
|
|
20
|
+
generateManifestFull,
|
|
21
|
+
generateManifestCode,
|
|
22
|
+
type GeneratedManifest,
|
|
23
|
+
} from "./generate-manifest.js";
|
|
24
|
+
|
|
25
|
+
export { buildRouteTrie, type TrieNode, type TrieLeaf } from "./route-trie.js";
|
|
26
|
+
|
|
27
|
+
export {
|
|
28
|
+
writePerModuleRouteTypes,
|
|
29
|
+
extractRoutesFromSource,
|
|
30
|
+
generatePerModuleTypesSource,
|
|
31
|
+
createScanFilter,
|
|
32
|
+
type ScanFilter,
|
|
33
|
+
} from "./generate-route-types.js";
|
|
34
|
+
|
|
35
|
+
export { hashParams } from "../prerender/param-hash.js";
|