Compare commits

...

3 commits

Author SHA1 Message Date
Patrick Stewart
56fbaa62d3 update: completed routing style feature all test pass 2024-12-31 12:16:24 -07:00
Patrick Stewart
50a12e4535 update: working on routing style feature 48 pass 1 fail 2024-12-31 12:04:37 -07:00
Patrick Stewart
a8226d7b87 add: adding routing styles to routing package 43 pass 6 fail 2024-12-31 11:53:22 -07:00
5 changed files with 1010 additions and 0 deletions

View file

@ -0,0 +1,117 @@
import 'router.dart';
/// Base interface for all routing styles.
///
/// This allows different routing patterns to be implemented while preserving
/// the core routing functionality. Each style wraps around the base [Router]
/// implementation, providing its own API while utilizing the underlying routing
/// system.
abstract class RoutingStyle<T> {
/// The underlying router instance that handles actual routing.
Router<T> get router;
/// Unique identifier for this routing style.
String get styleName;
/// Initialize the routing style.
///
/// This is called when the style is activated through the registry.
/// Use this to set up any style-specific configuration or state.
void initialize();
/// Clean up any resources used by this style.
///
/// This is called when switching to a different style or shutting down.
void dispose() {}
}
/// Registry for managing different routing styles.
///
/// The registry maintains a collection of available routing styles and handles
/// switching between them. It ensures only one style is active at a time while
/// preserving the underlying routing configuration.
class RoutingStyleRegistry<T> {
final Map<String, RoutingStyle<T>> _styles = {};
RoutingStyle<T>? _activeStyle;
final Router<T> _baseRouter;
/// Creates a new routing style registry.
///
/// The registry maintains its own base router instance that all styles
/// will wrap around, ensuring routing state is preserved when switching styles.
RoutingStyleRegistry() : _baseRouter = Router<T>();
/// Register a new routing style.
///
/// Each style must have a unique [styleName]. Attempting to register a style
/// with a name that's already registered will throw an exception.
///
/// ```dart
/// registry.registerStyle(ExpressStyle(registry.baseRouter));
/// registry.registerStyle(LaravelStyle(registry.baseRouter));
/// ```
void registerStyle(RoutingStyle<T> style) {
if (_styles.containsKey(style.styleName)) {
throw StateError(
'A style with name "${style.styleName}" is already registered');
}
_styles[style.styleName] = style;
}
/// Activate a registered routing style.
///
/// This makes the specified style active, initializing it and making its
/// routing pattern available. Any previously active style will be disposed.
///
/// ```dart
/// registry.useStyle('express'); // Use Express-style routing
/// registry.useStyle('laravel'); // Switch to Laravel-style routing
/// ```
///
/// Throws a [StateError] if the style name is not registered.
void useStyle(String styleName) {
if (!_styles.containsKey(styleName)) {
throw StateError('No routing style registered with name "$styleName"');
}
// Dispose previous style if exists
_activeStyle?.dispose();
// Activate new style
_activeStyle = _styles[styleName];
_activeStyle!.initialize();
}
/// The currently active routing style.
///
/// Returns null if no style is active.
RoutingStyle<T>? get activeStyle => _activeStyle;
/// The underlying router instance.
///
/// This router is shared across all styles, maintaining the routing state
/// even when switching between different routing patterns.
Router<T> get baseRouter => _baseRouter;
}
/// Base interface for middleware style adapters.
///
/// This allows different routing styles to adapt their middleware patterns
/// to work with the platform's middleware system.
abstract class MiddlewareStyle<T> {
/// Convert framework-specific middleware to platform middleware.
///
/// This allows each routing style to define how its middleware format
/// should be converted to work with the platform's middleware system.
///
/// ```dart
/// // Example Laravel-style middleware adaptation
/// T adaptMiddleware(dynamic middleware) {
/// if (middleware is String) {
/// return resolveMiddlewareFromContainer(middleware);
/// }
/// return middleware as T;
/// }
/// ```
T adaptMiddleware(dynamic originalMiddleware);
}

View file

