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

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