| import type { LoaderTree } from '../../server/lib/app-dir-module' |
| import type { Params } from '../../server/request/params' |
| import type { AppPageRouteModule } from '../../server/route-modules/app-page/module.compiled' |
| import type { AppRouteRouteModule } from '../../server/route-modules/app-route/module.compiled' |
| import { isAppPageRouteModule } from '../../server/route-modules/checks' |
| import type { DynamicParamTypes } from '../../shared/lib/app-router-types' |
| import { |
| parseAppRouteSegment, |
| type NormalizedAppRoute, |
| } from '../../shared/lib/router/routes/app' |
| import { parseLoaderTree } from '../../shared/lib/router/utils/parse-loader-tree' |
| import type { AppSegment } from '../segment-config/app/app-segments' |
| import { extractPathnameRouteParamSegmentsFromLoaderTree } from './app/extract-pathname-route-param-segments-from-loader-tree' |
| import { resolveParamValue } from '../../shared/lib/router/utils/resolve-param-value' |
| import type { FallbackRouteParam } from './types' |
|
|
| |
| |
| |
| |
| |
| |
| |
| export function encodeParam( |
| value: string | string[], |
| encoder: (value: string) => string |
| ) { |
| let replaceValue: string |
| if (Array.isArray(value)) { |
| replaceValue = value.map(encoder).join('/') |
| } else { |
| replaceValue = encoder(value) |
| } |
|
|
| return replaceValue |
| } |
|
|
| |
| |
| |
| |
| |
| |
| export function normalizePathname(pathname: string) { |
| return pathname.replace(/\\/g, '/').replace(/(?!^)\/$/, '') |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export function extractPathnameRouteParamSegments( |
| routeModule: AppRouteRouteModule | AppPageRouteModule, |
| segments: readonly Readonly<AppSegment>[], |
| route: NormalizedAppRoute |
| ): Array<{ |
| readonly name: string |
| readonly paramName: string |
| readonly paramType: DynamicParamTypes |
| }> { |
| |
| if (isAppPageRouteModule(routeModule)) { |
| const { pathnameRouteParamSegments } = |
| extractPathnameRouteParamSegmentsFromLoaderTree( |
| routeModule.userland.loaderTree, |
| route |
| ) |
| return pathnameRouteParamSegments |
| } |
|
|
| return extractPathnameRouteParamSegmentsFromSegments(segments) |
| } |
|
|
| export function extractPathnameRouteParamSegmentsFromSegments( |
| segments: readonly Readonly<AppSegment>[] |
| ): Array<{ |
| readonly name: string |
| readonly paramName: string |
| readonly paramType: DynamicParamTypes |
| }> { |
| |
|
|
| |
| |
| const result: Array<{ |
| readonly name: string |
| readonly paramName: string |
| readonly paramType: DynamicParamTypes |
| }> = [] |
|
|
| for (const segment of segments) { |
| |
| if (!segment.paramName || !segment.paramType) continue |
|
|
| |
| result.push({ |
| name: segment.name, |
| paramName: segment.paramName, |
| paramType: segment.paramType, |
| }) |
| } |
|
|
| return result |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export function resolveRouteParamsFromTree( |
| loaderTree: LoaderTree, |
| params: Params, |
| route: NormalizedAppRoute, |
| fallbackRouteParams: FallbackRouteParam[] |
| ): void { |
| |
| const stack: Array<{ |
| tree: LoaderTree |
| depth: number |
| }> = [{ tree: loaderTree, depth: 0 }] |
|
|
| while (stack.length > 0) { |
| const { tree, depth } = stack.pop()! |
| const { segment, parallelRoutes } = parseLoaderTree(tree) |
|
|
| const appSegment = parseAppRouteSegment(segment) |
|
|
| |
| |
| if ( |
| appSegment?.type === 'dynamic' && |
| !params.hasOwnProperty(appSegment.param.paramName) && |
| !fallbackRouteParams.some( |
| (param) => param.paramName === appSegment.param.paramName |
| ) |
| ) { |
| const { paramName, paramType } = appSegment.param |
|
|
| const paramValue = resolveParamValue( |
| paramName, |
| paramType, |
| depth, |
| route, |
| params |
| ) |
|
|
| if (paramValue !== undefined) { |
| params[paramName] = paramValue |
| } else if (paramType !== 'optional-catchall') { |
| |
| fallbackRouteParams.push({ paramName, paramType }) |
| } |
| } |
|
|
| |
| let nextDepth = depth |
| if ( |
| appSegment && |
| appSegment.type !== 'route-group' && |
| appSegment.type !== 'parallel-route' |
| ) { |
| nextDepth++ |
| } |
|
|
| |
| for (const parallelRoute of Object.values(parallelRoutes)) { |
| stack.push({ tree: parallelRoute, depth: nextDepth }) |
| } |
| } |
| } |
|
|