1- using LinkRouter . App . Models ;
1+ using System . Text ;
2+ using System . Text . Json . Serialization ;
3+ using System . Text . RegularExpressions ;
4+ using LinkRouter . App . Models ;
25
36namespace LinkRouter . App . Configuration ;
47
@@ -26,4 +29,83 @@ public class NotFoundBehaviorConfig
2629 public bool RedirectOn404 { get ; set ; } = false ;
2730 public string RedirectUrl { get ; set ; } = "https://example.com/404" ;
2831 }
32+
33+ [ JsonIgnore ]
34+ public static Regex PlaceholderPattern => new ( @"\\\{(\d|\w+)\}" ) ;
35+
36+ [ JsonIgnore ]
37+ public CompiledRoute [ ] ? CompiledRoutes { get ; set ; }
38+
39+ public void CompileRoutes ( )
40+ {
41+ var compiledRoutes = new List < CompiledRoute > ( ) ;
42+
43+ foreach ( var route in Routes )
44+ {
45+ if ( ! route . Route . StartsWith ( "/" ) )
46+ route . Route = "/" + route . Route ;
47+
48+ if ( ! route . Route . EndsWith ( "/" ) )
49+ route . Route += "/" ;
50+
51+ var compiled = new CompiledRoute
52+ {
53+ Route = route . Route ,
54+ RedirectUrl = route . RedirectUrl
55+ } ;
56+
57+ var replacements = new List < ( int Index , int Length , string NewText ) > ( ) ;
58+
59+ var escaped = Regex . Escape ( route . Route ) ;
60+
61+ var matches = PlaceholderPattern . Matches ( escaped ) ;
62+
63+
64+ foreach ( var match in matches . Select ( x => x ) )
65+ {
66+ // Check if the placeholder is immediately followed by another placeholder
67+
68+ Console . WriteLine ( "matchlenght: " + ( match . Index + match . Length + 2 ) + " route lenght" + escaped . Length ) ;
69+
70+ if ( escaped . Length >= match . Index + match . Length + 2 && escaped . Substring ( match . Index + match . Length , 2 ) == "\\ {" )
71+ throw new InvalidOperationException (
72+ $ "Placeholder { match . Groups [ 1 ] . Value } cannot be immediately followed by another placeholder. " +
73+ $ "Please add a string literal as separator.") ;
74+
75+ replacements . Add ( ( match . Index , match . Length , "(.+)" ) ) ;
76+ }
77+
78+ var compiledRouteBuilder = new StringBuilder ( escaped ) ;
79+
80+ foreach ( var replacement in replacements . OrderByDescending ( r => r . Index ) )
81+ {
82+ compiledRouteBuilder . Remove ( replacement . Index , replacement . Length ) ;
83+ compiledRouteBuilder . Insert ( replacement . Index , replacement . NewText ) ;
84+ }
85+
86+ compiled . CompiledPattern = new Regex ( compiledRouteBuilder . ToString ( ) , RegexOptions . Compiled ) ;
87+
88+ Console . WriteLine ( compiled . CompiledPattern . ToString ( ) ) ;
89+
90+ var duplicate = matches
91+ . Select ( ( m , i ) => m . Groups [ 1 ] . Value )
92+ . GroupBy ( x => x )
93+ . FirstOrDefault ( x => x . Count ( ) > 1 ) ;
94+
95+ if ( duplicate != null )
96+ throw new InvalidOperationException ( "Cannot use a placeholder twice in the route: " + duplicate . Key ) ;
97+
98+ compiled . Placeholders = matches
99+ . Select ( ( m , i ) => m . Groups [ 1 ] . Value )
100+ . Distinct ( )
101+ . Select ( ( name , i ) => ( name , i ) )
102+ . ToDictionary ( x => x . name , x => x . i + 1 ) ;
103+
104+ compiledRoutes . Add ( compiled ) ;
105+ }
106+
107+ CompiledRoutes = compiledRoutes
108+ . ToArray ( ) ;
109+ }
110+
29111}
0 commit comments