@@ -46,6 +46,12 @@ interface Route extends AngularRoute {
4646 */
4747const MODULE_PRELOAD_MAX = 10 ;
4848
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+
4955/**
5056 * Regular expression to match segments preceded by a colon in a string.
5157 */
@@ -391,7 +397,11 @@ async function* handleSSGRoute(
391397 meta . redirectTo = resolveRedirectTo ( currentRoutePath , redirectTo ) ;
392398 }
393399
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+ ) {
395405 // Route has no parameters
396406 yield {
397407 ...meta ,
@@ -415,7 +425,9 @@ async function* handleSSGRoute(
415425
416426 if ( serverConfigRouteTree ) {
417427 // Automatically resolve dynamic parameters for nested routes.
418- const catchAllRoutePath = joinUrlParts ( currentRoutePath , '**' ) ;
428+ const catchAllRoutePath = isCatchAllRoute
429+ ? currentRoutePath
430+ : joinUrlParts ( currentRoutePath , '**' ) ;
419431 const match = serverConfigRouteTree . match ( catchAllRoutePath ) ;
420432 if ( match && match . renderMode === RenderMode . Prerender && ! ( 'getPrerenderParams' in match ) ) {
421433 serverConfigRouteTree . insert ( catchAllRoutePath , {
@@ -429,20 +441,10 @@ async function* handleSSGRoute(
429441 const parameters = await runInInjectionContext ( parentInjector , ( ) => getPrerenderParams ( ) ) ;
430442 try {
431443 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 ) ;
446448
447449 yield {
448450 ...meta ,
@@ -473,6 +475,34 @@ async function* handleSSGRoute(
473475 }
474476}
475477
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+
476506/**
477507 * Resolves the `redirectTo` property for a given route.
478508 *
@@ -530,9 +560,9 @@ function buildServerConfigRouteTree({ routes, appShellRoute }: ServerRoutesConfi
530560 continue ;
531561 }
532562
533- if ( path . includes ( '* ' ) && 'getPrerenderParams' in metadata ) {
563+ if ( 'getPrerenderParams' in metadata && ( path . includes ( '/*/ ' ) || path . endsWith ( '/*' ) ) ) {
534564 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.` ,
536566 ) ;
537567 continue ;
538568 }
0 commit comments