@ -0,0 +1,219 @@
import '../router.dart';
import '../routing_style.dart';
/// Express-style routing implementation.
///
/// This is the default routing style that maintains compatibility with the
/// existing Express-like routing pattern. It provides the familiar app.get(),
/// app.post(), etc. methods while utilizing the underlying routing system.
class ExpressStyle<T> implements RoutingStyle<T> {
Router<T> _router;
@override
Router<T> get router => _router;
@override
String get styleName => 'express';
/// Creates a new Express-style router.
ExpressStyle(this._router);
@override
void initialize() {
// Express style is the default, so no special initialization needed
}
@override
void dispose() {
// Express style doesn't need special cleanup
}
/// Register a route that handles GET requests.
///
/// ```dart
/// app.get('/users', (req, res) {
/// // Handle GET request
/// });
/// ```
Route<T> get(String path, T handler, {List<T> middleware = const []}) {
return _router.get(path, _wrapHandler(handler),
middleware: middleware.map(_wrapMiddleware).toList());
}
/// Register a route that handles POST requests.
///
/// ```dart
/// app.post('/users', (req, res) {
/// // Handle POST request
/// });
/// ```
Route<T> post(String path, T handler, {List<T> middleware = const []}) {
return _router.post(path, _wrapHandler(handler),
middleware: middleware.map(_wrapMiddleware).toList());
}
/// Register a route that handles PUT requests.
///
/// ```dart
/// app.put('/users/:id', (req, res) {
/// // Handle PUT request
/// });
/// ```
Route<T> put(String path, T handler, {List<T> middleware = const []}) {
return _router.addRoute('PUT', path, _wrapHandler(handler),
middleware: middleware.map(_wrapMiddleware).toList());
}
/// Register a route that handles DELETE requests.
///
/// ```dart
/// app.delete('/users/:id', (req, res) {
/// // Handle DELETE request
/// });
/// ```
Route<T> delete(String path, T handler, {List<T> middleware = const []}) {
return _router.delete(path, _wrapHandler(handler),
middleware: middleware.map(_wrapMiddleware).toList());
}
/// Register a route that handles PATCH requests.
///
/// ```dart
/// app.patch('/users/:id', (req, res) {
/// // Handle PATCH request
/// });
/// ```
Route<T> patch(String path, T handler, {List<T> middleware = const []}) {
return _router.patch(path, _wrapHandler(handler),
middleware: middleware.map(_wrapMiddleware).toList());
}
/// Register a route that handles HEAD requests.
///
/// ```dart
/// app.head('/status', (req, res) {
/// // Handle HEAD request
/// });
/// ```
Route<T> head(String path, T handler, {List<T> middleware = const []}) {
return _router.head(path, _wrapHandler(handler),
middleware: middleware.map(_wrapMiddleware).toList());
}
/// Register a route that handles OPTIONS requests.
///
/// ```dart
/// app.options('/api', (req, res) {
/// // Handle OPTIONS request
/// });
/// ```
Route<T> options(String path, T handler, {List<T> middleware = const []}) {
return _router.options(path, _wrapHandler(handler),
middleware: middleware.map(_wrapMiddleware).toList());
}
/// Register a route that handles all HTTP methods.
///
/// ```dart
/// app.all('/any', (req, res) {
/// // Handle any HTTP method
/// });
/// ```
Route<T> all(String path, T handler, {List<T> middleware = const []}) {
return _router.all(path, _wrapHandler(handler),
middleware: middleware.map(_wrapMiddleware).toList());
}
/// Use middleware for all routes.
///
/// ```dart
/// app.use((req, res, next) {
/// // Middleware logic
/// next();
/// });
/// ```
void use(T 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<T>) {
route.handlers.insert(0, _wrapMiddleware(middleware));
}
}
}
/// Create a route group with optional prefix and middleware.
///
/// ```dart
/// app.group('/api', (router) {
/// router.get('/users', handler);
/// router.post('/users', createHandler);
/// }, middleware: [authMiddleware]);
/// ```
void group(String prefix, void Function(ExpressStyle<T> router) callback,
{List<T> middleware = const []}) {
// Create a new router for the group
var groupRouter = Router<T>();
// Create new style instance for group
var groupStyle = ExpressStyle<T>(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<T>) {
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;
}
}
/// Express middleware adapter.
///
/// This adapter maintains compatibility with Express-style middleware,
/// which is already in the format expected by the platform.
class ExpressMiddlewareStyle<T> implements MiddlewareStyle<T> {
@override
T adaptMiddleware(dynamic originalMiddleware) {
// Express middleware is already in the correct format
return originalMiddleware as T;
}
}

