@tanstack/router-core 1.132.0-alpha.12 → 1.132.0-alpha.15
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 +49 -27
- 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 +51 -29
- 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 +128 -47
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,
|
|
@@ -391,7 +416,7 @@ class RouterCore {
|
|
|
391
416
|
});
|
|
392
417
|
return isEqual;
|
|
393
418
|
};
|
|
394
|
-
const isSameUrl = this.latestLocation.href === next.href;
|
|
419
|
+
const isSameUrl = trimPathRight(this.latestLocation.href) === trimPathRight(next.href);
|
|
395
420
|
const previousCommitPromise = this.commitLocationPromise;
|
|
396
421
|
this.commitLocationPromise = createControlledPromise(() => {
|
|
397
422
|
previousCommitPromise?.resolve();
|
|
@@ -427,7 +452,7 @@ class RouterCore {
|
|
|
427
452
|
nextHistory.state.__hashScrollIntoViewOptions = hashScrollIntoView ?? this.options.defaultHashScrollIntoView ?? true;
|
|
428
453
|
this.shouldViewTransition = viewTransition;
|
|
429
454
|
this.history[next.replace ? "replace" : "push"](
|
|
430
|
-
nextHistory.
|
|
455
|
+
nextHistory.publicHref,
|
|
431
456
|
nextHistory.state,
|
|
432
457
|
{ ignoreBlocker }
|
|
433
458
|
);
|
|
@@ -480,7 +505,7 @@ class RouterCore {
|
|
|
480
505
|
if (reloadDocument) {
|
|
481
506
|
if (!href) {
|
|
482
507
|
const location = this.buildLocation({ to, ...rest });
|
|
483
|
-
href =
|
|
508
|
+
href = location.href;
|
|
484
509
|
}
|
|
485
510
|
if (rest.replace) {
|
|
486
511
|
window.location.replace(href);
|
|
@@ -827,7 +852,6 @@ class RouterCore {
|
|
|
827
852
|
const pending = opts?.pending === void 0 ? !this.state.isLoading : opts.pending;
|
|
828
853
|
const baseLocation = pending ? this.latestLocation : this.state.resolvedLocation || this.state.location;
|
|
829
854
|
const match = matchPathname(
|
|
830
|
-
this.basepath,
|
|
831
855
|
baseLocation.pathname,
|
|
832
856
|
{
|
|
833
857
|
...opts,
|
|
@@ -1005,7 +1029,7 @@ class RouterCore {
|
|
|
1005
1029
|
routeId: route.id,
|
|
1006
1030
|
params: previousMatch ? replaceEqualDeep(previousMatch.params, routeParams) : routeParams,
|
|
1007
1031
|
_strictParams: usedParams,
|
|
1008
|
-
pathname:
|
|
1032
|
+
pathname: interpolatedPath,
|
|
1009
1033
|
updatedAt: Date.now(),
|
|
1010
1034
|
search: previousMatch ? replaceEqualDeep(previousMatch.search, preMatchSearch) : preMatchSearch,
|
|
1011
1035
|
_strictSearch: strictMatchSearch,
|
|
@@ -1257,7 +1281,6 @@ function processRouteTree({
|
|
|
1257
1281
|
function getMatchedRoutes({
|
|
1258
1282
|
pathname,
|
|
1259
1283
|
routePathname,
|
|
1260
|
-
basepath,
|
|
1261
1284
|
caseSensitive,
|
|
1262
1285
|
routesByPath,
|
|
1263
1286
|
routesById,
|
|
@@ -1268,7 +1291,6 @@ function getMatchedRoutes({
|
|
|
1268
1291
|
const trimmedPath = trimPathRight(pathname);
|
|
1269
1292
|
const getMatchedParams = (route) => {
|
|
1270
1293
|
const result = matchPathname(
|
|
1271
|
-
basepath,
|
|
1272
1294
|
trimmedPath,
|
|
1273
1295
|
{
|
|
1274
1296
|
to: route.fullPath,
|