Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
5cea2f7
feat: access GoRouter.of from redirect methods
tomassasovsky Jul 30, 2025
05b94b7
refactor: update documentation for navigatorKey and extraCodec in Rou…
tomassasovsky Jul 30, 2025
c93570b
refactor: replace _currentRouterKey with currentRouterKey constant fo…
tomassasovsky Jul 30, 2025
c94be6f
Merge branch 'main' into feat/go-router-context-redirect
tomassasovsky Jul 30, 2025
858ea74
chore: release version 16.0.1 with fixes for redirect callbacks and c…
tomassasovsky Jul 31, 2025
d2b6d00
Merge branch 'main' into feat/go-router-context-redirect
tomassasovsky Jul 31, 2025
d90201c
Merge branch 'feat/go-router-context-redirect' of github.com:tomassas…
tomassasovsky Jul 31, 2025
61bc8ff
refactor: update documentation for GoRouter context methods to clarif…
tomassasovsky Jul 31, 2025
6309387
feat: implement error handling in router zone for GoRouter
tomassasovsky Aug 1, 2025
fec0356
refactor: replace runZoned with runZonedGuarded for improved error ha…
tomassasovsky Aug 2, 2025
e756161
Merge branch 'main' into feat/go-router-context-redirect
tomassasovsky Aug 2, 2025
2cdaa91
feat: enhance error handling in redirect callbacks and tests for GoRo…
tomassasovsky Aug 5, 2025
52d78a7
Merge branch 'feat/go-router-context-redirect' of github.com:tomassas…
tomassasovsky Aug 5, 2025
6221028
Merge branch 'main' of github.com:flutter/packages into feat/go-route…
tomassasovsky Sep 24, 2025
05c1cbc
chore: dart format
tomassasovsky Sep 25, 2025
7d8d0d5
chore: add copyright to constants.dart
tomassasovsky Sep 25, 2025
7beaf8e
Merge branch 'main' into feat/go-router-context-redirect
tomassasovsky Sep 25, 2025
1619f40
Merge branch 'main' into feat/go-router-context-redirect
tomassasovsky Sep 26, 2025
ddb6e9d
Merge branch 'main' into feat/go-router-context-redirect
tomassasovsky Oct 7, 2025
6bd4af8
Merge branch 'main' into feat/go-router-context-redirect
tomassasovsky Oct 9, 2025
f9b088f
Merge branch 'main' into feat/go-router-context-redirect
tomassasovsky Oct 9, 2025
eea054a
Merge branch 'main' into feat/go-router-context-redirect
chunhtai Oct 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
chore: dart format
  • Loading branch information
tomassasovsky committed Sep 25, 2025
commit 05c1cbcef287181c908cb454ee7b9321fbabbf2a
97 changes: 50 additions & 47 deletions packages/go_router/lib/src/configuration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import 'router.dart';
import 'state.dart';

/// The signature of the redirect callback.
typedef GoRouterRedirect = FutureOr<String?> Function(
BuildContext context, GoRouterState state);
typedef GoRouterRedirect =
FutureOr<String?> Function(BuildContext context, GoRouterState state);

typedef _NamedPath = ({String path, bool caseSensitive});

Expand Down Expand Up @@ -448,18 +448,28 @@ class RouteConfiguration {
return routeLevelRedirectResult
.then<RouteMatchList>(processRouteLevelRedirect)
.catchError((Object error) {
final GoException goException = error is GoException
? error
: GoException('Exception during route redirect: $error');
return _errorRouteMatchList(prevMatchList.uri, goException,
extra: prevMatchList.extra);
});
final GoException goException =
error is GoException
? error
: GoException(
'Exception during route redirect: $error',
);
return _errorRouteMatchList(
prevMatchList.uri,
goException,
extra: prevMatchList.extra,
);
});
} catch (exception) {
final GoException goException = exception is GoException
? exception
: GoException('Exception during route redirect: $exception');
return _errorRouteMatchList(prevMatchList.uri, goException,
extra: prevMatchList.extra);
final GoException goException =
exception is GoException
? exception
: GoException('Exception during route redirect: $exception');
return _errorRouteMatchList(
prevMatchList.uri,
goException,
extra: prevMatchList.extra,
);
}
}