View file

@ -0,0 +1,231 @@
import '../router.dart';
import '../routing_style.dart';
/// Laravel-style routing implementation.
///
/// This style provides a Laravel-like routing pattern while utilizing the
/// underlying routing system. It demonstrates how different routing styles
/// can be implemented on top of the core routing functionality.
class LaravelStyle<T> implements RoutingStyle<T> {
Router<T> _router;
String? _groupPrefix;
String? _groupName;
List<T> _currentMiddleware = [];
@override
Router<T> get router => _router;
@override
String get styleName => 'laravel';
/// Creates a new Laravel-style router.
LaravelStyle(this._router);
@override
void initialize() {
// Laravel style doesn't need special initialization
}
@override
void dispose() {
// Laravel style doesn't need special cleanup
}
/// Register a route with a specific HTTP method.
///
/// ```dart
/// Route::get('/users', handler);
/// Route::post('/users', handler);
/// ```
Route<T> route(String method, String path, T handler,
{List<T> middleware = const [], String? name}) {
var allMiddleware = [..._currentMiddleware, ...middleware];
// If we're in a group, prepend the group prefix to the path
var fullPath = _groupPrefix != null ? '$_groupPrefix$path' : path;
var route = _router.addRoute(method.toUpperCase(), fullPath, 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) {
// Clean up segments
var cleanSegments =
segments.map((s) => s.replaceAll(RegExp(r'[:{}/]'), '')).toList();
// Get the resource name from the last non-parameter segment
var resourceName = cleanSegments.last;
var hasParams =
segments.last.contains(':') || segments.last.contains('{');
if (hasParams && segments.length > 1) {
// If the last segment is a parameter, use the previous segment
resourceName = cleanSegments[segments.length - 2];
}
var prefix = _groupPrefix
?.replaceAll('/', '.')
.replaceAll(RegExp(r'^\.|\.$'), '') ??
'';
var namePrefix = prefix.isEmpty ? '' : '$prefix.';
// Generate name based on method and path
switch (method.toUpperCase()) {
case 'GET':
route.name = hasParams
? '$namePrefix$resourceName.show'
: '$namePrefix$resourceName.index';
break;
case 'POST':
route.name = '$namePrefix$resourceName.store';
break;
case 'PUT':
case 'PATCH':
route.name = '$namePrefix$resourceName.update';
break;
case 'DELETE':
route.name = '$namePrefix$resourceName.destroy';
break;
default:
route.name = '$namePrefix$resourceName';
}
}
}
return route;
}
/// Register a GET route.
///
/// ```dart
/// Route::get('/users', handler);
/// ```
Route<T> get(String path, T handler, {List<T> middleware = const []}) {
return route('GET', path, handler, middleware: middleware);
}
/// Register a POST route.
///
/// ```dart
/// Route::post('/users', handler);
/// ```
Route<T> post(String path, T handler, {List<T> middleware = const []}) {
return route('POST', path, handler, middleware: middleware);
}
/// Register a PUT route.
///
/// ```dart
/// Route::put('/users/{id}', handler);
/// ```
Route<T> put(String path, T handler, {List<T> middleware = const []}) {
return route('PUT', path, handler, middleware: middleware);
}
/// Register a DELETE route.
///
/// ```dart
/// Route::delete('/users/{id}', handler);
/// ```
Route<T> delete(String path, T handler, {List<T> middleware = const []}) {
return route('DELETE', path, handler, middleware: middleware);
}
/// Register a PATCH route.
///
/// ```dart
/// Route::patch('/users/{id}', handler);
/// ```
Route<T> patch(String path, T handler, {List<T> middleware = const []}) {
return route('PATCH', path, handler, middleware: middleware);
}
/// Create a route group with shared attributes.
///
/// ```dart
/// Route::group({
/// 'prefix': '/api',
/// 'middleware': ['auth'],
/// }, () {
/// Route::get('/users', handler);
/// Route::post('/users', handler);
/// });
/// ```
void group(Map<String, dynamic> attributes, void Function() callback) {
var prefix = attributes['prefix'] as String? ?? '';
var middleware = attributes['middleware'] as List<T>? ?? const [];
var groupName = attributes['name'] as String? ?? '';
// Store current state
var previousPrefix = _groupPrefix;
var previousName = _groupName;
var previousMiddleware = _currentMiddleware;
// Update group context
_groupPrefix = previousPrefix != null ? '$previousPrefix$prefix' : prefix;
_groupName = groupName.isNotEmpty ? groupName : prefix.replaceAll('/', '.');
_currentMiddleware = [...previousMiddleware, ...middleware];
// Execute callback in group context
callback();
// Restore previous state
_groupPrefix = previousPrefix;
_groupName = previousName;
_currentMiddleware = previousMiddleware;
}
/// Add a name to the last registered route.
///
/// ```dart
/// Route::get('/users', handler).name('users.index');
/// ```
Route<T> name(String name) {
var lastRoute = _router.routes.last;
lastRoute.name = name;
return lastRoute;
}
/// Register middleware for all routes.
///
/// ```dart
/// Route::middleware(['auth', 'throttle']);
/// ```
void middleware(List<T> middleware) {
_currentMiddleware.addAll(middleware);
// Apply middleware to all existing routes
for (var route in _router.routes) {
if (route is! SymlinkRoute<T>) {
route.handlers.insertAll(0, middleware);
}
}
}
}
/// Laravel middleware adapter.
///
/// This adapter converts Laravel-style middleware (strings or callables)
/// to the platform's middleware format.
class LaravelMiddlewareStyle<T> implements MiddlewareStyle<T> {
final Map<String, T Function()> _middlewareMap;
LaravelMiddlewareStyle(this._middlewareMap);
@override
T adaptMiddleware(dynamic originalMiddleware) {
if (originalMiddleware is String) {
var factory = _middlewareMap[originalMiddleware];
if (factory == null) {
throw StateError(
'No middleware registered for key "$originalMiddleware"');
}
return factory();
}
return originalMiddleware as T;
}
}

