@@ -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,11 @@ 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 (
402
+ ( isCatchAllRoute && ! getPrerenderParams ) ||
403
+ ( ! isCatchAllRoute && ! URL_PARAMETER_REGEXP . test ( currentRoutePath ) )
404
+ ) {
395
405
// Route has no parameters
396
406
yield {
397
407
...meta ,
@@ -415,7 +425,9 @@ async function* handleSSGRoute(
415
425
416
426
if ( serverConfigRouteTree ) {
417
427
// Automatically resolve dynamic parameters for nested routes.
418
- const catchAllRoutePath = joinUrlParts ( currentRoutePath , '**' ) ;
428
+ const catchAllRoutePath = isCatchAllRoute
429
+ ? currentRoutePath
430
+ : joinUrlParts ( currentRoutePath , '**' ) ;
419
431
const match = serverConfigRouteTree . match ( catchAllRoutePath ) ;
420
432
if ( match && match . renderMode === RenderMode . Prerender && ! ( 'getPrerenderParams' in match ) ) {
421
433
serverConfigRouteTree . insert ( catchAllRoutePath , {
@@ -429,20 +441,10 @@ async function* handleSSGRoute(
429
441
const parameters = await runInInjectionContext ( parentInjector , ( ) => getPrerenderParams ( ) ) ;
430
442
try {
431
443
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
- } ) ;
444
+ const replacer = handlePrerenderParamsReplacement ( params , currentRoutePath ) ;
445
+ const routeWithResolvedParams = currentRoutePath
446
+ . replace ( URL_PARAMETER_REGEXP , replacer )
447
+ . replace ( CATCH_ALL_REGEXP , replacer ) ;
446
448
447
449
yield {
448
450
...meta ,
@@ -473,6 +475,34 @@ async function* handleSSGRoute(
473
475
}
474
476
}
475
477
478
+ /**
479
+ * Creates a replacer function used for substituting parameter placeholders in a route path
480
+ * with their corresponding values provided in the `params` object.
481
+ *
482
+ * @param params - An object mapping parameter names to their string values.
483
+ * @param currentRoutePath - The current route path, used for constructing error messages.
484
+ * @returns A function that replaces a matched parameter placeholder (e.g., ':id') with its corresponding value.
485
+ */
486
+ function handlePrerenderParamsReplacement (
487
+ params : Record < string , string > ,
488
+ currentRoutePath : string ,
489
+ ) : ( substring : string , ...args : unknown [ ] ) => string {
490
+ return ( match ) => {
491
+ const parameterName = match . slice ( 1 ) ;
492
+ const value = params [ parameterName ] ;
493
+ if ( typeof value !== 'string' ) {
494
+ throw new Error (
495
+ `The 'getPrerenderParams' function defined for the '${ stripLeadingSlash ( currentRoutePath ) } ' route ` +
496
+ `returned a non-string value for parameter '${ parameterName } '. ` +
497
+ `Please make sure the 'getPrerenderParams' function returns values for all parameters ` +
498
+ 'specified in this route.' ,
499
+ ) ;
500
+ }
501
+
502
+ return parameterName === '**' ? `/${ value } ` : value ;
503
+ } ;
504
+ }
505
+
476
506
/**
477
507
* Resolves the `redirectTo` property for a given route.
478
508
*
@@ -530,9 +560,9 @@ function buildServerConfigRouteTree({ routes, appShellRoute }: ServerRoutesConfi
530
560
continue ;
531
561
}
532
562
533
- if ( path . includes ( '* ' ) && 'getPrerenderParams' in metadata ) {
563
+ if ( 'getPrerenderParams' in metadata && ( path . includes ( '/*/ ' ) || path . endsWith ( '/*' ) ) ) {
534
564
errors . push (
535
- `Invalid '${ path } ' route configuration: 'getPrerenderParams' cannot be used with a '*' or '**' route.` ,
565
+ `Invalid '${ path } ' route configuration: 'getPrerenderParams' cannot be used with a '*' route.` ,
536
566
) ;
537
567
continue ;
538
568
}
0 commit comments