Expand Down Expand Up @@ -505,29 +515,28 @@ class RouteConfiguration {
final RouteBase route = match.route;
try {
final FutureOr<String?> routeRedirectResult = _runInRouterZone(() {
return route.redirect!.call(
context,
match.buildState(this, matchList),
);
return route.redirect!.call(context, match.buildState(this, matchList));
});
if (routeRedirectResult is String?) {
return processRouteRedirect(routeRedirectResult);
}
return routeRedirectResult
.then<String?>(processRouteRedirect)
.catchError((Object error) {
// Convert any exception during async route redirect to a GoException
final GoException goException = error is GoException
? error
: GoException('Exception during route redirect: $error');
// Throw the GoException to be caught by the redirect handling chain
throw goException;
});
return routeRedirectResult.then<String?>(processRouteRedirect).catchError(
(Object error) {
// Convert any exception during async route redirect to a GoException
final GoException goException =
error is GoException
? error
: GoException('Exception during route redirect: $error');
// Throw the GoException to be caught by the redirect handling chain
throw goException;
},
);
} catch (exception) {
// Convert any exception during route redirect to a GoException
final GoException goException = exception is GoException
? exception
: GoException('Exception during route redirect: $exception');
final GoException goException =
exception is GoException
? exception
: GoException('Exception during route redirect: $exception');
// Throw the GoException to be caught by the redirect handling chain
throw goException;
}
Expand All @@ -543,9 +552,10 @@ class RouteConfiguration {
_addRedirect(redirectHistory, newMatch, previousLocation);
return newMatch;
} catch (exception) {
final GoException goException = exception is GoException
? exception
: GoException('Exception during redirect: $exception');
final GoException goException =
exception is GoException
? exception
: GoException('Exception during redirect: $exception');
log('Redirection exception: ${goException.message}');
return _errorRouteMatchList(previousLocation, goException);
}
Expand All @@ -561,18 +571,12 @@ class RouteConfiguration {
) {
if (redirects.contains(newMatch)) {
throw GoException(
'redirect loop detected ${_formatRedirectionHistory(<RouteMatchList>[
...redirects,
newMatch
])}',
'redirect loop detected ${_formatRedirectionHistory(<RouteMatchList>[...redirects, newMatch])}',
);
}
if (redirects.length > _routingConfig.value.redirectLimit) {
throw GoException(
'too many redirects ${_formatRedirectionHistory(<RouteMatchList>[
...redirects,
newMatch
])}',
'too many redirects ${_formatRedirectionHistory(<RouteMatchList>[...redirects, newMatch])}',
);
}

Expand Down Expand Up @@ -605,14 +609,13 @@ class RouteConfiguration {
(Object error, StackTrace stack) {
errorOccurred = true;
// Convert any exception during redirect to a GoException and rethrow
final GoException goException = error is GoException
? error
: GoException('Exception during redirect: $error');
final GoException goException =
error is GoException
? error
: GoException('Exception during redirect: $error');
throw goException;
},
zoneValues: <Object?, Object?>{
currentRouterKey: router,
},
zoneValues: <Object?, Object?>{currentRouterKey: router},
);

