@tanstack/react-router 1.49.1 → 1.49.2

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.
@@ -1,7 +1,7 @@
1
1
  import { Store, NoInfer } from '@tanstack/react-store';
2
2
  import { HistoryState, RouterHistory } from '@tanstack/history';
3
3
  import { Manifest } from './manifest.cjs';
4
- import { AnyContext, AnyRoute, AnyRouteWithContext, ErrorRouteComponent, NotFoundRouteComponent, RootRoute, RouteComponent, RouteMask } from './route.cjs';
4
+ import { AnyContext, AnyRoute, AnyRouteWithContext, AnySearchSchema, ErrorRouteComponent, NotFoundRouteComponent, RootRoute, RouteComponent, RouteMask } from './route.cjs';
5
5
  import { FullSearchSchema, RouteById, RoutePaths, RoutesById, RoutesByPath } from './routeInfo.cjs';
6
6
  import { ControlledPromise, NonNullableUpdater, PickAsRequired, Updater } from './utils.cjs';
7
7
  import { AnyRouteMatch, MakeRouteMatch, MatchRouteOptions } from './Matches.cjs';
@@ -423,6 +423,10 @@ export type RouterListener<TRouterEvent extends RouterEvent> = {
423
423
  fn: ListenerFn<TRouterEvent>;
424
424
  };
425
425
  export declare function createRouter<TRouteTree extends AnyRoute, TTrailingSlashOption extends TrailingSlashOption, TDehydrated extends Record<string, any> = Record<string, any>, TSerializedError extends Record<string, any> = Record<string, any>>(options: RouterConstructorOptions<TRouteTree, TTrailingSlashOption, TDehydrated, TSerializedError>): Router<TRouteTree, TTrailingSlashOption, TDehydrated, TSerializedError>;
