@tanstack/router-core 1.128.3 → 1.128.4
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/path.cjs.map +1 -1
- package/dist/cjs/path.d.cts +1 -0
- package/dist/cjs/router.cjs +50 -42
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/esm/path.d.ts +1 -0
- package/dist/esm/path.js.map +1 -1
- package/dist/esm/router.js +50 -42
- package/dist/esm/router.js.map +1 -1
- package/package.json +1 -1
- package/src/path.ts +2 -0
- package/src/router.ts +64 -54
package/package.json
CHANGED
package/src/path.ts
CHANGED
|
@@ -7,6 +7,8 @@ export interface Segment {
|
|
|
7
7
|
value: string
|
|
8
8
|
prefixSegment?: string
|
|
9
9
|
suffixSegment?: string
|
|
10
|
+
// Indicates if there is a static segment after this required/optional param
|
|
11
|
+
hasStaticAfter?: boolean
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
export function joinPaths(paths: Array<string | undefined>) {
|
package/src/router.ts
CHANGED
|
@@ -29,6 +29,7 @@ import { setupScrollRestoration } from './scroll-restoration'
|
|
|
29
29
|
import { defaultParseSearch, defaultStringifySearch } from './searchParams'
|
|
30
30
|
import { rootRouteId } from './root'
|
|
31
31
|
import { isRedirect, redirect } from './redirect'
|
|
32
|
+
import type { Segment } from './path'
|
|
32
33
|
import type { SearchParser, SearchSerializer } from './searchParams'
|
|
33
34
|
import type { AnyRedirect, ResolvedRedirect } from './redirect'
|
|
34
35
|
import type {
|
|
@@ -3178,6 +3179,27 @@ export type ProcessRouteTreeResult<TRouteLike extends RouteLike> = {
|
|
|
3178
3179
|
routesByPath: Record<string, TRouteLike>
|
|
3179
3180
|
flatRoutes: Array<TRouteLike>
|
|
3180
3181
|
}
|
|
3182
|
+
|
|
3183
|
+
const REQUIRED_PARAM_BASE_SCORE = 0.5
|
|
3184
|
+
const OPTIONAL_PARAM_BASE_SCORE = 0.4
|
|
3185
|
+
const WILDCARD_PARAM_BASE_SCORE = 0.25
|
|
3186
|
+
|
|
3187
|
+
function handleParam(segment: Segment, baseScore: number) {
|
|
3188
|
+
if (segment.prefixSegment && segment.suffixSegment) {
|
|
3189
|
+
return baseScore + 0.05
|
|
3190
|
+
}
|
|
3191
|
+
|
|
3192
|
+
if (segment.prefixSegment) {
|
|
3193
|
+
return baseScore + 0.02
|
|
3194
|
+
}
|
|
3195
|
+
|
|
3196
|
+
if (segment.suffixSegment) {
|
|
3197
|
+
return baseScore + 0.01
|
|
3198
|
+
}
|
|
3199
|
+
|
|
3200
|
+
return baseScore
|
|
3201
|
+
}
|
|
3202
|
+
|
|
3181
3203
|
export function processRouteTree<TRouteLike extends RouteLike>({
|
|
3182
3204
|
routeTree,
|
|
3183
3205
|
initRoute,
|
|
@@ -3224,9 +3246,11 @@ export function processRouteTree<TRouteLike extends RouteLike>({
|
|
|
3224
3246
|
const scoredRoutes: Array<{
|
|
3225
3247
|
child: TRouteLike
|
|
3226
3248
|
trimmed: string
|
|
3227
|
-
parsed:
|
|
3249
|
+
parsed: Array<Segment>
|
|
3228
3250
|
index: number
|
|
3229
3251
|
scores: Array<number>
|
|
3252
|
+
hasStaticAfter: boolean
|
|
3253
|
+
optionalParamCount: number
|
|
3230
3254
|
}> = []
|
|
3231
3255
|
|
|
3232
3256
|
const routes: Array<TRouteLike> = Object.values(routesById)
|
|
@@ -3244,63 +3268,50 @@ export function processRouteTree<TRouteLike extends RouteLike>({
|
|
|
3244
3268
|
parsed.shift()
|
|
3245
3269
|
}
|
|
3246
3270
|
|
|
3247
|
-
|
|
3271
|
+
let optionalParamCount = 0
|
|
3272
|
+
let hasStaticAfter = false
|
|
3273
|
+
const scores = parsed.map((segment, index) => {
|
|
3248
3274
|
if (segment.value === '/') {
|
|
3249
3275
|
return 0.75
|
|
3250
3276
|
}
|
|
3251
3277
|
|
|
3278
|
+
let baseScore: number | undefined = undefined
|
|
3252
3279
|
if (segment.type === 'param') {
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
}
|
|
3260
|
-
|
|
3261
|
-
if (segment.suffixSegment) {
|
|
3262
|
-
return 0.51
|
|
3263
|
-
}
|
|
3264
|
-
|
|
3265
|
-
return 0.5
|
|
3280
|
+
baseScore = REQUIRED_PARAM_BASE_SCORE
|
|
3281
|
+
} else if (segment.type === 'optional-param') {
|
|
3282
|
+
baseScore = OPTIONAL_PARAM_BASE_SCORE
|
|
3283
|
+
optionalParamCount++
|
|
3284
|
+
} else if (segment.type === 'wildcard') {
|
|
3285
|
+
baseScore = WILDCARD_PARAM_BASE_SCORE
|
|
3266
3286
|
}
|
|
3267
3287
|
|
|
3268
|
-
if (
|
|
3269
|
-
if
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
return 0.41
|
|
3279
|
-
}
|
|
3280
|
-
|
|
3281
|
-
return 0.4
|
|
3282
|
-
}
|
|
3283
|
-
|
|
3284
|
-
if (segment.type === 'wildcard') {
|
|
3285
|
-
if (segment.prefixSegment && segment.suffixSegment) {
|
|
3286
|
-
return 0.3
|
|
3287
|
-
}
|
|
3288
|
-
|
|
3289
|
-
if (segment.prefixSegment) {
|
|
3290
|
-
return 0.27
|
|
3291
|
-
}
|
|
3292
|
-
|
|
3293
|
-
if (segment.suffixSegment) {
|
|
3294
|
-
return 0.26
|
|
3288
|
+
if (baseScore) {
|
|
3289
|
+
// if there is any static segment (that is not an index) after a required / optional param,
|
|
3290
|
+
// we will boost this param so it ranks higher than a required/optional param without a static segment after it
|
|
3291
|
+
// JUST FOR SORTING, NOT FOR MATCHING
|
|
3292
|
+
for (let i = index + 1; i < parsed.length; i++) {
|
|
3293
|
+
const nextSegment = parsed[i]!
|
|
3294
|
+
if (nextSegment.type === 'pathname' && nextSegment.value !== '/') {
|
|
3295
|
+
hasStaticAfter = true
|
|
3296
|
+
return handleParam(segment, baseScore + 0.2)
|
|
3297
|
+
}
|
|
3295
3298
|
}
|
|
3296
3299
|
|
|
3297
|
-
return
|
|
3300
|
+
return handleParam(segment, baseScore)
|
|
3298
3301
|
}
|
|
3299
3302
|
|
|
3300
3303
|
return 1
|
|
3301
3304
|
})
|
|
3302
3305
|
|
|
3303
|
-
scoredRoutes.push({
|
|
3306
|
+
scoredRoutes.push({
|
|
3307
|
+
child: d,
|
|
3308
|
+
trimmed,
|
|
3309
|
+
parsed,
|
|
3310
|
+
index: i,
|
|
3311
|
+
scores,
|
|
3312
|
+
optionalParamCount,
|
|
3313
|
+
hasStaticAfter,
|
|
3314
|
+
})
|
|
3304
3315
|
})
|
|
3305
3316
|
|
|
3306
3317
|
const flatRoutes = scoredRoutes
|
|
@@ -3316,17 +3327,16 @@ export function processRouteTree<TRouteLike extends RouteLike>({
|
|
|
3316
3327
|
|
|
3317
3328
|
// If all common segments have equal scores, then consider length and specificity
|
|
3318
3329
|
if (a.scores.length !== b.scores.length) {
|
|
3319
|
-
// Count optional parameters in each route
|
|
3320
|
-
const aOptionalCount = a.parsed.filter(
|
|
3321
|
-
(seg) => seg.type === 'optional-param',
|
|
3322
|
-
).length
|
|
3323
|
-
const bOptionalCount = b.parsed.filter(
|
|
3324
|
-
(seg) => seg.type === 'optional-param',
|
|
3325
|
-
).length
|
|
3326
|
-
|
|
3327
3330
|
// If different number of optional parameters, fewer optional parameters wins (more specific)
|
|
3328
|
-
if
|
|
3329
|
-
|
|
3331
|
+
// only if both or none of the routes has static segments after the params
|
|
3332
|
+
if (a.optionalParamCount !== b.optionalParamCount) {
|
|
3333
|
+
if (a.hasStaticAfter === b.hasStaticAfter) {
|
|
3334
|
+
return a.optionalParamCount - b.optionalParamCount
|
|
3335
|
+
} else if (a.hasStaticAfter && !b.hasStaticAfter) {
|
|
3336
|
+
return -1
|
|
3337
|
+
} else if (!a.hasStaticAfter && b.hasStaticAfter) {
|
|
3338
|
+
return 1
|
|
3339
|
+
}
|
|
3330
3340
|
}
|
|
3331
3341
|
|
|
3332
3342
|
// If same number of optional parameters, longer path wins (for static segments)
|