@@ -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,8 @@ 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 ( ! isCatchAllRoute && ! URL_PARAMETER_REGEXP . test ( currentRoutePath ) ) {
395402 // Route has no parameters
396403 yield {
397404 ...meta ,
@@ -415,7 +422,9 @@ async function* handleSSGRoute(
415422
416423 if ( serverConfigRouteTree ) {
417424 // Automatically resolve dynamic parameters for nested routes.
418- const catchAllRoutePath = joinUrlParts ( currentRoutePath , '**' ) ;
425+ const catchAllRoutePath = isCatchAllRoute
426+ ? currentRoutePath
427+ : joinUrlParts ( currentRoutePath , '**' ) ;
419428 const match = serverConfigRouteTree . match ( catchAllRoutePath ) ;
420429 if ( match && match . renderMode === RenderMode . Prerender && ! ( 'getPrerenderParams' in match ) ) {
421430 serverConfigRouteTree . insert ( catchAllRoutePath , {
@@ -429,20 +438,9 @@ async function* handleSSGRoute(
429438 const parameters = await runInInjectionContext ( parentInjector , ( ) => getPrerenderParams ( ) ) ;
430439 try {
431440 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 ) ) ;
446444
447445 yield {
448446 ...meta ,
@@ -473,6 +471,34 @@ async function* handleSSGRoute(
473471 }
474472}
475473
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+
476502/**
477503 * Resolves the `redirectTo` property for a given route.
478504 *
@@ -530,9 +556,9 @@ function buildServerConfigRouteTree({ routes, appShellRoute }: ServerRoutesConfi
530556 continue ;
531557 }
532558
533- if ( path . includes ( '* ' ) && 'getPrerenderParams' in metadata ) {
559+ if ( 'getPrerenderParams' in metadata && ( path . includes ( '/*/ ' ) || path . endsWith ( '/*' ) ) ) {
534560 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.` ,
536562 ) ;
537563 continue ;
538564 }
0 commit comments