1+ import { safeCreateRegExp } from "../agent/safeCreateRegExp" ;
2+ import { escapeStringRegexp } from "./escapeStringRegexp" ;
13import { looksLikeASecret } from "./looksLikeASecret" ;
24import { safeDecodeURIComponent } from "./safeDecodeURIComponent" ;
35import { tryParseURLPath } from "./tryParseURLPath" ;
@@ -15,7 +17,7 @@ const HASH = /^(?:[a-f0-9]{32}|[a-f0-9]{40}|[a-f0-9]{64}|[a-f0-9]{128})$/i;
1517const HASH_LENGTHS = [ 32 , 40 , 64 , 128 ] ;
1618const NUMBER_ARRAY = / ^ \d + (?: , \d + ) * $ / ;
1719
18- export function buildRouteFromURL ( url : string ) {
20+ export function buildRouteFromURL ( url : string , custom : string [ ] = [ ] ) {
1921 let path = tryParseURLPath ( url ) ;
2022
2123 if ( ! path ) {
@@ -29,7 +31,10 @@ export function buildRouteFromURL(url: string) {
2931 }
3032 }
3133
32- const route = path . split ( "/" ) . map ( replaceURLSegmentWithParam ) . join ( "/" ) ;
34+ const route = path
35+ . split ( "/" )
36+ . map ( replaceURLSegmentWithCustomParam ( custom ) )
37+ . join ( "/" ) ;
3338
3439 if ( route === "/" ) {
3540 return "/" ;
@@ -42,6 +47,46 @@ export function buildRouteFromURL(url: string) {
4247 return route ;
4348}
4449
50+ function compileCustom ( pattern : string ) {
51+ if ( ! pattern . includes ( "{" ) || ! pattern . includes ( "}" ) ) {
52+ return undefined ;
53+ }
54+
55+ const supported : Record < string , string > = {
56+ "{digits}" : `\\d+` ,
57+ "{alpha}" : "[a-zA-Z]+" ,
58+ } ;
59+
60+ // Split the pattern into tokens (placeholders and literals)
61+ const placeholderRegex = / ( \{ [ a - z A - Z ] + } ) / g;
62+ const parts = pattern . split ( placeholderRegex ) ;
63+ const regexParts = parts . map ( ( part ) => {
64+ if ( supported [ part ] ) {
65+ return supported [ part ] ;
66+ }
67+
68+ return escapeStringRegexp ( part ) ;
69+ } ) ;
70+
71+ return safeCreateRegExp ( `^${ regexParts . join ( "" ) } $` , "" ) ;
72+ }
73+
74+ function replaceURLSegmentWithCustomParam ( custom : string [ ] ) {
75+ const customPatterns = custom
76+ . map ( compileCustom )
77+ . filter ( ( p ) => p !== undefined ) ;
78+
79+ return ( segment : string ) => {
80+ for ( const pattern of customPatterns ) {
81+ if ( pattern && pattern . test ( segment ) ) {
82+ return `:custom` ;
83+ }
84+ }
85+
86+ return replaceURLSegmentWithParam ( segment ) ;
87+ } ;
88+ }
89+
4590function replaceURLSegmentWithParam ( segment : string ) {
4691 const charCode = segment . charCodeAt ( 0 ) ;
4792 const startsWithNumber = charCode >= 48 && charCode <= 57 ; // ASCII codes for '0' to '9'
0 commit comments