@@ -111,6 +111,7 @@ import {
111
111
} from '../client-component-renderer-logger'
112
112
import { createServerModuleMap } from './action-utils'
113
113
import type { DeepReadonly } from '../../shared/lib/deep-readonly'
114
+ import { parseParameter } from '../../shared/lib/router/utils/route-regex'
114
115
115
116
export type GetDynamicParamFromSegment = (
116
117
// [slug] / [[slug]] / [...slug]
@@ -209,6 +210,7 @@ export type CreateSegmentPath = (child: FlightSegmentPath) => FlightSegmentPath
209
210
*/
210
211
function makeGetDynamicParamFromSegment (
211
212
params : { [ key : string ] : any } ,
213
+ pagePath : string ,
212
214
flightRouterState : FlightRouterState | undefined
213
215
) : GetDynamicParamFromSegment {
214
216
return function getDynamicParamFromSegment (
@@ -236,17 +238,46 @@ function makeGetDynamicParamFromSegment(
236
238
}
237
239
238
240
if ( ! value ) {
239
- // Handle case where optional catchall does not have a value, e.g. `/dashboard/[...slug]` when requesting `/dashboard`
240
- if ( segmentParam . type === 'optional-catchall' ) {
241
- const type = dynamicParamTypes [ segmentParam . type ]
241
+ const isCatchall = segmentParam . type === 'catchall'
242
+ const isOptionalCatchall = segmentParam . type === 'optional-catchall'
243
+
244
+ if ( isCatchall || isOptionalCatchall ) {
245
+ const dynamicParamType = dynamicParamTypes [ segmentParam . type ]
246
+ // handle the case where an optional catchall does not have a value,
247
+ // e.g. `/dashboard/[[...slug]]` when requesting `/dashboard`
248
+ if ( isOptionalCatchall ) {
249
+ return {
250
+ param : key ,
251
+ value : null ,
252
+ type : dynamicParamType ,
253
+ treeSegment : [ key , '' , dynamicParamType ] ,
254
+ }
255
+ }
256
+
257
+ // handle the case where a catchall or optional catchall does not have a value,
258
+ // e.g. `/foo/bar/hello` and `@slot/[...catchall]` or `@slot/[[...catchall]]` is matched
259
+ value = pagePath
260
+ . split ( '/' )
261
+ // remove the first empty string
262
+ . slice ( 1 )
263
+ // replace any dynamic params with the actual values
264
+ . map ( ( pathSegment ) => {
265
+ const param = parseParameter ( pathSegment )
266
+
267
+ // if the segment matches a param, return the param value
268
+ // otherwise, it's a static segment, so just return that
269
+ return params [ param . key ] ?? param . key
270
+ } )
271
+
242
272
return {
243
273
param : key ,
244
- value : null ,
245
- type : type ,
274
+ value,
275
+ type : dynamicParamType ,
246
276
// This value always has to be a string.
247
- treeSegment : [ key , '' , type ] ,
277
+ treeSegment : [ key , value . join ( '/' ) , dynamicParamType ] ,
248
278
}
249
279
}
280
+
250
281
return findDynamicParamFromRouterState ( flightRouterState , segment )
251
282
}
252
283
@@ -809,6 +840,7 @@ async function renderToHTMLOrFlightImpl(
809
840
810
841
const getDynamicParamFromSegment = makeGetDynamicParamFromSegment (
811
842
params ,
843
+ pagePath ,
812
844
// `FlightRouterState` is unconditionally provided here because this method uses it
813
845
// to extract dynamic params as a fallback if they're not present in the path.
814
846
parsedFlightRouterState
0 commit comments