@tanstack/router-core 1.154.14 → 1.156.0
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/new-process-route-tree.cjs +47 -42
- package/dist/cjs/new-process-route-tree.cjs.map +1 -1
- package/dist/cjs/new-process-route-tree.d.cts +13 -8
- package/dist/cjs/path.cjs +18 -14
- package/dist/cjs/path.cjs.map +1 -1
- package/dist/cjs/path.d.cts +11 -2
- package/dist/cjs/router.cjs +122 -57
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +19 -5
- package/dist/esm/new-process-route-tree.d.ts +13 -8
- package/dist/esm/new-process-route-tree.js +47 -42
- package/dist/esm/new-process-route-tree.js.map +1 -1
- package/dist/esm/path.d.ts +11 -2
- package/dist/esm/path.js +18 -14
- package/dist/esm/path.js.map +1 -1
- package/dist/esm/router.d.ts +19 -5
- package/dist/esm/router.js +124 -59
- package/dist/esm/router.js.map +1 -1
- package/package.json +1 -1
- package/src/new-process-route-tree.ts +78 -54
- package/src/path.ts +36 -16
- package/src/router.ts +174 -59
package/dist/cjs/path.d.cts
CHANGED
|
@@ -27,10 +27,19 @@ interface ResolvePathOptions {
|
|
|
27
27
|
* and supporting relative segments (`.`/`..`) and absolute `to` values.
|
|
28
28
|
*/
|
|
29
29
|
export declare function resolvePath({ base, to, trailingSlash, cache, }: ResolvePathOptions): string;
|
|
30
|
+
/**
|
|
31
|
+
* Create a pre-compiled decode config from allowed characters.
|
|
32
|
+
* This should be called once at router initialization.
|
|
33
|
+
*/
|
|
34
|
+
export declare function compileDecodeCharMap(pathParamsAllowedCharacters: ReadonlyArray<string>): (encoded: string) => string;
|
|
30
35
|
interface InterpolatePathOptions {
|
|
31
36
|
path?: string;
|
|
32
37
|
params: Record<string, unknown>;
|
|
33
|
-
|
|
38
|
+
/**
|
|
39
|
+
* A function that decodes a path parameter value.
|
|
40
|
+
* Obtained from `compileDecodeCharMap(pathParamsAllowedCharacters)`.
|
|
41
|
+
*/
|
|
42
|
+
decoder?: (encoded: string) => string;
|
|
34
43
|
}
|
|
35
44
|
type InterPolatePathResult = {
|
|
36
45
|
interpolatedPath: string;
|
|
@@ -43,5 +52,5 @@ type InterPolatePathResult = {
|
|
|
43
52
|
* - Encodes params safely (configurable allowed characters)
|
|
44
53
|
* - Supports `{-$optional}` segments, `{prefix{$id}suffix}` and `{$}` wildcards
|
|
45
54
|
*/
|
|
46
|
-
export declare function interpolatePath({ path, params,
|
|
55
|
+
export declare function interpolatePath({ path, params, decoder, }: InterpolatePathOptions): InterPolatePathResult;
|
|
47
56
|
export {};
|
package/dist/cjs/router.cjs
CHANGED
|
@@ -71,12 +71,10 @@ class RouterCore {
|
|
|
71
71
|
...newOptions
|
|
72
72
|
};
|
|
73
73
|
this.isServer = this.options.isServer ?? typeof document === "undefined";
|
|
74
|
-
|
|
75
|
-
this.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
])
|
|
79
|
-
) : void 0;
|
|
74
|
+
if (this.options.pathParamsAllowedCharacters)
|
|
75
|
+
this.pathParamsDecoder = path.compileDecodeCharMap(
|
|
76
|
+
this.options.pathParamsAllowedCharacters
|
|
77
|
+
);
|
|
80
78
|
if (!this.history || this.options.history && this.options.history !== this.history) {
|
|
81
79
|
if (!this.options.history) {
|
|
82
80
|
if (!this.isServer) {
|
|
@@ -99,7 +97,23 @@ class RouterCore {
|
|
|
99
97
|
}
|
|
100
98
|
if (this.options.routeTree !== this.routeTree) {
|
|
101
99
|
this.routeTree = this.options.routeTree;
|
|
102
|
-
|
|
100
|
+
let processRouteTreeResult;
|
|
101
|
+
if (this.isServer && globalThis.__TSR_CACHE__ && globalThis.__TSR_CACHE__.routeTree === this.routeTree) {
|
|
102
|
+
const cached = globalThis.__TSR_CACHE__;
|
|
103
|
+
this.resolvePathCache = cached.resolvePathCache;
|
|
104
|
+
processRouteTreeResult = cached.processRouteTreeResult;
|
|
105
|
+
} else {
|
|
106
|
+
this.resolvePathCache = lruCache.createLRUCache(1e3);
|
|
107
|
+
processRouteTreeResult = this.buildRouteTree();
|
|
108
|
+
if (this.isServer && globalThis.__TSR_CACHE__ === void 0) {
|
|
109
|
+
globalThis.__TSR_CACHE__ = {
|
|
110
|
+
routeTree: this.routeTree,
|
|
111
|
+
processRouteTreeResult,
|
|
112
|
+
resolvePathCache: this.resolvePathCache
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
this.setRoutes(processRouteTreeResult);
|
|
103
117
|
}
|
|
104
118
|
if (!this.__store && this.latestLocation) {
|
|
105
119
|
this.__store = new store.Store(getInitialRouterState(this.latestLocation), {
|
|
@@ -157,7 +171,7 @@ class RouterCore {
|
|
|
157
171
|
);
|
|
158
172
|
};
|
|
159
173
|
this.buildRouteTree = () => {
|
|
160
|
-
const
|
|
174
|
+
const result = newProcessRouteTree.processRouteTree(
|
|
161
175
|
this.routeTree,
|
|
162
176
|
this.options.caseSensitive,
|
|
163
177
|
(route, i) => {
|
|
@@ -167,18 +181,9 @@ class RouterCore {
|
|
|
167
181
|
}
|
|
168
182
|
);
|
|
169
183
|
if (this.options.routeMasks) {
|
|
170
|
-
newProcessRouteTree.processRouteMasks(this.options.routeMasks, processedTree);
|
|
171
|
-
}
|
|
172
|
-
this.routesById = routesById;
|
|
173
|
-
this.routesByPath = routesByPath;
|
|
174
|
-
this.processedTree = processedTree;
|
|
175
|
-
const notFoundRoute = this.options.notFoundRoute;
|
|
176
|
-
if (notFoundRoute) {
|
|
177
|
-
notFoundRoute.init({
|
|
178
|
-
originalIndex: 99999999999
|
|
179
|
-
});
|
|
180
|
-
this.routesById[notFoundRoute.id] = notFoundRoute;
|
|
184
|
+
newProcessRouteTree.processRouteMasks(this.options.routeMasks, result.processedTree);
|
|
181
185
|
}
|
|
186
|
+
return result;
|
|
182
187
|
};
|
|
183
188
|
this.subscribe = (eventType, fn) => {
|
|
184
189
|
const listener = {
|
|
@@ -233,7 +238,6 @@ class RouterCore {
|
|
|
233
238
|
}
|
|
234
239
|
return location;
|
|
235
240
|
};
|
|
236
|
-
this.resolvePathCache = lruCache.createLRUCache(1e3);
|
|
237
241
|
this.resolvePathWithBase = (from, path$1) => {
|
|
238
242
|
const resolvedPath = path.resolvePath({
|
|
239
243
|
base: from,
|
|
@@ -288,26 +292,23 @@ class RouterCore {
|
|
|
288
292
|
this.buildLocation = (opts) => {
|
|
289
293
|
const build = (dest = {}) => {
|
|
290
294
|
const currentLocation = dest._fromLocation || this.pendingBuiltLocation || this.latestLocation;
|
|
291
|
-
const
|
|
292
|
-
_buildLocation: true
|
|
293
|
-
});
|
|
294
|
-
const lastMatch = utils.last(allCurrentLocationMatches);
|
|
295
|
+
const lightweightResult = this.matchRoutesLightweight(currentLocation);
|
|
295
296
|
if (dest.from && process.env.NODE_ENV !== "production" && dest._isNavigate) {
|
|
296
297
|
const allFromMatches = this.getMatchedRoutes(dest.from).matchedRoutes;
|
|
297
|
-
const matchedFrom = utils.findLast(
|
|
298
|
+
const matchedFrom = utils.findLast(lightweightResult.matchedRoutes, (d) => {
|
|
298
299
|
return comparePaths(d.fullPath, dest.from);
|
|
299
300
|
});
|
|
300
301
|
const matchedCurrent = utils.findLast(allFromMatches, (d) => {
|
|
301
|
-
return comparePaths(d.fullPath,
|
|
302
|
+
return comparePaths(d.fullPath, lightweightResult.fullPath);
|
|
302
303
|
});
|
|
303
304
|
if (!matchedFrom && !matchedCurrent) {
|
|
304
305
|
console.warn(`Could not find match for from: ${dest.from}`);
|
|
305
306
|
}
|
|
306
307
|
}
|
|
307
|
-
const defaultedFromPath = dest.unsafeRelative === "path" ? currentLocation.pathname : dest.from ??
|
|
308
|
+
const defaultedFromPath = dest.unsafeRelative === "path" ? currentLocation.pathname : dest.from ?? lightweightResult.fullPath;
|
|
308
309
|
const fromPath = this.resolvePathWithBase(defaultedFromPath, ".");
|
|
309
|
-
const fromSearch =
|
|
310
|
-
const fromParams = { ...
|
|
310
|
+
const fromSearch = lightweightResult.search;
|
|
311
|
+
const fromParams = { ...lightweightResult.params };
|
|
311
312
|
const nextTo = dest.to ? this.resolvePathWithBase(fromPath, `${dest.to}`) : this.resolvePathWithBase(fromPath, ".");
|
|
312
313
|
const nextParams = dest.params === false || dest.params === null ? {} : (dest.params ?? true) === true ? fromParams : Object.assign(
|
|
313
314
|
fromParams,
|
|
@@ -346,7 +347,7 @@ class RouterCore {
|
|
|
346
347
|
path.interpolatePath({
|
|
347
348
|
path: nextTo,
|
|
348
349
|
params: nextParams,
|
|
349
|
-
|
|
350
|
+
decoder: this.pathParamsDecoder
|
|
350
351
|
}).interpolatedPath
|
|
351
352
|
);
|
|
352
353
|
let nextSearch = fromSearch;
|
|
@@ -1036,6 +1037,22 @@ class RouterCore {
|
|
|
1036
1037
|
get state() {
|
|
1037
1038
|
return this.__store.state;
|
|
1038
1039
|
}
|
|
1040
|
+
setRoutes({
|
|
1041
|
+
routesById,
|
|
1042
|
+
routesByPath,
|
|
1043
|
+
processedTree
|
|
1044
|
+
}) {
|
|
1045
|
+
this.routesById = routesById;
|
|
1046
|
+
this.routesByPath = routesByPath;
|
|
1047
|
+
this.processedTree = processedTree;
|
|
1048
|
+
const notFoundRoute = this.options.notFoundRoute;
|
|
1049
|
+
if (notFoundRoute) {
|
|
1050
|
+
notFoundRoute.init({
|
|
1051
|
+
originalIndex: 99999999999
|
|
1052
|
+
});
|
|
1053
|
+
this.routesById[notFoundRoute.id] = notFoundRoute;
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1039
1056
|
get looseRoutesById() {
|
|
1040
1057
|
return this.routesById;
|
|
1041
1058
|
}
|
|
@@ -1099,7 +1116,7 @@ class RouterCore {
|
|
|
1099
1116
|
const { interpolatedPath, usedParams } = path.interpolatePath({
|
|
1100
1117
|
path: route.fullPath,
|
|
1101
1118
|
params: routeParams,
|
|
1102
|
-
|
|
1119
|
+
decoder: this.pathParamsDecoder
|
|
1103
1120
|
});
|
|
1104
1121
|
const matchId = (
|
|
1105
1122
|
// route.id for disambiguation
|
|
@@ -1114,32 +1131,18 @@ class RouterCore {
|
|
|
1114
1131
|
const strictParams = existingMatch?._strictParams ?? usedParams;
|
|
1115
1132
|
let paramsError = void 0;
|
|
1116
1133
|
if (!existingMatch) {
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1134
|
+
try {
|
|
1135
|
+
extractStrictParams(route, usedParams, parsedParams, strictParams);
|
|
1136
|
+
} catch (err) {
|
|
1137
|
+
if (notFound.isNotFound(err) || redirect.isRedirect(err)) {
|
|
1138
|
+
paramsError = err;
|
|
1139
|
+
} else {
|
|
1140
|
+
paramsError = new PathParamError(err.message, {
|
|
1141
|
+
cause: err
|
|
1142
|
+
});
|
|
1122
1143
|
}
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
if (strictParseParams) {
|
|
1126
|
-
try {
|
|
1127
|
-
Object.assign(
|
|
1128
|
-
strictParams,
|
|
1129
|
-
strictParseParams(strictParams)
|
|
1130
|
-
);
|
|
1131
|
-
} catch (err) {
|
|
1132
|
-
if (notFound.isNotFound(err) || redirect.isRedirect(err)) {
|
|
1133
|
-
paramsError = err;
|
|
1134
|
-
} else {
|
|
1135
|
-
paramsError = new PathParamError(err.message, {
|
|
1136
|
-
cause: err
|
|
1137
|
-
});
|
|
1138
|
-
}
|
|
1139
|
-
if (opts?.throwOnError) {
|
|
1140
|
-
throw paramsError;
|
|
1141
|
-
}
|
|
1142
|
-
}
|
|
1144
|
+
if (opts?.throwOnError) {
|
|
1145
|
+
throw paramsError;
|
|
1143
1146
|
}
|
|
1144
1147
|
}
|
|
1145
1148
|
}
|
|
@@ -1208,7 +1211,7 @@ class RouterCore {
|
|
|
1208
1211
|
matches.forEach((match, index) => {
|
|
1209
1212
|
const route = this.looseRoutesById[match.routeId];
|
|
1210
1213
|
const existingMatch = this.getMatch(match.id);
|
|
1211
|
-
if (!existingMatch
|
|
1214
|
+
if (!existingMatch) {
|
|
1212
1215
|
const parentMatch = matches[index - 1];
|
|
1213
1216
|
const parentContext = getParentContext(parentMatch);
|
|
1214
1217
|
if (route.options.context) {
|
|
@@ -1235,6 +1238,53 @@ class RouterCore {
|
|
|
1235
1238
|
});
|
|
1236
1239
|
return matches;
|
|
1237
1240
|
}
|
|
1241
|
+
/**
|
|
1242
|
+
* Lightweight route matching for buildLocation.
|
|
1243
|
+
* Only computes fullPath, accumulated search, and params - skipping expensive
|
|
1244
|
+
* operations like AbortController, ControlledPromise, loaderDeps, and full match objects.
|
|
1245
|
+
*/
|
|
1246
|
+
matchRoutesLightweight(location) {
|
|
1247
|
+
const { matchedRoutes, routeParams, parsedParams } = this.getMatchedRoutes(
|
|
1248
|
+
location.pathname
|
|
1249
|
+
);
|
|
1250
|
+
const lastRoute = utils.last(matchedRoutes);
|
|
1251
|
+
const accumulatedSearch = { ...location.search };
|
|
1252
|
+
for (const route of matchedRoutes) {
|
|
1253
|
+
try {
|
|
1254
|
+
Object.assign(
|
|
1255
|
+
accumulatedSearch,
|
|
1256
|
+
validateSearch(route.options.validateSearch, accumulatedSearch)
|
|
1257
|
+
);
|
|
1258
|
+
} catch {
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
const lastStateMatch = utils.last(this.state.matches);
|
|
1262
|
+
const canReuseParams = lastStateMatch && lastStateMatch.routeId === lastRoute.id && location.pathname === this.state.location.pathname;
|
|
1263
|
+
let params;
|
|
1264
|
+
if (canReuseParams) {
|
|
1265
|
+
params = lastStateMatch.params;
|
|
1266
|
+
} else {
|
|
1267
|
+
const strictParams = { ...routeParams };
|
|
1268
|
+
for (const route of matchedRoutes) {
|
|
1269
|
+
try {
|
|
1270
|
+
extractStrictParams(
|
|
1271
|
+
route,
|
|
1272
|
+
routeParams,
|
|
1273
|
+
parsedParams ?? {},
|
|
1274
|
+
strictParams
|
|
1275
|
+
);
|
|
1276
|
+
} catch {
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
params = strictParams;
|
|
1280
|
+
}
|
|
1281
|
+
return {
|
|
1282
|
+
matchedRoutes,
|
|
1283
|
+
fullPath: lastRoute.fullPath,
|
|
1284
|
+
search: accumulatedSearch,
|
|
1285
|
+
params
|
|
1286
|
+
};
|
|
1287
|
+
}
|
|
1238
1288
|
}
|
|
1239
1289
|
class SearchParamError extends Error {
|
|
1240
1290
|
}
|
|
@@ -1397,6 +1447,21 @@ function findGlobalNotFoundRouteId(notFoundMode, routes) {
|
|
|
1397
1447
|
}
|
|
1398
1448
|
return root.rootRouteId;
|
|
1399
1449
|
}
|
|
1450
|
+
function extractStrictParams(route, referenceParams, parsedParams, accumulatedParams) {
|
|
1451
|
+
const parseParams = route.options.params?.parse ?? route.options.parseParams;
|
|
1452
|
+
if (parseParams) {
|
|
1453
|
+
if (route.options.skipRouteOnParseError) {
|
|
1454
|
+
for (const key in referenceParams) {
|
|
1455
|
+
if (key in parsedParams) {
|
|
1456
|
+
accumulatedParams[key] = parsedParams[key];
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
} else {
|
|
1460
|
+
const result = parseParams(accumulatedParams);
|
|
1461
|
+
Object.assign(accumulatedParams, result);
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1400
1465
|
exports.PathParamError = PathParamError;
|
|
1401
1466
|
exports.RouterCore = RouterCore;
|
|
1402
1467
|
exports.SearchParamError = SearchParamError;
|