[go_router] Cleans up route match API and introduces dart fix (#3819)
Clean up API around RouteMatch/RouteMatchList/GoRouterState,
This is a breaking change that renamed some of the GoRouterState property to have a more descriptive name as flutter style guide suggested https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#avoid-abbreviations
also introducing dart fix to help with migration
diff --git a/packages/go_router/CHANGELOG.md b/packages/go_router/CHANGELOG.md
index a0d7804..d46e9de 100644
--- a/packages/go_router/CHANGELOG.md
+++ b/packages/go_router/CHANGELOG.md
@@ -1,3 +1,19 @@
+## 7.0.0
+
+- **BREAKING CHANGE**:
+ - For the below changes, run `dart fix --apply` to automatically migrate your code.
+ - `GoRouteState.subloc` has been renamed to `GoRouteState.matchedLocation`.
+ - `GoRouteState.params` has been renamed to `GoRouteState.pathParameters`.
+ - `GoRouteState.fullpath` has been renamed to `GoRouteState.fullPath`.
+ - `GoRouteState.queryParams` has been renamed to `GoRouteState.queryParameters`.
+ - `params` and `queryParams` in `GoRouteState.namedLocation` have been renamed to `pathParameters` and `queryParameters`.
+ - `params` and `queryParams` in `GoRouter`'s `namedLocation`, `pushNamed`, `pushReplacementNamed`
+ `replaceNamed` have been renamed to `pathParameters` and `queryParameters`.
+ - For the below changes, please follow the [migration guide](https://docs.google.com/document/d/10Xbpifbs4E-zh6YE5akIO8raJq_m3FIXs6nUGdOspOg).
+ - `params` and `queryParams` in `BuildContext`'s `namedLocation`, `pushNamed`, `pushReplacementNamed`
+ `replaceNamed` have been renamed to `pathParameters` and `queryParameters`.
+- Cleans up API and makes RouteMatchList immutable.
+
## 6.5.9
- Removes navigator keys from `GoRouteData` and `ShellRouteData`.
diff --git a/packages/go_router/README.md b/packages/go_router/README.md
index daed219..eae5297 100644
--- a/packages/go_router/README.md
+++ b/packages/go_router/README.md
@@ -37,6 +37,7 @@
- [Error handling](https://pub.dev/documentation/go_router/latest/topics/Error%20handling-topic.html)
## Migration guides
+- [Migrating to 7.0.0](https://docs.google.com/document/d/10Xbpifbs4E-zh6YE5akIO8raJq_m3FIXs6nUGdOspOg).
- [Migrating to 6.0.0](https://flutter.dev/go/go-router-v6-breaking-changes)
- [Migrating to 5.1.2](https://flutter.dev/go/go-router-v5-1-2-breaking-changes)
- [Migrating to 5.0](https://flutter.dev/go/go-router-v5-breaking-changes)
diff --git a/packages/go_router/analysis_options.yaml b/packages/go_router/analysis_options.yaml
new file mode 100644
index 0000000..cfb845a
--- /dev/null
+++ b/packages/go_router/analysis_options.yaml
@@ -0,0 +1,5 @@
+include: ../../analysis_options.yaml
+
+analyzer:
+ exclude:
+ - "test_fixes/**"
diff --git a/packages/go_router/doc/configuration.md b/packages/go_router/doc/configuration.md
index ef4658a..09093d0 100644
--- a/packages/go_router/doc/configuration.md
+++ b/packages/go_router/doc/configuration.md
@@ -43,7 +43,7 @@
```dart
GoRoute(
path: '/users/:userId',
- builder: (context, state) => const UserScreen(id: state.params['userId']),
+ builder: (context, state) => const UserScreen(id: state.pathParameters['userId']),
),
```
@@ -55,7 +55,7 @@
```dart
GoRoute(
path: '/users',
- builder: (context, state) => const UsersScreen(filter: state.queryParams['filter']),
+ builder: (context, state) => const UsersScreen(filter: state.queryParameters['filter']),
),
```
diff --git a/packages/go_router/doc/named-routes.md b/packages/go_router/doc/named-routes.md
index 54705d1..861277c 100644
--- a/packages/go_router/doc/named-routes.md
+++ b/packages/go_router/doc/named-routes.md
@@ -14,7 +14,7 @@
```dart
TextButton(
onPressed: () {
- context.goNamed('song', params: {'songId': 123});
+ context.goNamed('song', pathParameters: {'songId': 123});
},
child: const Text('Go to song 2'),
),
@@ -25,7 +25,7 @@
```dart
TextButton(
onPressed: () {
- final String location = context.namedLocation('song', params: {'songId': 123});
+ final String location = context.namedLocation('song', pathParameters: {'songId': 123});
context.go(location);
},
child: const Text('Go to song 2'),
diff --git a/packages/go_router/example/lib/async_redirection.dart b/packages/go_router/example/lib/async_redirection.dart
index d91db6e..f84c14e 100644
--- a/packages/go_router/example/lib/async_redirection.dart
+++ b/packages/go_router/example/lib/async_redirection.dart
@@ -55,7 +55,7 @@
// cause go_router to reparse current route if StreamAuth has new sign-in
// information.
final bool loggedIn = await StreamAuthScope.of(context).isSignedIn();
- final bool loggingIn = state.subloc == '/login';
+ final bool loggingIn = state.matchedLocation == '/login';
if (!loggedIn) {
return '/login';
}
diff --git a/packages/go_router/example/lib/books/main.dart b/packages/go_router/example/lib/books/main.dart
index 73cb6f3..eb757e3 100644
--- a/packages/go_router/example/lib/books/main.dart
+++ b/packages/go_router/example/lib/books/main.dart
@@ -63,7 +63,7 @@
GoRoute(
path: '/book/:bookId',
redirect: (BuildContext context, GoRouterState state) =>
- '/books/all/${state.params['bookId']}',
+ '/books/all/${state.pathParameters['bookId']}',
),
GoRoute(
path: '/books/:kind(new|all|popular)',
@@ -72,14 +72,14 @@
key: _scaffoldKey,
child: BookstoreScaffold(
selectedTab: ScaffoldTab.books,
- child: BooksScreen(state.params['kind']!),
+ child: BooksScreen(state.pathParameters['kind']!),
),
),
routes: <GoRoute>[
GoRoute(
path: ':bookId',
builder: (BuildContext context, GoRouterState state) {
- final String bookId = state.params['bookId']!;
+ final String bookId = state.pathParameters['bookId']!;
final Book? selectedBook = libraryInstance.allBooks
.firstWhereOrNull((Book b) => b.id.toString() == bookId);
@@ -91,7 +91,7 @@
GoRoute(
path: '/author/:authorId',
redirect: (BuildContext context, GoRouterState state) =>
- '/authors/${state.params['authorId']}',
+ '/authors/${state.pathParameters['authorId']}',
),
GoRoute(
path: '/authors',
@@ -107,7 +107,7 @@
GoRoute(
path: ':authorId',
builder: (BuildContext context, GoRouterState state) {
- final int authorId = int.parse(state.params['authorId']!);
+ final int authorId = int.parse(state.pathParameters['authorId']!);
final Author? selectedAuthor = libraryInstance.allAuthors
.firstWhereOrNull((Author a) => a.id == authorId);
@@ -135,7 +135,7 @@
String? _guard(BuildContext context, GoRouterState state) {
final bool signedIn = _auth.signedIn;
- final bool signingIn = state.subloc == '/signin';
+ final bool signingIn = state.matchedLocation == '/signin';
// Go to /signin if the user is not signed in
if (!signedIn && !signingIn) {
diff --git a/packages/go_router/example/lib/named_routes.dart b/packages/go_router/example/lib/named_routes.dart
index a9d4604..9685fc4 100644
--- a/packages/go_router/example/lib/named_routes.dart
+++ b/packages/go_router/example/lib/named_routes.dart
@@ -84,14 +84,15 @@
name: 'family',
path: 'family/:fid',
builder: (BuildContext context, GoRouterState state) =>
- FamilyScreen(fid: state.params['fid']!),
+ FamilyScreen(fid: state.pathParameters['fid']!),
routes: <GoRoute>[
GoRoute(
name: 'person',
path: 'person/:pid',
builder: (BuildContext context, GoRouterState state) {
return PersonScreen(
- fid: state.params['fid']!, pid: state.params['pid']!);
+ fid: state.pathParameters['fid']!,
+ pid: state.pathParameters['pid']!);
},
),
],
@@ -119,7 +120,7 @@
ListTile(
title: Text(entry.value.name),
onTap: () => context.go(context.namedLocation('family',
- params: <String, String>{'fid': entry.key})),
+ pathParameters: <String, String>{'fid': entry.key})),
)
],
),
@@ -147,8 +148,8 @@
title: Text(entry.value.name),
onTap: () => context.go(context.namedLocation(
'person',
- params: <String, String>{'fid': fid, 'pid': entry.key},
- queryParams: <String, String>{'qid': 'quid'},
+ pathParameters: <String, String>{'fid': fid, 'pid': entry.key},
+ queryParameters: <String, String>{'qid': 'quid'},
)),
),
],
diff --git a/packages/go_router/example/lib/others/nav_observer.dart b/packages/go_router/example/lib/others/nav_observer.dart
index 2b8bfcb..038d337 100644
--- a/packages/go_router/example/lib/others/nav_observer.dart
+++ b/packages/go_router/example/lib/others/nav_observer.dart
@@ -108,8 +108,8 @@
ElevatedButton(
onPressed: () => context.goNamed(
'page2',
- params: <String, String>{'p1': 'pv1'},
- queryParams: <String, String>{'q1': 'qv1'},
+ pathParameters: <String, String>{'p1': 'pv1'},
+ queryParameters: <String, String>{'q1': 'qv1'},
),
child: const Text('Go to page 2'),
),
@@ -134,7 +134,7 @@
ElevatedButton(
onPressed: () => context.goNamed(
'page3',
- params: <String, String>{'p1': 'pv2'},
+ pathParameters: <String, String>{'p1': 'pv2'},
),
child: const Text('Go to page 3'),
),
diff --git a/packages/go_router/example/lib/others/push.dart b/packages/go_router/example/lib/others/push.dart
index 53567b6..06e3469 100644
--- a/packages/go_router/example/lib/others/push.dart
+++ b/packages/go_router/example/lib/others/push.dart
@@ -32,7 +32,7 @@
path: '/page2',
builder: (BuildContext context, GoRouterState state) =>
Page2ScreenWithPush(
- int.parse(state.queryParams['push-count']!),
+ int.parse(state.queryParameters['push-count']!),
),
),
],
diff --git a/packages/go_router/example/lib/path_and_query_parameters.dart b/packages/go_router/example/lib/path_and_query_parameters.dart
index 83d7b63..bf915a2 100755
--- a/packages/go_router/example/lib/path_and_query_parameters.dart
+++ b/packages/go_router/example/lib/path_and_query_parameters.dart
@@ -9,9 +9,9 @@
//
// The route segments that start with ':' are treated as path parameters when
// defining GoRoute[s]. The parameter values can be accessed through
-// GoRouterState.params.
+// GoRouterState.pathParameters.
//
-// The query parameters are automatically stored in GoRouterState.queryParams.
+// The query parameters are automatically stored in GoRouterState.queryParameters.
/// Family data class.
class Family {
@@ -84,8 +84,8 @@
path: 'family/:fid',
builder: (BuildContext context, GoRouterState state) {
return FamilyScreen(
- fid: state.params['fid']!,
- asc: state.queryParams['sort'] == 'asc',
+ fid: state.pathParameters['fid']!,
+ asc: state.queryParameters['sort'] == 'asc',
);
}),
],
@@ -149,7 +149,8 @@
actions: <Widget>[
IconButton(
onPressed: () => context.goNamed('family',
- params: <String, String>{'fid': fid}, queryParams: newQueries),
+ pathParameters: <String, String>{'fid': fid},
+ queryParameters: newQueries),
tooltip: 'sort ascending or descending',
icon: const Icon(Icons.sort),
)
diff --git a/packages/go_router/example/lib/redirection.dart b/packages/go_router/example/lib/redirection.dart
index 4e97f66..868944c 100644
--- a/packages/go_router/example/lib/redirection.dart
+++ b/packages/go_router/example/lib/redirection.dart
@@ -75,7 +75,7 @@
redirect: (BuildContext context, GoRouterState state) {
// if the user is not logged in, they need to login
final bool loggedIn = _loginInfo.loggedIn;
- final bool loggingIn = state.subloc == '/login';
+ final bool loggingIn = state.matchedLocation == '/login';
if (!loggedIn) {
return '/login';
}
diff --git a/packages/go_router/lib/fix_data.yaml b/packages/go_router/lib/fix_data.yaml
new file mode 100644
index 0000000..99f9782
--- /dev/null
+++ b/packages/go_router/lib/fix_data.yaml
@@ -0,0 +1,151 @@
+# Copyright 2014 The Flutter Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# For details regarding the *Flutter Fix* feature, see
+# https://flutter.dev/docs/development/tools/flutter-fix
+
+# Please add new fixes to the top of the file, separated by one blank line
+# from other fixes. In a comment, include a link to the PR where the change
+# requiring the fix was made.
+
+# Every fix must be tested. See the flutter/packages/flutter/test_fixes/README.md
+# file for instructions on testing these data driven fixes.
+
+# For documentation about this file format, see
+# https://dart.dev/go/data-driven-fixes
+
+version: 1
+transforms:
+ - title: "Replaces 'params' and 'queryParams' in 'GoRouter.replaceNamed' with `pathParameters` and `queryParameters`"
+ date: 2023-04-24
+ bulkApply: true
+ element:
+ uris: [ 'go_router.dart' ]
+ method: 'replaceNamed'
+ inClass: 'GoRouter'
+ changes:
+ - kind: 'renameParameter'
+ oldName: 'params'
+ newName: 'pathParameters'
+ - kind: 'renameParameter'
+ oldName: 'queryParams'
+ newName: 'queryParameters'
+ - title: "Replaces 'params' and 'queryParams' in 'GoRouter.pushReplacementNamed' with `pathParameters` and `queryParameters`"
+ date: 2023-04-24
+ bulkApply: true
+ element:
+ uris: [ 'go_router.dart' ]
+ method: 'pushReplacementNamed'
+ inClass: 'GoRouter'
+ changes:
+ - kind: 'renameParameter'
+ oldName: 'params'
+ newName: 'pathParameters'
+ - kind: 'renameParameter'
+ oldName: 'queryParams'
+ newName: 'queryParameters'
+
+ - title: "Replaces 'params' and 'queryParams' in 'GoRouter.pushNamed' with `pathParameters` and `queryParameters`"
+ date: 2023-04-24
+ bulkApply: true
+ element:
+ uris: [ 'go_router.dart' ]
+ method: 'pushNamed'
+ inClass: 'GoRouter'
+ changes:
+ - kind: 'renameParameter'
+ oldName: 'params'
+ newName: 'pathParameters'
+ - kind: 'renameParameter'
+ oldName: 'queryParams'
+ newName: 'queryParameters'
+
+ - title: "Replaces 'params' and 'queryParams' in 'GoRouter.goNamed' with `pathParameters` and `queryParameters`"
+ date: 2023-04-24
+ bulkApply: true
+ element:
+ uris: [ 'go_router.dart' ]
+ method: 'goNamed'
+ inClass: 'GoRouter'
+ changes:
+ - kind: 'renameParameter'
+ oldName: 'params'
+ newName: 'pathParameters'
+ - kind: 'renameParameter'
+ oldName: 'queryParams'
+ newName: 'queryParameters'
+
+ - title: "Replaces 'params' and 'queryParams' in 'GoRouter.namedLocation' with `pathParameters` and `queryParameters`"
+ date: 2023-04-24
+ bulkApply: true
+ element:
+ uris: [ 'go_router.dart' ]
+ method: 'namedLocation'
+ inClass: 'GoRouter'
+ changes:
+ - kind: 'renameParameter'
+ oldName: 'params'
+ newName: 'pathParameters'
+ - kind: 'renameParameter'
+ oldName: 'queryParams'
+ newName: 'queryParameters'
+
+ - title: "Replaces 'params' and 'queryParams' in 'GoRouterState.namedLocation' with `pathParameters` and `queryParameters`"
+ date: 2023-04-24
+ bulkApply: true
+ element:
+ uris: [ 'go_router.dart' ]
+ method: 'namedLocation'
+ inClass: 'GoRouterState'
+ changes:
+ - kind: 'renameParameter'
+ oldName: 'params'
+ newName: 'pathParameters'
+ - kind: 'renameParameter'
+ oldName: 'queryParams'
+ newName: 'queryParameters'
+
+ - title: "Replaces 'GoRouterState.queryParams' with 'GoRouterState.queryParameters'"
+ date: 2023-04-24
+ bulkApply: true
+ element:
+ uris: [ 'go_router.dart' ]
+ field: 'queryParams'
+ inClass: 'GoRouterState'
+ changes:
+ - kind: 'rename'
+ newName: 'queryParameters'
+
+ - title: "Replaces 'GoRouterState.fullpath' with 'GoRouterState.fullPath'"
+ date: 2023-04-24
+ bulkApply: true
+ element:
+ uris: [ 'go_router.dart' ]
+ field: 'fullpath'
+ inClass: 'GoRouterState'
+ changes:
+ - kind: 'rename'
+ newName: 'fullPath'
+
+ - title: "Replaces 'GoRouterState.params' with 'GoRouterState.pathParameters'"
+ date: 2023-04-24
+ bulkApply: true
+ element:
+ uris: [ 'go_router.dart' ]
+ field: 'params'
+ inClass: 'GoRouterState'
+ changes:
+ - kind: 'rename'
+ newName: 'pathParameters'
+
+ - title: "Replaces 'GoRouterState.subloc' with 'GoRouterState.matchedLocation'"
+ date: 2023-04-24
+ bulkApply: true
+ element:
+ uris: [ 'go_router.dart' ]
+ field: 'subloc'
+ inClass: 'GoRouterState'
+ changes:
+ - kind: 'rename'
+ newName: 'matchedLocation'
diff --git a/packages/go_router/lib/src/builder.dart b/packages/go_router/lib/src/builder.dart
index 681f1d2..c497a79 100644
--- a/packages/go_router/lib/src/builder.dart
+++ b/packages/go_router/lib/src/builder.dart
@@ -6,7 +6,6 @@
import 'package:flutter/widgets.dart';
import 'configuration.dart';
-import 'delegate.dart';
import 'logging.dart';
import 'match.dart';
import 'matching.dart';
@@ -254,7 +253,7 @@
}
/// Helper method that builds a [GoRouterState] object for the given [match]
- /// and [params].
+ /// and [pathParameters].
@visibleForTesting
GoRouterState buildState(RouteMatchList matchList, RouteMatch match) {
final RouteBase route = match.route;
@@ -269,13 +268,14 @@
return GoRouterState(
configuration,
location: effectiveMatchList.uri.toString(),
- subloc: match.subloc,
+ matchedLocation: match.matchedLocation,
name: name,
path: path,
- fullpath: effectiveMatchList.fullpath,
- params: Map<String, String>.from(effectiveMatchList.pathParameters),
+ fullPath: effectiveMatchList.fullPath,
+ pathParameters:
+ Map<String, String>.from(effectiveMatchList.pathParameters),
error: match.error,
- queryParams: effectiveMatchList.uri.queryParameters,
+ queryParameters: effectiveMatchList.uri.queryParameters,
queryParametersAll: effectiveMatchList.uri.queryParametersAll,
extra: match.extra,
pageKey: match.pageKey,
@@ -397,7 +397,10 @@
return _pageBuilderForAppType!(
key: state.pageKey,
name: state.name ?? state.path,
- arguments: <String, String>{...state.params, ...state.queryParams},
+ arguments: <String, String>{
+ ...state.pathParameters,
+ ...state.queryParameters
+ },
restorationId: state.pageKey.value,
child: child,
);
@@ -444,9 +447,9 @@
final GoRouterState state = GoRouterState(
configuration,
location: uri.toString(),
- subloc: uri.path,
+ matchedLocation: uri.path,
name: null,
- queryParams: uri.queryParameters,
+ queryParameters: uri.queryParameters,
queryParametersAll: uri.queryParametersAll,
error: Exception(error),
pageKey: const ValueKey<String>('error'),
diff --git a/packages/go_router/lib/src/configuration.dart b/packages/go_router/lib/src/configuration.dart
index c17b708..2c2f8e7 100644
--- a/packages/go_router/lib/src/configuration.dart
+++ b/packages/go_router/lib/src/configuration.dart
@@ -97,7 +97,7 @@
if (route is! GoRoute) {
continue;
}
- for (final String pathParam in route.pathParams) {
+ for (final String pathParam in route.pathParameters) {
if (usedPathParams.containsKey(pathParam)) {
final bool sameRoute = usedPathParams[pathParam] == route;
throw GoError(
@@ -106,7 +106,7 @@
usedPathParams[pathParam] = route;
}
_debugVerifyNoDuplicatePathParameter(route.routes, usedPathParams);
- route.pathParams.forEach(usedPathParams.remove);
+ route.pathParameters.forEach(usedPathParams.remove);
}
return true;
}
@@ -128,14 +128,14 @@
/// Looks up the url location by a [GoRoute]'s name.
String namedLocation(
String name, {
- Map<String, String> params = const <String, String>{},
- Map<String, dynamic> queryParams = const <String, dynamic>{},
+ Map<String, String> pathParameters = const <String, String>{},
+ Map<String, dynamic> queryParameters = const <String, dynamic>{},
}) {
assert(() {
log.info('getting location for name: '
'"$name"'
- '${params.isEmpty ? '' : ', params: $params'}'
- '${queryParams.isEmpty ? '' : ', queryParams: $queryParams'}');
+ '${pathParameters.isEmpty ? '' : ', pathParameters: $pathParameters'}'
+ '${queryParameters.isEmpty ? '' : ', queryParameters: $queryParameters'}');
return true;
}());
final String keyName = name.toLowerCase();
@@ -146,24 +146,24 @@
final List<String> paramNames = <String>[];
patternToRegExp(path, paramNames);
for (final String paramName in paramNames) {
- assert(params.containsKey(paramName),
+ assert(pathParameters.containsKey(paramName),
'missing param "$paramName" for $path');
}
// Check that there are no extra params
- for (final String key in params.keys) {
+ for (final String key in pathParameters.keys) {
assert(paramNames.contains(key), 'unknown param "$key" for $path');
}
return true;
}());
final Map<String, String> encodedParams = <String, String>{
- for (final MapEntry<String, String> param in params.entries)
+ for (final MapEntry<String, String> param in pathParameters.entries)
param.key: Uri.encodeComponent(param.value)
};
final String location = patternToPath(path, encodedParams);
return Uri(
path: location,
- queryParameters: queryParams.isEmpty ? null : queryParams)
+ queryParameters: queryParameters.isEmpty ? null : queryParameters)
.toString();
}
@@ -196,9 +196,9 @@
int depth, StringBuffer sb) {
for (final RouteBase route in routes) {
if (route is GoRoute) {
- final String fullpath = concatenatePaths(parentFullpath, route.path);
- sb.writeln(' => ${''.padLeft(depth * 2)}$fullpath');
- _debugFullPathsFor(route.routes, fullpath, depth + 1, sb);
+ final String fullPath = concatenatePaths(parentFullpath, route.path);
+ sb.writeln(' => ${''.padLeft(depth * 2)}$fullPath');
+ _debugFullPathsFor(route.routes, fullPath, depth + 1, sb);
} else if (route is ShellRoute) {
_debugFullPathsFor(route.routes, parentFullpath, depth, sb);
}
diff --git a/packages/go_router/lib/src/delegate.dart b/packages/go_router/lib/src/delegate.dart
index 279c10d..a62906a 100644
--- a/packages/go_router/lib/src/delegate.dart
+++ b/packages/go_router/lib/src/delegate.dart
@@ -86,15 +86,19 @@
RouteMatchList matches, ValueKey<String> pageKey) async {
final ImperativeRouteMatch<T> newPageKeyMatch = ImperativeRouteMatch<T>(
route: matches.last.route,
- subloc: matches.last.subloc,
+ matchedLocation: matches.last.matchedLocation,
extra: matches.last.extra,
error: matches.last.error,
pageKey: pageKey,
matches: matches,
);
- _matchList.push(newPageKeyMatch);
- return newPageKeyMatch._future;
+ _matchList = _matchList.push(newPageKeyMatch);
+ return newPageKeyMatch.future;
+ }
+
+ void _remove(RouteMatch match) {
+ _matchList = _matchList.remove(match);
}
/// Pushes the given location onto the page stack.
@@ -108,7 +112,7 @@
Future<T?> push<T extends Object?>(RouteMatchList matches) async {
assert(matches.last.route is! ShellRoute);
- final ValueKey<String> pageKey = _getNewKeyForPath(matches.fullpath);
+ final ValueKey<String> pageKey = _getNewKeyForPath(matches.fullPath);
final Future<T?> future = _push(matches, pageKey);
notifyListeners();
return future;
@@ -155,7 +159,7 @@
if (match is ImperativeRouteMatch) {
match.complete(result);
}
- _matchList.remove(match!);
+ _remove(match!);
notifyListeners();
assert(() {
_debugAssertMatchListNotEmpty();
@@ -175,7 +179,7 @@
/// state and not run any page animation.
void pushReplacement(RouteMatchList matches) {
assert(matches.last.route is! ShellRoute);
- _matchList.remove(_matchList.last);
+ _remove(_matchList.last);
push(matches); // [push] will notify the listeners.
}
@@ -193,7 +197,7 @@
assert(matches.last.route is! ShellRoute);
final RouteMatch routeMatch = _matchList.last;
final ValueKey<String> pageKey = routeMatch.pageKey;
- _matchList.remove(routeMatch);
+ _remove(routeMatch);
_push(matches, pageKey);
notifyListeners();
}
@@ -309,32 +313,3 @@
return true;
}
}
-
-/// The route match that represent route pushed through [GoRouter.push].
-class ImperativeRouteMatch<T> extends RouteMatch {
- /// Constructor for [ImperativeRouteMatch].
- ImperativeRouteMatch({
- required super.route,
- required super.subloc,
- required super.extra,
- required super.error,
- required super.pageKey,
- required this.matches,
- }) : _completer = Completer<T?>();
-
- /// The matches that produces this route match.
- final RouteMatchList matches;
-
- /// The completer for the future returned by [GoRouter.push].
- final Completer<T?> _completer;
-
- /// Called when the corresponding [Route] associated with this route match is
- /// completed.
- void complete([dynamic value]) {
- _completer.complete(value as T?);
- }
-
- /// The future of the [RouteMatch] completer.
- /// When the future completes, this will return the value passed to [complete].
- Future<T?> get _future => _completer.future;
-}
diff --git a/packages/go_router/lib/src/match.dart b/packages/go_router/lib/src/match.dart
index 0cb7041..7c3c736 100644
--- a/packages/go_router/lib/src/match.dart
+++ b/packages/go_router/lib/src/match.dart
@@ -2,35 +2,44 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'dart:async';
+
import 'package:flutter/widgets.dart';
import 'matching.dart';
import 'path_utils.dart';
import 'route.dart';
-/// An instance of a GoRoute plus information about the current location.
+/// An matched result by matching a [RouteBase] against a location.
+///
+/// This is typically created by calling [RouteMatch.match].
+@immutable
class RouteMatch {
/// Constructor for [RouteMatch].
- RouteMatch({
+ const RouteMatch({
required this.route,
- required this.subloc,
+ required this.matchedLocation,
required this.extra,
required this.error,
required this.pageKey,
});
- // ignore: public_member_api_docs
+ /// Generate a [RouteMatch] object by matching the `route` with
+ /// `remainingLocation`.
+ ///
+ /// The extracted path parameters, as the result of the matching, are stored
+ /// into `pathParameters`.
static RouteMatch? match({
required RouteBase route,
- required String restLoc, // e.g. person/p1
- required String parentSubloc, // e.g. /family/f2
+ required String remainingLocation, // e.g. person/p1
+ required String matchedLocation, // e.g. /family/f2
required Map<String, String> pathParameters,
required Object? extra,
}) {
if (route is ShellRoute) {
return RouteMatch(
route: route,
- subloc: restLoc,
+ matchedLocation: remainingLocation,
extra: extra,
error: null,
pageKey: ValueKey<String>(route.hashCode.toString()),
@@ -38,7 +47,7 @@
} else if (route is GoRoute) {
assert(!route.path.contains('//'));
- final RegExpMatch? match = route.matchPatternAsPrefix(restLoc);
+ final RegExpMatch? match = route.matchPatternAsPrefix(remainingLocation);
if (match == null) {
return null;
}
@@ -48,23 +57,31 @@
pathParameters[param.key] = Uri.decodeComponent(param.value);
}
final String pathLoc = patternToPath(route.path, encodedParams);
- final String subloc = concatenatePaths(parentSubloc, pathLoc);
+ final String newMatchedLocation =
+ concatenatePaths(matchedLocation, pathLoc);
return RouteMatch(
route: route,
- subloc: subloc,
+ matchedLocation: newMatchedLocation,
extra: extra,
error: null,
pageKey: ValueKey<String>(route.hashCode.toString()),
);
}
- throw MatcherError('Unexpected route type: $route', restLoc);
+ throw MatcherError('Unexpected route type: $route', remainingLocation);
}
/// The matched route.
final RouteBase route;
- /// The matched location.
- final String subloc; // e.g. /family/f2
+ /// The location string that matches the [route].
+ ///
+ /// for example:
+ ///
+ /// uri = '/family/f2/person/p2'
+ /// route = GoRoute('/family/:id)
+ ///
+ /// matchedLocation = '/family/f2'
+ final String matchedLocation;
/// An extra object to pass along with the navigation.
final Object? extra;
@@ -74,4 +91,59 @@
/// Value key of type string, to hold a unique reference to a page.
final ValueKey<String> pageKey;
+
+ @override
+ bool operator ==(Object other) {
+ if (other.runtimeType != runtimeType) {
+ return false;
+ }
+ return other is RouteMatch &&
+ route == other.route &&
+ matchedLocation == other.matchedLocation &&
+ extra == other.extra &&
+ pageKey == other.pageKey;
+ }
+
+ @override
+ int get hashCode => Object.hash(route, matchedLocation, extra, pageKey);
+}
+
+/// The route match that represent route pushed through [GoRouter.push].
+class ImperativeRouteMatch<T> extends RouteMatch {
+ /// Constructor for [ImperativeRouteMatch].
+ ImperativeRouteMatch({
+ required super.route,
+ required super.matchedLocation,
+ required super.extra,
+ required super.error,
+ required super.pageKey,
+ required this.matches,
+ }) : _completer = Completer<T?>();
+
+ /// The matches that produces this route match.
+ final RouteMatchList matches;
+
+ /// The completer for the future returned by [GoRouter.push].
+ final Completer<T?> _completer;
+
+ /// Called when the corresponding [Route] associated with this route match is
+ /// completed.
+ void complete([dynamic value]) {
+ _completer.complete(value as T?);
+ }
+
+ /// The future of the [RouteMatch] completer.
+ /// When the future completes, this will return the value passed to [complete].
+ Future<T?> get future => _completer.future;
+
+ // An ImperativeRouteMatch has its own life cycle due the the _completer.
+ // comparing _completer between instances would be the same thing as
+ // comparing object reference.
+ @override
+ bool operator ==(Object other) {
+ return identical(this, other);
+ }
+
+ @override
+ int get hashCode => identityHashCode(this);
}
diff --git a/packages/go_router/lib/src/matching.dart b/packages/go_router/lib/src/matching.dart
index b67c69b..5855204 100644
--- a/packages/go_router/lib/src/matching.dart
+++ b/packages/go_router/lib/src/matching.dart
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'configuration.dart';
-import 'delegate.dart';
import 'match.dart';
import 'path_utils.dart';
@@ -25,16 +25,17 @@
final Map<String, String> pathParameters = <String, String>{};
final List<RouteMatch> matches =
_getLocRouteMatches(uri, extra, pathParameters);
- return RouteMatchList(matches, uri, pathParameters);
+ return RouteMatchList(
+ matches: matches, uri: uri, pathParameters: pathParameters);
}
List<RouteMatch> _getLocRouteMatches(
Uri uri, Object? extra, Map<String, String> pathParameters) {
final List<RouteMatch>? result = _getLocRouteRecursively(
- loc: uri.path,
- restLoc: uri.path,
+ location: uri.path,
+ remainingLocation: uri.path,
routes: configuration.routes,
- parentSubloc: '',
+ matchedLocation: '',
pathParameters: pathParameters,
extra: extra,
);
@@ -50,19 +51,50 @@
/// The list of [RouteMatch] objects.
///
/// This corresponds to the GoRouter's history.
+@immutable
class RouteMatchList {
/// RouteMatchList constructor.
- RouteMatchList(List<RouteMatch> matches, this._uri, this.pathParameters)
- : _matches = matches,
- fullpath = _generateFullPath(matches);
+ RouteMatchList({
+ required this.matches,
+ required this.uri,
+ required this.pathParameters,
+ }) : fullPath = _generateFullPath(matches);
/// Constructs an empty matches object.
- static RouteMatchList empty =
- RouteMatchList(<RouteMatch>[], Uri.parse(''), const <String, String>{});
+ static RouteMatchList empty = RouteMatchList(
+ matches: const <RouteMatch>[],
+ uri: Uri(),
+ pathParameters: const <String, String>{});
+
+ /// The route matches.
+ final List<RouteMatch> matches;
+
+ /// Parameters for the matched route, URI-encoded.
+ ///
+ /// The parameters only reflects [RouteMatch]s that are not
+ /// [ImperativeRouteMatch].
+ final Map<String, String> pathParameters;
+
+ /// The uri of the current match.
+ ///
+ /// This uri only reflects [RouteMatch]s that are not [ImperativeRouteMatch].
+ final Uri uri;
+
+ /// the full path pattern that matches the uri.
+ ///
+ /// For example:
+ ///
+ /// ```dart
+ /// '/family/:fid/person/:pid'
+ /// ```
+ final String fullPath;
/// Generates the full path (ex: `'/family/:fid/person/:pid'`) of a list of
/// [RouteMatch].
///
+ /// This method ignores [ImperativeRouteMatch]s in the `matches`, as they
+ /// don't contribute to the path.
+ ///
/// This methods considers that [matches]'s elements verify the go route
/// structure given to `GoRouter`. For example, if the routes structure is
///
@@ -90,7 +122,8 @@
static String _generateFullPath(Iterable<RouteMatch> matches) {
final StringBuffer buffer = StringBuffer();
bool addsSlash = false;
- for (final RouteMatch match in matches) {
+ for (final RouteMatch match in matches
+ .where((RouteMatch match) => match is! ImperativeRouteMatch)) {
final RouteBase route = match.route;
if (route is GoRoute) {
if (addsSlash) {
@@ -103,66 +136,61 @@
return buffer.toString();
}
- final List<RouteMatch> _matches;
-
- /// the full path pattern that matches the uri.
- ///
- /// For example:
- ///
- /// ```dart
- /// '/family/:fid/person/:pid'
- /// ```
- final String fullpath;
-
- /// Parameters for the matched route, URI-encoded.
- final Map<String, String> pathParameters;
-
- /// The uri of the current match.
- Uri get uri => _uri;
- Uri _uri;
-
/// Returns true if there are no matches.
- bool get isEmpty => _matches.isEmpty;
+ bool get isEmpty => matches.isEmpty;
/// Returns true if there are matches.
- bool get isNotEmpty => _matches.isNotEmpty;
+ bool get isNotEmpty => matches.isNotEmpty;
- /// Pushes a match onto the list of matches.
- void push(RouteMatch match) {
- _matches.add(match);
+ /// Returns a new instance of RouteMatchList with the input `match` pushed
+ /// onto the current instance.
+ RouteMatchList push<T>(ImperativeRouteMatch<T> match) {
+ // Imperative route match doesn't change the uri and path parameters.
+ return _copyWith(matches: <RouteMatch>[...matches, match]);
}
- /// Removes the match from the list.
- void remove(RouteMatch match) {
- final int index = _matches.indexOf(match);
+ /// Returns a new instance of RouteMatchList with the input `match` removed
+ /// from the current instance.
+ RouteMatchList remove(RouteMatch match) {
+ final List<RouteMatch> newMatches = matches.toList();
+ final int index = newMatches.indexOf(match);
assert(index != -1);
- _matches.removeRange(index, _matches.length);
+ newMatches.removeRange(index, newMatches.length);
// Also pop ShellRoutes when there are no subsequent route matches
- while (_matches.isNotEmpty && _matches.last.route is ShellRoute) {
- _matches.removeLast();
+ while (newMatches.isNotEmpty && newMatches.last.route is ShellRoute) {
+ newMatches.removeLast();
+ }
+ // Removing ImperativeRouteMatch should not change uri and pathParameters.
+ if (match is ImperativeRouteMatch) {
+ return _copyWith(matches: newMatches);
}
final String fullPath = _generateFullPath(
- _matches.where((RouteMatch match) => match is! ImperativeRouteMatch));
+ newMatches.where((RouteMatch match) => match is! ImperativeRouteMatch));
// Need to remove path parameters that are no longer in the fullPath.
final List<String> newParameters = <String>[];
patternToRegExp(fullPath, newParameters);
final Set<String> validParameters = newParameters.toSet();
- pathParameters.removeWhere(
- (String key, String value) => !validParameters.contains(key));
-
- _uri = _uri.replace(path: patternToPath(fullPath, pathParameters));
+ final Map<String, String> newPathParameters =
+ Map<String, String>.fromEntries(
+ pathParameters.entries.where((MapEntry<String, String> value) =>
+ validParameters.contains(value.key)),
+ );
+ final Uri newUri =
+ uri.replace(path: patternToPath(fullPath, newPathParameters));
+ return _copyWith(
+ matches: newMatches,
+ uri: newUri,
+ pathParameters: newPathParameters,
+ );
}
/// An optional object provided by the app during navigation.
- Object? get extra => _matches.isEmpty ? null : _matches.last.extra;
+ Object? get extra => matches.isEmpty ? null : matches.last.extra;
/// The last matching route.
- RouteMatch get last => _matches.last;
-
- /// The route matches.
- List<RouteMatch> get matches => _matches;
+ RouteMatch get last => matches.last;
/// Returns true if the current match intends to display an error screen.
bool get isError => matches.length == 1 && matches.first.error != null;
@@ -170,9 +198,44 @@
/// Returns the error that this match intends to display.
Exception? get error => matches.first.error;
+ RouteMatchList _copyWith({
+ List<RouteMatch>? matches,
+ Uri? uri,
+ Map<String, String>? pathParameters,
+ }) {
+ return RouteMatchList(
+ matches: matches ?? this.matches,
+ uri: uri ?? this.uri,
+ pathParameters: pathParameters ?? this.pathParameters);
+ }
+
+ @override
+ bool operator ==(Object other) {
+ if (other.runtimeType != runtimeType) {
+ return false;
+ }
+ return other is RouteMatchList &&
+ const ListEquality<RouteMatch>().equals(matches, other.matches) &&
+ uri == other.uri &&
+ const MapEquality<String, String>()
+ .equals(pathParameters, other.pathParameters);
+ }
+
+ @override
+ int get hashCode {
+ return Object.hash(
+ Object.hashAll(matches),
+ uri,
+ Object.hashAllUnordered(
+ pathParameters.entries.map<int>((MapEntry<String, String> entry) =>
+ Object.hash(entry.key, entry.value)),
+ ),
+ );
+ }
+
@override
String toString() {
- return '${objectRuntimeType(this, 'RouteMatchList')}($fullpath)';
+ return '${objectRuntimeType(this, 'RouteMatchList')}($fullPath)';
}
}
@@ -198,17 +261,17 @@
/// For example, for a given `loc` `/a/b/c/d`, this function will return the
/// list of [RouteBase] `[GoRouteA(), GoRouterB(), GoRouteC(), GoRouterD()]`.
///
-/// - [loc] is the complete URL to match (without the query parameters). For
-/// example, for the URL `/a/b?c=0`, [loc] will be `/a/b`.
-/// - [restLoc] is the remaining part of the URL to match while [parentSubloc]
+/// - [location] is the complete URL to match (without the query parameters). For
+/// example, for the URL `/a/b?c=0`, [location] will be `/a/b`.
+/// - [remainingLocation] is the remaining part of the URL to match while [matchedLocation]
/// is the part of the URL that has already been matched. For examples, for
-/// the URL `/a/b/c/d`, at some point, [restLoc] would be `/c/d` and
-/// [parentSubloc] will be `/a/b`.
-/// - [routes] are the possible [RouteBase] to match to [restLoc].
+/// the URL `/a/b/c/d`, at some point, [remainingLocation] would be `/c/d` and
+/// [matchedLocation] will be `/a/b`.
+/// - [routes] are the possible [RouteBase] to match to [remainingLocation].
List<RouteMatch>? _getLocRouteRecursively({
- required String loc,
- required String restLoc,
- required String parentSubloc,
+ required String location,
+ required String remainingLocation,
+ required String matchedLocation,
required List<RouteBase> routes,
required Map<String, String> pathParameters,
required Object? extra,
@@ -221,8 +284,8 @@
final RouteMatch? match = RouteMatch.match(
route: route,
- restLoc: restLoc,
- parentSubloc: parentSubloc,
+ remainingLocation: remainingLocation,
+ matchedLocation: matchedLocation,
pathParameters: subPathParameters,
extra: extra,
);
@@ -232,9 +295,9 @@
}
if (match.route is GoRoute &&
- match.subloc.toLowerCase() == loc.toLowerCase()) {
+ match.matchedLocation.toLowerCase() == location.toLowerCase()) {
// If it is a complete match, then return the matched route
- // NOTE: need a lower case match because subloc is canonicalized to match
+ // NOTE: need a lower case match because matchedLocation is canonicalized to match
// the path case whereas the location can be of any case and still match
result = <RouteMatch>[match];
} else if (route.routes.isEmpty) {
@@ -245,21 +308,21 @@
final String childRestLoc;
final String newParentSubLoc;
if (match.route is ShellRoute) {
- childRestLoc = restLoc;
- newParentSubLoc = parentSubloc;
+ childRestLoc = remainingLocation;
+ newParentSubLoc = matchedLocation;
} else {
- assert(loc.startsWith(match.subloc));
- assert(restLoc.isNotEmpty);
+ assert(location.startsWith(match.matchedLocation));
+ assert(remainingLocation.isNotEmpty);
- childRestLoc =
- loc.substring(match.subloc.length + (match.subloc == '/' ? 0 : 1));
- newParentSubLoc = match.subloc;
+ childRestLoc = location.substring(match.matchedLocation.length +
+ (match.matchedLocation == '/' ? 0 : 1));
+ newParentSubLoc = match.matchedLocation;
}
final List<RouteMatch>? subRouteMatch = _getLocRouteRecursively(
- loc: loc,
- restLoc: childRestLoc,
- parentSubloc: newParentSubLoc,
+ location: location,
+ remainingLocation: childRestLoc,
+ matchedLocation: newParentSubLoc,
routes: route.routes,
pathParameters: subPathParameters,
extra: extra,
@@ -284,20 +347,21 @@
RouteMatchList errorScreen(Uri uri, String errorMessage) {
final Exception error = Exception(errorMessage);
return RouteMatchList(
- <RouteMatch>[
- RouteMatch(
- subloc: uri.path,
- extra: null,
- error: error,
- route: GoRoute(
- path: uri.toString(),
- pageBuilder: (BuildContext context, GoRouterState state) {
- throw UnimplementedError();
- },
- ),
- pageKey: const ValueKey<String>('error'),
+ matches: <RouteMatch>[
+ RouteMatch(
+ matchedLocation: uri.path,
+ extra: null,
+ error: error,
+ route: GoRoute(
+ path: uri.toString(),
+ pageBuilder: (BuildContext context, GoRouterState state) {
+ throw UnimplementedError();
+ },
),
- ],
- uri,
- const <String, String>{});
+ pageKey: const ValueKey<String>('error'),
+ ),
+ ],
+ uri: uri,
+ pathParameters: const <String, String>{},
+ );
}
diff --git a/packages/go_router/lib/src/misc/extensions.dart b/packages/go_router/lib/src/misc/extensions.dart
index 47f5b08..05dbd0f 100644
--- a/packages/go_router/lib/src/misc/extensions.dart
+++ b/packages/go_router/lib/src/misc/extensions.dart
@@ -12,11 +12,11 @@
/// Get a location from route name and parameters.
String namedLocation(
String name, {
- Map<String, String> params = const <String, String>{},
- Map<String, dynamic> queryParams = const <String, dynamic>{},
+ Map<String, String> pathParameters = const <String, String>{},
+ Map<String, dynamic> queryParameters = const <String, dynamic>{},
}) =>
- GoRouter.of(this)
- .namedLocation(name, params: params, queryParams: queryParams);
+ GoRouter.of(this).namedLocation(name,
+ pathParameters: pathParameters, queryParameters: queryParameters);
/// Navigate to a location.
void go(String location, {Object? extra}) =>
@@ -25,14 +25,14 @@
/// Navigate to a named route.
void goNamed(
String name, {
- Map<String, String> params = const <String, String>{},
- Map<String, dynamic> queryParams = const <String, dynamic>{},
+ Map<String, String> pathParameters = const <String, String>{},
+ Map<String, dynamic> queryParameters = const <String, dynamic>{},
Object? extra,
}) =>
GoRouter.of(this).goNamed(
name,
- params: params,
- queryParams: queryParams,
+ pathParameters: pathParameters,
+ queryParameters: queryParameters,
extra: extra,
);
@@ -50,14 +50,14 @@
/// Navigate to a named route onto the page stack.
Future<T?> pushNamed<T extends Object?>(
String name, {
- Map<String, String> params = const <String, String>{},
- Map<String, dynamic> queryParams = const <String, dynamic>{},
+ Map<String, String> pathParameters = const <String, String>{},
+ Map<String, dynamic> queryParameters = const <String, dynamic>{},
Object? extra,
}) =>
GoRouter.of(this).pushNamed<T>(
name,
- params: params,
- queryParams: queryParams,
+ pathParameters: pathParameters,
+ queryParameters: queryParameters,
extra: extra,
);
@@ -81,7 +81,7 @@
GoRouter.of(this).pushReplacement(location, extra: extra);
/// Replaces the top-most page of the page stack with the named route w/
- /// optional parameters, e.g. `name='person', params={'fid': 'f2', 'pid':
+ /// optional parameters, e.g. `name='person', pathParameters={'fid': 'f2', 'pid':
/// 'p1'}`.
///
/// See also:
@@ -89,14 +89,14 @@
/// * [pushNamed] which pushes a named route onto the page stack.
void pushReplacementNamed(
String name, {
- Map<String, String> params = const <String, String>{},
- Map<String, dynamic> queryParams = const <String, dynamic>{},
+ Map<String, String> pathParameters = const <String, String>{},
+ Map<String, dynamic> queryParameters = const <String, dynamic>{},
Object? extra,
}) =>
GoRouter.of(this).pushReplacementNamed(
name,
- params: params,
- queryParams: queryParams,
+ pathParameters: pathParameters,
+ queryParameters: queryParameters,
extra: extra,
);
@@ -117,8 +117,8 @@
/// preserving the page key.
///
/// This will preserve the state and not run any page animation. Optional
- /// parameters can be providded to the named route, e.g. `name='person',
- /// params={'fid': 'f2', 'pid': 'p1'}`.
+ /// parameters can be provided to the named route, e.g. `name='person',
+ /// pathParameters={'fid': 'f2', 'pid': 'p1'}`.
///
/// See also:
/// * [pushNamed] which pushes the given location onto the page stack.
@@ -126,8 +126,8 @@
/// stack but always uses a new page key.
void replaceNamed(
String name, {
- Map<String, String> params = const <String, String>{},
- Map<String, dynamic> queryParams = const <String, dynamic>{},
+ Map<String, String> pathParameters = const <String, String>{},
+ Map<String, dynamic> queryParameters = const <String, dynamic>{},
Object? extra,
}) =>
GoRouter.of(this).replaceNamed(name, extra: extra);
diff --git a/packages/go_router/lib/src/parser.dart b/packages/go_router/lib/src/parser.dart
index a888daf..7fd00cf 100644
--- a/packages/go_router/lib/src/parser.dart
+++ b/packages/go_router/lib/src/parser.dart
@@ -8,7 +8,6 @@
import 'package:flutter/widgets.dart';
import 'configuration.dart';
-import 'delegate.dart';
import 'information_provider.dart';
import 'logging.dart';
import 'match.dart';
@@ -72,12 +71,12 @@
// If there is a matching error for the initial location, we should
// still try to process the top-level redirects.
initialMatches = RouteMatchList(
- <RouteMatch>[],
+ matches: const <RouteMatch>[],
// TODO(chunhtai): remove this ignore and migrate the code
// https://github.com/flutter/flutter/issues/124045.
// ignore: deprecated_member_use, unnecessary_non_null_assertion
- Uri.parse(canonicalUri(routeInformation.location!)),
- const <String, String>{},
+ uri: Uri.parse(canonicalUri(routeInformation.location!)),
+ pathParameters: const <String, String>{},
);
}
Future<RouteMatchList> processRedirectorResult(RouteMatchList matches) {
diff --git a/packages/go_router/lib/src/redirection.dart b/packages/go_router/lib/src/redirection.dart
index 3ebef5c..3ac4a5b 100644
--- a/packages/go_router/lib/src/redirection.dart
+++ b/packages/go_router/lib/src/redirection.dart
@@ -96,8 +96,8 @@
name: null,
// No name available at the top level trim the query params off the
// sub-location to match route.redirect
- subloc: prevMatchList.uri.path,
- queryParams: prevMatchList.uri.queryParameters,
+ matchedLocation: prevMatchList.uri.path,
+ queryParameters: prevMatchList.uri.queryParameters,
queryParametersAll: prevMatchList.uri.queryParametersAll,
extra: extra,
pageKey: const ValueKey<String>('topLevel'),
@@ -138,13 +138,13 @@
GoRouterState(
configuration,
location: matchList.uri.toString(),
- subloc: match.subloc,
+ matchedLocation: match.matchedLocation,
name: route.name,
path: route.path,
- fullpath: matchList.fullpath,
+ fullPath: matchList.fullPath,
extra: match.extra,
- params: matchList.pathParameters,
- queryParams: matchList.uri.queryParameters,
+ pathParameters: matchList.pathParameters,
+ queryParameters: matchList.uri.queryParameters,
queryParametersAll: matchList.uri.queryParametersAll,
pageKey: match.pageKey,
),
diff --git a/packages/go_router/lib/src/route.dart b/packages/go_router/lib/src/route.dart
index 7f4b9c1..21e8053 100644
--- a/packages/go_router/lib/src/route.dart
+++ b/packages/go_router/lib/src/route.dart
@@ -42,7 +42,7 @@
/// GoRoute(
/// path: 'family/:fid',
/// pageBuilder: (BuildContext context, GoRouterState state) {
-/// final Family family = Families.family(state.params['fid']!);
+/// final Family family = Families.family(state.pathParameters['fid']!);
/// return MaterialPage<void>(
/// key: state.pageKey,
/// child: FamilyPage(family: family),
@@ -52,8 +52,8 @@
/// GoRoute(
/// path: 'person/:pid',
/// pageBuilder: (BuildContext context, GoRouterState state) {
-/// final Family family = Families.family(state.params['fid']!);
-/// final Person person = family.person(state.params['pid']!);
+/// final Family family = Families.family(state.pathParameters['fid']!);
+/// final Person person = family.person(state.pathParameters['pid']!);
/// return MaterialPage<void>(
/// key: state.pageKey,
/// child: PersonPage(family: family, person: person),
@@ -137,7 +137,7 @@
'builder, pageBuilder, or redirect must be provided'),
super._() {
// cache the path regexp and parameters
- _pathRE = patternToRegExp(path, pathParams);
+ _pathRE = patternToRegExp(path, pathParameters);
}
/// Optional name of the route.
@@ -169,8 +169,8 @@
///
/// context.go(
/// context.namedLocation('family'),
- /// params: <String, String>{'fid': 123},
- /// queryParams: <String, String>{'qid': 'quid'},
+ /// pathParameters: <String, String>{'fid': 123},
+ /// queryParameters: <String, String>{'qid': 'quid'},
/// );
/// ```
///
@@ -228,7 +228,7 @@
/// path: '/',
/// builder: (BuildContext context, GoRouterState state) => FamilyPage(
/// families: Families.family(
- /// state.params['id'],
+ /// state.pathParameters['id'],
/// ),
/// ),
/// ),
@@ -306,11 +306,11 @@
/// Extract the path parameters from a match.
Map<String, String> extractPathParams(RegExpMatch match) =>
- extractPathParameters(pathParams, match);
+ extractPathParameters(pathParameters, match);
/// The path parameters in this route.
@internal
- final List<String> pathParams = <String>[];
+ final List<String> pathParameters = <String>[];
@override
String toString() {
diff --git a/packages/go_router/lib/src/router.dart b/packages/go_router/lib/src/router.dart
index 134c46e..e9b4ec6 100644
--- a/packages/go_router/lib/src/router.dart
+++ b/packages/go_router/lib/src/router.dart
@@ -8,6 +8,7 @@
import 'delegate.dart';
import 'information_provider.dart';
import 'logging.dart';
+import 'match.dart';
import 'matching.dart';
import 'misc/inherited_router.dart';
import 'parser.dart';
@@ -179,13 +180,13 @@
/// This is useful for redirecting to a named location.
String namedLocation(
String name, {
- Map<String, String> params = const <String, String>{},
- Map<String, dynamic> queryParams = const <String, dynamic>{},
+ Map<String, String> pathParameters = const <String, String>{},
+ Map<String, dynamic> queryParameters = const <String, dynamic>{},
}) =>
_routeInformationParser.configuration.namedLocation(
name,
- params: params,
- queryParams: queryParams,
+ pathParameters: pathParameters,
+ queryParameters: queryParameters,
);
/// Navigate to a URI location w/ optional query parameters, e.g.
@@ -203,16 +204,17 @@
}
/// Navigate to a named route w/ optional parameters, e.g.
- /// `name='person', params={'fid': 'f2', 'pid': 'p1'}`
+ /// `name='person', pathParameters={'fid': 'f2', 'pid': 'p1'}`
/// Navigate to the named route.
void goNamed(
String name, {
- Map<String, String> params = const <String, String>{},
- Map<String, dynamic> queryParams = const <String, dynamic>{},
+ Map<String, String> pathParameters = const <String, String>{},
+ Map<String, dynamic> queryParameters = const <String, dynamic>{},
Object? extra,
}) =>
go(
- namedLocation(name, params: params, queryParams: queryParams),
+ namedLocation(name,
+ pathParameters: pathParameters, queryParameters: queryParameters),
extra: extra,
);
@@ -245,15 +247,16 @@
}
/// Push a named route onto the page stack w/ optional parameters, e.g.
- /// `name='person', params={'fid': 'f2', 'pid': 'p1'}`
+ /// `name='person', pathParameters={'fid': 'f2', 'pid': 'p1'}`
Future<T?> pushNamed<T extends Object?>(
String name, {
- Map<String, String> params = const <String, String>{},
- Map<String, dynamic> queryParams = const <String, dynamic>{},
+ Map<String, String> pathParameters = const <String, String>{},
+ Map<String, dynamic> queryParameters = const <String, dynamic>{},
Object? extra,
}) =>
push<T>(
- namedLocation(name, params: params, queryParams: queryParams),
+ namedLocation(name,
+ pathParameters: pathParameters, queryParameters: queryParameters),
extra: extra,
);
@@ -283,7 +286,7 @@
}
/// Replaces the top-most page of the page stack with the named route w/
- /// optional parameters, e.g. `name='person', params={'fid': 'f2', 'pid':
+ /// optional parameters, e.g. `name='person', pathParameters={'fid': 'f2', 'pid':
/// 'p1'}`.
///
/// See also:
@@ -291,12 +294,13 @@
/// * [pushNamed] which pushes a named route onto the page stack.
void pushReplacementNamed(
String name, {
- Map<String, String> params = const <String, String>{},
- Map<String, dynamic> queryParams = const <String, dynamic>{},
+ Map<String, String> pathParameters = const <String, String>{},
+ Map<String, dynamic> queryParameters = const <String, dynamic>{},
Object? extra,
}) {
pushReplacement(
- namedLocation(name, params: params, queryParams: queryParams),
+ namedLocation(name,
+ pathParameters: pathParameters, queryParameters: queryParameters),
extra: extra,
);
}
@@ -332,7 +336,7 @@
///
/// This will preserve the state and not run any page animation. Optional
/// parameters can be providded to the named route, e.g. `name='person',
- /// params={'fid': 'f2', 'pid': 'p1'}`.
+ /// pathParameters={'fid': 'f2', 'pid': 'p1'}`.
///
/// See also:
/// * [pushNamed] which pushes the given location onto the page stack.
@@ -340,12 +344,13 @@
/// stack but always uses a new page key.
void replaceNamed(
String name, {
- Map<String, String> params = const <String, String>{},
- Map<String, dynamic> queryParams = const <String, dynamic>{},
+ Map<String, String> pathParameters = const <String, String>{},
+ Map<String, dynamic> queryParameters = const <String, dynamic>{},
Object? extra,
}) {
replace(
- namedLocation(name, params: params, queryParams: queryParams),
+ namedLocation(name,
+ pathParameters: pathParameters, queryParameters: queryParameters),
extra: extra,
);
}
diff --git a/packages/go_router/lib/src/state.dart b/packages/go_router/lib/src/state.dart
index 57c68a2..c360cef 100644
--- a/packages/go_router/lib/src/state.dart
+++ b/packages/go_router/lib/src/state.dart
@@ -16,12 +16,12 @@
const GoRouterState(
this._configuration, {
required this.location,
- required this.subloc,
+ required this.matchedLocation,
required this.name,
this.path,
- this.fullpath,
- this.params = const <String, String>{},
- this.queryParams = const <String, String>{},
+ this.fullPath,
+ this.pathParameters = const <String, String>{},
+ this.queryParameters = const <String, String>{},
this.queryParametersAll = const <String, List<String>>{},
this.extra,
this.error,
@@ -35,8 +35,15 @@
/// The full location of the route, e.g. /family/f2/person/p1
final String location;
- /// The location of this sub-route, e.g. /family/f2
- final String subloc;
+ /// The matched location until this point.
+ ///
+ /// For example:
+ ///
+ /// location = /family/f2/person/p1
+ /// route = GoRoute('/family/:id')
+ ///
+ /// matchedLocation = /family/f2
+ final String matchedLocation;
/// The optional name of the route.
final String? name;
@@ -45,13 +52,13 @@
final String? path;
/// The full path to this sub-route, e.g. /family/:fid
- final String? fullpath;
+ final String? fullPath;
/// The parameters for this sub-route, e.g. {'fid': 'f2'}
- final Map<String, String> params;
+ final Map<String, String> pathParameters;
/// The query parameters for the location, e.g. {'from': '/family/f2'}
- final Map<String, String> queryParams;
+ final Map<String, String> queryParameters;
/// The query parameters for the location,
/// e.g. `{'q1': ['v1'], 'q2': ['v2', 'v3']}`
@@ -98,7 +105,7 @@
/// class MyWidget extends StatelessWidget {
/// @override
/// Widget build(BuildContext context) {
- /// return Text('${GoRouterState.of(context).params['id']}');
+ /// return Text('${GoRouterState.of(context).pathParameters['id']}');
/// }
/// }
/// ```
@@ -125,26 +132,27 @@
/// Get a location from route name and parameters.
/// This is useful for redirecting to a named location.
- @Deprecated('Use GoRouter.of(context).namedLocation instead')
+ // TODO(chunhtai): remove this method when go_router can provide a way to
+ // look up named location during redirect.
String namedLocation(
String name, {
- Map<String, String> params = const <String, String>{},
- Map<String, String> queryParams = const <String, String>{},
+ Map<String, String> pathParameters = const <String, String>{},
+ Map<String, String> queryParameters = const <String, String>{},
}) {
return _configuration.namedLocation(name,
- params: params, queryParams: queryParams);
+ pathParameters: pathParameters, queryParameters: queryParameters);
}
@override
bool operator ==(Object other) {
return other is GoRouterState &&
other.location == location &&
- other.subloc == subloc &&
+ other.matchedLocation == matchedLocation &&
other.name == name &&
other.path == path &&
- other.fullpath == fullpath &&
- other.params == params &&
- other.queryParams == queryParams &&
+ other.fullPath == fullPath &&
+ other.pathParameters == pathParameters &&
+ other.queryParameters == queryParameters &&
other.queryParametersAll == queryParametersAll &&
other.extra == extra &&
other.error == error &&
@@ -152,8 +160,18 @@
}
@override
- int get hashCode => Object.hash(location, subloc, name, path, fullpath,
- params, queryParams, queryParametersAll, extra, error, pageKey);
+ int get hashCode => Object.hash(
+ location,
+ matchedLocation,
+ name,
+ path,
+ fullPath,
+ pathParameters,
+ queryParameters,
+ queryParametersAll,
+ extra,
+ error,
+ pageKey);
}
/// An inherited widget to host a [GoRouterStateRegistry] for the subtree.
diff --git a/packages/go_router/pubspec.yaml b/packages/go_router/pubspec.yaml
index bf4b672..4d1cb1f 100644
--- a/packages/go_router/pubspec.yaml
+++ b/packages/go_router/pubspec.yaml
@@ -1,7 +1,7 @@
name: go_router
description: A declarative router for Flutter based on Navigation 2 supporting
deep linking, data-driven routes and more
-version: 6.5.9
+version: 7.0.0
repository: https://github.com/flutter/packages/tree/main/packages/go_router
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+go_router%22
@@ -21,3 +21,4 @@
dev_dependencies:
flutter_test:
sdk: flutter
+ path: ^1.8.2
diff --git a/packages/go_router/test/builder_test.dart b/packages/go_router/test/builder_test.dart
index 04e7543..81f4182 100644
--- a/packages/go_router/test/builder_test.dart
+++ b/packages/go_router/test/builder_test.dart
@@ -29,17 +29,17 @@
);
final RouteMatchList matches = RouteMatchList(
- <RouteMatch>[
+ matches: <RouteMatch>[
RouteMatch(
route: config.routes.first as GoRoute,
- subloc: '/',
+ matchedLocation: '/',
extra: null,
error: null,
pageKey: const ValueKey<String>('/'),
),
],
- Uri.parse('/'),
- const <String, String>{});
+ uri: Uri.parse('/'),
+ pathParameters: const <String, String>{});
await tester.pumpWidget(
_BuilderTestWidget(
@@ -76,17 +76,17 @@
);
final RouteMatchList matches = RouteMatchList(
- <RouteMatch>[
+ matches: <RouteMatch>[
RouteMatch(
route: config.routes.first,
- subloc: '/',
+ matchedLocation: '/',
extra: null,
error: null,
pageKey: const ValueKey<String>('/'),
),
],
- Uri.parse('/'),
- <String, String>{});
+ uri: Uri.parse('/'),
+ pathParameters: const <String, String>{});
await tester.pumpWidget(
_BuilderTestWidget(
@@ -118,17 +118,17 @@
);
final RouteMatchList matches = RouteMatchList(
- <RouteMatch>[
+ matches: <RouteMatch>[
RouteMatch(
route: config.routes.first as GoRoute,
- subloc: '/',
+ matchedLocation: '/',
extra: null,
error: null,
pageKey: const ValueKey<String>('/'),
),
],
- Uri.parse('/'),
- <String, String>{});
+ uri: Uri.parse('/'),
+ pathParameters: const <String, String>{});
await tester.pumpWidget(
_BuilderTestWidget(
@@ -173,24 +173,24 @@
);
final RouteMatchList matches = RouteMatchList(
- <RouteMatch>[
+ matches: <RouteMatch>[
RouteMatch(
route: config.routes.first,
- subloc: '',
+ matchedLocation: '',
extra: null,
error: null,
pageKey: const ValueKey<String>(''),
),
RouteMatch(
route: config.routes.first.routes.first,
- subloc: '/details',
+ matchedLocation: '/details',
extra: null,
error: null,
pageKey: const ValueKey<String>('/details'),
),
],
- Uri.parse('/details'),
- <String, String>{});
+ uri: Uri.parse('/details'),
+ pathParameters: const <String, String>{});
await tester.pumpWidget(
_BuilderTestWidget(
@@ -248,17 +248,17 @@
);
final RouteMatchList matches = RouteMatchList(
- <RouteMatch>[
+ matches: <RouteMatch>[
RouteMatch(
route: config.routes.first.routes.first as GoRoute,
- subloc: '/a/details',
+ matchedLocation: '/a/details',
extra: null,
error: null,
pageKey: const ValueKey<String>('/a/details'),
),
],
- Uri.parse('/a/details'),
- <String, String>{});
+ uri: Uri.parse('/a/details'),
+ pathParameters: const <String, String>{});
await tester.pumpWidget(
_BuilderTestWidget(
diff --git a/packages/go_router/test/delegate_test.dart b/packages/go_router/test/delegate_test.dart
index e40084a..a0533a1 100644
--- a/packages/go_router/test/delegate_test.dart
+++ b/packages/go_router/test/delegate_test.dart
@@ -5,7 +5,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:go_router/go_router.dart';
-import 'package:go_router/src/delegate.dart';
import 'package:go_router/src/match.dart';
import 'package:go_router/src/misc/error_screen.dart';
diff --git a/packages/go_router/test/go_router_state_test.dart b/packages/go_router/test/go_router_state_test.dart
index 59cee73..b1d0eb5 100644
--- a/packages/go_router/test/go_router_state_test.dart
+++ b/packages/go_router/test/go_router_state_test.dart
@@ -17,13 +17,13 @@
path: '/',
builder: (BuildContext context, _) {
final GoRouterState state = GoRouterState.of(context);
- return Text('/ ${state.queryParams['p']}');
+ return Text('/ ${state.queryParameters['p']}');
}),
GoRoute(
path: '/a',
builder: (BuildContext context, _) {
final GoRouterState state = GoRouterState.of(context);
- return Text('/a ${state.queryParams['p']}');
+ return Text('/a ${state.queryParameters['p']}');
}),
];
final GoRouter router = await createRouter(routes, tester);
@@ -83,7 +83,7 @@
builder: (_, __) {
return Builder(builder: (BuildContext context) {
return Text(
- '2 ${GoRouterState.of(context).params['id']}');
+ '2 ${GoRouterState.of(context).pathParameters['id']}');
});
}),
]),
diff --git a/packages/go_router/test/go_router_test.dart b/packages/go_router/test/go_router_test.dart
index dca1199..a93b492 100644
--- a/packages/go_router/test/go_router_test.dart
+++ b/packages/go_router/test/go_router_test.dart
@@ -11,7 +11,6 @@
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:go_router/go_router.dart';
-import 'package:go_router/src/delegate.dart';
import 'package:go_router/src/match.dart';
import 'package:go_router/src/matching.dart';
import 'package:logging/logging.dart';
@@ -152,7 +151,7 @@
await tester.pumpAndSettle();
final List<RouteMatch> matches = router.routerDelegate.matches.matches;
expect(matches, hasLength(1));
- expect(matches.first.subloc, '/login');
+ expect(matches.first.matchedLocation, '/login');
expect(find.byType(LoginScreen), findsOneWidget);
});
@@ -181,7 +180,7 @@
await tester.pumpAndSettle();
final List<RouteMatch> matches = router.routerDelegate.matches.matches;
expect(matches, hasLength(1));
- expect(matches.first.subloc, '/login');
+ expect(matches.first.matchedLocation, '/login');
expect(find.byType(LoginScreen), findsOneWidget);
});
@@ -205,7 +204,7 @@
await tester.pumpAndSettle();
final List<RouteMatch> matches = router.routerDelegate.matches.matches;
expect(matches, hasLength(1));
- expect(matches.first.subloc, '/login');
+ expect(matches.first.matchedLocation, '/login');
expect(find.byType(LoginScreen), findsOneWidget);
});
@@ -224,7 +223,7 @@
await tester.pumpAndSettle();
final List<RouteMatch> matches = router.routerDelegate.matches.matches;
expect(matches, hasLength(1));
- expect(matches.first.subloc, '/profile/foo');
+ expect(matches.first.matchedLocation, '/profile/foo');
expect(find.byType(DummyScreen), findsOneWidget);
});
@@ -243,7 +242,7 @@
await tester.pumpAndSettle();
final List<RouteMatch> matches = router.routerDelegate.matches.matches;
expect(matches, hasLength(1));
- expect(matches.first.subloc, '/profile/foo');
+ expect(matches.first.matchedLocation, '/profile/foo');
expect(find.byType(DummyScreen), findsOneWidget);
});
@@ -355,9 +354,9 @@
await tester.pumpAndSettle();
final List<RouteMatch> matches = router.routerDelegate.matches.matches;
expect(matches.length, 2);
- expect(matches.first.subloc, '/');
+ expect(matches.first.matchedLocation, '/');
expect(find.byType(HomeScreen, skipOffstage: false), findsOneWidget);
- expect(matches[1].subloc, '/login');
+ expect(matches[1].matchedLocation, '/login');
expect(find.byType(LoginScreen), findsOneWidget);
});
@@ -402,9 +401,9 @@
{
final RouteMatchList matches = router.routerDelegate.matches;
expect(matches.matches.length, 2);
- expect(matches.matches.first.subloc, '/');
+ expect(matches.matches.first.matchedLocation, '/');
expect(find.byType(HomeScreen, skipOffstage: false), findsOneWidget);
- expect(matches.matches[1].subloc, '/login');
+ expect(matches.matches[1].matchedLocation, '/login');
expect(find.byType(LoginScreen), findsOneWidget);
}
@@ -413,9 +412,9 @@
{
final RouteMatchList matches = router.routerDelegate.matches;
expect(matches.matches.length, 2);
- expect(matches.matches.first.subloc, '/');
+ expect(matches.matches.first.matchedLocation, '/');
expect(find.byType(HomeScreen, skipOffstage: false), findsOneWidget);
- expect(matches.matches[1].subloc, '/family/f2');
+ expect(matches.matches[1].matchedLocation, '/family/f2');
expect(find.byType(FamilyScreen), findsOneWidget);
}
@@ -424,11 +423,11 @@
{
final RouteMatchList matches = router.routerDelegate.matches;
expect(matches.matches.length, 3);
- expect(matches.matches.first.subloc, '/');
+ expect(matches.matches.first.matchedLocation, '/');
expect(find.byType(HomeScreen, skipOffstage: false), findsOneWidget);
- expect(matches.matches[1].subloc, '/family/f2');
+ expect(matches.matches[1].matchedLocation, '/family/f2');
expect(find.byType(FamilyScreen, skipOffstage: false), findsOneWidget);
- expect(matches.matches[2].subloc, '/family/f2/person/p1');
+ expect(matches.matches[2].matchedLocation, '/family/f2/person/p1');
expect(find.byType(PersonScreen), findsOneWidget);
}
});
@@ -494,11 +493,11 @@
path: '/',
builder: (BuildContext context, GoRouterState state) {
expect(state.location, '/');
- expect(state.subloc, '/');
+ expect(state.matchedLocation, '/');
expect(state.name, 'home');
expect(state.path, '/');
- expect(state.fullpath, '/');
- expect(state.params, <String, String>{});
+ expect(state.fullPath, '/');
+ expect(state.pathParameters, <String, String>{});
expect(state.error, null);
if (state.extra != null) {
expect(state.extra! as int, 1);
@@ -511,11 +510,11 @@
path: 'login',
builder: (BuildContext context, GoRouterState state) {
expect(state.location, '/login');
- expect(state.subloc, '/login');
+ expect(state.matchedLocation, '/login');
expect(state.name, 'login');
expect(state.path, 'login');
- expect(state.fullpath, '/login');
- expect(state.params, <String, String>{});
+ expect(state.fullPath, '/login');
+ expect(state.pathParameters, <String, String>{});
expect(state.error, null);
expect(state.extra! as int, 2);
return const LoginScreen();
@@ -529,14 +528,14 @@
state.location,
anyOf(<String>['/family/f2', '/family/f2/person/p1']),
);
- expect(state.subloc, '/family/f2');
+ expect(state.matchedLocation, '/family/f2');
expect(state.name, 'family');
expect(state.path, 'family/:fid');
- expect(state.fullpath, '/family/:fid');
- expect(state.params, <String, String>{'fid': 'f2'});
+ expect(state.fullPath, '/family/:fid');
+ expect(state.pathParameters, <String, String>{'fid': 'f2'});
expect(state.error, null);
expect(state.extra! as int, 3);
- return FamilyScreen(state.params['fid']!);
+ return FamilyScreen(state.pathParameters['fid']!);
},
routes: <GoRoute>[
GoRoute(
@@ -544,18 +543,18 @@
path: 'person/:pid',
builder: (BuildContext context, GoRouterState state) {
expect(state.location, '/family/f2/person/p1');
- expect(state.subloc, '/family/f2/person/p1');
+ expect(state.matchedLocation, '/family/f2/person/p1');
expect(state.name, 'person');
expect(state.path, 'person/:pid');
- expect(state.fullpath, '/family/:fid/person/:pid');
+ expect(state.fullPath, '/family/:fid/person/:pid');
expect(
- state.params,
+ state.pathParameters,
<String, String>{'fid': 'f2', 'pid': 'p1'},
);
expect(state.error, null);
expect(state.extra! as int, 4);
- return PersonScreen(
- state.params['fid']!, state.params['pid']!);
+ return PersonScreen(state.pathParameters['fid']!,
+ state.pathParameters['pid']!);
},
),
],
@@ -585,7 +584,7 @@
GoRoute(
path: '/family/:fid',
builder: (BuildContext context, GoRouterState state) =>
- FamilyScreen(state.params['fid']!),
+ FamilyScreen(state.pathParameters['fid']!),
),
];
@@ -595,7 +594,7 @@
await tester.pumpAndSettle();
final List<RouteMatch> matches = router.routerDelegate.matches.matches;
- // NOTE: match the lower case, since subloc is canonicalized to match the
+ // NOTE: match the lower case, since location is canonicalized to match the
// path case whereas the location can be any case; so long as the path
// produces a match regardless of the location case, we win!
expect(router.location.toLowerCase(), loc.toLowerCase());
@@ -1321,7 +1320,7 @@
name: 'person',
path: 'person/:pid',
builder: (BuildContext context, GoRouterState state) {
- expect(state.params,
+ expect(state.pathParameters,
<String, String>{'fid': 'f2', 'pid': 'p1'});
return const PersonScreen('dummy', 'dummy');
},
@@ -1334,7 +1333,7 @@
final GoRouter router = await createRouter(routes, tester);
router.goNamed('person',
- params: <String, String>{'fid': 'f2', 'pid': 'p1'});
+ pathParameters: <String, String>{'fid': 'f2', 'pid': 'p1'});
});
testWidgets('too few params', (WidgetTester tester) async {
@@ -1364,7 +1363,7 @@
];
await expectLater(() async {
final GoRouter router = await createRouter(routes, tester);
- router.goNamed('person', params: <String, String>{'fid': 'f2'});
+ router.goNamed('person', pathParameters: <String, String>{'fid': 'f2'});
await tester.pump();
}, throwsA(isAssertionError));
});
@@ -1388,7 +1387,7 @@
name: 'PeRsOn',
path: 'person/:pid',
builder: (BuildContext context, GoRouterState state) {
- expect(state.params,
+ expect(state.pathParameters,
<String, String>{'fid': 'f2', 'pid': 'p1'});
return const PersonScreen('dummy', 'dummy');
},
@@ -1401,7 +1400,7 @@
final GoRouter router = await createRouter(routes, tester);
router.goNamed('person',
- params: <String, String>{'fid': 'f2', 'pid': 'p1'});
+ pathParameters: <String, String>{'fid': 'f2', 'pid': 'p1'});
});
testWidgets('too few params', (WidgetTester tester) async {
@@ -1431,7 +1430,7 @@
await expectLater(() async {
final GoRouter router = await createRouter(routes, tester);
router.goNamed('family',
- params: <String, String>{'fid': 'f2', 'pid': 'p1'});
+ pathParameters: <String, String>{'fid': 'f2', 'pid': 'p1'});
}, throwsA(isAssertionError));
});
@@ -1445,7 +1444,7 @@
GoRoute(
path: '/family/:fid',
builder: (BuildContext context, GoRouterState state) => FamilyScreen(
- state.params['fid']!,
+ state.pathParameters['fid']!,
),
routes: <GoRoute>[
GoRoute(
@@ -1453,8 +1452,8 @@
path: 'person:pid',
builder: (BuildContext context, GoRouterState state) =>
PersonScreen(
- state.params['fid']!,
- state.params['pid']!,
+ state.pathParameters['fid']!,
+ state.pathParameters['pid']!,
),
),
],
@@ -1463,7 +1462,7 @@
final GoRouter router = await createRouter(routes, tester);
router.goNamed('person',
- params: <String, String>{'fid': 'f2', 'pid': 'p1'});
+ pathParameters: <String, String>{'fid': 'f2', 'pid': 'p1'});
await tester.pumpAndSettle();
expect(find.byType(PersonScreen), findsOneWidget);
});
@@ -1476,15 +1475,15 @@
name: 'page1',
path: '/page1/:param1',
builder: (BuildContext c, GoRouterState s) {
- expect(s.params['param1'], param1);
+ expect(s.pathParameters['param1'], param1);
return const DummyScreen();
},
),
];
final GoRouter router = await createRouter(routes, tester);
- final String loc = router
- .namedLocation('page1', params: <String, String>{'param1': param1});
+ final String loc = router.namedLocation('page1',
+ pathParameters: <String, String>{'param1': param1});
router.go(loc);
await tester.pumpAndSettle();
@@ -1501,7 +1500,7 @@
name: 'page1',
path: '/page1',
builder: (BuildContext c, GoRouterState s) {
- expect(s.queryParams['param1'], param1);
+ expect(s.queryParameters['param1'], param1);
return const DummyScreen();
},
),
@@ -1509,7 +1508,7 @@
final GoRouter router = await createRouter(routes, tester);
final String loc = router.namedLocation('page1',
- queryParams: <String, String>{'param1': param1});
+ queryParameters: <String, String>{'param1': param1});
router.go(loc);
await tester.pumpAndSettle();
final RouteMatchList matches = router.routerDelegate.matches;
@@ -1542,7 +1541,7 @@
final GoRouter router = await createRouter(routes, tester,
redirect: (BuildContext context, GoRouterState state) {
redirected = true;
- return state.subloc == '/login' ? null : '/login';
+ return state.matchedLocation == '/login' ? null : '/login';
});
expect(router.location, '/login');
@@ -1617,7 +1616,9 @@
routes,
tester,
redirect: (BuildContext context, GoRouterState state) =>
- state.subloc == '/login' ? null : state.namedLocation('login'),
+ state.matchedLocation == '/login'
+ ? null
+ : state.namedLocation('login'),
);
expect(router.location, '/login');
});
@@ -1682,7 +1683,7 @@
final GoRouter router = await createRouter(routes, tester,
redirect: (BuildContext context, GoRouterState state) {
redirected = true;
- return state.subloc == '/login' ? null : '/login';
+ return state.matchedLocation == '/login' ? null : '/login';
});
redirected = false;
// Directly set the url through platform message.
@@ -1750,7 +1751,7 @@
final GoRouter router = await createRouter(routes, tester,
redirect: (BuildContext context, GoRouterState state) =>
- state.subloc == '/dummy1' ? '/dummy2' : null);
+ state.matchedLocation == '/dummy1' ? '/dummy2' : null);
router.go('/dummy1');
await tester.pump();
expect(router.location, '/');
@@ -1759,9 +1760,9 @@
testWidgets('top-level redirect loop', (WidgetTester tester) async {
final GoRouter router = await createRouter(<GoRoute>[], tester,
redirect: (BuildContext context, GoRouterState state) =>
- state.subloc == '/'
+ state.matchedLocation == '/'
? '/login'
- : state.subloc == '/login'
+ : state.matchedLocation == '/login'
? '/'
: null);
@@ -1809,7 +1810,7 @@
],
tester,
redirect: (BuildContext context, GoRouterState state) =>
- state.subloc == '/' ? '/login' : null,
+ state.matchedLocation == '/' ? '/login' : null,
);
final List<RouteMatch> matches = router.routerDelegate.matches.matches;
@@ -1826,9 +1827,9 @@
<GoRoute>[],
tester,
redirect: (BuildContext context, GoRouterState state) =>
- state.subloc == '/'
+ state.matchedLocation == '/'
? '/login?from=${state.location}'
- : state.subloc == '/login'
+ : state.matchedLocation == '/login'
? '/'
: null,
);
@@ -1841,7 +1842,7 @@
expect(screen.ex, isNotNull);
});
- testWidgets('expect null path/fullpath on top-level redirect',
+ testWidgets('expect null path/fullPath on top-level redirect',
(WidgetTester tester) async {
final List<GoRoute> routes = <GoRoute>[
GoRoute(
@@ -1884,12 +1885,12 @@
initialLocation: '/login?from=/',
redirect: (BuildContext context, GoRouterState state) {
expect(Uri.parse(state.location).queryParameters, isNotEmpty);
- expect(Uri.parse(state.subloc).queryParameters, isEmpty);
+ expect(Uri.parse(state.matchedLocation).queryParameters, isEmpty);
expect(state.path, isNull);
- expect(state.fullpath, isNull);
- expect(state.params.length, 0);
- expect(state.queryParams.length, 1);
- expect(state.queryParams['from'], '/');
+ expect(state.fullPath, isNull);
+ expect(state.pathParameters.length, 0);
+ expect(state.queryParameters.length, 1);
+ expect(state.queryParameters['from'], '/');
return null;
},
);
@@ -1906,11 +1907,11 @@
path: '/book/:bookId',
redirect: (BuildContext context, GoRouterState state) {
expect(state.location, loc);
- expect(state.subloc, loc);
+ expect(state.matchedLocation, loc);
expect(state.path, '/book/:bookId');
- expect(state.fullpath, '/book/:bookId');
- expect(state.params, <String, String>{'bookId': '0'});
- expect(state.queryParams.length, 0);
+ expect(state.fullPath, '/book/:bookId');
+ expect(state.pathParameters, <String, String>{'bookId': '0'});
+ expect(state.queryParameters.length, 0);
return null;
},
builder: (BuildContext c, GoRouterState s) => const HomeScreen(),
@@ -1938,18 +1939,18 @@
GoRoute(
path: 'family/:fid',
builder: (BuildContext c, GoRouterState s) =>
- FamilyScreen(s.params['fid']!),
+ FamilyScreen(s.pathParameters['fid']!),
routes: <GoRoute>[
GoRoute(
path: 'person/:pid',
redirect: (BuildContext context, GoRouterState s) {
- expect(s.params['fid'], 'f2');
- expect(s.params['pid'], 'p1');
+ expect(s.pathParameters['fid'], 'f2');
+ expect(s.pathParameters['pid'], 'p1');
return null;
},
builder: (BuildContext c, GoRouterState s) => PersonScreen(
- s.params['fid']!,
- s.params['pid']!,
+ s.pathParameters['fid']!,
+ s.pathParameters['pid']!,
),
),
],
@@ -2221,7 +2222,7 @@
GoRoute(
path: '/family/:fid',
builder: (BuildContext context, GoRouterState state) =>
- FamilyScreen(state.params['fid']!),
+ FamilyScreen(state.pathParameters['fid']!),
),
];
@@ -2249,7 +2250,7 @@
GoRoute(
path: '/family',
builder: (BuildContext context, GoRouterState state) => FamilyScreen(
- state.queryParams['fid']!,
+ state.queryParameters['fid']!,
),
),
];
@@ -2275,7 +2276,7 @@
GoRoute(
path: '/page1/:param1',
builder: (BuildContext c, GoRouterState s) {
- expect(s.params['param1'], param1);
+ expect(s.pathParameters['param1'], param1);
return const DummyScreen();
},
),
@@ -2298,7 +2299,7 @@
GoRoute(
path: '/page1',
builder: (BuildContext c, GoRouterState s) {
- expect(s.queryParams['param1'], param1);
+ expect(s.queryParameters['param1'], param1);
return const DummyScreen();
},
),
@@ -2346,10 +2347,10 @@
GoRoute(
path: '/',
builder: (BuildContext context, GoRouterState state) {
- log.info('id= ${state.params['id']}');
- expect(state.params.length, 0);
- expect(state.queryParams.length, 1);
- expect(state.queryParams['id'], anyOf('0', '1'));
+ log.info('id= ${state.pathParameters['id']}');
+ expect(state.pathParameters.length, 0);
+ expect(state.queryParameters.length, 1);
+ expect(state.queryParameters['id'], anyOf('0', '1'));
return const HomeScreen();
},
),
@@ -2359,7 +2360,7 @@
);
final RouteMatchList matches = router.routerDelegate.matches;
expect(matches.matches, hasLength(1));
- expect(matches.fullpath, '/');
+ expect(matches.fullPath, '/');
expect(find.byType(HomeScreen), findsOneWidget);
});
@@ -2369,8 +2370,8 @@
GoRoute(
path: '/:id',
builder: (BuildContext context, GoRouterState state) {
- expect(state.params, <String, String>{'id': '0'});
- expect(state.queryParams, <String, String>{'id': '1'});
+ expect(state.pathParameters, <String, String>{'id': '0'});
+ expect(state.queryParameters, <String, String>{'id': '1'});
return const HomeScreen();
},
),
@@ -2382,7 +2383,7 @@
await tester.pumpAndSettle();
final RouteMatchList matches = router.routerDelegate.matches;
expect(matches.matches, hasLength(1));
- expect(matches.fullpath, '/:id');
+ expect(matches.fullPath, '/:id');
expect(find.byType(HomeScreen), findsOneWidget);
});
@@ -2394,15 +2395,15 @@
path: '/family',
builder: (BuildContext context, GoRouterState state) =>
FamilyScreen(
- state.queryParams['fid']!,
+ state.queryParameters['fid']!,
),
),
GoRoute(
path: '/person',
builder: (BuildContext context, GoRouterState state) =>
PersonScreen(
- state.queryParams['fid']!,
- state.queryParams['pid']!,
+ state.queryParameters['fid']!,
+ state.queryParameters['pid']!,
),
),
],
@@ -2470,13 +2471,13 @@
GoRoute(
path: '/family/:fid',
builder: (BuildContext context, GoRouterState state) =>
- FamilyScreen(state.params['fid']!),
+ FamilyScreen(state.pathParameters['fid']!),
routes: <GoRoute>[
GoRoute(
path: 'person/:pid',
builder: (BuildContext context, GoRouterState state) {
- final String fid = state.params['fid']!;
- final String pid = state.params['pid']!;
+ final String fid = state.pathParameters['fid']!;
+ final String pid = state.pathParameters['pid']!;
return PersonScreen(fid, pid);
},
@@ -2536,7 +2537,7 @@
final GoRouter router = await createRouter(routes, tester);
- router.goNamed('page', queryParams: const <String, dynamic>{
+ router.goNamed('page', queryParameters: const <String, dynamic>{
'q1': 'v1',
'q2': <String>['v2', 'v3'],
});
@@ -2694,12 +2695,12 @@
);
key.currentContext!.namedLocation(
name,
- params: params,
- queryParams: queryParams,
+ pathParameters: params,
+ queryParameters: queryParams,
);
expect(router.name, name);
- expect(router.params, params);
- expect(router.queryParams, queryParams);
+ expect(router.pathParameters, params);
+ expect(router.queryParameters, queryParams);
});
testWidgets('calls [go] on closest GoRouter', (WidgetTester tester) async {
@@ -2729,13 +2730,13 @@
);
key.currentContext!.goNamed(
name,
- params: params,
- queryParams: queryParams,
+ pathParameters: params,
+ queryParameters: queryParams,
extra: extra,
);
expect(router.name, name);
- expect(router.params, params);
- expect(router.queryParams, queryParams);
+ expect(router.pathParameters, params);
+ expect(router.queryParameters, queryParams);
expect(router.extra, extra);
});
@@ -2787,13 +2788,13 @@
);
key.currentContext!.pushNamed(
name,
- params: params,
- queryParams: queryParams,
+ pathParameters: params,
+ queryParameters: queryParams,
extra: extra,
);
expect(router.name, name);
- expect(router.params, params);
- expect(router.queryParams, queryParams);
+ expect(router.pathParameters, params);
+ expect(router.queryParameters, queryParams);
expect(router.extra, extra);
});
@@ -2810,15 +2811,15 @@
);
final String? result = await router.pushNamed<String>(
name,
- params: params,
- queryParams: queryParams,
+ pathParameters: params,
+ queryParameters: queryParams,
extra: extra,
);
expect(result, extra);
expect(router.extra, extra);
expect(router.name, name);
- expect(router.params, params);
- expect(router.queryParams, queryParams);
+ expect(router.pathParameters, params);
+ expect(router.queryParameters, queryParams);
});
testWidgets('calls [pop] on closest GoRouter', (WidgetTester tester) async {
diff --git a/packages/go_router/test/inherited_test.dart b/packages/go_router/test/inherited_test.dart
index 7afa9fe..1b7fb3f 100644
--- a/packages/go_router/test/inherited_test.dart
+++ b/packages/go_router/test/inherited_test.dart
@@ -130,8 +130,8 @@
@override
Future<T?> pushNamed<T extends Object?>(String name,
- {Map<String, String> params = const <String, String>{},
- Map<String, dynamic> queryParams = const <String, dynamic>{},
+ {Map<String, String> pathParameters = const <String, String>{},
+ Map<String, dynamic> queryParameters = const <String, dynamic>{},
Object? extra}) {
latestPushedName = name;
return Future<T?>.value();
diff --git a/packages/go_router/test/match_test.dart b/packages/go_router/test/match_test.dart
index aa14db1..712f379 100644
--- a/packages/go_router/test/match_test.dart
+++ b/packages/go_router/test/match_test.dart
@@ -17,8 +17,8 @@
final Map<String, String> pathParameters = <String, String>{};
final RouteMatch? match = RouteMatch.match(
route: route,
- restLoc: '/users/123',
- parentSubloc: '',
+ remainingLocation: '/users/123',
+ matchedLocation: '',
pathParameters: pathParameters,
extra: const _Extra('foo'),
);
@@ -26,14 +26,14 @@
fail('Null match');
}
expect(match.route, route);
- expect(match.subloc, '/users/123');
+ expect(match.matchedLocation, '/users/123');
expect(pathParameters['userId'], '123');
expect(match.extra, const _Extra('foo'));
expect(match.error, isNull);
expect(match.pageKey, isNotNull);
});
- test('subloc', () {
+ test('matchedLocation', () {
final GoRoute route = GoRoute(
path: 'users/:userId',
builder: _builder,
@@ -41,8 +41,8 @@
final Map<String, String> pathParameters = <String, String>{};
final RouteMatch? match = RouteMatch.match(
route: route,
- restLoc: 'users/123',
- parentSubloc: '/home',
+ remainingLocation: 'users/123',
+ matchedLocation: '/home',
pathParameters: pathParameters,
extra: const _Extra('foo'),
);
@@ -50,7 +50,7 @@
fail('Null match');
}
expect(match.route, route);
- expect(match.subloc, '/home/users/123');
+ expect(match.matchedLocation, '/home/users/123');
expect(pathParameters['userId'], '123');
expect(match.extra, const _Extra('foo'));
expect(match.error, isNull);
@@ -70,8 +70,8 @@
final Map<String, String> pathParameters = <String, String>{};
final RouteMatch? match = RouteMatch.match(
route: route,
- restLoc: 'users/123',
- parentSubloc: '/home',
+ remainingLocation: 'users/123',
+ matchedLocation: '/home',
pathParameters: pathParameters,
extra: const _Extra('foo'),
);
@@ -94,16 +94,16 @@
final Map<String, String> pathParameters = <String, String>{};
final RouteMatch? match1 = RouteMatch.match(
route: route,
- restLoc: 'users/123',
- parentSubloc: '/home',
+ remainingLocation: 'users/123',
+ matchedLocation: '/home',
pathParameters: pathParameters,
extra: const _Extra('foo'),
);
final RouteMatch? match2 = RouteMatch.match(
route: route,
- restLoc: 'users/1234',
- parentSubloc: '/home',
+ remainingLocation: 'users/1234',
+ matchedLocation: '/home',
pathParameters: pathParameters,
extra: const _Extra('foo1'),
);
@@ -119,16 +119,16 @@
final Map<String, String> pathParameters = <String, String>{};
final RouteMatch? match1 = RouteMatch.match(
route: route,
- restLoc: 'users/123',
- parentSubloc: '/home',
+ remainingLocation: 'users/123',
+ matchedLocation: '/home',
pathParameters: pathParameters,
extra: const _Extra('foo'),
);
final RouteMatch? match2 = RouteMatch.match(
route: route,
- restLoc: 'users/1234',
- parentSubloc: '/home',
+ remainingLocation: 'users/1234',
+ matchedLocation: '/home',
pathParameters: pathParameters,
extra: const _Extra('foo1'),
);
diff --git a/packages/go_router/test/matching_test.dart b/packages/go_router/test/matching_test.dart
index c92533b..daf8ccc 100644
--- a/packages/go_router/test/matching_test.dart
+++ b/packages/go_router/test/matching_test.dart
@@ -5,6 +5,7 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:go_router/src/configuration.dart';
+import 'package:go_router/src/match.dart';
import 'package:go_router/src/matching.dart';
import 'package:go_router/src/router.dart';
@@ -27,4 +28,50 @@
final RouteMatchList matches = router.routerDelegate.matches;
expect(matches.toString(), contains('/page-0'));
});
+
+ test('RouteMatchList compares', () async {
+ final GoRoute route = GoRoute(
+ path: '/page-0',
+ builder: (BuildContext context, GoRouterState state) =>
+ const Placeholder(),
+ );
+ final Map<String, String> params1 = <String, String>{};
+ final RouteMatch match1 = RouteMatch.match(
+ route: route,
+ remainingLocation: '/page-0',
+ matchedLocation: '',
+ pathParameters: params1,
+ extra: null,
+ )!;
+
+ final Map<String, String> params2 = <String, String>{};
+ final RouteMatch match2 = RouteMatch.match(
+ route: route,
+ remainingLocation: '/page-0',
+ matchedLocation: '',
+ pathParameters: params2,
+ extra: null,
+ )!;
+
+ final RouteMatchList matches1 = RouteMatchList(
+ matches: <RouteMatch>[match1],
+ uri: Uri.parse(''),
+ pathParameters: params1,
+ );
+
+ final RouteMatchList matches2 = RouteMatchList(
+ matches: <RouteMatch>[match2],
+ uri: Uri.parse(''),
+ pathParameters: params2,
+ );
+
+ final RouteMatchList matches3 = RouteMatchList(
+ matches: <RouteMatch>[match2],
+ uri: Uri.parse('/page-0'),
+ pathParameters: params2,
+ );
+
+ expect(matches1 == matches2, isTrue);
+ expect(matches1 == matches3, isFalse);
+ });
}
diff --git a/packages/go_router/test/parser_test.dart b/packages/go_router/test/parser_test.dart
index 1cc4048..76a068b 100644
--- a/packages/go_router/test/parser_test.dart
+++ b/packages/go_router/test/parser_test.dart
@@ -65,7 +65,7 @@
expect(matches.length, 1);
expect(matchesObj.uri.toString(), '/');
expect(matches[0].extra, isNull);
- expect(matches[0].subloc, '/');
+ expect(matches[0].matchedLocation, '/');
expect(matches[0].route, routes[0]);
final Object extra = Object();
@@ -75,11 +75,11 @@
expect(matches.length, 2);
expect(matchesObj.uri.toString(), '/abc?def=ghi');
expect(matches[0].extra, extra);
- expect(matches[0].subloc, '/');
+ expect(matches[0].matchedLocation, '/');
expect(matches[0].route, routes[0]);
expect(matches[1].extra, extra);
- expect(matches[1].subloc, '/abc');
+ expect(matches[1].matchedLocation, '/abc');
expect(matches[1].route, routes[0].routes[0]);
});
@@ -126,11 +126,11 @@
expect(configuration.namedLocation('lowercase'), '/abc');
expect(
configuration.namedLocation('lowercase',
- queryParams: const <String, String>{'q': '1'}),
+ queryParameters: const <String, String>{'q': '1'}),
'/abc?q=1');
expect(
configuration.namedLocation('lowercase',
- queryParams: const <String, String>{'q': '1', 'g': '2'}),
+ queryParameters: const <String, String>{'q': '1', 'g': '2'}),
'/abc?q=1&g=2');
});
@@ -160,7 +160,7 @@
expect(
configuration
- .namedLocation('routeName', queryParams: const <String, dynamic>{
+ .namedLocation('routeName', queryParameters: const <String, dynamic>{
'q1': 'v1',
'q2': <String>['v2', 'v3'],
}),
@@ -198,7 +198,7 @@
expect(matches.length, 1);
expect(matchesObj.uri.toString(), '/def');
expect(matches[0].extra, isNull);
- expect(matches[0].subloc, '/def');
+ expect(matches[0].matchedLocation, '/def');
expect(matches[0].error!.toString(),
'Exception: no routes for location: /def');
});
@@ -268,10 +268,10 @@
expect(matchesObj.pathParameters['uid'], '123');
expect(matchesObj.pathParameters['fid'], '456');
expect(matches[0].extra, isNull);
- expect(matches[0].subloc, '/');
+ expect(matches[0].matchedLocation, '/');
expect(matches[1].extra, isNull);
- expect(matches[1].subloc, '/123/family/456');
+ expect(matches[1].matchedLocation, '/123/family/456');
});
testWidgets(
@@ -309,9 +309,9 @@
expect(matches.length, 2);
expect(matchesObj.uri.toString(), '/123/family/345');
- expect(matches[0].subloc, '/');
+ expect(matches[0].matchedLocation, '/');
- expect(matches[1].subloc, '/123/family/345');
+ expect(matches[1].matchedLocation, '/123/family/345');
});
testWidgets(
@@ -349,9 +349,9 @@
expect(matches.length, 2);
expect(matchesObj.uri.toString(), '/123/family/345');
- expect(matches[0].subloc, '/');
+ expect(matches[0].matchedLocation, '/');
- expect(matches[1].subloc, '/123/family/345');
+ expect(matches[1].matchedLocation, '/123/family/345');
});
testWidgets(
diff --git a/packages/go_router/test/test_helpers.dart b/packages/go_router/test/test_helpers.dart
index b81f4c2..d2187d4 100644
--- a/packages/go_router/test/test_helpers.dart
+++ b/packages/go_router/test/test_helpers.dart
@@ -37,18 +37,18 @@
GoRouterNamedLocationSpy({required super.routes});
String? name;
- Map<String, String>? params;
- Map<String, dynamic>? queryParams;
+ Map<String, String>? pathParameters;
+ Map<String, dynamic>? queryParameters;
@override
String namedLocation(
String name, {
- Map<String, String> params = const <String, String>{},
- Map<String, dynamic> queryParams = const <String, dynamic>{},
+ Map<String, String> pathParameters = const <String, String>{},
+ Map<String, dynamic> queryParameters = const <String, dynamic>{},
}) {
this.name = name;
- this.params = params;
- this.queryParams = queryParams;
+ this.pathParameters = pathParameters;
+ this.queryParameters = queryParameters;
return '';
}
}
@@ -70,20 +70,20 @@
GoRouterGoNamedSpy({required super.routes});
String? name;
- Map<String, String>? params;
- Map<String, dynamic>? queryParams;
+ Map<String, String>? pathParameters;
+ Map<String, dynamic>? queryParameters;
Object? extra;
@override
void goNamed(
String name, {
- Map<String, String> params = const <String, String>{},
- Map<String, dynamic> queryParams = const <String, dynamic>{},
+ Map<String, String> pathParameters = const <String, String>{},
+ Map<String, dynamic> queryParameters = const <String, dynamic>{},
Object? extra,
}) {
this.name = name;
- this.params = params;
- this.queryParams = queryParams;
+ this.pathParameters = pathParameters;
+ this.queryParameters = queryParameters;
this.extra = extra;
}
}
@@ -106,20 +106,20 @@
GoRouterPushNamedSpy({required super.routes});
String? name;
- Map<String, String>? params;
- Map<String, dynamic>? queryParams;
+ Map<String, String>? pathParameters;
+ Map<String, dynamic>? queryParameters;
Object? extra;
@override
Future<T?> pushNamed<T extends Object?>(
String name, {
- Map<String, String> params = const <String, String>{},
- Map<String, dynamic> queryParams = const <String, dynamic>{},
+ Map<String, String> pathParameters = const <String, String>{},
+ Map<String, dynamic> queryParameters = const <String, dynamic>{},
Object? extra,
}) {
this.name = name;
- this.params = params;
- this.queryParams = queryParams;
+ this.pathParameters = pathParameters;
+ this.queryParameters = queryParameters;
this.extra = extra;
return Future<T?>.value(extra as T?);
}
diff --git a/packages/go_router/test_fixes/README.md b/packages/go_router/test_fixes/README.md
new file mode 100644
index 0000000..994d67d
--- /dev/null
+++ b/packages/go_router/test_fixes/README.md
@@ -0,0 +1,17 @@
+## Directory contents
+
+The Dart files and golden master `.expect` files in this directory are used to
+test the [`dart fix` framework](https://dart.dev/tools/dart-fix) refactorings
+used by the go_router package
+
+See the packages/packages/go_router/lib/fix_data.yaml directory for the current
+package:go_router data-driven fixes.
+
+To run these tests locally, execute this command in the
+packages/packages/go_router/test_fixes directory.
+```sh
+dart fix --compare-to-golden
+```
+
+For more documentation about Data Driven Fixes, see
+https://dart.dev/go/data-driven-fixes#test-folder.
diff --git a/packages/go_router/test_fixes/analysis_options.yaml b/packages/go_router/test_fixes/analysis_options.yaml
new file mode 100644
index 0000000..7cca7b1
--- /dev/null
+++ b/packages/go_router/test_fixes/analysis_options.yaml
@@ -0,0 +1 @@
+# This ensures that parent analysis options do not accidentally break the fix tests.
diff --git a/packages/go_router/test_fixes/go_router.dart b/packages/go_router/test_fixes/go_router.dart
new file mode 100644
index 0000000..5811737
--- /dev/null
+++ b/packages/go_router/test_fixes/go_router.dart
@@ -0,0 +1,44 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:go_router/go_router.dart';
+
+void main() {
+ const GoRouterState state = GoRouterState();
+ final GoRouter router = GoRouter(routes: <RouteBase>[]);
+ state.fullpath;
+ state.params;
+ state.subloc;
+ state.queryParams;
+ state.namedLocation(
+ 'name',
+ params: <String, String>{},
+ queryParams: <String, String>{},
+ );
+ router.namedLocation(
+ 'name',
+ params: <String, String>{},
+ queryParams: <String, String>{},
+ );
+ router.goNamed(
+ 'name',
+ params: <String, String>{},
+ queryParams: <String, String>{},
+ );
+ router.pushNamed(
+ 'name',
+ params: <String, String>{},
+ queryParams: <String, String>{},
+ );
+ router.pushReplacementNamed(
+ 'name',
+ params: <String, String>{},
+ queryParams: <String, String>{},
+ );
+ router.replaceNamed(
+ 'name',
+ params: <String, String>{},
+ queryParams: <String, String>{},
+ );
+}
diff --git a/packages/go_router/test_fixes/go_router.dart.expect b/packages/go_router/test_fixes/go_router.dart.expect
new file mode 100644
index 0000000..c2c5aa6
--- /dev/null
+++ b/packages/go_router/test_fixes/go_router.dart.expect
@@ -0,0 +1,44 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:go_router/go_router.dart';
+
+void main() {
+ const GoRouterState state = GoRouterState();
+ final GoRouter router = GoRouter(routes: <RouteBase>[]);
+ state.fullPath;
+ state.pathParameters;
+ state.matchedLocation;
+ state.queryParameters;
+ state.namedLocation(
+ 'name',
+ pathParameters: <String, String>{},
+ queryParameters: <String, String>{},
+ );
+ router.namedLocation(
+ 'name',
+ pathParameters: <String, String>{},
+ queryParameters: <String, String>{},
+ );
+ router.goNamed(
+ 'name',
+ pathParameters: <String, String>{},
+ queryParameters: <String, String>{},
+ );
+ router.pushNamed(
+ 'name',
+ pathParameters: <String, String>{},
+ queryParameters: <String, String>{},
+ );
+ router.pushReplacementNamed(
+ 'name',
+ pathParameters: <String, String>{},
+ queryParameters: <String, String>{},
+ );
+ router.replaceNamed(
+ 'name',
+ pathParameters: <String, String>{},
+ queryParameters: <String, String>{},
+ );
+}
diff --git a/packages/go_router/tool/run_tests.dart b/packages/go_router/tool/run_tests.dart
new file mode 100644
index 0000000..39fe8cc
--- /dev/null
+++ b/packages/go_router/tool/run_tests.dart
@@ -0,0 +1,51 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Called from the custom-tests CI action.
+//
+// usage: dart run tool/run_tests.dart
+
+// ignore_for_file: avoid_print
+
+import 'dart:io';
+import 'package:path/path.dart' as p;
+
+Future<void> main(List<String> args) async {
+ if (!Platform.isMacOS) {
+ print('This test can only be run on macOS.');
+ exit(0);
+ }
+ final Directory packageRoot =
+ Directory(p.dirname(Platform.script.path)).parent;
+ final int status = await _runProcess(
+ 'dart',
+ <String>[
+ 'fix',
+ '--compare-to-golden',
+ ],
+ workingDirectory: p.join(packageRoot.path, 'test_fixes'),
+ );
+
+ exit(status);
+}
+
+Future<Process> _streamOutput(Future<Process> processFuture) async {
+ final Process process = await processFuture;
+ stdout.addStream(process.stdout);
+ stderr.addStream(process.stderr);
+ return process;
+}
+
+Future<int> _runProcess(
+ String command,
+ List<String> arguments, {
+ String? workingDirectory,
+}) async {
+ final Process process = await _streamOutput(Process.start(
+ command,
+ arguments,
+ workingDirectory: workingDirectory,
+ ));
+ return process.exitCode;
+}
diff --git a/script/configs/custom_analysis.yaml b/script/configs/custom_analysis.yaml
index 93e2744..569f9e1 100644
--- a/script/configs/custom_analysis.yaml
+++ b/script/configs/custom_analysis.yaml
@@ -23,3 +23,5 @@
- rfw/example
# Disables docs requirements, as it is test code.
- web_benchmarks/testing/test_app
+# Has some test files that are intentionally broken to conduct dart fix tests.
+- go_router