426
+ type MatchRoutesOpts = {
427
+ preload?: boolean;
428
+ throwOnError?: boolean;
429
+ };
426
430
  export declare class Router<in out TRouteTree extends AnyRoute, in out TTrailingSlashOption extends TrailingSlashOption, in out TDehydrated extends Record<string, any> = Record<string, any>, in out TSerializedError extends Record<string, any> = Record<string, any>> {
427
431
  tempLocationKey: string | undefined;
428
432
  resetNextScroll: boolean;
@@ -465,10 +469,18 @@ export declare class Router<in out TRouteTree extends AnyRoute, in out TTrailing
465
469
  parseLocation: (previousLocation?: ParsedLocation<FullSearchSchema<TRouteTree>>) => ParsedLocation<FullSearchSchema<TRouteTree>>;
466
470
  resolvePathWithBase: (from: string, path: string) => string;
467
471
  get looseRoutesById(): Record<string, AnyRoute>;
468
- matchRoutes: (next: ParsedLocation, opts?: {
469
- preload?: boolean;
470
- throwOnError?: boolean;
471
- }) => Array<AnyRouteMatch>;
472
+ /**
473
+ @deprecated use the following signature instead
474
+ ```ts
475
+ matchRoutes (
476
+ next: ParsedLocation,
477
+ opts?: { preload?: boolean; throwOnError?: boolean },
478
+ ): Array<AnyRouteMatch>;
479
+ ```
480
+ */
481
+ matchRoutes(pathname: string, locationSearch: AnySearchSchema, opts?: MatchRoutesOpts): Array<AnyRouteMatch>;
482
+ matchRoutes(next: ParsedLocation, opts?: MatchRoutesOpts): Array<AnyRouteMatch>;
483
+ private matchRoutesInternal;
472
484
  cancelMatch: (id: string) => void;
473
485
  cancelMatches: () => void;
474
486
  buildLocation: BuildLocationFn;
@@ -518,3 +530,4 @@ export declare function defaultSerializeError(err: unknown): {
518
530
  } | {
519
531
  data: unknown;
520
532
  };
533
+ export {};
@@ -1,7 +1,7 @@
1
1
  import { Store, NoInfer } from '@tanstack/react-store';
2
2
  import { HistoryState, RouterHistory } from '@tanstack/history';
3
3
  import { Manifest } from './manifest.js';
4
- import { AnyContext, AnyRoute, AnyRouteWithContext, ErrorRouteComponent, NotFoundRouteComponent, RootRoute, RouteComponent, RouteMask } from './route.js';
4
+ import { AnyContext, AnyRoute, AnyRouteWithContext, AnySearchSchema, ErrorRouteComponent, NotFoundRouteComponent, RootRoute, RouteComponent, RouteMask } from './route.js';
5
5
  import { FullSearchSchema, RouteById, RoutePaths, RoutesById, RoutesByPath } from './routeInfo.js';
6
6
  import { ControlledPromise, NonNullableUpdater, PickAsRequired, Updater } from './utils.js';
7
7
  import { AnyRouteMatch, MakeRouteMatch, MatchRouteOptions } from './Matches.js';
@@ -423,6 +423,10 @@ export type RouterListener<TRouterEvent extends RouterEvent> = {
423
423
  fn: ListenerFn<TRouterEvent>;
424
424
  };
425
425
  export declare function createRouter<TRouteTree extends AnyRoute, TTrailingSlashOption extends TrailingSlashOption, TDehydrated extends Record<string, any> = Record<string, any>, TSerializedError extends Record<string, any> = Record<string, any>>(options: RouterConstructorOptions<TRouteTree, TTrailingSlashOption, TDehydrated, TSerializedError>): Router<TRouteTree, TTrailingSlashOption, TDehydrated, TSerializedError>;
426
+ type MatchRoutesOpts = {
427
+ preload?: boolean;
428
+ throwOnError?: boolean;
429
+ };
426
430
  export declare class Router<in out TRouteTree extends AnyRoute, in out TTrailingSlashOption extends TrailingSlashOption, in out TDehydrated extends Record<string, any> = Record<string, any>, in out TSerializedError extends Record<string, any> = Record<string, any>> {
427
431
  tempLocationKey: string | undefined;
428
432
  resetNextScroll: boolean;
@@ -465,10 +469,18 @@ export declare class Router<in out TRouteTree extends AnyRoute, in out TTrailing
465
469
  parseLocation: (previousLocation?: ParsedLocation<FullSearchSchema<TRouteTree>>) => ParsedLocation<FullSearchSchema<TRouteTree>>;
466
470
  resolvePathWithBase: (from: string, path: string) => string;
467
471
  get looseRoutesById(): Record<string, AnyRoute>;
468
- matchRoutes: (next: ParsedLocation, opts?: {
469
- preload?: boolean;
470
- throwOnError?: boolean;
471
- }) => Array<AnyRouteMatch>;
472
+ /**
473
+ @deprecated use the following signature instead
474
+ ```ts
475
+ matchRoutes (
476
+ next: ParsedLocation,
477
+ opts?: { preload?: boolean; throwOnError?: boolean },
478
+ ): Array<AnyRouteMatch>;
479
+ ```
480
+ */
481
+ matchRoutes(pathname: string, locationSearch: AnySearchSchema, opts?: MatchRoutesOpts): Array<AnyRouteMatch>;
482
+ matchRoutes(next: ParsedLocation, opts?: MatchRoutesOpts): Array<AnyRouteMatch>;
483
+ private matchRoutesInternal;
472
484
  cancelMatch: (id: string) => void;
473
485
  cancelMatches: () => void;
474
486
  buildLocation: BuildLocationFn;
@@ -518,3 +530,4 @@ export declare function defaultSerializeError(err: unknown): {
518
530
  } | {
519
531
  data: unknown;
520
532
  };
533
+ export {};
@@ -4,7 +4,7 @@ import invariant from "tiny-invariant";
4
4
  import warning from "tiny-warning";
5
5
  import { rootRouteId } from "./root.js";
6
6
  import { defaultStringifySearch, defaultParseSearch } from "./searchParams.js";
7
- import { createControlledPromise, replaceEqualDeep, pick, deepEqual, last, functionalUpdate } from "./utils.js";
7
+ import { pick, createControlledPromise, deepEqual, replaceEqualDeep, last, functionalUpdate } from "./utils.js";
8
8
  import { trimPath, trimPathLeft, parsePathname, resolvePath, cleanPath, matchPathname, trimPathRight, interpolatePath, joinPaths } from "./path.js";
9
9
  import { isResolvedRedirect, isRedirect } from "./redirects.js";
10
10
  import { isNotFound } from "./not-found.js";
@@ -209,200 +209,6 @@ class Router {
209
209
  });
210
210
  return resolvedPath;
211
211
  };
