@@ -440,9 +440,20 @@ function flattenRoutes<
440
440
}
441
441
442
442
/**
443
- * Computes all combinations of optional path segments for a given path.
443
+ * Computes all combinations of optional path segments for a given path,
444
+ * excluding combinations that are ambiguous and of lower priority.
445
+ *
446
+ * For example, `/one/:two?/three/:four?/:five?` explodes to:
447
+ * - `/one/three`
448
+ * - `/one/:two/three`
449
+ * - `/one/three/:four`
450
+ * - `/one/three/:five`
451
+ * - `/one/:two/three/:four`
452
+ * - `/one/:two/three/:five`
453
+ * - `/one/three/:four/:five`
454
+ * - `/one/:two/three/:four/:five`
444
455
*/
445
- let _explodeOptionalSegments = ( path : string ) : string [ ] => {
456
+ function explodeOptionalSegments ( path : string ) : string [ ] {
446
457
let segments = path . split ( "/" ) ;
447
458
if ( segments . length === 0 ) return [ ] ;
448
459
@@ -459,66 +470,23 @@ let _explodeOptionalSegments = (path: string): string[] => {
459
470
return isOptional ? [ "" , required ] : [ required ] ;
460
471
}
461
472
462
- let restExploded = _explodeOptionalSegments ( rest . join ( "/" ) ) ;
463
- return restExploded . flatMap ( ( subpath ) => {
464
- // /one + / + :two/three -> /one/:two/three
465
- let requiredExploded = subpath === "" ? required : required + "/" + subpath ;
466
- // For optional segments, return the exploded path _without_ current segment first (`subpath`)
467
- // and exploded path _with_ current segment later (`subpath`)
468
- // This ensures that exploded paths are emitted in priority order
469
- // `/one/three/:four` will come before `/one/three/:five`
470
- return isOptional ? [ subpath , requiredExploded ] : [ requiredExploded ] ;
471
- } ) ;
472
- } ;
473
-
474
- /**
475
- * Computes all combinations of optional path segments for a given path,
476
- * excluding combinations that are ambiguous and of lower priority.
477
- *
478
- * For example, `/one/:two?/three/:four?/:five?` explodes to:
479
- * - `/one/three`
480
- * - `/one/:two/three`
481
- * - `/one/three/:four`
482
- * - `/one/:two/three/:four`
483
- * - `/one/three/:four/:five`
484
- * - `/one/:two/three/:four/:five`
485
- *
486
- * Note that these paths are not returned:
487
- * - `/one/three/:five` (because `/one/three/:four` has priority)
488
- * - `/one/:two/three/:five` (because `/one/:two/three/:four` has priority)
489
- */
490
- let explodeOptionalSegments = ( path : string ) => {
491
- let result : string [ ] = [ ] ;
492
- // Compute hash for dynamic path segments
493
- // /one/:two/three/:four -> /one/:/three/:
494
- let dynamicHash = ( subpath : string ) =>
495
- subpath
496
- . split ( "/" )
497
- . map ( ( segment ) => ( segment . startsWith ( ":" ) ? ":" : segment ) )
498
- . join ( "/" ) ;
499
-
500
- let dynamicHashes = new Set < string > ( ) ;
501
- for ( let exploded of _explodeOptionalSegments ( path ) ) {
502
- let hash = dynamicHash ( exploded ) ;
503
-
504
- // `/one/three/:four` and `/one/three/:five` have the same hash: `/one/three/:`
505
- // so we only emit the first one of these we come across
506
- // _explodeOptionalSegments returns exploded paths in priority order,
507
- // so `/one/three/:four` will come before `/one/three/:five`
508
- if ( dynamicHashes . has ( hash ) ) continue ;
509
-
510
- dynamicHashes . add ( hash ) ;
511
-
512
- // for absolute paths, ensure `/` instead of empty segment
513
- if ( path . startsWith ( "/" ) && exploded === "" ) {
514
- result . push ( "/" ) ;
515
- continue ;
516
- }
517
-
518
- result . push ( exploded ) ;
519
- }
520
- return result ;
521
- } ;
473
+ let restExploded = explodeOptionalSegments ( rest . join ( "/" ) ) ;
474
+ return restExploded
475
+ . flatMap ( ( subpath ) => {
476
+ // /one + / + :two/three -> /one/:two/three
477
+ let requiredExploded =
478
+ subpath === "" ? required : required + "/" + subpath ;
479
+ // For optional segments, return the exploded path _without_ current segment first (`subpath`)
480
+ // and exploded path _with_ current segment later (`subpath`)
481
+ // This ensures that exploded paths are emitted in priority order
482
+ // `/one/three/:four` will come before `/one/three/:five`
483
+ return isOptional ? [ subpath , requiredExploded ] : [ requiredExploded ] ;
484
+ } )
485
+ . map ( ( exploded ) => {
486
+ // for absolute paths, ensure `/` instead of empty segment
487
+ return path . startsWith ( "/" ) && exploded === "" ? "/" : exploded ;
488
+ } ) ;
489
+ }
522
490
523
491
function rankRouteBranches ( branches : RouteBranch [ ] ) : void {
524
492
branches . sort ( ( a , b ) =>
0 commit comments