@@ -46,6 +46,12 @@ interface Route extends AngularRoute {
46
46
*/
47
47
const MODULE_PRELOAD_MAX = 10 ;
48
48
49
+ /**
50
+ * Regular expression to match a catch-all route pattern in a URL path,
51
+ * specifically one that ends with '/**'.
52
+ */
53
+ const CATCH_ALL_REGEXP = / \/ ( \* \* ) $ / ;
54
+
49
55
/**
50
56
* Regular expression to match segments preceded by a colon in a string.
51
57
*/
@@ -391,7 +397,8 @@ async function* handleSSGRoute(
391
397
meta . redirectTo = resolveRedirectTo ( currentRoutePath , redirectTo ) ;
392
398
}
393
399
394
- if ( ! URL_PARAMETER_REGEXP . test ( currentRoutePath ) ) {
400
+ const isCatchAllRoute = CATCH_ALL_REGEXP . test ( currentRoutePath ) ;
401
+ if ( ! isCatchAllRoute && ! URL_PARAMETER_REGEXP . test ( currentRoutePath ) ) {
395
402
// Route has no parameters
396
403
yield {
397
404
...meta ,
@@ -415,7 +422,9 @@ async function* handleSSGRoute(
415
422
416
423
if ( serverConfigRouteTree ) {
417
424
// Automatically resolve dynamic parameters for nested routes.
418
- const catchAllRoutePath = joinUrlParts ( currentRoutePath , '**' ) ;
425
+ const catchAllRoutePath = isCatchAllRoute
426
+ ? currentRoutePath
427
+ : joinUrlParts ( currentRoutePath , '**' ) ;
419
428
const match = serverConfigRouteTree . match ( catchAllRoutePath ) ;
420
429
if ( match && match . renderMode === RenderMode . Prerender && ! ( 'getPrerenderParams' in match ) ) {
421
430
serverConfigRouteTree . insert ( catchAllRoutePath , {
@@ -429,20 +438,9 @@ async function* handleSSGRoute(
429
438
const parameters = await runInInjectionContext ( parentInjector , ( ) => getPrerenderParams ( ) ) ;
430
439
try {
431
440
for ( const params of parameters ) {
432
- const routeWithResolvedParams = currentRoutePath . replace ( URL_PARAMETER_REGEXP , ( match ) => {
433
- const parameterName = match . slice ( 1 ) ;
434
- const value = params [ parameterName ] ;
435
- if ( typeof value !== 'string' ) {
436
- throw new Error (
437
- `The 'getPrerenderParams' function defined for the '${ stripLeadingSlash ( currentRoutePath ) } ' route ` +
438
- `returned a non-string value for parameter '${ parameterName } '. ` +
439
- `Please make sure the 'getPrerenderParams' function returns values for all parameters ` +
440
- 'specified in this route.' ,
441
- ) ;
442
- }
443
-
444
- return value ;
445
- } ) ;
441
+ const routeWithResolvedParams = currentRoutePath
442
+ . replace ( URL_PARAMETER_REGEXP , handlePrerenderParamsReplacement ( params , currentRoutePath ) )
443
+ . replace ( CATCH_ALL_REGEXP , handlePrerenderParamsReplacement ( params , currentRoutePath ) ) ;
446
444
447
445
yield {
448
446
...meta ,
@@ -473,6 +471,34 @@ async function* handleSSGRoute(
473
471
}
474
472
}
475
473
474
+ /**
475
+ * Creates a replacer function used for substituting parameter placeholders in a route path
476
+ * with their corresponding values provided in the `params` object.
477
+ *
478
+ * @param params - An object mapping parameter names to their string values.
479
+ * @param currentRoutePath - The current route path, used for constructing error messages.
480
+ * @returns A function that replaces a matched parameter placeholder (e.g., ':id') with its corresponding value.
481
+ */
482
+ function handlePrerenderParamsReplacement (
483
+ params : Record < string , string > ,
484
+ currentRoutePath : string ,
485
+ ) : ( substring : string , ...args : unknown [ ] ) => string {
486
+ return ( match ) => {
487
+ const parameterName = match . slice ( 1 ) ;
488
+ const value = params [ parameterName ] ;
489
+ if ( typeof value !== 'string' ) {
490
+ throw new Error (
491
+ `The 'getPrerenderParams' function defined for the '${ stripLeadingSlash ( currentRoutePath ) } ' route ` +
492
+ `returned a non-string value for parameter '${ parameterName } '. ` +
493
+ `Please make sure the 'getPrerenderParams' function returns values for all parameters ` +
494
+ 'specified in this route.' ,
495
+ ) ;
496
+ }
497
+
498
+ return parameterName === '**' ? `/${ value } ` : value ;
499
+ } ;
500
+ }
501
+
476
502
/**
477
503
* Resolves the `redirectTo` property for a given route.
478
504
*
@@ -530,9 +556,9 @@ function buildServerConfigRouteTree({ routes, appShellRoute }: ServerRoutesConfi
530
556
continue ;
531
557
}
532
558
533
- if ( path . includes ( '* ' ) && 'getPrerenderParams' in metadata ) {
559
+ if ( 'getPrerenderParams' in metadata && ( path . includes ( '/*/ ' ) || path . endsWith ( '/*' ) ) ) {
534
560
errors . push (
535
- `Invalid '${ path } ' route configuration: 'getPrerenderParams' cannot be used with a '*' or '**' route.` ,
561
+ `Invalid '${ path } ' route configuration: 'getPrerenderParams' cannot be used with a '*' route.` ,
536
562
) ;
537
563
continue ;
538
564
}
0 commit comments