212
- this.matchRoutes = (next, opts) => {
213
- let routeParams = {};
214
- const foundRoute = this.flatRoutes.find((route) => {
215
- const matchedParams = matchPathname(
216
- this.basepath,
217
- trimPathRight(next.pathname),
218
- {
219
- to: route.fullPath,
220
- caseSensitive: route.options.caseSensitive ?? this.options.caseSensitive,
221
- fuzzy: true
222
- }
223
- );
224
- if (matchedParams) {
225
- routeParams = matchedParams;
226
- return true;
227
- }
228
- return false;
229
- });
230
- let routeCursor = foundRoute || this.routesById[rootRouteId];
231
- const matchedRoutes = [routeCursor];
232
- let isGlobalNotFound = false;
233
- if (
234
- // If we found a route, and it's not an index route and we have left over path
235
- foundRoute ? foundRoute.path !== "/" && routeParams["**"] : (
236
- // Or if we didn't find a route and we have left over path
237
- trimPathRight(next.pathname)
238
- )
239
- ) {
240
- if (this.options.notFoundRoute) {
241
- matchedRoutes.push(this.options.notFoundRoute);
242
- } else {
243
- isGlobalNotFound = true;
244
- }
245
- }
246
- while (routeCursor.parentRoute) {
247
- routeCursor = routeCursor.parentRoute;
248
- matchedRoutes.unshift(routeCursor);
249
- }
250
- const globalNotFoundRouteId = (() => {
251
- if (!isGlobalNotFound) {
252
- return void 0;
253
- }
254
- if (this.options.notFoundMode !== "root") {
255
- for (let i = matchedRoutes.length - 1; i >= 0; i--) {
256
- const route = matchedRoutes[i];
257
- if (route.children) {
258
- return route.id;
259
- }
260
- }
261
- }
262
- return rootRouteId;
263
- })();
264
- const parseErrors = matchedRoutes.map((route) => {
265
- var _a;
266
- let parsedParamsError;
267
- const parseParams = ((_a = route.options.params) == null ? void 0 : _a.parse) ?? route.options.parseParams;
268
- if (parseParams) {
269
- try {
270
- const parsedParams = parseParams(routeParams);
271
- Object.assign(routeParams, parsedParams);
272
- } catch (err) {
273
- parsedParamsError = new PathParamError(err.message, {
274
- cause: err
275
- });
276
- if (opts == null ? void 0 : opts.throwOnError) {
277
- throw parsedParamsError;
278
- }
279
- return parsedParamsError;
280
- }
281
- }
282
- return;
283
- });
284
- const matches = [];
285
- matchedRoutes.forEach((route, index) => {
286
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
287
- const parentMatch = matches[index - 1];
288
- const [preMatchSearch, searchError] = (() => {
289
- const parentSearch = (parentMatch == null ? void 0 : parentMatch.search) ?? next.search;
290
- try {
291
- const validator = typeof route.options.validateSearch === "object" ? route.options.validateSearch.parse : route.options.validateSearch;
292
- const search = (validator == null ? void 0 : validator(parentSearch)) ?? {};
293
- return [
294
- {
295
- ...parentSearch,
296
- ...search
297
- },
298
- void 0
299
- ];
300
- } catch (err) {
301
- const searchParamError = new SearchParamError(err.message, {
302
- cause: err
303
- });
304
- if (opts == null ? void 0 : opts.throwOnError) {
305
- throw searchParamError;
306
- }
307
- return [parentSearch, searchParamError];
308
- }
309
- })();
310
- const loaderDeps = ((_b = (_a = route.options).loaderDeps) == null ? void 0 : _b.call(_a, {
311
- search: preMatchSearch
312
- })) ?? "";
313
- const loaderDepsHash = loaderDeps ? JSON.stringify(loaderDeps) : "";
314
- const interpolatedPath = interpolatePath({
315
- path: route.fullPath,
316
- params: routeParams
317
- });
318
- const matchId = interpolatePath({
319
- path: route.id,
320
- params: routeParams,
321
- leaveWildcards: true
322
- }) + loaderDepsHash;
323
- const existingMatch = this.getMatch(matchId);
324
- const cause = this.state.matches.find((d) => d.id === matchId) ? "stay" : "enter";
325
- let match;
326
- if (existingMatch) {
327
- match = {
328
- ...existingMatch,
329
- cause,
330
- params: routeParams
331
- };
332
- } else {
333
- const status = route.options.loader || route.options.beforeLoad || route.lazyFn ? "pending" : "success";
334
- match = {
335
- id: matchId,
336
- index,
337
- routeId: route.id,
338
- params: routeParams,
339
- pathname: joinPaths([this.basepath, interpolatedPath]),
340
- updatedAt: Date.now(),
341
- search: {},
342
- searchError: void 0,
343
- status,
344
- isFetching: false,
345
- error: void 0,
346
- paramsError: parseErrors[index],
347
- __routeContext: {},
348
- __beforeLoadContext: {},
349
- context: {},
350
- abortController: new AbortController(),
351
- fetchCount: 0,
352
- cause,
353
- loaderDeps,
354
- invalid: false,
355
- preload: false,
356
- links: (_d = (_c = route.options).links) == null ? void 0 : _d.call(_c),
357
- scripts: (_f = (_e = route.options).scripts) == null ? void 0 : _f.call(_e),
358
- staticData: route.options.staticData || {},
359
- loadPromise: createControlledPromise()
360
- };
361
- }
362
- if (match.status === "success") {
363
- match.meta = (_h = (_g = route.options).meta) == null ? void 0 : _h.call(_g, {
364
- matches,
365
- match,
366
- params: match.params,
367
- loaderData: match.loaderData
368
- });
369
- match.headers = (_j = (_i = route.options).headers) == null ? void 0 : _j.call(_i, {
370
- loaderData: match.loaderData
371
- });
372
- }
373
- if (!(opts == null ? void 0 : opts.preload)) {
374
- match.globalNotFound = globalNotFoundRouteId === route.id;
375
- }
376
- match.search = replaceEqualDeep(match.search, preMatchSearch);
377
- match.searchError = searchError;
378
- const parentMatchId = parentMatch == null ? void 0 : parentMatch.id;
379
- const parentContext = !parentMatchId ? this.options.context ?? {} : parentMatch.context ?? this.options.context ?? {};
380
- match.context = {
381
- ...parentContext,
382
- ...match.__routeContext,
383
- ...match.__beforeLoadContext
384
- };
385
- const contextFnContext = {
386
- search: match.search,
387
- params: match.params,
388
- context: match.context,
389
- location: next,
390
- navigate: (opts2) => this.navigate({ ...opts2, _fromLocation: next }),
391
- buildLocation: this.buildLocation,
392
- cause: match.cause,
393
- abortController: match.abortController,
394
- preload: !!match.preload
395
- };
396
- match.__routeContext = ((_l = (_k = route.options).context) == null ? void 0 : _l.call(_k, contextFnContext)) ?? {};
397
- match.context = {
398
- ...parentContext,
399
- ...match.__routeContext,
400
- ...match.__beforeLoadContext
401
- };
402
- matches.push(match);
403
- });
404
- return matches;
405
- };
406
212
  this.cancelMatch = (id) => {
407
213
  const match = this.getMatch(id);
408
214
  if (!match) return;
@@ -1414,6 +1220,213 @@ class Router {
1414
1220
  get looseRoutesById() {
1415
1221
  return this.routesById;
1416
1222
  }
1223
+ matchRoutes(pathnameOrNext, locationSearchOrOpts, opts) {
1224
+ if (typeof pathnameOrNext === "string") {
1225
+ return this.matchRoutesInternal(
1226
+ {
1227
+ pathname: pathnameOrNext,
1228
+ search: locationSearchOrOpts
1229
+ },
1230
+ opts
1231
+ );
1232
+ } else {
1233
+ return this.matchRoutesInternal(pathnameOrNext, locationSearchOrOpts);
1234
+ }
1235
+ }
1236
+ matchRoutesInternal(next, opts) {
1237
+ let routeParams = {};
1238
+ const foundRoute = this.flatRoutes.find((route) => {
1239
+ const matchedParams = matchPathname(
1240
+ this.basepath,
1241
+ trimPathRight(next.pathname),
1242
+ {
1243
+ to: route.fullPath,
1244
+ caseSensitive: route.options.caseSensitive ?? this.options.caseSensitive,
1245
+ fuzzy: true
1246
+ }
1247
+ );
1248
+ if (matchedParams) {
1249
+ routeParams = matchedParams;
1250
+ return true;
1251
+ }
1252
+ return false;
1253
+ });
1254
+ let routeCursor = foundRoute || this.routesById[rootRouteId];
1255
+ const matchedRoutes = [routeCursor];
1256
+ let isGlobalNotFound = false;
1257
+ if (
1258
+ // If we found a route, and it's not an index route and we have left over path
1259
+ foundRoute ? foundRoute.path !== "/" && routeParams["**"] : (
1260
+ // Or if we didn't find a route and we have left over path
1261
+ trimPathRight(next.pathname)
1262
+ )
1263
+ ) {
1264
+ if (this.options.notFoundRoute) {
1265
+ matchedRoutes.push(this.options.notFoundRoute);
1266
+ } else {
1267
+ isGlobalNotFound = true;
1268
+ }
1269
+ }
1270
+ while (routeCursor.parentRoute) {
1271
+ routeCursor = routeCursor.parentRoute;
1272
+ matchedRoutes.unshift(routeCursor);
1273
+ }
1274
+ const globalNotFoundRouteId = (() => {
1275
+ if (!isGlobalNotFound) {
1276
+ return void 0;
1277
+ }
1278
+ if (this.options.notFoundMode !== "root") {
1279
+ for (let i = matchedRoutes.length - 1; i >= 0; i--) {
1280
+ const route = matchedRoutes[i];
1281
+ if (route.children) {
1282
+ return route.id;
1283
+ }
1284
+ }
1285
+ }
1286
+ return rootRouteId;
1287
+ })();
1288
+ const parseErrors = matchedRoutes.map((route) => {
1289
+ var _a;
1290
+ let parsedParamsError;
1291
+ const parseParams = ((_a = route.options.params) == null ? void 0 : _a.parse) ?? route.options.parseParams;
1292
+ if (parseParams) {
1293
+ try {
1294
+ const parsedParams = parseParams(routeParams);
1295
+ Object.assign(routeParams, parsedParams);
1296
+ } catch (err) {
1297
+ parsedParamsError = new PathParamError(err.message, {
1298
+ cause: err
1299
+ });
1300
+ if (opts == null ? void 0 : opts.throwOnError) {
1301
+ throw parsedParamsError;
1302
+ }
1303
+ return parsedParamsError;
1304
+ }
1305
+ }
1306
+ return;
1307
+ });
1308
+ const matches = [];
1309
+ matchedRoutes.forEach((route, index) => {
1310
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
1311
+ const parentMatch = matches[index - 1];
1312
+ const [preMatchSearch, searchError] = (() => {
1313
+ const parentSearch = (parentMatch == null ? void 0 : parentMatch.search) ?? next.search;
1314
+ try {
1315
+ const validator = typeof route.options.validateSearch === "object" ? route.options.validateSearch.parse : route.options.validateSearch;
1316
+ const search = (validator == null ? void 0 : validator(parentSearch)) ?? {};
1317
+ return [
1318
+ {
1319
+ ...parentSearch,
1320
+ ...search
1321
+ },
1322
+ void 0
1323
+ ];
1324
+ } catch (err) {
1325
+ const searchParamError = new SearchParamError(err.message, {
1326
+ cause: err
1327
+ });
1328
+ if (opts == null ? void 0 : opts.throwOnError) {
1329
+ throw searchParamError;
1330
+ }
1331
+ return [parentSearch, searchParamError];
1332
+ }
1333
+ })();
1334
+ const loaderDeps = ((_b = (_a = route.options).loaderDeps) == null ? void 0 : _b.call(_a, {
1335
+ search: preMatchSearch
1336
+ })) ?? "";
1337
+ const loaderDepsHash = loaderDeps ? JSON.stringify(loaderDeps) : "";
1338
+ const interpolatedPath = interpolatePath({
1339
+ path: route.fullPath,
1340
+ params: routeParams
1341
+ });
1342
+ const matchId = interpolatePath({
1343
+ path: route.id,
1344
+ params: routeParams,
1345
+ leaveWildcards: true
1346
+ }) + loaderDepsHash;
1347
+ const existingMatch = this.getMatch(matchId);
1348
+ const cause = this.state.matches.find((d) => d.id === matchId) ? "stay" : "enter";
1349
+ let match;
1350
+ if (existingMatch) {
1351
+ match = {
1352
+ ...existingMatch,
1353
+ cause,
1354
+ params: routeParams
1355
+ };
1356
+ } else {
1357
+ const status = route.options.loader || route.options.beforeLoad || route.lazyFn ? "pending" : "success";
1358
+ match = {
1359
+ id: matchId,
1360
+ index,
1361
+ routeId: route.id,
1362
+ params: routeParams,
1363
+ pathname: joinPaths([this.basepath, interpolatedPath]),
1364
+ updatedAt: Date.now(),
1365
+ search: {},
1366
+ searchError: void 0,
1367
+ status,
1368
+ isFetching: false,
1369
+ error: void 0,
1370
+ paramsError: parseErrors[index],
1371
+ __routeContext: {},
1372
+ __beforeLoadContext: {},
1373
+ context: {},
1374
+ abortController: new AbortController(),
1375
+ fetchCount: 0,
1376
+ cause,
1377
+ loaderDeps,
1378
+ invalid: false,
1379
+ preload: false,
1380
+ links: (_d = (_c = route.options).links) == null ? void 0 : _d.call(_c),
1381
+ scripts: (_f = (_e = route.options).scripts) == null ? void 0 : _f.call(_e),
1382
+ staticData: route.options.staticData || {},
1383
+ loadPromise: createControlledPromise()
1384
+ };
1385
+ }
1386
+ if (match.status === "success") {
1387
+ match.meta = (_h = (_g = route.options).meta) == null ? void 0 : _h.call(_g, {
1388
+ matches,
1389
+ match,
1390
+ params: match.params,
1391
+ loaderData: match.loaderData
1392
+ });
1393
+ match.headers = (_j = (_i = route.options).headers) == null ? void 0 : _j.call(_i, {
1394
+ loaderData: match.loaderData
1395
+ });
1396
+ }
1397
+ if (!(opts == null ? void 0 : opts.preload)) {
1398
+ match.globalNotFound = globalNotFoundRouteId === route.id;
1399
+ }
1400
+ match.search = replaceEqualDeep(match.search, preMatchSearch);
1401
+ match.searchError = searchError;
1402
+ const parentMatchId = parentMatch == null ? void 0 : parentMatch.id;
1403
+ const parentContext = !parentMatchId ? this.options.context ?? {} : parentMatch.context ?? this.options.context ?? {};
1404
+ match.context = {
1405
+ ...parentContext,
1406
+ ...match.__routeContext,
1407
+ ...match.__beforeLoadContext
1408
+ };
1409
+ const contextFnContext = {
1410
+ search: match.search,
1411
+ params: match.params,
1412
+ context: match.context,
1413
+ location: next,
1414
+ navigate: (opts2) => this.navigate({ ...opts2, _fromLocation: next }),
1415
+ buildLocation: this.buildLocation,
1416
+ cause: match.cause,
1417
+ abortController: match.abortController,
1418
+ preload: !!match.preload
1419
+ };
1420
+ match.__routeContext = ((_l = (_k = route.options).context) == null ? void 0 : _l.call(_k, contextFnContext)) ?? {};
1421
+ match.context = {
1422
+ ...parentContext,
1423
+ ...match.__routeContext,
1424
+ ...match.__beforeLoadContext
1425
+ };
1426
+ matches.push(match);
1427
+ });
1428
+ return matches;
1429
+ }
1417
1430
  }
1418
1431
  function lazyFn(fn, key) {
1419
1432
  return async (...args) => {