@rangojs/router 0.0.0-experimental.13 → 0.0.0-experimental.13221847
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 +9 -0
- package/README.md +884 -4
- package/dist/bin/rango.js +1531 -212
- package/dist/vite/index.js +3995 -2489
- package/package.json +57 -52
- package/skills/breadcrumbs/SKILL.md +250 -0
- package/skills/cache-guide/SKILL.md +262 -0
- package/skills/caching/SKILL.md +85 -23
- package/skills/composability/SKILL.md +172 -0
- package/skills/debug-manifest/SKILL.md +12 -8
- package/skills/document-cache/SKILL.md +18 -16
- package/skills/fonts/SKILL.md +6 -4
- package/skills/hooks/SKILL.md +328 -70
- package/skills/host-router/SKILL.md +218 -0
- package/skills/intercept/SKILL.md +131 -8
- package/skills/layout/SKILL.md +100 -3
- package/skills/links/SKILL.md +62 -15
- package/skills/loader/SKILL.md +368 -42
- package/skills/middleware/SKILL.md +171 -34
- package/skills/mime-routes/SKILL.md +14 -10
- package/skills/parallel/SKILL.md +137 -1
- package/skills/prerender/SKILL.md +366 -28
- package/skills/rango/SKILL.md +85 -21
- package/skills/response-routes/SKILL.md +136 -83
- package/skills/route/SKILL.md +195 -21
- package/skills/router-setup/SKILL.md +123 -30
- package/skills/theme/SKILL.md +9 -8
- package/skills/typesafety/SKILL.md +240 -102
- package/skills/use-cache/SKILL.md +324 -0
- package/src/__internal.ts +102 -4
- package/src/bin/rango.ts +312 -15
- package/src/browser/action-coordinator.ts +97 -0
- package/src/browser/action-response-classifier.ts +99 -0
- package/src/browser/event-controller.ts +92 -64
- package/src/browser/history-state.ts +80 -0
- package/src/browser/intercept-utils.ts +52 -0
- package/src/browser/link-interceptor.ts +24 -4
- package/src/browser/logging.ts +11 -0
- package/src/browser/merge-segment-loaders.ts +20 -12
- package/src/browser/navigation-bridge.ts +266 -558
- package/src/browser/navigation-client.ts +132 -75
- package/src/browser/navigation-store.ts +33 -50
- package/src/browser/navigation-transaction.ts +297 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +303 -309
- package/src/browser/prefetch/cache.ts +206 -0
- package/src/browser/prefetch/fetch.ts +144 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +48 -0
- package/src/browser/prefetch/queue.ts +128 -0
- package/src/browser/rango-state.ts +112 -0
- package/src/browser/react/Link.tsx +190 -70
- package/src/browser/react/NavigationProvider.tsx +78 -11
- package/src/browser/react/context.ts +6 -0
- package/src/browser/react/filter-segment-order.ts +11 -0
- package/src/browser/react/index.ts +12 -12
- package/src/browser/react/location-state-shared.ts +95 -53
- package/src/browser/react/location-state.ts +60 -15
- package/src/browser/react/mount-context.ts +6 -1
- 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 +29 -51
- package/src/browser/react/use-client-cache.ts +5 -3
- package/src/browser/react/use-handle.ts +29 -70
- package/src/browser/react/use-link-status.ts +6 -5
- package/src/browser/react/use-navigation.ts +22 -63
- 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 +80 -97
- package/src/browser/response-adapter.ts +73 -0
- package/src/browser/rsc-router.tsx +188 -57
- package/src/browser/scroll-restoration.ts +117 -44
- package/src/browser/segment-reconciler.ts +221 -0
- package/src/browser/segment-structure-assert.ts +16 -0
- package/src/browser/server-action-bridge.ts +488 -606
- package/src/browser/shallow.ts +6 -1
- package/src/browser/types.ts +116 -47
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/generate-manifest.ts +63 -21
- package/src/build/generate-route-types.ts +36 -1038
- package/src/build/index.ts +2 -5
- package/src/build/route-trie.ts +38 -12
- 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 +479 -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 +342 -0
- package/src/cache/cache-scope.ts +122 -303
- package/src/cache/cf/cf-cache-store.ts +571 -17
- package/src/cache/cf/index.ts +13 -3
- package/src/cache/document-cache.ts +116 -77
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +41 -0
- package/src/cache/index.ts +1 -15
- package/src/cache/memory-segment-store.ts +191 -13
- 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 +72 -122
- package/src/client.rsc.tsx +3 -1
- package/src/client.tsx +84 -126
- package/src/component-utils.ts +4 -4
- package/src/components/DefaultDocument.tsx +5 -1
- package/src/context-var.ts +86 -0
- package/src/debug.ts +19 -9
- package/src/errors.ts +77 -7
- package/src/handle.ts +12 -7
- package/src/handles/MetaTags.tsx +73 -20
- package/src/handles/breadcrumbs.ts +66 -0
- package/src/handles/index.ts +1 -0
- package/src/handles/meta.ts +30 -13
- package/src/host/cookie-handler.ts +21 -15
- package/src/host/errors.ts +8 -8
- package/src/host/index.ts +4 -7
- package/src/host/pattern-matcher.ts +27 -27
- package/src/host/router.ts +61 -39
- package/src/host/testing.ts +8 -8
- package/src/host/types.ts +15 -7
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +65 -45
- package/src/index.rsc.ts +104 -40
- package/src/index.ts +122 -67
- package/src/internal-debug.ts +9 -3
- package/src/loader.rsc.ts +18 -93
- package/src/loader.ts +26 -9
- package/src/network-error-thrower.tsx +3 -1
- package/src/outlet-provider.tsx +45 -0
- package/src/prerender/param-hash.ts +4 -2
- package/src/prerender/store.ts +121 -17
- package/src/prerender.ts +325 -20
- package/src/reverse.ts +144 -124
- package/src/root-error-boundary.tsx +41 -29
- package/src/route-content-wrapper.tsx +7 -4
- package/src/route-definition/dsl-helpers.ts +959 -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 -1450
- package/src/route-map-builder.ts +87 -133
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +41 -6
- package/src/router/content-negotiation.ts +116 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +9 -9
- package/src/router/find-match.ts +160 -0
- package/src/router/handler-context.ts +324 -116
- package/src/router/intercept-resolution.ts +11 -4
- package/src/router/lazy-includes.ts +237 -0
- package/src/router/loader-resolution.ts +179 -133
- package/src/router/logging.ts +112 -6
- package/src/router/manifest.ts +58 -19
- package/src/router/match-api.ts +89 -88
- package/src/router/match-context.ts +4 -2
- package/src/router/match-handlers.ts +440 -0
- package/src/router/match-middleware/background-revalidation.ts +86 -89
- package/src/router/match-middleware/cache-lookup.ts +295 -49
- package/src/router/match-middleware/cache-store.ts +56 -13
- package/src/router/match-middleware/intercept-resolution.ts +45 -22
- package/src/router/match-middleware/segment-resolution.ts +20 -9
- package/src/router/match-pipelines.ts +10 -45
- package/src/router/match-result.ts +44 -21
- package/src/router/metrics.ts +240 -15
- package/src/router/middleware-cookies.ts +55 -0
- package/src/router/middleware-types.ts +222 -0
- package/src/router/middleware.ts +327 -369
- package/src/router/pattern-matching.ts +169 -31
- package/src/router/prerender-match.ts +402 -0
- package/src/router/preview-match.ts +170 -0
- package/src/router/revalidation.ts +105 -14
- package/src/router/router-context.ts +40 -21
- 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 +677 -0
- package/src/router/segment-resolution/helpers.ts +263 -0
- package/src/router/segment-resolution/loader-cache.ts +199 -0
- package/src/router/segment-resolution/revalidation.ts +1296 -0
- package/src/router/segment-resolution/static-store.ts +67 -0
- package/src/router/segment-resolution.ts +21 -1354
- package/src/router/segment-wrappers.ts +291 -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 +96 -29
- package/src/router/types.ts +15 -9
- package/src/router.ts +642 -2366
- package/src/rsc/handler-context.ts +45 -0
- package/src/rsc/handler.ts +639 -1027
- package/src/rsc/helpers.ts +140 -6
- package/src/rsc/index.ts +0 -20
- package/src/rsc/loader-fetch.ts +209 -0
- package/src/rsc/manifest-init.ts +86 -0
- package/src/rsc/nonce.ts +14 -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 +237 -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 +38 -11
- package/src/search-params.ts +66 -54
- package/src/segment-system.tsx +165 -17
- package/src/server/context.ts +237 -54
- package/src/server/cookie-store.ts +190 -0
- package/src/server/fetchable-loader-store.ts +11 -6
- package/src/server/handle-store.ts +94 -15
- package/src/server/loader-registry.ts +15 -56
- package/src/server/request-context.ts +438 -71
- package/src/server.ts +26 -164
- package/src/ssr/index.tsx +101 -31
- package/src/static-handler.ts +22 -4
- package/src/theme/ThemeProvider.tsx +21 -15
- package/src/theme/ThemeScript.tsx +5 -5
- package/src/theme/constants.ts +5 -2
- package/src/theme/index.ts +4 -14
- package/src/theme/theme-context.ts +4 -30
- package/src/theme/theme-script.ts +21 -18
- 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 +773 -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 +109 -0
- package/src/types/segments.ts +150 -0
- package/src/types.ts +1 -1795
- 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 -1323
- package/src/use-loader.tsx +85 -77
- 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 +108 -0
- package/src/vite/discovery/virtual-module-codegen.ts +203 -0
- package/src/vite/index.ts +11 -2259
- package/src/vite/plugin-types.ts +48 -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/{expose-action-id.ts → plugins/expose-action-id.ts} +72 -47
- package/src/vite/{expose-id-utils.ts → plugins/expose-id-utils.ts} +8 -43
- 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 +266 -0
- package/src/vite/{virtual-entries.ts → plugins/virtual-entries.ts} +23 -14
- package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
- package/src/vite/rango.ts +445 -0
- package/src/vite/router-discovery.ts +777 -0
- package/src/vite/{ast-handler-extract.ts → utils/ast-handler-extract.ts} +181 -9
- 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/{package-resolution.ts → utils/package-resolution.ts} +25 -29
- package/src/vite/utils/prerender-utils.ts +189 -0
- package/src/vite/utils/shared-utils.ts +169 -0
- package/CLAUDE.md +0 -43
- package/dist/vite/index.named-routes.gen.ts +0 -103
- package/src/browser/lru-cache.ts +0 -69
- package/src/browser/request-controller.ts +0 -164
- package/src/cache/memory-store.ts +0 -253
- package/src/href-context.ts +0 -33
- package/src/router.gen.ts +0 -6
- package/src/static-handler.gen.ts +0 -5
- package/src/urls.gen.ts +0 -8
- package/src/vite/expose-internal-ids.ts +0 -1167
- /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
|
@@ -16,6 +16,7 @@ export interface ParsedSegment {
|
|
|
16
16
|
value: string; // static text, param name, or "*"
|
|
17
17
|
optional: boolean;
|
|
18
18
|
constraint?: string[]; // enum values like ["en", "gb"]
|
|
19
|
+
suffix?: string; // literal text after param in same segment (e.g., ".html")
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
/**
|
|
@@ -38,11 +39,22 @@ export function parsePattern(pattern: string): ParsedSegment[] {
|
|
|
38
39
|
// - :param(a|b)
|
|
39
40
|
// - :param(a|b)?
|
|
40
41
|
// - *
|
|
41
|
-
const segmentRegex =
|
|
42
|
+
const segmentRegex =
|
|
43
|
+
/\/(:([a-zA-Z_][a-zA-Z0-9_]*)(\(([^)]+)\))?(\?)?([^/]*)|(\*)|([^/]+))/g;
|
|
42
44
|
|
|
43
45
|
let match;
|
|
44
46
|
while ((match = segmentRegex.exec(pattern)) !== null) {
|
|
45
|
-
const [
|
|
47
|
+
const [
|
|
48
|
+
,
|
|
49
|
+
,
|
|
50
|
+
paramName,
|
|
51
|
+
,
|
|
52
|
+
constraint,
|
|
53
|
+
optional,
|
|
54
|
+
suffix,
|
|
55
|
+
wildcard,
|
|
56
|
+
staticText,
|
|
57
|
+
] = match;
|
|
46
58
|
|
|
47
59
|
if (wildcard) {
|
|
48
60
|
segments.push({ type: "wildcard", value: "*", optional: false });
|
|
@@ -52,6 +64,7 @@ export function parsePattern(pattern: string): ParsedSegment[] {
|
|
|
52
64
|
value: paramName,
|
|
53
65
|
optional: optional === "?",
|
|
54
66
|
constraint: constraint ? constraint.split("|") : undefined,
|
|
67
|
+
suffix: suffix || undefined,
|
|
55
68
|
});
|
|
56
69
|
} else if (staticText) {
|
|
57
70
|
segments.push({ type: "static", value: staticText, optional: false });
|
|
@@ -61,6 +74,48 @@ export function parsePattern(pattern: string): ParsedSegment[] {
|
|
|
61
74
|
return segments;
|
|
62
75
|
}
|
|
63
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Compiled pattern result containing regex, param metadata, and trailing slash info.
|
|
79
|
+
*/
|
|
80
|
+
export interface CompiledPattern {
|
|
81
|
+
regex: RegExp;
|
|
82
|
+
paramNames: string[];
|
|
83
|
+
optionalParams: Set<string>;
|
|
84
|
+
hasTrailingSlash: boolean;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Module-level cache for compiled patterns. Route patterns are a finite set
|
|
88
|
+
// defined at build time, so this map is bounded by the number of routes.
|
|
89
|
+
const compiledPatternCache = new Map<string, CompiledPattern>();
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Get a compiled pattern from cache or compile and cache it.
|
|
93
|
+
* Avoids O(routes) regex compilations per request in the fallback path.
|
|
94
|
+
*/
|
|
95
|
+
export function getCompiledPattern(pattern: string): CompiledPattern {
|
|
96
|
+
let compiled = compiledPatternCache.get(pattern);
|
|
97
|
+
if (compiled) return compiled;
|
|
98
|
+
compiled = compilePattern(pattern);
|
|
99
|
+
compiledPatternCache.set(pattern, compiled);
|
|
100
|
+
return compiled;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Return the current size of the compiled pattern cache.
|
|
105
|
+
* Exposed for testing.
|
|
106
|
+
*/
|
|
107
|
+
export function getPatternCacheSize(): number {
|
|
108
|
+
return compiledPatternCache.size;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Clear the compiled pattern cache.
|
|
113
|
+
* Exposed for testing.
|
|
114
|
+
*/
|
|
115
|
+
export function clearPatternCache(): void {
|
|
116
|
+
compiledPatternCache.clear();
|
|
117
|
+
}
|
|
118
|
+
|
|
64
119
|
/**
|
|
65
120
|
* Compile a route pattern to regex
|
|
66
121
|
*
|
|
@@ -78,12 +133,7 @@ export function parsePattern(pattern: string): ParsedSegment[] {
|
|
|
78
133
|
* compilePattern("/:locale(en|gb)/blog") // matches /en/blog or /gb/blog
|
|
79
134
|
* compilePattern("/:locale(en|gb)?/blog") // matches /blog, /en/blog, or /gb/blog
|
|
80
135
|
*/
|
|
81
|
-
export function compilePattern(pattern: string): {
|
|
82
|
-
regex: RegExp;
|
|
83
|
-
paramNames: string[];
|
|
84
|
-
optionalParams: Set<string>;
|
|
85
|
-
hasTrailingSlash: boolean;
|
|
86
|
-
} {
|
|
136
|
+
export function compilePattern(pattern: string): CompiledPattern {
|
|
87
137
|
// Detect if pattern has trailing slash (but not just "/")
|
|
88
138
|
const hasTrailingSlash = pattern.length > 1 && pattern.endsWith("/");
|
|
89
139
|
// Remove trailing slash for parsing (we'll add it back to regex if needed)
|
|
@@ -101,16 +151,19 @@ export function compilePattern(pattern: string): {
|
|
|
101
151
|
regexPattern += "/(.*)";
|
|
102
152
|
} else if (segment.type === "param") {
|
|
103
153
|
paramNames.push(segment.value);
|
|
154
|
+
const suffixPattern = segment.suffix ? escapeRegex(segment.suffix) : "";
|
|
104
155
|
const valuePattern = segment.constraint
|
|
105
|
-
? `(${segment.constraint.join("|")})`
|
|
106
|
-
:
|
|
156
|
+
? `(${segment.constraint.map(escapeRegex).join("|")})`
|
|
157
|
+
: segment.suffix
|
|
158
|
+
? "([^/]+?)"
|
|
159
|
+
: "([^/]+)";
|
|
107
160
|
|
|
108
161
|
if (segment.optional) {
|
|
109
162
|
optionalParams.add(segment.value);
|
|
110
163
|
// Optional: make the whole /segment optional
|
|
111
|
-
regexPattern += `(?:/${valuePattern})?`;
|
|
164
|
+
regexPattern += `(?:/${valuePattern}${suffixPattern})?`;
|
|
112
165
|
} else {
|
|
113
|
-
regexPattern += `/${valuePattern}`;
|
|
166
|
+
regexPattern += `/${valuePattern}${suffixPattern}`;
|
|
114
167
|
}
|
|
115
168
|
} else {
|
|
116
169
|
// Static segment
|
|
@@ -240,7 +293,7 @@ export interface LazyEvaluationNeeded<TEnv = any> {
|
|
|
240
293
|
* Type guard to check if result is a lazy evaluation needed response
|
|
241
294
|
*/
|
|
242
295
|
export function isLazyEvaluationNeeded<TEnv>(
|
|
243
|
-
result: RouteMatchResult<TEnv> | LazyEvaluationNeeded<TEnv> | null
|
|
296
|
+
result: RouteMatchResult<TEnv> | LazyEvaluationNeeded<TEnv> | null,
|
|
244
297
|
): result is LazyEvaluationNeeded<TEnv> {
|
|
245
298
|
return result !== null && "lazyEntry" in result;
|
|
246
299
|
}
|
|
@@ -261,12 +314,16 @@ export function enableMatchDebug(enabled: boolean): void {
|
|
|
261
314
|
}
|
|
262
315
|
|
|
263
316
|
export function getMatchDebugStats(): MatchDebugStats {
|
|
264
|
-
return {
|
|
317
|
+
return {
|
|
318
|
+
entriesChecked: debugStats.entriesChecked,
|
|
319
|
+
entriesSkipped: debugStats.entriesSkipped,
|
|
320
|
+
routesChecked: debugStats.routesChecked,
|
|
321
|
+
};
|
|
265
322
|
}
|
|
266
323
|
|
|
267
324
|
export function findMatch<TEnv>(
|
|
268
325
|
pathname: string,
|
|
269
|
-
routesEntries: RouteEntry<TEnv>[]
|
|
326
|
+
routesEntries: RouteEntry<TEnv>[],
|
|
270
327
|
): RouteMatchResult<TEnv> | LazyEvaluationNeeded<TEnv> | null {
|
|
271
328
|
const effectiveDebug = debugEnabled || isRouterDebugEnabled();
|
|
272
329
|
|
|
@@ -282,7 +339,8 @@ export function findMatch<TEnv>(
|
|
|
282
339
|
}
|
|
283
340
|
}
|
|
284
341
|
|
|
285
|
-
const pathnameHasTrailingSlash =
|
|
342
|
+
const pathnameHasTrailingSlash =
|
|
343
|
+
pathname.length > 1 && pathname.endsWith("/");
|
|
286
344
|
// Try alternate pathname for redirect matching
|
|
287
345
|
const alternatePathname = pathnameHasTrailingSlash
|
|
288
346
|
? pathname.slice(0, -1)
|
|
@@ -334,14 +392,20 @@ export function findMatch<TEnv>(
|
|
|
334
392
|
fullPattern = entry.prefix + pattern;
|
|
335
393
|
}
|
|
336
394
|
|
|
337
|
-
const { regex, paramNames, optionalParams, hasTrailingSlash } =
|
|
395
|
+
const { regex, paramNames, optionalParams, hasTrailingSlash } =
|
|
396
|
+
getCompiledPattern(fullPattern);
|
|
338
397
|
|
|
339
398
|
// Get trailing slash mode for this route (per-route config or pattern-based)
|
|
340
|
-
const trailingSlashMode: TrailingSlashMode | undefined =
|
|
341
|
-
|
|
399
|
+
const trailingSlashMode: TrailingSlashMode | undefined =
|
|
400
|
+
entry.trailingSlash?.[routeKey];
|
|
342
401
|
|
|
343
402
|
// Prerender flag from entry metadata (set by urls() for prerender handlers)
|
|
344
|
-
const prFlag = entry.prerenderRouteKeys?.has(routeKey)
|
|
403
|
+
const prFlag = entry.prerenderRouteKeys?.has(routeKey)
|
|
404
|
+
? { pr: true as const }
|
|
405
|
+
: {};
|
|
406
|
+
const ptFlag = entry.passthroughRouteKeys?.has(routeKey)
|
|
407
|
+
? { pt: true as const }
|
|
408
|
+
: {};
|
|
345
409
|
|
|
346
410
|
// Try exact match first
|
|
347
411
|
const match = regex.exec(pathname);
|
|
@@ -360,15 +424,42 @@ export function findMatch<TEnv>(
|
|
|
360
424
|
}
|
|
361
425
|
|
|
362
426
|
// Check if trailing slash mode requires redirect even on exact match
|
|
363
|
-
if (
|
|
427
|
+
if (
|
|
428
|
+
trailingSlashMode === "always" &&
|
|
429
|
+
!pathnameHasTrailingSlash &&
|
|
430
|
+
pathname !== "/"
|
|
431
|
+
) {
|
|
364
432
|
// Mode says always have trailing slash, but pathname doesn't have it
|
|
365
|
-
return {
|
|
433
|
+
return {
|
|
434
|
+
entry,
|
|
435
|
+
routeKey,
|
|
436
|
+
params,
|
|
437
|
+
optionalParams,
|
|
438
|
+
redirectTo: pathname + "/",
|
|
439
|
+
...prFlag,
|
|
440
|
+
...ptFlag,
|
|
441
|
+
};
|
|
366
442
|
} else if (trailingSlashMode === "never" && pathnameHasTrailingSlash) {
|
|
367
443
|
// Mode says never have trailing slash, but pathname has it
|
|
368
|
-
return {
|
|
444
|
+
return {
|
|
445
|
+
entry,
|
|
446
|
+
routeKey,
|
|
447
|
+
params,
|
|
448
|
+
optionalParams,
|
|
449
|
+
redirectTo: pathname.slice(0, -1),
|
|
450
|
+
...prFlag,
|
|
451
|
+
...ptFlag,
|
|
452
|
+
};
|
|
369
453
|
}
|
|
370
454
|
|
|
371
|
-
return {
|
|
455
|
+
return {
|
|
456
|
+
entry,
|
|
457
|
+
routeKey,
|
|
458
|
+
params,
|
|
459
|
+
optionalParams,
|
|
460
|
+
...prFlag,
|
|
461
|
+
...ptFlag,
|
|
462
|
+
};
|
|
372
463
|
}
|
|
373
464
|
|
|
374
465
|
// Try alternate pathname (opposite trailing slash)
|
|
@@ -382,24 +473,71 @@ export function findMatch<TEnv>(
|
|
|
382
473
|
// Determine redirect behavior based on mode
|
|
383
474
|
if (trailingSlashMode === "ignore") {
|
|
384
475
|
// Match without redirect
|
|
385
|
-
return {
|
|
476
|
+
return {
|
|
477
|
+
entry,
|
|
478
|
+
routeKey,
|
|
479
|
+
params,
|
|
480
|
+
optionalParams,
|
|
481
|
+
...prFlag,
|
|
482
|
+
...ptFlag,
|
|
483
|
+
};
|
|
386
484
|
} else if (trailingSlashMode === "never") {
|
|
387
485
|
// Redirect to no trailing slash
|
|
388
486
|
if (pathnameHasTrailingSlash) {
|
|
389
|
-
return {
|
|
487
|
+
return {
|
|
488
|
+
entry,
|
|
489
|
+
routeKey,
|
|
490
|
+
params,
|
|
491
|
+
optionalParams,
|
|
492
|
+
redirectTo: alternatePathname,
|
|
493
|
+
...prFlag,
|
|
494
|
+
...ptFlag,
|
|
495
|
+
};
|
|
390
496
|
}
|
|
391
|
-
return {
|
|
497
|
+
return {
|
|
498
|
+
entry,
|
|
499
|
+
routeKey,
|
|
500
|
+
params,
|
|
501
|
+
optionalParams,
|
|
502
|
+
...prFlag,
|
|
503
|
+
...ptFlag,
|
|
504
|
+
};
|
|
392
505
|
} else if (trailingSlashMode === "always") {
|
|
393
506
|
// Redirect to with trailing slash
|
|
394
507
|
if (!pathnameHasTrailingSlash) {
|
|
395
|
-
return {
|
|
508
|
+
return {
|
|
509
|
+
entry,
|
|
510
|
+
routeKey,
|
|
511
|
+
params,
|
|
512
|
+
optionalParams,
|
|
513
|
+
redirectTo: alternatePathname,
|
|
514
|
+
...prFlag,
|
|
515
|
+
...ptFlag,
|
|
516
|
+
};
|
|
396
517
|
}
|
|
397
|
-
return {
|
|
518
|
+
return {
|
|
519
|
+
entry,
|
|
520
|
+
routeKey,
|
|
521
|
+
params,
|
|
522
|
+
optionalParams,
|
|
523
|
+
...prFlag,
|
|
524
|
+
...ptFlag,
|
|
525
|
+
};
|
|
398
526
|
} else {
|
|
399
527
|
// No explicit mode - use pattern-based detection
|
|
400
528
|
// Redirect to canonical form (what the pattern defines)
|
|
401
|
-
const canonicalPath = hasTrailingSlash
|
|
402
|
-
|
|
529
|
+
const canonicalPath = hasTrailingSlash
|
|
530
|
+
? alternatePathname
|
|
531
|
+
: pathname.slice(0, -1);
|
|
532
|
+
return {
|
|
533
|
+
entry,
|
|
534
|
+
routeKey,
|
|
535
|
+
params,
|
|
536
|
+
optionalParams,
|
|
537
|
+
redirectTo: canonicalPath,
|
|
538
|
+
...prFlag,
|
|
539
|
+
...ptFlag,
|
|
540
|
+
};
|
|
403
541
|
}
|
|
404
542
|
}
|
|
405
543
|
}
|