diff --git a/packages/routing/lib/src/styles/express_style.dart b/packages/routing/lib/src/styles/express_style.dart index 5f10830..79264a9 100644 --- a/packages/routing/lib/src/styles/express_style.dart +++ b/packages/routing/lib/src/styles/express_style.dart @@ -7,7 +7,7 @@ import '../routing_style.dart'; /// existing Express-like routing pattern. It provides the familiar app.get(), /// app.post(), etc. methods while utilizing the underlying routing system. class ExpressStyle implements RoutingStyle { - final Router _router; + Router _router; @override Router get router => _router; @@ -36,7 +36,8 @@ class ExpressStyle implements RoutingStyle { /// }); /// ``` Route get(String path, T handler, {List middleware = const []}) { - return _router.get(path, handler, middleware: middleware); + return _router.get(path, _wrapHandler(handler), + middleware: middleware.map(_wrapMiddleware).toList()); } /// Register a route that handles POST requests. @@ -47,7 +48,8 @@ class ExpressStyle implements RoutingStyle { /// }); /// ``` Route post(String path, T handler, {List middleware = const []}) { - return _router.post(path, handler, middleware: middleware); + return _router.post(path, _wrapHandler(handler), + middleware: middleware.map(_wrapMiddleware).toList()); } /// Register a route that handles PUT requests. @@ -58,7 +60,8 @@ class ExpressStyle implements RoutingStyle { /// }); /// ``` Route put(String path, T handler, {List middleware = const []}) { - return _router.put(path, handler, middleware: middleware) as Route; + return _router.addRoute('PUT', path, _wrapHandler(handler), + middleware: middleware.map(_wrapMiddleware).toList()); } /// Register a route that handles DELETE requests. @@ -69,7 +72,8 @@ class ExpressStyle implements RoutingStyle { /// }); /// ``` Route delete(String path, T handler, {List middleware = const []}) { - return _router.delete(path, handler, middleware: middleware); + return _router.delete(path, _wrapHandler(handler), + middleware: middleware.map(_wrapMiddleware).toList()); } /// Register a route that handles PATCH requests. @@ -80,7 +84,8 @@ class ExpressStyle implements RoutingStyle { /// }); /// ``` Route patch(String path, T handler, {List middleware = const []}) { - return _router.patch(path, handler, middleware: middleware); + return _router.patch(path, _wrapHandler(handler), + middleware: middleware.map(_wrapMiddleware).toList()); } /// Register a route that handles HEAD requests. @@ -91,7 +96,8 @@ class ExpressStyle implements RoutingStyle { /// }); /// ``` Route head(String path, T handler, {List middleware = const []}) { - return _router.head(path, handler, middleware: middleware); + return _router.head(path, _wrapHandler(handler), + middleware: middleware.map(_wrapMiddleware).toList()); } /// Register a route that handles OPTIONS requests. @@ -102,7 +108,8 @@ class ExpressStyle implements RoutingStyle { /// }); /// ``` Route options(String path, T handler, {List middleware = const []}) { - return _router.options(path, handler, middleware: middleware); + return _router.options(path, _wrapHandler(handler), + middleware: middleware.map(_wrapMiddleware).toList()); } /// Register a route that handles all HTTP methods. @@ -113,7 +120,8 @@ class ExpressStyle implements RoutingStyle { /// }); /// ``` Route all(String path, T handler, {List middleware = const []}) { - return _router.all(path, handler, middleware: middleware); + return _router.all(path, _wrapHandler(handler), + middleware: middleware.map(_wrapMiddleware).toList()); } /// Use middleware for all routes. @@ -125,7 +133,16 @@ class ExpressStyle implements RoutingStyle { /// }); /// ``` void use(T middleware) { - _router.chain([middleware]); + // Chain middleware and update router + var chainedRouter = _router.chain([_wrapMiddleware(middleware)]); + _router = chainedRouter; + + // Apply middleware to existing routes + for (var route in _router.routes) { + if (route is! SymlinkRoute) { + route.handlers.insert(0, _wrapMiddleware(middleware)); + } + } } /// Create a route group with optional prefix and middleware. @@ -138,9 +155,54 @@ class ExpressStyle implements RoutingStyle { /// ``` void group(String prefix, void Function(ExpressStyle router) callback, {List middleware = const []}) { - _router.group(prefix, (router) { - callback(ExpressStyle(router)); - }, middleware: middleware); + // Create a new router for the group + var groupRouter = Router(); + + // Create new style instance for group + var groupStyle = ExpressStyle(groupRouter); + + // Execute callback with group style + callback(groupStyle); + + // Apply middleware to all routes in the group + if (middleware.isNotEmpty) { + for (var route in groupRouter.routes) { + if (route is! SymlinkRoute) { + route.handlers.insertAll(0, middleware.map(_wrapMiddleware).toList()); + } + } + } + + // Mount group router with prefix + _router.mount(prefix, groupRouter); + } + + // Helper to wrap handler functions to match expected signature + T _wrapHandler(T handler) { + if (handler is Function) { + return ((req, res) { + if (handler is Function(dynamic, dynamic)) { + handler(req, res); + } else if (handler is Function(dynamic, dynamic, Function)) { + handler(req, res, () {}); + } + }) as T; + } + return handler; + } + + // Helper to wrap middleware functions to match expected signature + T _wrapMiddleware(T middleware) { + if (middleware is Function) { + return ((req, res) { + if (middleware is Function(dynamic, dynamic, Function)) { + middleware(req, res, () {}); + } else if (middleware is Function(dynamic, dynamic)) { + middleware(req, res); + } + }) as T; + } + return middleware; } } diff --git a/packages/routing/lib/src/styles/laravel_style.dart b/packages/routing/lib/src/styles/laravel_style.dart index a5d089b..9c86eda 100644 --- a/packages/routing/lib/src/styles/laravel_style.dart +++ b/packages/routing/lib/src/styles/laravel_style.dart @@ -7,7 +7,10 @@ import '../routing_style.dart'; /// underlying routing system. It demonstrates how different routing styles /// can be implemented on top of the core routing functionality. class LaravelStyle implements RoutingStyle { - final Router _router; + Router _router; + String? _groupPrefix; + String? _groupName; + List _currentMiddleware = []; @override Router get router => _router; @@ -35,9 +38,49 @@ class LaravelStyle implements RoutingStyle { /// Route::post('/users', handler); /// ``` Route route(String method, String path, T handler, - {List middleware = const []}) { - return _router.addRoute(method.toUpperCase(), path, handler, - middleware: middleware); + {List middleware = const [], String? name}) { + var allMiddleware = [..._currentMiddleware, ...middleware]; + var route = _router.addRoute(method.toUpperCase(), path, handler, + middleware: allMiddleware); + + // Auto-generate route name if not provided + if (name != null) { + route.name = name; + } else { + // Convert path to route name (e.g., /users/{id} -> users.show) + var segments = path.split('/').where((s) => s.isNotEmpty).toList(); + if (segments.isNotEmpty) { + var lastSegment = segments.last; + var prefix = segments.length > 1 ? segments[segments.length - 2] : ''; + var groupPrefix = _groupName ?? _groupPrefix?.replaceAll('/', '.'); + var namePrefix = groupPrefix != null ? '$groupPrefix.' : ''; + + // Generate name based on method and path + switch (method.toUpperCase()) { + case 'GET': + route.name = lastSegment.contains(':') || lastSegment.contains('{') + ? '$namePrefix${prefix.isEmpty ? lastSegment : prefix}.show' + : '$namePrefix${lastSegment}.index'; + break; + case 'POST': + route.name = + '$namePrefix${prefix.isEmpty ? lastSegment : prefix}.store'; + break; + case 'PUT': + case 'PATCH': + route.name = + '$namePrefix${prefix.isEmpty ? lastSegment : prefix}.update'; + break; + case 'DELETE': + route.name = + '$namePrefix${prefix.isEmpty ? lastSegment : prefix}.destroy'; + break; + default: + route.name = '$namePrefix$lastSegment'; + } + } + } + return route; } /// Register a GET route. @@ -99,27 +142,40 @@ class LaravelStyle implements RoutingStyle { void group(Map attributes, void Function() callback) { var prefix = attributes['prefix'] as String? ?? ''; var middleware = attributes['middleware'] as List? ?? const []; + var groupName = attributes['name'] as String? ?? ''; - _router.group(prefix, (groupRouter) { - // Store current router - var parentRouter = _router; - // Create new style instance for group - var groupStyle = LaravelStyle(groupRouter); - // Set current instance as the active one - _activeInstance = groupStyle; - // Execute callback - callback(); - // Restore parent instance - _activeInstance = this; - }, middleware: middleware); + // Create new router for group + var groupRouter = Router(); + + // Create new style instance for group + var groupStyle = LaravelStyle(groupRouter); + + // Set group prefix and name for route naming + groupStyle._groupPrefix = prefix; + groupStyle._groupName = groupName; + groupStyle._currentMiddleware = [..._currentMiddleware, ...middleware]; + + // Store previous active instance + var previousInstance = _activeInstance; + // Set group style as active instance + _activeInstance = groupStyle; + + // Execute callback with group context + callback(); + + // Mount group router with prefix + var route = _router.mount(prefix, groupRouter); + if (groupName.isNotEmpty) { + route.name = groupName; + } + + // Restore previous active instance + _activeInstance = previousInstance; } // Track active instance for group context static LaravelStyle? _activeInstance; - // Forward calls to active instance - LaravelStyle get _current => _activeInstance as LaravelStyle? ?? this; - /// Add a name to the last registered route. /// /// ```dart @@ -137,7 +193,14 @@ class LaravelStyle implements RoutingStyle { /// Route::middleware(['auth', 'throttle']); /// ``` void middleware(List middleware) { - _router.chain(middleware); + _currentMiddleware.addAll(middleware); + + // Apply middleware to all existing routes + for (var route in _router.routes) { + if (route is! SymlinkRoute) { + route.handlers.insertAll(0, middleware); + } + } } }