@tanstack/router-core 1.121.0-alpha.1 → 1.121.0-alpha.11

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.
@@ -194,9 +194,8 @@ class RouterCore {
194
194
  },
195
195
  opts
196
196
  );
197
- } else {
198
- return this.matchRoutesInternal(pathnameOrNext, locationSearchOrOpts);
199
197
  }
198
+ return this.matchRoutesInternal(pathnameOrNext, locationSearchOrOpts);
200
199
  };
201
200
  this.getMatchedRoutes = (pathname, routePathname) => {
202
201
  return getMatchedRoutes({
@@ -222,173 +221,92 @@ class RouterCore {
222
221
  });
223
222
  };
224
223
  this.buildLocation = (opts) => {
225
- const build = (dest = {}, matchedRoutesResult) => {
226
- var _a, _b, _c, _d, _e, _f, _g;
227
- const fromMatches = dest._fromLocation ? this.matchRoutes(dest._fromLocation, { _buildLocation: true }) : this.state.matches;
228
- const fromMatch = dest.from != null ? fromMatches.find(
229
- (d) => matchPathname(this.basepath, trimPathRight(d.pathname), {
230
- to: dest.from,
231
- caseSensitive: false,
232
- fuzzy: false
233
- })
234
- ) : void 0;
235
- const fromPath = (fromMatch == null ? void 0 : fromMatch.pathname) || this.latestLocation.pathname;
236
- invariant(
237
- dest.from == null || fromMatch != null,
238
- "Could not find match for from: " + dest.from
239
- );
240
- const fromSearch = ((_a = this.state.pendingMatches) == null ? void 0 : _a.length) ? (_b = last(this.state.pendingMatches)) == null ? void 0 : _b.search : ((_c = last(fromMatches)) == null ? void 0 : _c.search) || this.latestLocation.search;
241
- const stayingMatches = matchedRoutesResult == null ? void 0 : matchedRoutesResult.matchedRoutes.filter(
242
- (d) => fromMatches.find((e) => e.routeId === d.id)
243
- );
244
- let pathname;
245
- if (dest.to) {
246
- const resolvePathTo = (fromMatch == null ? void 0 : fromMatch.fullPath) || ((_d = last(fromMatches)) == null ? void 0 : _d.fullPath) || this.latestLocation.pathname;
247
- pathname = this.resolvePathWithBase(resolvePathTo, `${dest.to}`);
248
- } else {
249
- const fromRouteByFromPathRouteId = this.routesById[(_e = stayingMatches == null ? void 0 : stayingMatches.find((route) => {
250
- const interpolatedPath = interpolatePath({
251
- path: route.fullPath,
252
- params: (matchedRoutesResult == null ? void 0 : matchedRoutesResult.routeParams) ?? {},
253
- decodeCharMap: this.pathParamsDecodeCharMap
254
- }).interpolatedPath;
255
- const pathname2 = joinPaths([this.basepath, interpolatedPath]);
256
- return pathname2 === fromPath;
257
- })) == null ? void 0 : _e.id];
258
- pathname = this.resolvePathWithBase(
259
- fromPath,
260
- (fromRouteByFromPathRouteId == null ? void 0 : fromRouteByFromPathRouteId.to) ?? fromPath
261
- );
224
+ const build = (dest = {}) => {
225
+ var _a;
226
+ const currentLocation = dest._fromLocation || this.latestLocation;
227
+ const allFromMatches = this.matchRoutes(currentLocation, {
228
+ _buildLocation: true
229
+ });
230
+ const lastMatch = last(allFromMatches);
231
+ let fromPath = lastMatch.fullPath;
232
+ if (dest.unsafeRelative === "path") {
233
+ fromPath = currentLocation.pathname;
234
+ } else if (dest.to && dest.from) {
235
+ fromPath = dest.from;
236
+ const existingFrom = [...allFromMatches].reverse().find((d) => {
237
+ return d.fullPath === fromPath || d.fullPath === joinPaths([fromPath, "/"]);
238
+ });
239
+ if (!existingFrom) {
240
+ console.warn(`Could not find match for from: ${dest.from}`);
241
+ }
262
242
  }
263
- const prevParams = { ...(_f = last(fromMatches)) == null ? void 0 : _f.params };
264
- let nextParams = (dest.params ?? true) === true ? prevParams : {
265
- ...prevParams,
266
- ...functionalUpdate(dest.params, prevParams)
243
+ const fromSearch = lastMatch.search;
244
+ const fromParams = { ...lastMatch.params };
245
+ const nextTo = dest.to ? this.resolvePathWithBase(fromPath, `${dest.to}`) : fromPath;
246
+ let nextParams = (dest.params ?? true) === true ? fromParams : {
247
+ ...fromParams,
248
+ ...functionalUpdate(dest.params, fromParams)
267
249
  };
250
+ const destRoutes = this.matchRoutes(
251
+ nextTo,
252
+ {},
253
+ {
254
+ _buildLocation: true
255
+ }
256
+ ).map((d) => this.looseRoutesById[d.routeId]);
268
257
  if (Object.keys(nextParams).length > 0) {
269
- matchedRoutesResult == null ? void 0 : matchedRoutesResult.matchedRoutes.map((route) => {
258
+ destRoutes.map((route) => {
270
259
  var _a2;
271
260
  return ((_a2 = route.options.params) == null ? void 0 : _a2.stringify) ?? route.options.stringifyParams;
272
261
  }).filter(Boolean).forEach((fn) => {
273
262
  nextParams = { ...nextParams, ...fn(nextParams) };
274
263
  });
275
264
  }
276
- pathname = interpolatePath({
277
- path: pathname,
265
+ const nextPathname = interpolatePath({
266
+ path: nextTo,
278
267
  params: nextParams ?? {},
279
268
  leaveWildcards: false,
280
269
  leaveParams: opts.leaveParams,
281
270
  decodeCharMap: this.pathParamsDecodeCharMap
282
271
  }).interpolatedPath;
283
- let search = fromSearch;
284
- if (opts._includeValidateSearch && ((_g = this.options.search) == null ? void 0 : _g.strict)) {
272
+ let nextSearch = fromSearch;
273
+ if (opts._includeValidateSearch && ((_a = this.options.search) == null ? void 0 : _a.strict)) {
285
274
  let validatedSearch = {};
286
- matchedRoutesResult == null ? void 0 : matchedRoutesResult.matchedRoutes.forEach((route) => {
275
+ destRoutes.forEach((route) => {
287
276
  try {
288
277
  if (route.options.validateSearch) {
289
278
  validatedSearch = {
290
279
  ...validatedSearch,
291
280
  ...validateSearch(route.options.validateSearch, {
292
281
  ...validatedSearch,
293
- ...search
282
+ ...nextSearch
294
283
  }) ?? {}
295
284
  };
296
285
  }
297
286
  } catch {
298
287
  }
299
288
  });
300
- search = validatedSearch;
289
+ nextSearch = validatedSearch;
301
290
  }
302
- const applyMiddlewares = (search2) => {
303
- const allMiddlewares = (matchedRoutesResult == null ? void 0 : matchedRoutesResult.matchedRoutes.reduce(
304
- (acc, route) => {
305
- var _a2;
306
- const middlewares = [];
307
- if ("search" in route.options) {
308
- if ((_a2 = route.options.search) == null ? void 0 : _a2.middlewares) {
309
- middlewares.push(...route.options.search.middlewares);
310
- }
311
- } else if (route.options.preSearchFilters || route.options.postSearchFilters) {
312
- const legacyMiddleware = ({
313
- search: search3,
314
- next
315
- }) => {
316
- let nextSearch = search3;
317
- if ("preSearchFilters" in route.options && route.options.preSearchFilters) {
318
- nextSearch = route.options.preSearchFilters.reduce(
319
- (prev, next2) => next2(prev),
320
- search3
321
- );
322
- }
323
- const result = next(nextSearch);
324
- if ("postSearchFilters" in route.options && route.options.postSearchFilters) {
325
- return route.options.postSearchFilters.reduce(
326
- (prev, next2) => next2(prev),
327
- result
328
- );
329
- }
330
- return result;
331
- };
332
- middlewares.push(legacyMiddleware);
333
- }
334
- if (opts._includeValidateSearch && route.options.validateSearch) {
335
- const validate = ({ search: search3, next }) => {
336
- const result = next(search3);
337
- try {
338
- const validatedSearch = {
339
- ...result,
340
- ...validateSearch(
341
- route.options.validateSearch,
342
- result
343
- ) ?? {}
344
- };
345
- return validatedSearch;
346
- } catch {
347
- return result;
348
- }
349
- };
350
- middlewares.push(validate);
351
- }
352
- return acc.concat(middlewares);
353
- },
354
- []
355
- )) ?? [];
356
- const final = ({ search: search3 }) => {
357
- if (!dest.search) {
358
- return {};
359
- }
360
- if (dest.search === true) {
361
- return search3;
362
- }
363
- return functionalUpdate(dest.search, search3);
364
- };
365
- allMiddlewares.push(final);
366
- const applyNext = (index, currentSearch) => {
367
- if (index >= allMiddlewares.length) {
368
- return currentSearch;
369
- }
370
- const middleware = allMiddlewares[index];
371
- const next = (newSearch) => {
372
- return applyNext(index + 1, newSearch);
373
- };
374
- return middleware({ search: currentSearch, next });
375
- };
376
- return applyNext(0, search2);
377
- };
378
- search = applyMiddlewares(search);
379
- search = replaceEqualDeep(fromSearch, search);
380
- const searchStr = this.options.stringifySearch(search);
381
- const hash = dest.hash === true ? this.latestLocation.hash : dest.hash ? functionalUpdate(dest.hash, this.latestLocation.hash) : void 0;
291
+ nextSearch = applySearchMiddleware({
292
+ search: nextSearch,
293
+ dest,
294
+ destRoutes,
295
+ _includeValidateSearch: opts._includeValidateSearch
296
+ });
297
+ nextSearch = replaceEqualDeep(fromSearch, nextSearch);
298
+ const searchStr = this.options.stringifySearch(nextSearch);
299
+ const hash = dest.hash === true ? currentLocation.hash : dest.hash ? functionalUpdate(dest.hash, currentLocation.hash) : void 0;
382
300
  const hashStr = hash ? `#${hash}` : "";
383
- let nextState = dest.state === true ? this.latestLocation.state : dest.state ? functionalUpdate(dest.state, this.latestLocation.state) : {};
384
- nextState = replaceEqualDeep(this.latestLocation.state, nextState);
301
+ let nextState = dest.state === true ? currentLocation.state : dest.state ? functionalUpdate(dest.state, currentLocation.state) : {};
302
+ nextState = replaceEqualDeep(currentLocation.state, nextState);
385
303
  return {
386
- pathname,
387
- search,
304
+ pathname: nextPathname,
305
+ search: nextSearch,
388
306
  searchStr,
389
307
  state: nextState,
390
308
  hash: hash ?? "",
391
- href: `${pathname}${searchStr}${hashStr}`,
309
+ href: `${nextPathname}${searchStr}${hashStr}`,
392
310
  unmaskOnReload: dest.unmaskOnReload
393
311
  };
394
312
  };
@@ -420,20 +338,11 @@ class RouterCore {
420
338
  maskedNext = build(maskedDest);
421
339
  }
422
340
  }
423
- const nextMatches = this.getMatchedRoutes(
424
- next.pathname,
425
- dest.to
426
- );
427
- const final = build(dest, nextMatches);
428
341
  if (maskedNext) {
429
- const maskedMatches = this.getMatchedRoutes(
430
- maskedNext.pathname,
431
- maskedDest == null ? void 0 : maskedDest.to
432
- );
433
- const maskedFinal = build(maskedDest, maskedMatches);
434
- final.maskedLocation = maskedFinal;
342
+ const maskedFinal = build(maskedDest);
343
+ next.maskedLocation = maskedFinal;
435
344
  }
436
- return final;
345
+ return next;
437
346
  };
438
347
  if (opts.mask) {
439
348
  return buildWithMatches(opts, {
@@ -1005,7 +914,7 @@ class RouterCore {
1005
914
  loaderPromise: createControlledPromise(),
1006
915
  preload: !!preload && !this.state.matches.find((d) => d.id === matchId)
1007
916
  }));
1008
- const executeHead = () => {
917
+ const executeHead = async () => {
1009
918
  var _a2, _b2, _c2, _d2, _e, _f;
1010
919
  const match = this.getMatch(matchId);
1011
920
  if (!match) {
@@ -1017,20 +926,13 @@ class RouterCore {
1017
926
  params: match.params,
1018
927
  loaderData: match.loaderData
1019
928
  };
1020
- const headFnContent = (_b2 = (_a2 = route.options).head) == null ? void 0 : _b2.call(_a2, assetContext);
929
+ const headFnContent = await ((_b2 = (_a2 = route.options).head) == null ? void 0 : _b2.call(_a2, assetContext));
1021
930
  const meta = headFnContent == null ? void 0 : headFnContent.meta;
1022
931
  const links = headFnContent == null ? void 0 : headFnContent.links;
1023
932
  const headScripts = headFnContent == null ? void 0 : headFnContent.scripts;
1024
- const scripts = (_d2 = (_c2 = route.options).scripts) == null ? void 0 : _d2.call(_c2, assetContext);
1025
- const headers = (_f = (_e = route.options).headers) == null ? void 0 : _f.call(_e, assetContext);
1026
- updateMatch(matchId, (prev) => ({
1027
- ...prev,
1028
- meta,
1029
- links,
1030
- headScripts,
1031
- headers,
1032
- scripts
1033
- }));
933
+ const scripts = await ((_d2 = (_c2 = route.options).scripts) == null ? void 0 : _d2.call(_c2, assetContext));
934
+ const headers = await ((_f = (_e = route.options).headers) == null ? void 0 : _f.call(_e, assetContext));
935
+ return { meta, links, headScripts, headers, scripts };
1034
936
  };
1035
937
  const runLoader = async () => {
1036
938
  var _a2, _b2, _c2, _d2, _e;
@@ -1055,17 +957,19 @@ class RouterCore {
1055
957
  await route._lazyPromise;
1056
958
  await potentialPendingMinPromise();
1057
959
  await route._componentsPromise;
1058
- batch(() => {
1059
- updateMatch(matchId, (prev) => ({
1060
- ...prev,
1061
- error: void 0,
1062
- status: "success",
1063
- isFetching: false,
1064
- updatedAt: Date.now(),
1065
- loaderData
1066
- }));
1067
- executeHead();
1068
- });
960
+ updateMatch(matchId, (prev) => ({
961
+ ...prev,
962
+ error: void 0,
963
+ status: "success",
964
+ isFetching: false,
965
+ updatedAt: Date.now(),
966
+ loaderData
967
+ }));
968
+ const head = await executeHead();
969
+ updateMatch(matchId, (prev) => ({
970
+ ...prev,
971
+ ...head
972
+ }));
1069
973
  } catch (e) {
1070
974
  let error = e;
1071
975
  await potentialPendingMinPromise();
@@ -1079,28 +983,26 @@ class RouterCore {
1079
983
  onErrorError
1080
984
  );
1081
985
  }
1082
- batch(() => {
1083
- updateMatch(matchId, (prev) => ({
1084
- ...prev,
1085
- error,
1086
- status: "error",
1087
- isFetching: false
1088
- }));
1089
- executeHead();
1090
- });
986
+ const head = await executeHead();
987
+ updateMatch(matchId, (prev) => ({
988
+ ...prev,
989
+ error,
990
+ status: "error",
991
+ isFetching: false,
992
+ ...head
993
+ }));
1091
994
  }
1092
995
  (_e = this.serverSsr) == null ? void 0 : _e.onMatchSettled({
1093
996
  router: this,
1094
997
  match: this.getMatch(matchId)
1095
998
  });
1096
999
  } catch (err) {
1097
- batch(() => {
1098
- updateMatch(matchId, (prev) => ({
1099
- ...prev,
1100
- loaderPromise: void 0
1101
- }));
1102
- executeHead();
1103
- });
1000
+ const head = await executeHead();
1001
+ updateMatch(matchId, (prev) => ({
1002
+ ...prev,
1003
+ loaderPromise: void 0,
1004
+ ...head
1005
+ }));
1104
1006
  handleRedirectAndNotFound(this.getMatch(matchId), err);
1105
1007
  }
1106
1008
  };
@@ -1128,7 +1030,11 @@ class RouterCore {
1128
1030
  } else if (status !== "success" || loaderShouldRunAsync && sync) {
1129
1031
  await runLoader();
1130
1032
  } else {
1131
- executeHead();
1033
+ const head = await executeHead();
1034
+ updateMatch(matchId, (prev) => ({
1035
+ ...prev,
1036
+ ...head
1037
+ }));
1132
1038
  }
1133
1039
  }
1134
1040
  if (!loaderIsRunningAsync) {
@@ -1792,6 +1698,84 @@ function getMatchedRoutes({
1792
1698
  }
1793
1699
  return { matchedRoutes, routeParams, foundRoute };
1794
1700
  }
1701
+ function applySearchMiddleware({
1702
+ search,
1703
+ dest,
1704
+ destRoutes,
1705
+ _includeValidateSearch
1706
+ }) {
1707
+ const allMiddlewares = destRoutes.reduce(
1708
+ (acc, route) => {
1709
+ var _a;
1710
+ const middlewares = [];
1711
+ if ("search" in route.options) {
1712
+ if ((_a = route.options.search) == null ? void 0 : _a.middlewares) {
1713
+ middlewares.push(...route.options.search.middlewares);
1714
+ }
1715
+ } else if (route.options.preSearchFilters || route.options.postSearchFilters) {
1716
+ const legacyMiddleware = ({
1717
+ search: search2,
1718
+ next
1719
+ }) => {
1720
+ let nextSearch = search2;
1721
+ if ("preSearchFilters" in route.options && route.options.preSearchFilters) {
1722
+ nextSearch = route.options.preSearchFilters.reduce(
1723
+ (prev, next2) => next2(prev),
1724
+ search2
1725
+ );
1726
+ }
1727
+ const result = next(nextSearch);
1728
+ if ("postSearchFilters" in route.options && route.options.postSearchFilters) {
1729
+ return route.options.postSearchFilters.reduce(
1730
+ (prev, next2) => next2(prev),
1731
+ result
1732
+ );
1733
+ }
1734
+ return result;
1735
+ };
1736
+ middlewares.push(legacyMiddleware);
1737
+ }
1738
+ if (_includeValidateSearch && route.options.validateSearch) {
1739
+ const validate = ({ search: search2, next }) => {
1740
+ const result = next(search2);
1741
+ try {
1742
+ const validatedSearch = {
1743
+ ...result,
1744
+ ...validateSearch(route.options.validateSearch, result) ?? {}
1745
+ };
1746
+ return validatedSearch;
1747
+ } catch {
1748
+ return result;
1749
+ }
1750
+ };
1751
+ middlewares.push(validate);
1752
+ }
1753
+ return acc.concat(middlewares);
1754
+ },
1755
+ []
1756
+ ) ?? [];
1757
+ const final = ({ search: search2 }) => {
1758
+ if (!dest.search) {
1759
+ return {};
1760
+ }
1761
+ if (dest.search === true) {
1762
+ return search2;
1763
+ }
1764
+ return functionalUpdate(dest.search, search2);
1765
+ };
1766
+ allMiddlewares.push(final);
1767
+ const applyNext = (index, currentSearch) => {
1768
+ if (index >= allMiddlewares.length) {
1769
+ return currentSearch;
1770
+ }
1771
+ const middleware = allMiddlewares[index];
1772
+ const next = (newSearch) => {
1773
+ return applyNext(index + 1, newSearch);
1774
+ };
1775
+ return middleware({ search: currentSearch, next });
1776
+ };
1777
+ return applyNext(0, search);
1778
+ }
1795
1779
  export {
1796
1780
  PathParamError,
1797
1781
  RouterCore,