if (errorOccurred) {
Expand Down
39 changes: 22 additions & 17 deletions packages/go_router/lib/src/parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ import 'router.dart';
///
/// The returned [RouteMatchList] is used as parsed result for the
/// [GoRouterDelegate].
typedef ParserExceptionHandler = RouteMatchList Function(
BuildContext context,
RouteMatchList routeMatchList,
);
typedef ParserExceptionHandler =
RouteMatchList Function(
BuildContext context,
RouteMatchList routeMatchList,
);

/// Converts between incoming URLs and a [RouteMatchList] using [RouteMatcher].
/// Also performs redirection using [RouteRedirector].
Expand Down Expand Up @@ -181,9 +182,10 @@ class GoRouteInformationParser extends RouteInformationParser<RouteMatchList> {
}
return redirectedFuture.catchError((Object error) {
// Convert any exception during redirect to a GoException
final GoException goException = error is GoException
? error
: GoException('Exception during redirect: $error');
final GoException goException =
error is GoException
? error
: GoException('Exception during redirect: $error');
// Return an error match list instead of throwing
return RouteMatchList(
matches: const <RouteMatch>[],
Expand All @@ -195,17 +197,20 @@ class GoRouteInformationParser extends RouteInformationParser<RouteMatchList> {
});
} catch (exception) {
// Convert any exception during redirect to a GoException
final GoException goException = exception is GoException
? exception
: GoException('Exception during redirect: $exception');
final GoException goException =
exception is GoException
? exception
: GoException('Exception during redirect: $exception');
// Return an error match list instead of throwing
return SynchronousFuture<RouteMatchList>(RouteMatchList(
matches: const <RouteMatch>[],
extra: routeMatch.extra,
error: goException,
uri: routeMatch.uri,
pathParameters: const <String, String>{},
));
return SynchronousFuture<RouteMatchList>(
RouteMatchList(
matches: const <RouteMatch>[],
extra: routeMatch.extra,
error: goException,
uri: routeMatch.uri,
pathParameters: const <String, String>{},
),
);
}
}

Expand Down
105 changes: 52 additions & 53 deletions packages/go_router/lib/src/router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import 'state.dart';
/// The function signature of [GoRouter.onException].
///
/// Use `state.error` to access the exception.
typedef GoExceptionHandler = void Function(
BuildContext context, GoRouterState state, GoRouter router);
typedef GoExceptionHandler =
void Function(BuildContext context, GoRouterState state, GoRouter router);

/// A set of parameters that defines routing in GoRouter.
///
Expand All @@ -46,8 +46,7 @@ class RoutingConfig {
static FutureOr<String?> _defaultRedirect(
BuildContext context,
GoRouterState state,
) =>
null;
) => null;

/// The supported routes.
///
Expand Down Expand Up @@ -184,23 +183,23 @@ class GoRouter implements RouterConfig<RouteMatchList> {
GlobalKey<NavigatorState>? navigatorKey,
String? restorationScopeId,
bool requestFocus = true,
}) : _routingConfig = routingConfig,
backButtonDispatcher = RootBackButtonDispatcher(),
assert(
initialExtra == null || initialLocation != null,
'initialLocation must be set in order to use initialExtra',
),
assert(
!overridePlatformDefaultLocation || initialLocation != null,
'Initial location must be set to override platform default',
),
assert(
(onException == null ? 0 : 1) +
(errorPageBuilder == null ? 0 : 1) +
(errorBuilder == null ? 0 : 1) <
2,
'Only one of onException, errorPageBuilder, or errorBuilder can be provided.',
) {
}) : _routingConfig = routingConfig,
backButtonDispatcher = RootBackButtonDispatcher(),
assert(
initialExtra == null || initialLocation != null,
'initialLocation must be set in order to use initialExtra',
),
assert(
!overridePlatformDefaultLocation || initialLocation != null,
'Initial location must be set to override platform default',
),
assert(
(onException == null ? 0 : 1) +
(errorPageBuilder == null ? 0 : 1) +
(errorBuilder == null ? 0 : 1) <
2,
'Only one of onException, errorPageBuilder, or errorBuilder can be provided.',
) {
setLogging(enabled: debugLogDiagnostics);
WidgetsFlutterBinding.ensureInitialized();

Expand Down Expand Up @@ -254,8 +253,9 @@ class GoRouter implements RouterConfig<RouteMatchList> {
requestFocus: requestFocus,
// wrap the returned Navigator to enable GoRouter.of(context).go() et al,
// allowing the caller to wrap the navigator themselves
builderWithNav: (BuildContext context, Widget child) =>
InheritedGoRouter(goRouter: this, child: child),
builderWithNav:
(BuildContext context, Widget child) =>
InheritedGoRouter(goRouter: this, child: child),
);

assert(() {
Expand Down Expand Up @@ -345,13 +345,12 @@ class GoRouter implements RouterConfig<RouteMatchList> {
Map<String, String> pathParameters = const <String, String>{},
Map<String, dynamic> queryParameters = const <String, dynamic>{},
String? fragment,
}) =>
configuration.namedLocation(
name,
pathParameters: pathParameters,
queryParameters: queryParameters,
fragment: fragment,
);
}) => configuration.namedLocation(
name,
pathParameters: pathParameters,
queryParameters: queryParameters,
fragment: fragment,
);

/// Navigate to a URI location w/ optional query parameters, e.g.
/// `/family/f2/person/p1?color=blue`
Expand Down Expand Up @@ -379,17 +378,16 @@ class GoRouter implements RouterConfig<RouteMatchList> {
Object? extra,
String? fragment,
}) =>

/// Construct location with optional fragment, using null-safe navigation
go(
namedLocation(
name,
pathParameters: pathParameters,
queryParameters: queryParameters,
fragment: fragment,
),
extra: extra,
);
/// Construct location with optional fragment, using null-safe navigation
go(
namedLocation(
name,
pathParameters: pathParameters,
queryParameters: queryParameters,
fragment: fragment,
),
extra: extra,
);

/// Push a URI location onto the page stack w/ optional query parameters, e.g.
/// `/family/f2/person/p1?color=blue`.
Expand All @@ -416,15 +414,14 @@ class GoRouter implements RouterConfig<RouteMatchList> {
Map<String, String> pathParameters = const <String, String>{},
Map<String, dynamic> queryParameters = const <String, dynamic>{},
Object? extra,
}) =>
push<T>(
namedLocation(
name,
pathParameters: pathParameters,
queryParameters: queryParameters,
),
extra: extra,
);
}) => push<T>(
namedLocation(
name,
pathParameters: pathParameters,
queryParameters: queryParameters,
),
extra: extra,
);

/// Replaces the top-most page of the page stack with the given URL location
/// w/ optional query parameters, e.g. `/family/f2/person/p1?color=blue`.
Expand Down Expand Up @@ -552,9 +549,11 @@ class GoRouter implements RouterConfig<RouteMatchList> {

/// The current GoRouter in the widget tree, if any.
static GoRouter? maybeOf(BuildContext context) {
final InheritedGoRouter? inherited = context
.getElementForInheritedWidgetOfExactType<InheritedGoRouter>()
?.widget as InheritedGoRouter?;
final InheritedGoRouter? inherited =
context
.getElementForInheritedWidgetOfExactType<InheritedGoRouter>()
?.widget
as InheritedGoRouter?;
if (inherited != null) {
return inherited.goRouter;
}
Expand Down
Loading