import '../../get_navigation.dart'; class RouteDecoder { final List treeBranch; GetPage? get route => treeBranch.isEmpty ? null : treeBranch.last; final Map parameters; final Object? arguments; const RouteDecoder( this.treeBranch, this.parameters, this.arguments, ); void replaceArguments(Object? arguments) { final _route = route; if (_route != null) { final index = treeBranch.indexOf(_route); treeBranch[index] = _route.copy(arguments: arguments); } } void replaceParameters(Object? arguments) { final _route = route; if (_route != null) { final index = treeBranch.indexOf(_route); treeBranch[index] = _route.copy(parameters: parameters); } } } class ParseRouteTree { ParseRouteTree({ required this.routes, }); final List routes; RouteDecoder matchRoute(String name, {Object? arguments}) { final uri = Uri.parse(name); // /home/profile/123 => home,profile,123 => /,/home,/home/profile,/home/profile/123 final split = uri.path.split('/').where((element) => element.isNotEmpty); var curPath = '/'; final cumulativePaths = [ '/', ]; for (var item in split) { if (curPath.endsWith('/')) { curPath += '$item'; } else { curPath += '/$item'; } cumulativePaths.add(curPath); } final treeBranch = cumulativePaths .map((e) => MapEntry(e, _findRoute(e))) .where((element) => element.value != null) .map((e) => MapEntry(e.key, e.value!)) .toList(); final params = Map.from(uri.queryParameters); if (treeBranch.isNotEmpty) { //route is found, do further parsing to get nested query params final lastRoute = treeBranch.last; final parsedParams = _parseParams(name, lastRoute.value.path); if (parsedParams.isNotEmpty) { params.addAll(parsedParams); } //copy parameters to all pages. final mappedTreeBranch = treeBranch .map( (e) => e.value.copy( parameters: { if (e.value.parameters != null) ...e.value.parameters!, ...params, }, name: e.key, ), ) .toList(); return RouteDecoder( mappedTreeBranch, params, arguments, ); } //route not found return RouteDecoder( treeBranch.map((e) => e.value).toList(), params, arguments, ); } void addRoutes(List getPages) { for (final route in getPages) { addRoute(route); } } void addRoute(GetPage route) { routes.add(route); // Add Page children. for (var page in _flattenPage(route)) { addRoute(page); } } List _flattenPage(GetPage route) { final result = []; if (route.children.isEmpty) { return result; } final parentPath = route.name; for (var page in route.children) { // Add Parent middlewares to children final parentMiddlewares = [ if (page.middlewares != null) ...page.middlewares!, if (route.middlewares != null) ...route.middlewares! ]; result.add( _addChild( page, parentPath, parentMiddlewares, ), ); final children = _flattenPage(page); for (var child in children) { result.add(_addChild( child, parentPath, [ ...parentMiddlewares, if (child.middlewares != null) ...child.middlewares!, ], )); } } return result; } /// Change the Path for a [GetPage] GetPage _addChild( GetPage origin, String parentPath, List middlewares) => origin.copy( middlewares: middlewares, name: (parentPath + origin.name).replaceAll(r'//', '/'), ); GetPage? _findRoute(String name) { return routes.firstWhereOrNull( (route) => route.path.regex.hasMatch(name), ); } Map _parseParams(String path, PathDecoded routePath) { final params = {}; var idx = path.indexOf('?'); if (idx > -1) { path = path.substring(0, idx); final uri = Uri.tryParse(path); if (uri != null) { params.addAll(uri.queryParameters); } } var paramsMatch = routePath.regex.firstMatch(path); for (var i = 0; i < routePath.keys.length; i++) { var param = Uri.decodeQueryComponent(paramsMatch![i + 1]!); params[routePath.keys[i]!] = param; } return params; } } extension FirstWhereExt on List { /// The first element satisfying [test], or `null` if there are none. T? firstWhereOrNull(bool Function(T element) test) { for (var element in this) { if (test(element)) return element; } return null; } }