@tanstack/router-core 1.120.5 → 1.121.0-alpha.3

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.
Files changed (51) hide show
  1. package/dist/cjs/fileRoute.d.cts +6 -2
  2. package/dist/cjs/index.cjs +3 -0
  3. package/dist/cjs/index.cjs.map +1 -1
  4. package/dist/cjs/index.d.cts +6 -6
  5. package/dist/cjs/link.cjs.map +1 -1
  6. package/dist/cjs/link.d.cts +18 -1
  7. package/dist/cjs/path.cjs +130 -16
  8. package/dist/cjs/path.cjs.map +1 -1
  9. package/dist/cjs/path.d.cts +17 -0
  10. package/dist/cjs/redirect.cjs +17 -14
  11. package/dist/cjs/redirect.cjs.map +1 -1
  12. package/dist/cjs/redirect.d.cts +13 -7
  13. package/dist/cjs/route.cjs +12 -1
  14. package/dist/cjs/route.cjs.map +1 -1
  15. package/dist/cjs/route.d.cts +19 -18
  16. package/dist/cjs/router.cjs +268 -195
  17. package/dist/cjs/router.cjs.map +1 -1
  18. package/dist/cjs/router.d.cts +46 -3
  19. package/dist/cjs/typePrimitives.d.cts +2 -2
  20. package/dist/cjs/utils.cjs.map +1 -1
  21. package/dist/cjs/utils.d.cts +3 -0
  22. package/dist/esm/fileRoute.d.ts +6 -2
  23. package/dist/esm/index.d.ts +6 -6
  24. package/dist/esm/index.js +5 -2
  25. package/dist/esm/link.d.ts +18 -1
  26. package/dist/esm/link.js.map +1 -1
  27. package/dist/esm/path.d.ts +17 -0
  28. package/dist/esm/path.js +130 -16
  29. package/dist/esm/path.js.map +1 -1
  30. package/dist/esm/redirect.d.ts +13 -7
  31. package/dist/esm/redirect.js +17 -14
  32. package/dist/esm/redirect.js.map +1 -1
  33. package/dist/esm/route.d.ts +19 -18
  34. package/dist/esm/route.js +12 -1
  35. package/dist/esm/route.js.map +1 -1
  36. package/dist/esm/router.d.ts +46 -3
  37. package/dist/esm/router.js +271 -198
  38. package/dist/esm/router.js.map +1 -1
  39. package/dist/esm/typePrimitives.d.ts +2 -2
  40. package/dist/esm/utils.d.ts +3 -0
  41. package/dist/esm/utils.js.map +1 -1
  42. package/package.json +2 -2
  43. package/src/fileRoute.ts +90 -1
  44. package/src/index.ts +14 -6
  45. package/src/link.ts +97 -11
  46. package/src/path.ts +181 -16
  47. package/src/redirect.ts +37 -22
  48. package/src/route.ts +109 -39
  49. package/src/router.ts +373 -250
  50. package/src/typePrimitives.ts +2 -2
  51. package/src/utils.ts +15 -0
@@ -2,12 +2,12 @@ import { Store, batch } from "@tanstack/store";
2
2
  import { createMemoryHistory, createBrowserHistory, parseHref } from "@tanstack/history";
3
3
  import invariant from "tiny-invariant";
4
4
  import { pick, createControlledPromise, deepEqual, replaceEqualDeep, last, functionalUpdate } from "./utils.js";
5
- import { trimPath, trimPathLeft, parsePathname, resolvePath, cleanPath, trimPathRight, matchPathname, interpolatePath, joinPaths } from "./path.js";
5
+ import { trimPath, resolvePath, cleanPath, matchPathname, trimPathRight, interpolatePath, joinPaths, trimPathLeft, parsePathname } from "./path.js";
6
6
  import { isNotFound } from "./not-found.js";
7
7
  import { setupScrollRestoration } from "./scroll-restoration.js";
8
8
  import { defaultParseSearch, defaultStringifySearch } from "./searchParams.js";
9
9
  import { rootRouteId } from "./root.js";
