Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 25 additions & 8 deletions packages/router-core/src/new-process-route-tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,8 @@ type RouteMatch<T extends Extract<RouteLike, { fullPath: string }>> = {
route: T
params: Record<string, string>
branch: ReadonlyArray<T>
/** Parsed params from routes with skipRouteOnParseError, accumulated during matching */
parsedParams?: Record<string, unknown>
}

export function findRouteMatch<
Expand Down Expand Up @@ -804,7 +806,11 @@ function findMatch<T extends RouteLike>(
path: string,
segmentTree: AnySegmentNode<T>,
fuzzy = false,
): { route: T; params: Record<string, string> } | null {
): {
route: T
params: Record<string, string>
parsedParams?: Record<string, unknown>
} | null {
const parts = path.split('/')
const leaf = getNodeMatch(path, parts, segmentTree, fuzzy)
if (!leaf) return null
Expand All @@ -813,6 +819,7 @@ function findMatch<T extends RouteLike>(
return {
route,
params,
parsedParams: leaf.parsedParams,
}
}

Expand Down Expand Up @@ -938,10 +945,10 @@ type MatchStackFrame<T extends RouteLike> = {
optionals: number
/** intermediary state for param extraction */
extract?: { part: number; node: number; path: number }
/** intermediary params from param extraction */
// TODO: I'm not sure, but I think we need both the raw strings for `interpolatePath` and the parsed values for the final match object
// I think they can still be accumulated (separately) in a single object (each) because `interpolatePath` returns the `usedParams` anyway
/** intermediary raw string params from param extraction (for interpolatePath) */
params?: Record<string, string>
/** intermediary parsed params from routes with skipRouteOnParseError */
parsedParams?: Record<string, unknown>
}

function getNodeMatch<T extends RouteLike>(
Expand All @@ -953,7 +960,7 @@ function getNodeMatch<T extends RouteLike>(
// quick check for root index
// this is an optimization, algorithm should work correctly without this block
if (path === '/' && segmentTree.index)
return { node: segmentTree.index, skipped: 0 }
return { node: segmentTree.index, skipped: 0, parsedParams: undefined }

const trailingSlash = !last(parts)
const pathIsIndex = trailingSlash && path !== '/'
Expand Down Expand Up @@ -987,13 +994,14 @@ function getNodeMatch<T extends RouteLike>(
while (stack.length) {
const frame = stack.pop()!
const { node, index, skipped, depth, statics, dynamics, optionals } = frame
let { extract, params } = frame
let { extract, params, parsedParams } = frame

if (node.skipRouteOnParseError && node.parse) {
const result = validateMatchParams(path, parts, frame)
if (!result) continue
params = result[0]
extract = result[1]
parsedParams = frame.parsedParams
}

// In fuzzy mode, track the best partial match we've found so far
Expand Down Expand Up @@ -1030,6 +1038,7 @@ function getNodeMatch<T extends RouteLike>(
optionals,
extract,
params,
parsedParams,
}
if (node.index.skipRouteOnParseError && node.index.parse) {
const result = validateMatchParams(path, parts, indexFrame)
Expand Down Expand Up @@ -1075,6 +1084,7 @@ function getNodeMatch<T extends RouteLike>(
optionals,
extract,
params,
parsedParams,
}
if (segment.skipRouteOnParseError && segment.parse) {
const result = validateMatchParams(path, parts, frame)
Expand Down Expand Up @@ -1102,6 +1112,7 @@ function getNodeMatch<T extends RouteLike>(
optionals,
extract,
params,
parsedParams,
}) // enqueue skipping the optional
}
if (!isBeyondPath) {
Expand All @@ -1125,6 +1136,7 @@ function getNodeMatch<T extends RouteLike>(
optionals: optionals + 1,
extract,
params,
parsedParams,
})
}
}
Expand Down Expand Up @@ -1152,6 +1164,7 @@ function getNodeMatch<T extends RouteLike>(
optionals,
extract,
params,
parsedParams,
})
}
}
Expand All @@ -1172,6 +1185,7 @@ function getNodeMatch<T extends RouteLike>(
optionals,
extract,
params,
parsedParams,
})
}
}
Expand All @@ -1190,6 +1204,7 @@ function getNodeMatch<T extends RouteLike>(
optionals,
extract,
params,
parsedParams,
})
}
}
Expand All @@ -1209,6 +1224,7 @@ function getNodeMatch<T extends RouteLike>(
optionals,
extract,
params,
parsedParams,
})
}
}
Expand Down Expand Up @@ -1247,8 +1263,9 @@ function validateMatchParams<T extends RouteLike>(
const result = extractParams(path, parts, frame)
frame.params = result[0]
frame.extract = result[1]
result[0] = frame.node.parse!(result[0])
frame.params = result[0]
const parsedParams = frame.node.parse!(result[0])
// Accumulate parsed params from this route
frame.parsedParams = { ...frame.parsedParams, ...parsedParams }
return result
} catch {
return null
Expand Down
18 changes: 15 additions & 3 deletions packages/router-core/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,7 @@ export type GetMatchRoutesFn = (pathname: string) => {
routeParams: Record<string, string>
foundRoute: AnyRoute | undefined
parseError?: unknown
parsedParams?: Record<string, unknown>
}

export type EmitFn = (routerEvent: RouterEvent) => void
Expand Down Expand Up @@ -1249,7 +1250,7 @@ export class RouterCore<
opts?: MatchRoutesOpts,
): Array<AnyRouteMatch> {
const matchedRoutesResult = this.getMatchedRoutes(next.pathname)
const { foundRoute, routeParams } = matchedRoutesResult
const { foundRoute, routeParams, parsedParams } = matchedRoutesResult
let { matchedRoutes } = matchedRoutesResult
let isGlobalNotFound = false

Expand Down Expand Up @@ -1393,7 +1394,13 @@ export class RouterCore<
const strictParseParams =
route.options.params?.parse ?? route.options.parseParams

if (strictParseParams) {
// Skip parsing if this route was already parsed during matching (skipRouteOnParseError)
const alreadyParsed =
route.options.skipRouteOnParseError &&
strictParseParams &&
parsedParams !== undefined

if (strictParseParams && !alreadyParsed) {
try {
Object.assign(
strictParams,
Expand All @@ -1412,6 +1419,9 @@ export class RouterCore<
throw paramsError
}
}
} else if (alreadyParsed) {
// Use the pre-parsed params from matching
Object.assign(strictParams, parsedParams)
}
}

Expand Down Expand Up @@ -2693,15 +2703,17 @@ export function getMatchedRoutes<TRouteLike extends RouteLike>({
const trimmedPath = trimPathRight(pathname)

let foundRoute: TRouteLike | undefined = undefined
let parsedParams: Record<string, unknown> | undefined = undefined
const match = findRouteMatch<TRouteLike>(trimmedPath, processedTree, true)
if (match) {
foundRoute = match.route
Object.assign(routeParams, match.params) // Copy params, because they're cached
parsedParams = match.parsedParams
}

const matchedRoutes = match?.branch || [routesById[rootRouteId]!]

return { matchedRoutes, routeParams, foundRoute }
return { matchedRoutes, routeParams, foundRoute, parsedParams }
}

function applySearchMiddleware({
Expand Down
Loading
Loading