View file

@ -0,0 +1,237 @@
import 'package:platform_routing/src/router.dart';
import 'package:platform_routing/src/routing_style.dart';
import 'package:platform_routing/src/styles/express_style.dart';
import 'package:test/test.dart';
// Test style implementation
class _TestStyle implements RoutingStyle<Function> {
final Router<Function> _router;
final void Function() _onDispose;
_TestStyle(this._router, this._onDispose);
@override
Router<Function> get router => _router;
@override
String get styleName => 'test';
@override
void initialize() {}
@override
void dispose() {
_onDispose();
}
}
void main() {
group('RoutingStyleRegistry', () {
late RoutingStyleRegistry<Function> registry;
setUp(() {
registry = RoutingStyleRegistry<Function>();
});
test('registers and activates styles', () {
var expressStyle = ExpressStyle<Function>(registry.baseRouter);
// Register style
registry.registerStyle(expressStyle);
expect(registry.activeStyle, isNull);
// Activate style
registry.useStyle('express');
expect(registry.activeStyle, equals(expressStyle));
});
test('throws on duplicate style registration', () {
var style1 = ExpressStyle<Function>(registry.baseRouter);
var style2 = ExpressStyle<Function>(registry.baseRouter);
registry.registerStyle(style1);
expect(
() => registry.registerStyle(style2),
throwsStateError,
);
});
test('throws when activating unregistered style', () {
expect(
() => registry.useStyle('nonexistent'),
throwsStateError,
);
});
test('disposes previous style when switching', () {
var disposed = false;
var testStyle = _TestStyle(registry.baseRouter, () => disposed = true);
var expressStyle = ExpressStyle<Function>(registry.baseRouter);
registry.registerStyle(testStyle);
registry.registerStyle(expressStyle);
// Activate test style
registry.useStyle('test');
expect(disposed, isFalse);
// Switch to express style
registry.useStyle('express');
expect(disposed, isTrue);
});
});
group('ExpressStyle', () {
late RoutingStyleRegistry<Function> registry;
late ExpressStyle<Function> style;
setUp(() {
registry = RoutingStyleRegistry<Function>();
style = ExpressStyle<Function>(registry.baseRouter);
registry.registerStyle(style);
registry.useStyle('express');
});
test('maintains express-style routing pattern', () {
var handlerCalled = false;
var middlewareCalled = false;
// Register middleware
style.use((req, res, next) {
middlewareCalled = true;
next();
});
// Register route
style.get('/test', (req, res) {
handlerCalled = true;
});
// Simulate request
var results = registry.baseRouter.resolveAbsolute('/test', method: 'GET');
expect(results, isNotEmpty);
// Execute handlers
for (var result in results) {
for (var handler in result.handlers) {
handler(null, null);
}
}
expect(middlewareCalled, isTrue);
expect(handlerCalled, isTrue);
});
test('supports route groups', () {
var routes = <String>[];
style.group('/api', (router) {
router.get('/users', (req, res) {
routes.add('/api/users');
});
router.post('/users', (req, res) {
routes.add('/api/users');
});
});
// Verify routes were registered
var getResults =
registry.baseRouter.resolveAbsolute('/api/users', method: 'GET');
var postResults =
registry.baseRouter.resolveAbsolute('/api/users', method: 'POST');
expect(getResults, isNotEmpty);
expect(postResults, isNotEmpty);
});
test('supports all HTTP methods', () {
var methods = [
'GET',
'POST',
'PUT',
'DELETE',
'PATCH',
'HEAD',
'OPTIONS'
];
var calledMethods = <String>[];
// Register routes for each method
for (var method in methods) {
switch (method) {
case 'GET':
style.get('/test', (req, res) => calledMethods.add(method));
break;
case 'POST':
style.post('/test', (req, res) => calledMethods.add(method));
break;
case 'PUT':
style.put('/test', (req, res) => calledMethods.add(method));
break;
case 'DELETE':
style.delete('/test', (req, res) => calledMethods.add(method));
break;
case 'PATCH':
style.patch('/test', (req, res) => calledMethods.add(method));
break;
case 'HEAD':
style.head('/test', (req, res) => calledMethods.add(method));
break;
case 'OPTIONS':
style.options('/test', (req, res) => calledMethods.add(method));
break;
}
}
// Verify each method resolves
for (var method in methods) {
var results =
registry.baseRouter.resolveAbsolute('/test', method: method);
expect(results, isNotEmpty, reason: 'Method $method should resolve');
// Execute handler
for (var result in results) {
for (var handler in result.handlers) {
handler(null, null);
}
}
}
// Verify each method was called
expect(calledMethods, containsAll(methods));
});
test('supports middleware in route groups', () {
var middlewareCalled = false;
var handlerCalled = false;
style.group('/api', (router) {
router.get('/test', (req, res) {
handlerCalled = true;
});
}, middleware: [
(req, res, next) {
middlewareCalled = true;
next();
}
]);
// Simulate request
var results =
registry.baseRouter.resolveAbsolute('/api/test', method: 'GET');
expect(results, isNotEmpty);
// Execute handlers
for (var result in results) {
for (var handler in result.handlers) {
handler(null, null);
}
}
expect(middlewareCalled, isTrue);
expect(handlerCalled, isTrue);
});
});
}

