@@ -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,10 @@ 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 replacer = handlePrerenderParamsReplacement ( params , currentRoutePath ) ;
442
+ const routeWithResolvedParams = currentRoutePath
443
+ . replace ( URL_PARAMETER_REGEXP , replacer )
444
+ . replace ( CATCH_ALL_REGEXP , replacer ) ;
446
445
447
446
yield {
448
447
...meta ,
@@ -473,6 +472,34 @@ async function* handleSSGRoute(
473
472
}
474
473
}
475
474
475
+ /**
476
+ * Creates a replacer function used for substituting parameter placeholders in a route path
477
+ * with their corresponding values provided in the `params` object.
478
+ *
479
+ * @param params - An object mapping parameter names to their string values.
480
+ * @param currentRoutePath - The current route path, used for constructing error messages.
481
+ * @returns A function that replaces a matched parameter placeholder (e.g., ':id') with its corresponding value.
482
+ */
483
+ function handlePrerenderParamsReplacement (
484
+ params : Record < string , string > ,
485
+ currentRoutePath : string ,
486
+ ) : ( substring : string , ...args : unknown [ ] ) => string {
487
+ return ( match ) => {
488
+ const parameterName = match . slice ( 1 ) ;
489
+ const value = params [ parameterName ] ;
490
+ if ( typeof value !== 'string' ) {
491
+ throw new Error (
492
+ `The 'getPrerenderParams' function defined for the '${ stripLeadingSlash ( currentRoutePath ) } ' route ` +
493
+ `returned a non-string value for parameter '${ parameterName } '. ` +
494
+ `Please make sure the 'getPrerenderParams' function returns values for all parameters ` +
495
+ 'specified in this route.' ,
496
+ ) ;
497
+ }
498
+
499
+ return parameterName === '**' ? `/${ value } ` : value ;
500
+ } ;
501
+ }
502
+
476
503
/**
477
504
* Resolves the `redirectTo` property for a given route.
478
505
*
@@ -530,9 +557,9 @@ function buildServerConfigRouteTree({ routes, appShellRoute }: ServerRoutesConfi
530
557
continue ;
531
558
}
532
559
533
- if ( path . includes ( '* ' ) && 'getPrerenderParams' in metadata ) {
560
+ if ( 'getPrerenderParams' in metadata && ( path . includes ( '/*/ ' ) || path . endsWith ( '/*' ) ) ) {
534
561
errors . push (
535
- `Invalid '${ path } ' route configuration: 'getPrerenderParams' cannot be used with a '*' or '**' route.` ,
562
+ `Invalid '${ path } ' route configuration: 'getPrerenderParams' cannot be used with a '*' route.` ,
536
563
) ;
537
564
continue ;
538
565
}
0 commit comments