@@ -142,31 +142,84 @@ class Router {
142142
143143 /// Handle all request to [route] using [handler] .
144144 void all (String route, Function handler) {
145- _routes.add (RouterEntry ('ALL' , route, handler));
145+ _all (route, handler, mounted: false );
146+ }
147+
148+ void _all (String route, Function handler, {required bool mounted}) {
149+ _routes.add (RouterEntry ('ALL' , route, handler, mounted: mounted));
146150 }
147151
148152 /// Mount a handler below a prefix.
149- ///
150- /// In this case prefix may not contain any parameters, nor
151- void mount (String prefix, Handler handler) {
153+ void mount (String prefix, Function handler) {
152154 if (! prefix.startsWith ('/' )) {
153155 throw ArgumentError .value (prefix, 'prefix' , 'must start with a slash' );
154156 }
155157
156158 // first slash is always in request.handlerPath
157159 final path = prefix.substring (1 );
160+ const pathParam = '__path' ;
158161 if (prefix.endsWith ('/' )) {
159- all (prefix + '<path|[^]*>' , (Request request) {
160- return handler (request.change (path: path));
161- });
162+ _all (
163+ prefix + '<$pathParam |[^]*>' ,
164+ (Request request, RouterEntry route) {
165+ // Remove path param from extracted route params
166+ final paramsList = [...route.params]..removeLast ();
167+ return _invokeMountedHandler (request, handler, path, paramsList);
168+ },
169+ mounted: true ,
170+ );
162171 } else {
163- all (prefix, (Request request) {
164- return handler (request.change (path: path));
165- });
166- all (prefix + '/<path|[^]*>' , (Request request) {
167- return handler (request.change (path: path + '/' ));
168- });
172+ _all (
173+ prefix,
174+ (Request request, RouterEntry route) {
175+ return _invokeMountedHandler (request, handler, path, route.params);
176+ },
177+ mounted: true ,
178+ );
179+ _all (
180+ prefix + '/<$pathParam |[^]*>' ,
181+ (Request request, RouterEntry route) {
182+ // Remove path param from extracted route params
183+ final paramsList = [...route.params]..removeLast ();
184+ return _invokeMountedHandler (
185+ request, handler, path + '/' , paramsList);
186+ },
187+ mounted: true ,
188+ );
189+ }
190+ }
191+
192+ Future <Response > _invokeMountedHandler (Request request, Function handler,
193+ String path, List <String > paramsList) async {
194+ final params = _getParamsFromRequest (request);
195+ final resolvedPath = _replaceParamsInPath (request, path, params);
196+
197+ return await Function .apply (handler, [
198+ request.change (path: resolvedPath),
199+ ...paramsList.map ((n) => params[n]),
200+ ]) as Response ;
201+ }
202+
203+ Map <String , String > _getParamsFromRequest (Request request) {
204+ return request.context['shelf_router/params' ] as Map <String , String >;
205+ }
206+
207+ /// Replaces the variable slots (<someVar>) from [path] with the
208+ /// values from [params]
209+ String _replaceParamsInPath (
210+ Request request,
211+ String path,
212+ Map <String , String > params,
213+ ) {
214+ // TODO(davidmartos96): Maybe this could be done in a different way
215+ // to avoid replacing the path N times, N being the number of params
216+ var resolvedPath = path;
217+ for (final paramEntry in params.entries) {
218+ resolvedPath =
219+ resolvedPath.replaceFirst ('<${paramEntry .key }>' , paramEntry.value);
169220 }
221+
222+ return resolvedPath;
170223 }
171224
172225 /// Route incoming requests to registered handlers.
0 commit comments