@tanstack/router-core 1.132.0-alpha.12 → 1.132.0-alpha.16
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/dist/cjs/index.cjs +5 -1
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +3 -1
- package/dist/cjs/location.d.cts +38 -0
- package/dist/cjs/path.cjs +6 -49
- package/dist/cjs/path.cjs.map +1 -1
- package/dist/cjs/path.d.cts +3 -6
- package/dist/cjs/rewrite.cjs +63 -0
- package/dist/cjs/rewrite.cjs.map +1 -0
- package/dist/cjs/rewrite.d.cts +22 -0
- package/dist/cjs/router.cjs +50 -29
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +49 -2
- package/dist/esm/index.d.ts +3 -1
- package/dist/esm/index.js +6 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/location.d.ts +38 -0
- package/dist/esm/path.d.ts +3 -6
- package/dist/esm/path.js +6 -49
- package/dist/esm/path.js.map +1 -1
- package/dist/esm/rewrite.d.ts +22 -0
- package/dist/esm/rewrite.js +63 -0
- package/dist/esm/rewrite.js.map +1 -0
- package/dist/esm/router.d.ts +49 -2
- package/dist/esm/router.js +52 -31
- package/dist/esm/router.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +8 -1
- package/src/location.ts +38 -0
- package/src/path.ts +5 -66
- package/src/rewrite.ts +70 -0
- package/src/router.ts +129 -49
package/dist/esm/router.d.ts
CHANGED
|
@@ -178,6 +178,18 @@ export interface RouterOptions<TRouteTree extends AnyRoute, TTrailingSlashOption
|
|
|
178
178
|
/**
|
|
179
179
|
* The basepath for then entire router. This is useful for mounting a router instance at a subpath.
|
|
180
180
|
*
|
|
181
|
+
* @deprecated - use `rewrite.input` with the new `rewriteBasepath` utility instead:
|
|
182
|
+
* ```ts
|
|
183
|
+
* const router = createRouter({
|
|
184
|
+
* routeTree,
|
|
185
|
+
* rewrite: rewriteBasepath('/basepath')
|
|
186
|
+
* // Or wrap existing rewrite functionality
|
|
187
|
+
* rewrite: rewriteBasepath('/basepath', {
|
|
188
|
+
* output: ({ url }) => {...},
|
|
189
|
+
* input: ({ url }) => {...},
|
|
190
|
+
* })
|
|
191
|
+
* })
|
|
192
|
+
* ```
|
|
181
193
|
* @default '/'
|
|
182
194
|
* @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#basepath-property)
|
|
183
195
|
*/
|
|
@@ -328,7 +340,41 @@ export interface RouterOptions<TRouteTree extends AnyRoute, TTrailingSlashOption
|
|
|
328
340
|
*/
|
|
329
341
|
disableGlobalCatchBoundary?: boolean;
|
|
330
342
|
serializationAdapters?: ReadonlyArray<AnySerializationAdapter>;
|
|
343
|
+
/**
|
|
344
|
+
* Configures how the router will rewrite the location between the actual href and the internal href of the router.
|
|
345
|
+
*
|
|
346
|
+
* @default undefined
|
|
347
|
+
* @description You can provide a custom rewrite pair (in/out) or use the utilities like `rewriteBasepath` as a convenience for common use cases, or even do both!
|
|
348
|
+
* This is useful for basepath rewriting, shifting data from the origin to the path (for things like )
|
|
349
|
+
*/
|
|
350
|
+
rewrite?: LocationRewrite;
|
|
351
|
+
origin?: string;
|
|
331
352
|
}
|
|
353
|
+
export type LocationRewrite = {
|
|
354
|
+
/**
|
|
355
|
+
* A function that will be called to rewrite the URL before it is interpreted by the router from the history instance.
|
|
356
|
+
* Utilities like `rewriteBasepath` are provided as a convenience for common use cases.
|
|
357
|
+
*
|
|
358
|
+
* @default undefined
|
|
359
|
+
*/
|
|
360
|
+
input?: LocationRewriteFunction;
|
|
361
|
+
/**
|
|
362
|
+
* A function that will be called to rewrite the URL before it is committed to the actual history instance from the router.
|
|
363
|
+
* Utilities like `rewriteBasepath` are provided as a convenience for common use cases.
|
|
364
|
+
*
|
|
365
|
+
* @default undefined
|
|
366
|
+
*/
|
|
367
|
+
output?: LocationRewriteFunction;
|
|
368
|
+
};
|
|
369
|
+
/**
|
|
370
|
+
* A function that will be called to rewrite the URL.
|
|
371
|
+
*
|
|
372
|
+
* @param url The URL to rewrite.
|
|
373
|
+
* @returns The rewritten URL (as a URL instance or full href string) or undefined if no rewrite is needed.
|
|
374
|
+
*/
|
|
375
|
+
export type LocationRewriteFunction = ({ url, }: {
|
|
376
|
+
url: URL;
|
|
377
|
+
}) => undefined | string | URL;
|
|
332
378
|
export interface RouterState<in out TRouteTree extends AnyRoute = AnyRoute, in out TRouteMatch = MakeRouteMatchUnion> {
|
|
333
379
|
status: 'pending' | 'idle';
|
|
334
380
|
loadedAt: number;
|
|
@@ -495,6 +541,8 @@ export declare class RouterCore<in out TRouteTree extends AnyRoute, in out TTrai
|
|
|
495
541
|
__store: Store<RouterState<TRouteTree>>;
|
|
496
542
|
options: PickAsRequired<RouterOptions<TRouteTree, TTrailingSlashOption, TDefaultStructuralSharingOption, TRouterHistory, TDehydrated>, 'stringifySearch' | 'parseSearch' | 'context'>;
|
|
497
543
|
history: TRouterHistory;
|
|
544
|
+
rewrite?: LocationRewrite;
|
|
545
|
+
origin?: string;
|
|
498
546
|
latestLocation: ParsedLocation<FullSearchSchema<TRouteTree>>;
|
|
499
547
|
basepath: string;
|
|
500
548
|
routeTree: TRouteTree;
|
|
@@ -577,10 +625,9 @@ export declare function processRouteTree<TRouteLike extends RouteLike>({ routeTr
|
|
|
577
625
|
routeTree: TRouteLike;
|
|
578
626
|
initRoute?: (route: TRouteLike, index: number) => void;
|
|
579
627
|
}): ProcessRouteTreeResult<TRouteLike>;
|
|
580
|
-
export declare function getMatchedRoutes<TRouteLike extends RouteLike>({ pathname, routePathname,
|
|
628
|
+
export declare function getMatchedRoutes<TRouteLike extends RouteLike>({ pathname, routePathname, caseSensitive, routesByPath, routesById, flatRoutes, parseCache, }: {
|
|
581
629
|
pathname: string;
|
|
582
630
|
routePathname?: string;
|
|
583
|
-
basepath: string;
|
|
584
631
|
caseSensitive?: boolean;
|
|
585
632
|
routesByPath: Record<string, TRouteLike>;
|
|
586
633
|
routesById: Record<string, TRouteLike>;
|
package/dist/esm/router.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Store, batch } from "@tanstack/store";
|
|
2
|
-
import {
|
|
2
|
+
import { createBrowserHistory, parseHref } from "@tanstack/history";
|
|
3
3
|
import invariant from "tiny-invariant";
|
|
4
4
|
import { createControlledPromise, deepEqual, replaceEqualDeep, last, findLast, functionalUpdate } from "./utils.js";
|
|
5
|
-
import {
|
|
5
|
+
import { resolvePath, cleanPath, trimPathRight, trimPath, matchPathname, interpolatePath, trimPathLeft, parsePathname, SEGMENT_TYPE_PARAM, SEGMENT_TYPE_OPTIONAL_PARAM, SEGMENT_TYPE_WILDCARD, SEGMENT_TYPE_PATHNAME } 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";
|
|
@@ -10,6 +10,7 @@ import { rootRouteId } from "./root.js";
|
|
|
10
10
|
import { redirect, isRedirect } from "./redirect.js";
|
|
11
11
|
import { createLRUCache } from "./lru-cache.js";
|
|
12
12
|
import { loadMatches, loadRouteChunk, routeNeedsPreload } from "./load-matches.js";
|
|
13
|
+
import { rewriteBasepath, composeRewrites, executeRewriteInput, executeRewriteOutput } from "./rewrite.js";
|
|
13
14
|
function defaultSerializeError(err) {
|
|
14
15
|
if (err instanceof Error) {
|
|
15
16
|
const obj = {
|
|
@@ -54,7 +55,6 @@ class RouterCore {
|
|
|
54
55
|
"The notFoundRoute API is deprecated and will be removed in the next major version. See https://tanstack.com/router/v1/docs/framework/react/guide/not-found-errors#migrating-from-notfoundroute for more info."
|
|
55
56
|
);
|
|
56
57
|
}
|
|
57
|
-
const previousOptions = this.options;
|
|
58
58
|
this.options = {
|
|
59
59
|
...this.options,
|
|
60
60
|
...newOptions
|
|
@@ -66,24 +66,43 @@ class RouterCore {
|
|
|
66
66
|
char
|
|
67
67
|
])
|
|
68
68
|
) : void 0;
|
|
69
|
-
if (!this.
|
|
70
|
-
if (
|
|
71
|
-
this.
|
|
69
|
+
if (!this.history || this.options.history && this.options.history !== this.history) {
|
|
70
|
+
if (!this.options.history) {
|
|
71
|
+
if (!this.isServer) {
|
|
72
|
+
this.history = createBrowserHistory();
|
|
73
|
+
}
|
|
72
74
|
} else {
|
|
73
|
-
this.
|
|
75
|
+
this.history = this.options.history;
|
|
74
76
|
}
|
|
75
77
|
}
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
})
|
|
78
|
+
if (this.options.basepath) {
|
|
79
|
+
const basepathRewrite = rewriteBasepath({
|
|
80
|
+
basepath: this.options.basepath
|
|
81
|
+
});
|
|
82
|
+
if (this.options.rewrite) {
|
|
83
|
+
this.rewrite = composeRewrites([basepathRewrite, this.options.rewrite]);
|
|
84
|
+
} else {
|
|
85
|
+
this.rewrite = basepathRewrite;
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
this.rewrite = this.options.rewrite;
|
|
89
|
+
}
|
|
90
|
+
this.origin = this.options.origin;
|
|
91
|
+
if (!this.origin) {
|
|
92
|
+
if (!this.isServer) {
|
|
93
|
+
this.origin = window.origin;
|
|
94
|
+
} else {
|
|
95
|
+
this.origin = "http://localhost";
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (this.history) {
|
|
80
99
|
this.updateLatestLocation();
|
|
81
100
|
}
|
|
82
101
|
if (this.options.routeTree !== this.routeTree) {
|
|
83
102
|
this.routeTree = this.options.routeTree;
|
|
84
103
|
this.buildRouteTree();
|
|
85
104
|
}
|
|
86
|
-
if (!this.__store) {
|
|
105
|
+
if (!this.__store && this.latestLocation) {
|
|
87
106
|
this.__store = new Store(getInitialRouterState(this.latestLocation), {
|
|
88
107
|
onUpdate: () => {
|
|
89
108
|
this.__store.state = {
|
|
@@ -147,19 +166,24 @@ class RouterCore {
|
|
|
147
166
|
};
|
|
148
167
|
this.parseLocation = (locationToParse, previousLocation) => {
|
|
149
168
|
const parse = ({
|
|
150
|
-
|
|
151
|
-
search,
|
|
152
|
-
hash,
|
|
169
|
+
href,
|
|
153
170
|
state
|
|
154
171
|
}) => {
|
|
155
|
-
const
|
|
172
|
+
const fullUrl = new URL(href, this.origin);
|
|
173
|
+
const url = executeRewriteInput(this.rewrite, fullUrl);
|
|
174
|
+
const parsedSearch = this.options.parseSearch(url.search);
|
|
156
175
|
const searchStr = this.options.stringifySearch(parsedSearch);
|
|
176
|
+
url.search = searchStr;
|
|
177
|
+
const fullPath = url.href.replace(url.origin, "");
|
|
178
|
+
const { pathname, hash } = url;
|
|
157
179
|
return {
|
|
180
|
+
href: fullPath,
|
|
181
|
+
publicHref: href,
|
|
182
|
+
url: url.href,
|
|
158
183
|
pathname,
|
|
159
184
|
searchStr,
|
|
160
185
|
search: replaceEqualDeep(previousLocation?.search, parsedSearch),
|
|
161
186
|
hash: hash.split("#").reverse()[0] ?? "",
|
|
162
|
-
href: `${pathname}${searchStr}${hash}`,
|
|
163
187
|
state: replaceEqualDeep(previousLocation?.state, state)
|
|
164
188
|
};
|
|
165
189
|
};
|
|
@@ -179,11 +203,9 @@ class RouterCore {
|
|
|
179
203
|
};
|
|
180
204
|
this.resolvePathWithBase = (from, path) => {
|
|
181
205
|
const resolvedPath = resolvePath({
|
|
182
|
-
basepath: this.basepath,
|
|
183
206
|
base: from,
|
|
184
207
|
to: cleanPath(path),
|
|
185
208
|
trailingSlash: this.options.trailingSlash,
|
|
186
|
-
caseSensitive: this.options.caseSensitive,
|
|
187
209
|
parseCache: this.parsePathnameCache
|
|
188
210
|
});
|
|
189
211
|
return resolvedPath;
|
|
@@ -205,7 +227,6 @@ class RouterCore {
|
|
|
205
227
|
return getMatchedRoutes({
|
|
206
228
|
pathname,
|
|
207
229
|
routePathname,
|
|
208
|
-
basepath: this.basepath,
|
|
209
230
|
caseSensitive: this.options.caseSensitive,
|
|
210
231
|
routesByPath: this.routesByPath,
|
|
211
232
|
routesById: this.routesById,
|
|
@@ -313,13 +334,18 @@ class RouterCore {
|
|
|
313
334
|
const hashStr = hash ? `#${hash}` : "";
|
|
314
335
|
let nextState = dest.state === true ? currentLocation.state : dest.state ? functionalUpdate(dest.state, currentLocation.state) : {};
|
|
315
336
|
nextState = replaceEqualDeep(currentLocation.state, nextState);
|
|
337
|
+
const fullPath = `${nextPathname}${searchStr}${hashStr}`;
|
|
338
|
+
const url = new URL(fullPath, this.origin);
|
|
339
|
+
const rewrittenUrl = executeRewriteOutput(this.rewrite, url);
|
|
316
340
|
return {
|
|
341
|
+
publicHref: rewrittenUrl.pathname + rewrittenUrl.search + rewrittenUrl.hash,
|
|
342
|
+
href: fullPath,
|
|
343
|
+
url: rewrittenUrl.href,
|
|
317
344
|
pathname: nextPathname,
|
|
318
345
|
search: nextSearch,
|
|
319
346
|
searchStr,
|
|
320
347
|
state: nextState,
|
|
321
348
|
hash: hash ?? "",
|
|
322
|
-
href: `${nextPathname}${searchStr}${hashStr}`,
|
|
323
349
|
unmaskOnReload: dest.unmaskOnReload
|
|
324
350
|
};
|
|
325
351
|
};
|
|
@@ -330,7 +356,6 @@ class RouterCore {
|
|
|
330
356
|
let params = {};
|
|
331
357
|
const foundMask = this.options.routeMasks?.find((d) => {
|
|
332
358
|
const match = matchPathname(
|
|
333
|
-
this.basepath,
|
|
334
359
|
next.pathname,
|
|
335
360
|
{
|
|
336
361
|
to: d.from,
|
|
@@ -356,8 +381,7 @@ class RouterCore {
|
|
|
356
381
|
}
|
|
357
382
|
}
|
|
358
383
|
if (maskedNext) {
|
|
359
|
-
|
|
360
|
-
next.maskedLocation = maskedFinal;
|
|
384
|
+
next.maskedLocation = maskedNext;
|
|
361
385
|
}
|
|
362
386
|
return next;
|
|
363
387
|
};
|
|
@@ -391,7 +415,7 @@ class RouterCore {
|
|
|
391
415
|
});
|
|
392
416
|
return isEqual;
|
|
393
417
|
};
|
|
394
|
-
const isSameUrl = this.latestLocation.href === next.href;
|
|
418
|
+
const isSameUrl = trimPathRight(this.latestLocation.href) === trimPathRight(next.href);
|
|
395
419
|
const previousCommitPromise = this.commitLocationPromise;
|
|
396
420
|
this.commitLocationPromise = createControlledPromise(() => {
|
|
397
421
|
previousCommitPromise?.resolve();
|
|
@@ -427,7 +451,7 @@ class RouterCore {
|
|
|
427
451
|
nextHistory.state.__hashScrollIntoViewOptions = hashScrollIntoView ?? this.options.defaultHashScrollIntoView ?? true;
|
|
428
452
|
this.shouldViewTransition = viewTransition;
|
|
429
453
|
this.history[next.replace ? "replace" : "push"](
|
|
430
|
-
nextHistory.
|
|
454
|
+
nextHistory.publicHref,
|
|
431
455
|
nextHistory.state,
|
|
432
456
|
{ ignoreBlocker }
|
|
433
457
|
);
|
|
@@ -480,7 +504,7 @@ class RouterCore {
|
|
|
480
504
|
if (reloadDocument) {
|
|
481
505
|
if (!href) {
|
|
482
506
|
const location = this.buildLocation({ to, ...rest });
|
|
483
|
-
href =
|
|
507
|
+
href = location.href;
|
|
484
508
|
}
|
|
485
509
|
if (rest.replace) {
|
|
486
510
|
window.location.replace(href);
|
|
@@ -827,7 +851,6 @@ class RouterCore {
|
|
|
827
851
|
const pending = opts?.pending === void 0 ? !this.state.isLoading : opts.pending;
|
|
828
852
|
const baseLocation = pending ? this.latestLocation : this.state.resolvedLocation || this.state.location;
|
|
829
853
|
const match = matchPathname(
|
|
830
|
-
this.basepath,
|
|
831
854
|
baseLocation.pathname,
|
|
832
855
|
{
|
|
833
856
|
...opts,
|
|
@@ -1005,7 +1028,7 @@ class RouterCore {
|
|
|
1005
1028
|
routeId: route.id,
|
|
1006
1029
|
params: previousMatch ? replaceEqualDeep(previousMatch.params, routeParams) : routeParams,
|
|
1007
1030
|
_strictParams: usedParams,
|
|
1008
|
-
pathname:
|
|
1031
|
+
pathname: interpolatedPath,
|
|
1009
1032
|
updatedAt: Date.now(),
|
|
1010
1033
|
search: previousMatch ? replaceEqualDeep(previousMatch.search, preMatchSearch) : preMatchSearch,
|
|
1011
1034
|
_strictSearch: strictMatchSearch,
|
|
@@ -1257,7 +1280,6 @@ function processRouteTree({
|
|
|
1257
1280
|
function getMatchedRoutes({
|
|
1258
1281
|
pathname,
|
|
1259
1282
|
routePathname,
|
|
1260
|
-
basepath,
|
|
1261
1283
|
caseSensitive,
|
|
1262
1284
|
routesByPath,
|
|
1263
1285
|
routesById,
|
|
@@ -1268,7 +1290,6 @@ function getMatchedRoutes({
|
|
|
1268
1290
|
const trimmedPath = trimPathRight(pathname);
|
|
1269
1291
|
const getMatchedParams = (route) => {
|
|
1270
1292
|
const result = matchPathname(
|
|
1271
|
-
basepath,
|
|
1272
1293
|
trimmedPath,
|
|
1273
1294
|
{
|
|
1274
1295
|
to: route.fullPath,
|