10
- import { isResolvedRedirect, isRedirect } from "./redirect.js";
10
+ import { isRedirect } from "./redirect.js";
11
11
  function defaultSerializeError(err) {
12
12
  if (err instanceof Error) {
13
13
  const obj = {
@@ -46,6 +46,7 @@ class RouterCore {
46
46
  this.isScrollRestoring = false;
47
47
  this.isScrollRestorationSetup = false;
48
48
  this.startTransition = (fn) => fn();
49
+ this.isShell = false;
49
50
  this.update = (newOptions) => {
50
51
  var _a;
51
52
  if (newOptions.notFoundRoute) {
@@ -72,10 +73,7 @@ class RouterCore {
72
73
  this.basepath = `/${trimPath(newOptions.basepath)}`;
73
74
  }
74
75
  }
75
- if (
76
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
77
- !this.history || this.options.history && this.options.history !== this.history
78
- ) {
76
+ if (!this.history || this.options.history && this.options.history !== this.history) {
79
77
  this.history = this.options.history ?? (this.isServer ? createMemoryHistory({
80
78
  initialEntries: [this.basepath || "/"]
81
79
  }) : createBrowserHistory());
@@ -98,16 +96,28 @@ class RouterCore {
98
96
  });
99
97
  setupScrollRestoration(this);
100
98
  }
101
- if (typeof window !== "undefined" && "CSS" in window && // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
102
- typeof ((_a = window.CSS) == null ? void 0 : _a.supports) === "function") {
99
+ if (typeof window !== "undefined" && "CSS" in window && typeof ((_a = window.CSS) == null ? void 0 : _a.supports) === "function") {
103
100
  this.isViewTransitionTypesSupported = window.CSS.supports(
104
101
  "selector(:active-view-transition-type(a)"
105
102
  );
106
103
  }
104
+ if (this.latestLocation.search.__TSS_SHELL) {
105
+ this.isShell = true;
106
+ }
107
107
  };
108
108
  this.buildRouteTree = () => {
109
- this.routesById = {};
110
- this.routesByPath = {};
109
+ const { routesById, routesByPath, flatRoutes } = processRouteTree({
110
+ routeTree: this.routeTree,
111
+ initRoute: (route, i) => {
112
+ route.init({
113
+ originalIndex: i,
114
+ defaultSsr: this.options.defaultSsr
115
+ });
116
+ }
117
+ });
118
+ this.routesById = routesById;
119
+ this.routesByPath = routesByPath;
120
+ this.flatRoutes = flatRoutes;
111
121
  const notFoundRoute = this.options.notFoundRoute;
112
122
  if (notFoundRoute) {
113
123
  notFoundRoute.init({
@@ -116,77 +126,6 @@ class RouterCore {
116
126
  });
117
127
  this.routesById[notFoundRoute.id] = notFoundRoute;
118
128
  }
119
- const recurseRoutes = (childRoutes) => {
120
- childRoutes.forEach((childRoute, i) => {
121
- childRoute.init({
122
- originalIndex: i,
123
- defaultSsr: this.options.defaultSsr
124
- });
125
- const existingRoute = this.routesById[childRoute.id];
126
- invariant(
127
- !existingRoute,
128
- `Duplicate routes found with id: ${String(childRoute.id)}`
129
- );
130
- this.routesById[childRoute.id] = childRoute;
131
- if (!childRoute.isRoot && childRoute.path) {
132
- const trimmedFullPath = trimPathRight(childRoute.fullPath);
133
- if (!this.routesByPath[trimmedFullPath] || childRoute.fullPath.endsWith("/")) {
134
- this.routesByPath[trimmedFullPath] = childRoute;
135
- }
136
- }
137
- const children = childRoute.children;
138
- if (children == null ? void 0 : children.length) {
139
- recurseRoutes(children);
140
- }
141
- });
142
- };
143
- recurseRoutes([this.routeTree]);
144
- const scoredRoutes = [];
145
- const routes = Object.values(this.routesById);
146
- routes.forEach((d, i) => {
147
- var _a;
148
- if (d.isRoot || !d.path) {
149
- return;
150
- }
151
- const trimmed = trimPathLeft(d.fullPath);
152
- const parsed = parsePathname(trimmed);
153
- while (parsed.length > 1 && ((_a = parsed[0]) == null ? void 0 : _a.value) === "/") {
154
- parsed.shift();
155
- }
156
- const scores = parsed.map((segment) => {
157
- if (segment.value === "/") {
158
- return 0.75;
159
- }
160
- if (segment.type === "param") {
161
- return 0.5;
162
- }
163
- if (segment.type === "wildcard") {
164
- return 0.25;
165
- }
166
- return 1;
167
- });
168
- scoredRoutes.push({ child: d, trimmed, parsed, index: i, scores });
169
- });
170
- this.flatRoutes = scoredRoutes.sort((a, b) => {
171
- const minLength = Math.min(a.scores.length, b.scores.length);
172
- for (let i = 0; i < minLength; i++) {
173
- if (a.scores[i] !== b.scores[i]) {
174
- return b.scores[i] - a.scores[i];
175
- }
176
- }
177
- if (a.scores.length !== b.scores.length) {
178
- return b.scores.length - a.scores.length;
179
- }
180
- for (let i = 0; i < minLength; i++) {
181
- if (a.parsed[i].value !== b.parsed[i].value) {
182
- return a.parsed[i].value > b.parsed[i].value ? 1 : -1;
183
- }
184
- }
185
- return a.index - b.index;
186
- }).map((d, i) => {
187
- d.child.rank = i;
188
- return d.child;
189
- });
190
129
  };
191
130
  this.subscribe = (eventType, fn) => {
192
131
  const listener = {
@@ -259,37 +198,16 @@ class RouterCore {
259
198
  return this.matchRoutesInternal(pathnameOrNext, locationSearchOrOpts);
260
199
  }
261
200
  };
262
- this.getMatchedRoutes = (next, dest) => {
263
- let routeParams = {};
264
- const trimmedPath = trimPathRight(next.pathname);
265
- const getMatchedParams = (route) => {
266
- const result = matchPathname(this.basepath, trimmedPath, {
267
- to: route.fullPath,
268
- caseSensitive: route.options.caseSensitive ?? this.options.caseSensitive,
269
- fuzzy: true
270
- });
271
- return result;
272
- };
273
- let foundRoute = (dest == null ? void 0 : dest.to) !== void 0 ? this.routesByPath[dest.to] : void 0;
274
- if (foundRoute) {
275
- routeParams = getMatchedParams(foundRoute);
276
- } else {
277
- foundRoute = this.flatRoutes.find((route) => {
278
- const matchedParams = getMatchedParams(route);
279
- if (matchedParams) {
280
- routeParams = matchedParams;
281
- return true;
282
- }
283
- return false;
284
- });
285
- }
286
- let routeCursor = foundRoute || this.routesById[rootRouteId];
287
- const matchedRoutes = [routeCursor];
288
- while (routeCursor.parentRoute) {
289
- routeCursor = routeCursor.parentRoute;
290
- matchedRoutes.unshift(routeCursor);
291
- }
292
- return { matchedRoutes, routeParams, foundRoute };
201
+ this.getMatchedRoutes = (pathname, routePathname) => {
202
+ return getMatchedRoutes({
203
+ pathname,
204
+ routePathname,
205
+ basepath: this.basepath,
206
+ caseSensitive: this.options.caseSensitive,
207
+ routesByPath: this.routesByPath,
208
+ routesById: this.routesById,
209
+ flatRoutes: this.flatRoutes
210
+ });
293
211
  };
294
212
  this.cancelMatch = (id) => {
295
213
  const match = this.getMatch(id);
@@ -502,10 +420,16 @@ class RouterCore {
502
420
  maskedNext = build(maskedDest);
503
421
  }
504
422
  }
505
- const nextMatches = this.getMatchedRoutes(next, dest);
423
+ const nextMatches = this.getMatchedRoutes(
424
+ next.pathname,
425
+ dest.to
426
+ );
506
427
  const final = build(dest, nextMatches);
507
428
  if (maskedNext) {
508
- const maskedMatches = this.getMatchedRoutes(maskedNext, maskedDest);
429
+ const maskedMatches = this.getMatchedRoutes(
430
+ maskedNext.pathname,
431
+ maskedDest == null ? void 0 : maskedDest.to
432
+ );
509
433
  const maskedFinal = build(maskedDest, maskedMatches);
510
434
  final.maskedLocation = maskedFinal;
511
435
  }
@@ -616,6 +540,13 @@ class RouterCore {
616
540
  });
617
541
  };
618
542
  this.navigate = ({ to, reloadDocument, href, ...rest }) => {
543
+ if (!reloadDocument && href) {
544
+ try {
545
+ new URL(`${href}`);
546
+ reloadDocument = true;
547
+ } catch {
548
+ }
549
+ }
619
550
  if (reloadDocument) {
620
551
  if (!href) {
621
552
  const location = this.buildLocation({ to, ...rest });
@@ -634,8 +565,23 @@ class RouterCore {
634
565
  to
635
566
  });
636
567
  };
637
- this.load = async (opts) => {
568
+ this.beforeLoad = () => {
569
+ this.cancelMatches();
638
570
  this.latestLocation = this.parseLocation(this.latestLocation);
571
+ const pendingMatches = this.matchRoutes(this.latestLocation);
572
+ this.__store.setState((s) => ({
573
+ ...s,
574
+ status: "pending",
575
+ isLoading: true,
576
+ location: this.latestLocation,
577
+ pendingMatches,
578
+ // If a cached moved to pendingMatches, remove it from cachedMatches
579
+ cachedMatches: s.cachedMatches.filter((d) => {
580
+ return !pendingMatches.find((e) => e.id === d.id);
581
+ })
582
+ }));
583
+ };
584
+ this.load = async (opts) => {
639
585
  let redirect;
640
586
  let notFound;
641
587
  let loadPromise;
@@ -643,24 +589,9 @@ class RouterCore {
643
589
  this.startTransition(async () => {
644
590
  var _a;
645
591
  try {
592
+ this.beforeLoad();
646
593
  const next = this.latestLocation;
647
594
  const prevLocation = this.state.resolvedLocation;
648
- this.cancelMatches();
649
- let pendingMatches;
650
- batch(() => {
651
- pendingMatches = this.matchRoutes(next);
652
- this.__store.setState((s) => ({
653
- ...s,
654
- status: "pending",
655
- isLoading: true,
656
- location: next,
657
- pendingMatches,
658
- // If a cached moved to pendingMatches, remove it from cachedMatches
659
- cachedMatches: s.cachedMatches.filter((d) => {
660
- return !pendingMatches.find((e) => e.id === d.id);
661
- })
662
- }));
663
- });
664
595
  if (!this.state.redirect) {
665
596
  this.emit({
666
597
  type: "onBeforeNavigate",
@@ -679,7 +610,7 @@ class RouterCore {
679
610
  });
680
611
  await this.loadMatches({
681
612
  sync: opts == null ? void 0 : opts.sync,
682
- matches: pendingMatches,
613
+ matches: this.state.pendingMatches,
683
614
  location: next,
684
615
  // eslint-disable-next-line @typescript-eslint/require-await
685
616
  onReady: async () => {
@@ -728,11 +659,11 @@ class RouterCore {
728
659
  }
729
660
  });
730
661
  } catch (err) {
731
- if (isResolvedRedirect(err)) {
662
+ if (isRedirect(err)) {
732
663
  redirect = err;
733
664
  if (!this.isServer) {
734
665
  this.navigate({
735
- ...redirect,
666
+ ...redirect.options,
736
667
  replace: true,
737
668
  ignoreBlocker: true
738
669
  });
@@ -742,7 +673,7 @@ class RouterCore {
742
673
  }
743
674
  this.__store.setState((s) => ({
744
675
  ...s,
745
- statusCode: redirect ? redirect.statusCode : notFound ? 404 : s.matches.some((d) => d.status === "error") ? 500 : 200,
676
+ statusCode: redirect ? redirect.status : notFound ? 404 : s.matches.some((d) => d.status === "error") ? 500 : 200,
746
677
  redirect
747
678
  }));
748
679
  }
@@ -840,12 +771,14 @@ class RouterCore {
840
771
  };
841
772
  const handleRedirectAndNotFound = (match, err) => {
842
773
  var _a, _b, _c, _d;
843
- if (isResolvedRedirect(err)) {
844
- if (!err.reloadDocument) {
845
- throw err;
846
- }
847
- }
848
774
  if (isRedirect(err) || isNotFound(err)) {
775
+ if (isRedirect(err)) {
776
+ if (err.redirectHandled) {
777
+ if (!err.options.reloadDocument) {
778
+ throw err;
779
+ }
780
+ }
781
+ }
849
782
  updateMatch(match.id, (prev) => ({
850
783
  ...prev,
851
784
  status: isRedirect(err) ? "redirected" : isNotFound(err) ? "notFound" : "error",
@@ -862,7 +795,9 @@ class RouterCore {
862
795
  (_c = match.loadPromise) == null ? void 0 : _c.resolve();
863
796
  if (isRedirect(err)) {
864
797
  rendered = true;
865
- err = this.resolveRedirect({ ...err, _fromLocation: location });
798
+ err.options._fromLocation = location;
799
+ err.redirectHandled = true;
800
+ err = this.resolveRedirect(err);
866
801
  throw err;
867
802
  } else if (isNotFound(err)) {
868
803
  this._handleNotFound(matches, err, {
@@ -1070,7 +1005,7 @@ class RouterCore {
1070
1005
  loaderPromise: createControlledPromise(),
1071
1006
  preload: !!preload && !this.state.matches.find((d) => d.id === matchId)
1072
1007
  }));
1073
- const executeHead = () => {
1008
+ const executeHead = async () => {
1074
1009
  var _a2, _b2, _c2, _d2, _e, _f;
1075
1010
  const match = this.getMatch(matchId);
1076
1011
  if (!match) {
@@ -1082,20 +1017,13 @@ class RouterCore {
1082
1017
  params: match.params,
1083
1018
  loaderData: match.loaderData
1084
1019
  };
1085
- const headFnContent = (_b2 = (_a2 = route.options).head) == null ? void 0 : _b2.call(_a2, assetContext);
1020
+ const headFnContent = await ((_b2 = (_a2 = route.options).head) == null ? void 0 : _b2.call(_a2, assetContext));
1086
1021
  const meta = headFnContent == null ? void 0 : headFnContent.meta;
1087
1022
  const links = headFnContent == null ? void 0 : headFnContent.links;
1088
1023
  const headScripts = headFnContent == null ? void 0 : headFnContent.scripts;
1089
- const scripts = (_d2 = (_c2 = route.options).scripts) == null ? void 0 : _d2.call(_c2, assetContext);
1090
- const headers = (_f = (_e = route.options).headers) == null ? void 0 : _f.call(_e, assetContext);
1091
- updateMatch(matchId, (prev) => ({
1092
- ...prev,
1093
- meta,
1094
- links,
1095
- headScripts,
1096
- headers,
1097
- scripts
1098
- }));
1024
+ const scripts = await ((_d2 = (_c2 = route.options).scripts) == null ? void 0 : _d2.call(_c2, assetContext));
1025
+ const headers = await ((_f = (_e = route.options).headers) == null ? void 0 : _f.call(_e, assetContext));
1026
+ return { meta, links, headScripts, headers, scripts };
1099
1027
  };
1100
1028
  const runLoader = async () => {
1101
1029
  var _a2, _b2, _c2, _d2, _e;
@@ -1120,17 +1048,19 @@ class RouterCore {
1120
1048
  await route._lazyPromise;
1121
1049
  await potentialPendingMinPromise();
1122
1050
  await route._componentsPromise;
1123
- batch(() => {
1124
- updateMatch(matchId, (prev) => ({
1125
- ...prev,
1126
- error: void 0,
1127
- status: "success",
1128
- isFetching: false,
1129
- updatedAt: Date.now(),
1130
- loaderData
1131
- }));
1132
- executeHead();
1133
- });
1051
+ updateMatch(matchId, (prev) => ({
1052
+ ...prev,
1053
+ error: void 0,
1054
+ status: "success",
1055
+ isFetching: false,
1056
+ updatedAt: Date.now(),
1057
+ loaderData
1058
+ }));
1059
+ const head = await executeHead();
1060
+ updateMatch(matchId, (prev) => ({
1061
+ ...prev,
1062
+ ...head
1063
+ }));
1134
1064
  } catch (e) {
1135
1065
  let error = e;
1136
1066
  await potentialPendingMinPromise();
@@ -1144,28 +1074,26 @@ class RouterCore {
1144
1074
  onErrorError
1145
1075
  );
1146
1076
  }
1147
- batch(() => {
1148
- updateMatch(matchId, (prev) => ({
1149
- ...prev,
1150
- error,
1151
- status: "error",
1152
- isFetching: false
1153
- }));
1154
- executeHead();
1155
- });
1077
+ const head = await executeHead();
1078
+ updateMatch(matchId, (prev) => ({
1079
+ ...prev,
1080
+ error,
1081
+ status: "error",
1082
+ isFetching: false,
1083
+ ...head
1084
+ }));
1156
1085
  }
1157
1086
  (_e = this.serverSsr) == null ? void 0 : _e.onMatchSettled({
1158
1087
  router: this,
1159
1088
  match: this.getMatch(matchId)
1160
1089
  });
1161
1090
  } catch (err) {
1162
- batch(() => {
1163
- updateMatch(matchId, (prev) => ({
1164
- ...prev,
1165
- loaderPromise: void 0
1166
- }));
1167
- executeHead();
1168
- });
1091
+ const head = await executeHead();
1092
+ updateMatch(matchId, (prev) => ({
1093
+ ...prev,
1094
+ loaderPromise: void 0,
1095
+ ...head
1096
+ }));
1169
1097
  handleRedirectAndNotFound(this.getMatch(matchId), err);
1170
1098
  }
1171
1099
  };
@@ -1185,15 +1113,19 @@ class RouterCore {
1185
1113
  loaderPromise: void 0
1186
1114
  }));
1187
1115
  } catch (err) {
1188
- if (isResolvedRedirect(err)) {
1189
- await this.navigate(err);
1116
+ if (isRedirect(err)) {
1117
+ await this.navigate(err.options);
1190
1118
  }
1191
1119
  }
1192
1120
  })();
1193
1121
  } else if (status !== "success" || loaderShouldRunAsync && sync) {
1194
1122
  await runLoader();
1195
1123
  } else {
1196
- executeHead();
1124
+ const head = await executeHead();
1125
+ updateMatch(matchId, (prev) => ({
1126
+ ...prev,
1127
+ ...head
1128
+ }));
1197
1129
  }
1198
1130
  }
1199
1131
  if (!loaderIsRunningAsync) {
@@ -1252,10 +1184,13 @@ class RouterCore {
1252
1184
  });
1253
1185
  return this.load({ sync: opts == null ? void 0 : opts.sync });
1254
1186
  };
1255
- this.resolveRedirect = (err) => {
1256
- const redirect = err;
1257
- if (!redirect.href) {
1258
- redirect.href = this.buildLocation(redirect).href;
1187
+ this.resolveRedirect = (redirect) => {
1188
+ if (!redirect.options.href) {
1189
+ redirect.options.href = this.buildLocation(redirect.options).href;
1190
+ redirect.headers.set("Location", redirect.options.href);
1191
+ }
1192
+ if (!redirect.headers.get("Location")) {
1193
+ redirect.headers.set("Location", redirect.options.href);
1259
1194
  }
1260
1195
  return redirect;
1261
1196
  };
@@ -1357,11 +1292,11 @@ class RouterCore {
1357
1292
  return matches;
1358
1293
  } catch (err) {
1359
1294
  if (isRedirect(err)) {
1360
- if (err.reloadDocument) {
1295
+ if (err.options.reloadDocument) {
1361
1296
  return void 0;
1362
1297
  }
1363
1298
  return await this.preloadRoute({
1364
- ...err,
1299
+ ...err.options,
1365
1300
  _fromLocation: next
1366
1301
  });
1367
1302
  }
@@ -1465,9 +1400,10 @@ class RouterCore {
1465
1400
  return this.routesById;
1466
1401
  }
1467
1402
  matchRoutesInternal(next, opts) {
1403
+ var _a;
1468
1404
  const { foundRoute, matchedRoutes, routeParams } = this.getMatchedRoutes(
1469
- next,
1470
- opts == null ? void 0 : opts.dest
1405
+ next.pathname,
1406
+ (_a = opts == null ? void 0 : opts.dest) == null ? void 0 : _a.to
1471
1407
  );
1472
1408
  let isGlobalNotFound = false;
1473
1409
  if (
@@ -1498,9 +1434,9 @@ class RouterCore {
1498
1434
  return rootRouteId;
1499
1435
  })();
1500
1436
  const parseErrors = matchedRoutes.map((route) => {
1501
- var _a;
1437
+ var _a2;
1502
1438
  let parsedParamsError;
1503
- const parseParams = ((_a = route.options.params) == null ? void 0 : _a.parse) ?? route.options.parseParams;
1439
+ const parseParams = ((_a2 = route.options.params) == null ? void 0 : _a2.parse) ?? route.options.parseParams;
1504
1440
  if (parseParams) {
1505
1441
  try {
1506
1442
  const parsedParams = parseParams(routeParams);
@@ -1524,7 +1460,7 @@ class RouterCore {
1524
1460
  return parentContext;
1525
1461
  };
1526
1462
  matchedRoutes.forEach((route, index) => {
1527
- var _a, _b;
1463
+ var _a2, _b;
1528
1464
  const parentMatch = matches[index - 1];
1529
1465
  const [preMatchSearch, strictMatchSearch, searchError] = (() => {
1530
1466
  const parentSearch = (parentMatch == null ? void 0 : parentMatch.search) ?? next.search;
@@ -1552,7 +1488,7 @@ class RouterCore {
1552
1488
  return [parentSearch, {}, searchParamError];
1553
1489
  }
1554
1490
  })();
1555
- const loaderDeps = ((_b = (_a = route.options).loaderDeps) == null ? void 0 : _b.call(_a, {
1491
+ const loaderDeps = ((_b = (_a2 = route.options).loaderDeps) == null ? void 0 : _b.call(_a2, {
1556
1492
  search: preMatchSearch
1557
1493
  })) ?? "";
1558
1494
  const loaderDepsHash = loaderDeps ? JSON.stringify(loaderDeps) : "";
@@ -1630,7 +1566,7 @@ class RouterCore {
1630
1566
  matches.push(match);
1631
1567
  });
1632
1568
  matches.forEach((match, index) => {
1633
- var _a, _b;
1569
+ var _a2, _b;
1634
1570
  const route = this.looseRoutesById[match.routeId];
1635
1571
  const existingMatch = this.getMatch(match.id);
1636
1572
  if (!existingMatch && (opts == null ? void 0 : opts._buildLocation) !== true) {
@@ -1648,7 +1584,7 @@ class RouterCore {
1648
1584
  preload: !!match.preload,
1649
1585
  matches
1650
1586
  };
1651
- match.__routeContext = ((_b = (_a = route.options).context) == null ? void 0 : _b.call(_a, contextFnContext)) ?? {};
1587
+ match.__routeContext = ((_b = (_a2 = route.options).context) == null ? void 0 : _b.call(_a2, contextFnContext)) ?? {};
1652
1588
  match.context = {
1653
1589
  ...parentContext,
1654
1590
  ...match.__routeContext,
@@ -1718,6 +1654,141 @@ function routeNeedsPreload(route) {
1718
1654
  }
1719
1655
  return false;
1720
1656
  }
1657
+ function processRouteTree({
1658
+ routeTree,
1659
+ initRoute
1660
+ }) {
1661
+ const routesById = {};
1662
+ const routesByPath = {};
1663
+ const recurseRoutes = (childRoutes) => {
1664
+ childRoutes.forEach((childRoute, i) => {
1665
+ initRoute == null ? void 0 : initRoute(childRoute, i);
1666
+ const existingRoute = routesById[childRoute.id];
1667
+ invariant(
1668
+ !existingRoute,
1669
+ `Duplicate routes found with id: ${String(childRoute.id)}`
1670
+ );
1671
+ routesById[childRoute.id] = childRoute;
1672
+ if (!childRoute.isRoot && childRoute.path) {
1673
+ const trimmedFullPath = trimPathRight(childRoute.fullPath);
1674
+ if (!routesByPath[trimmedFullPath] || childRoute.fullPath.endsWith("/")) {
1675
+ routesByPath[trimmedFullPath] = childRoute;
1676
+ }
1677
+ }
1678
+ const children = childRoute.children;
1679
+ if (children == null ? void 0 : children.length) {
1680
+ recurseRoutes(children);
1681
+ }
1682
+ });
1683
+ };
1684
+ recurseRoutes([routeTree]);
1685
+ const scoredRoutes = [];
1686
+ const routes = Object.values(routesById);
1687
+ routes.forEach((d, i) => {
1688
+ var _a;
1689
+ if (d.isRoot || !d.path) {
1690
+ return;
1691
+ }
1692
+ const trimmed = trimPathLeft(d.fullPath);
1693
+ const parsed = parsePathname(trimmed);
1694
+ while (parsed.length > 1 && ((_a = parsed[0]) == null ? void 0 : _a.value) === "/") {
1695
+ parsed.shift();
1696
+ }
1697
+ const scores = parsed.map((segment) => {
1698
+ if (segment.value === "/") {
1699
+ return 0.75;
1700
+ }
1701
+ if (segment.type === "param" && segment.prefixSegment && segment.suffixSegment) {
1702
+ return 0.55;
1703
+ }
1704
+ if (segment.type === "param" && segment.prefixSegment) {
1705
+ return 0.52;
1706
+ }
1707
+ if (segment.type === "param" && segment.suffixSegment) {
1708
+ return 0.51;
1709
+ }
1710
+ if (segment.type === "param") {
1711
+ return 0.5;
1712
+ }
1713
+ if (segment.type === "wildcard" && segment.prefixSegment && segment.suffixSegment) {
1714
+ return 0.3;
1715
+ }
1716
+ if (segment.type === "wildcard" && segment.prefixSegment) {
1717
+ return 0.27;
1718
+ }
1719
+ if (segment.type === "wildcard" && segment.suffixSegment) {
1720
+ return 0.26;
1721
+ }
1722
+ if (segment.type === "wildcard") {
1723
+ return 0.25;
1724
+ }
1725
+ return 1;
1726
+ });
1727
+ scoredRoutes.push({ child: d, trimmed, parsed, index: i, scores });
1728
+ });
1729
+ const flatRoutes = scoredRoutes.sort((a, b) => {
1730
+ const minLength = Math.min(a.scores.length, b.scores.length);
1731
+ for (let i = 0; i < minLength; i++) {
1732
+ if (a.scores[i] !== b.scores[i]) {
1733
+ return b.scores[i] - a.scores[i];
1734
+ }
1735
+ }
1736
+ if (a.scores.length !== b.scores.length) {
1737
+ return b.scores.length - a.scores.length;
1738
+ }
1739
+ for (let i = 0; i < minLength; i++) {
1740
+ if (a.parsed[i].value !== b.parsed[i].value) {
1741
+ return a.parsed[i].value > b.parsed[i].value ? 1 : -1;
1742
+ }
1743
+ }
1744
+ return a.index - b.index;
1745
+ }).map((d, i) => {
1746
+ d.child.rank = i;
1747
+ return d.child;
1748
+ });
1749
+ return { routesById, routesByPath, flatRoutes };
1750
+ }
1751
+ function getMatchedRoutes({
1752
+ pathname,
1753
+ routePathname,
1754
+ basepath,
1755
+ caseSensitive,
1756
+ routesByPath,
1757
+ routesById,
1758
+ flatRoutes
1759
+ }) {
1760
+ let routeParams = {};
1761
+ const trimmedPath = trimPathRight(pathname);
1762
+ const getMatchedParams = (route) => {
1763
+ var _a;
1764
+ const result = matchPathname(basepath, trimmedPath, {
1765
+ to: route.fullPath,
1766
+ caseSensitive: ((_a = route.options) == null ? void 0 : _a.caseSensitive) ?? caseSensitive,
1767
+ fuzzy: true
1768
+ });
1769
+ return result;
1770
+ };
1771
+ let foundRoute = routePathname !== void 0 ? routesByPath[routePathname] : void 0;
1772
+ if (foundRoute) {
1773
+ routeParams = getMatchedParams(foundRoute);
1774
+ } else {
1775
+ foundRoute = flatRoutes.find((route) => {
1776
+ const matchedParams = getMatchedParams(route);
1777
+ if (matchedParams) {
1778
+ routeParams = matchedParams;
1779
+ return true;
1780
+ }
1781
+ return false;
1782
+ });
1783
+ }
1784
+ let routeCursor = foundRoute || routesById[rootRouteId];
1785
+ const matchedRoutes = [routeCursor];
1786
+ while (routeCursor.parentRoute) {
1787
+ routeCursor = routeCursor.parentRoute;
1788
+ matchedRoutes.unshift(routeCursor);
1789
+ }
1790
+ return { matchedRoutes, routeParams, foundRoute };
1791
+ }
1721
1792
  export {
1722
1793
  PathParamError,
1723
1794
  RouterCore,
@@ -1726,6 +1797,8 @@ export {
1726
1797
  defaultSerializeError,
1727
1798
  getInitialRouterState,
1728
1799
  getLocationChangeInfo,
1729
- lazyFn
1800
+ getMatchedRoutes,
1801
+ lazyFn,
1802
+ processRouteTree
1730
1803
  };
1731
1804
  //# sourceMappingURL=router.js.map