View file

@ -0,0 +1,206 @@
import 'package:platform_routing/src/routing_style.dart';
import 'package:platform_routing/src/styles/laravel_style.dart';
import 'package:test/test.dart';
typedef NextFunction = void Function();
typedef MiddlewareFunction = void Function(dynamic, dynamic, NextFunction);
typedef RouteHandler = void Function(dynamic, dynamic);
void executeHandler(Function? handler) {
if (handler == null) return;
if (handler is RouteHandler) {
handler(null, null);
} else if (handler is MiddlewareFunction) {
handler(null, null, () {});
}
}
void main() {
group('LaravelStyle', () {
late RoutingStyleRegistry<Function> registry;
late LaravelStyle<Function> style;
setUp(() {
registry = RoutingStyleRegistry<Function>();
style = LaravelStyle<Function>(registry.baseRouter);
registry.registerStyle(style);
registry.useStyle('laravel');
});
test('supports Laravel-style route registration', () {
var handlerCalled = false;
var middlewareCalled = false;
// Register middleware
middleware(req, res, NextFunction next) {
middlewareCalled = true;
next();
}
style.middleware([middleware]);
// Register route
handler(req, res) {
handlerCalled = true;
}
style.get('/test', handler).name!;
// Simulate request
var results = registry.baseRouter.resolveAbsolute('/test', method: 'GET');
expect(results, isNotEmpty);
// Execute handlers
for (var result in results) {
for (var handler in result.handlers) {
executeHandler(handler);
}
}
expect(middlewareCalled, isTrue);
expect(handlerCalled, isTrue);
});
test('supports Laravel-style route groups', () {
var routes = <String>[];
var groupMiddlewareCalled = false;
// Register middleware
middleware(req, res, NextFunction next) {
groupMiddlewareCalled = true;
next();
}
style.group({
'prefix': '/api',
'middleware': [middleware],
}, () {
getHandler(req, res) {
routes.add('/api/users');
}
postHandler(req, res) {
routes.add('/api/users');
}
style.get('/users', getHandler).name!;
style.post('/users', postHandler).name!;
});
// Verify routes were registered
var getResults =
registry.baseRouter.resolveAbsolute('/api/users', method: 'GET');
var postResults =
registry.baseRouter.resolveAbsolute('/api/users', method: 'POST');
expect(getResults, isNotEmpty);
expect(postResults, isNotEmpty);
// Verify route names
var namedRoute = registry.baseRouter.routes
.firstWhere((r) => r.name == 'api.users.index');
expect(namedRoute, isNotNull);
// Execute handlers to verify middleware
for (var result in getResults) {
for (var handler in result.handlers) {
executeHandler(handler);
}
}
expect(groupMiddlewareCalled, isTrue);
expect(routes, contains('/api/users'));
});
test('supports all HTTP methods', () {
var methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'];
var calledMethods = <String>[];
// Register routes for each method
for (var method in methods) {
handler(req, res) {
calledMethods.add(method);
}
style.route(method, '/test', handler).name!;
}
// Verify each method resolves
for (var method in methods) {
var results =
registry.baseRouter.resolveAbsolute('/test', method: method);
expect(results, isNotEmpty, reason: 'Method $method should resolve');
// Execute handler
for (var result in results) {
for (var handler in result.handlers) {
executeHandler(handler);
}
}
}
// Verify each method was called
expect(calledMethods, containsAll(methods));
});
test('supports named routes', () {
handler(req, res) {}
style.get('/users', handler).name!;
style.post('/users', handler).name!;
style.get('/users/:id', handler).name!;
var routes = registry.baseRouter.routes;
expect(routes.any((r) => r.name == 'users.index'), isTrue);
expect(routes.any((r) => r.name == 'users.store'), isTrue);
expect(routes.any((r) => r.name == 'users.show'), isTrue);
});
test('supports middleware string resolution', () {
var authCalled = false;
var throttleCalled = false;
MiddlewareFunction createAuthMiddleware() {
return (req, res, NextFunction next) {
authCalled = true;
next();
};
}
MiddlewareFunction createThrottleMiddleware() {
return (req, res, NextFunction next) {
throttleCalled = true;
next();
};
}
var middlewareAdapter = LaravelMiddlewareStyle<Function>({
'auth': createAuthMiddleware,
'throttle': createThrottleMiddleware,
});
// Test string to middleware conversion
var authMiddleware =
middlewareAdapter.adaptMiddleware('auth') as MiddlewareFunction;
var throttleMiddleware =
middlewareAdapter.adaptMiddleware('throttle') as MiddlewareFunction;
// Execute middleware
doNext() {}
authMiddleware(null, null, doNext);
throttleMiddleware(null, null, doNext);
expect(authCalled, isTrue);
expect(throttleCalled, isTrue);
});
test('throws on unknown middleware string', () {
var adapter = LaravelMiddlewareStyle<Function>({});
expect(
() => adapter.adaptMiddleware('unknown'),
throwsStateError,
);
});
});
}