Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/go_router/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 13.2.3

- Fixes an issue where deep links without path caused an exception

## 13.2.2

- Fixes restoreRouteInformation issue when GoRouter.optionURLReflectsImperativeAPIs is true and the last match is ShellRouteMatch
Expand Down
18 changes: 13 additions & 5 deletions packages/go_router/lib/src/parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,19 @@ class GoRouteInformationParser extends RouteInformationParser<RouteMatchList> {
}

late final RouteMatchList initialMatches;
initialMatches = configuration.findMatch(
routeInformation.uri.path.isEmpty
? '${routeInformation.uri}/'
: routeInformation.uri.toString(),
extra: state.extra);
if (routeInformation.uri.hasEmptyPath) {
String newUri = '${routeInformation.uri.origin}/';
if (routeInformation.uri.hasQuery) {
newUri += '?${routeInformation.uri.query}';
}
if (routeInformation.uri.hasFragment) {
newUri += '#${routeInformation.uri.fragment}';
}
initialMatches = configuration.findMatch(newUri, extra: state.extra);
} else {
initialMatches = configuration.findMatch(routeInformation.uri.toString(),
extra: state.extra);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: add comma

}
if (initialMatches.isError) {
log('No initial matches: ${routeInformation.uri.path}');
}
Expand Down
4 changes: 2 additions & 2 deletions packages/go_router/lib/src/path_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -125,20 +125,20 @@ String canonicalUri(String loc) {
throw GoException('Location cannot be empty.');
}
String canon = Uri.parse(loc).toString();
final Uri uri = Uri.parse(canon);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line128 should be after line 129

I can think of a corner test case /profile/?

canon = canon.endsWith('?') ? canon.substring(0, canon.length - 1) : canon;

// remove trailing slash except for when you shouldn't, e.g.
// /profile/ => /profile
// / => /
// /login?from=/ => login?from=/
canon = canon.endsWith('/') && canon != '/' && !canon.contains('?')
canon = uri.path.endsWith('/') && uri.path != '/' && !uri.hasQuery

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add && !uri.hasFragment

? canon.substring(0, canon.length - 1)
: canon;

// replace '/?', except for first occurrence, from path only
// /login/?from=/ => /login?from=/
// /?from=/ => /?from=/
final Uri uri = Uri.parse(canon);
final int pathStartIndex = uri.host.isNotEmpty
? uri.toString().indexOf(uri.host) + uri.host.length
: uri.hasScheme
Expand Down
2 changes: 1 addition & 1 deletion packages/go_router/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -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: 13.2.2
version: 13.2.3
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

Expand Down
47 changes: 45 additions & 2 deletions packages/go_router/test/parser_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,54 @@ void main() {
});

testWidgets(
"GoRouteInformationParser can parse deeplink route and maintain uri's scheme and host",
"GoRouteInformationParser can parse deeplink root route and maintain uri's scheme, host, query and fragment",
(WidgetTester tester) async {
const String expectedScheme = 'https';
const String expectedHost = 'www.example.com';
const String expectedQuery = 'abc=def';
const String expectedFragment = 'abc';
const String expectedUriString =
'$expectedScheme://$expectedHost/?$expectedQuery#$expectedFragment';
final List<GoRoute> routes = <GoRoute>[
GoRoute(
path: '/',
builder: (_, __) => const Placeholder(),
),
];
final GoRouteInformationParser parser = await createParser(
tester,
routes: routes,
redirectLimit: 100,
redirect: (_, __) => null,
);

final BuildContext context = tester.element(find.byType(Router<Object>));

final RouteMatchList matchesObj =
await parser.parseRouteInformationWithDependencies(
createRouteInformation(expectedUriString), context);
final List<RouteMatchBase> matches = matchesObj.matches;
expect(matches.length, 1);
expect(matchesObj.uri.toString(), expectedUriString);
expect(matchesObj.uri.scheme, expectedScheme);
expect(matchesObj.uri.host, expectedHost);
expect(matchesObj.uri.query, expectedQuery);
expect(matchesObj.uri.fragment, expectedFragment);

expect(matches[0].matchedLocation, '/');
expect(matches[0].route, routes[0]);
});

testWidgets(
"GoRouteInformationParser can parse deeplink route with a path and maintain uri's scheme, host, query and fragment",
(WidgetTester tester) async {
const String expectedScheme = 'https';
const String expectedHost = 'www.example.com';
const String expectedPath = '/abc';
const String expectedQuery = 'abc=def';
const String expectedFragment = 'abc';
const String expectedUriString =
'$expectedScheme://$expectedHost$expectedPath';
'$expectedScheme://$expectedHost$expectedPath?$expectedQuery#$expectedFragment';
final List<GoRoute> routes = <GoRoute>[
GoRoute(
path: '/',
Expand Down Expand Up @@ -119,6 +160,8 @@ void main() {
expect(matchesObj.uri.scheme, expectedScheme);
expect(matchesObj.uri.host, expectedHost);
expect(matchesObj.uri.path, expectedPath);
expect(matchesObj.uri.query, expectedQuery);
expect(matchesObj.uri.fragment, expectedFragment);

expect(matches[0].matchedLocation, '/');
expect(matches[0].route, routes[0]);
Expand Down
4 changes: 4 additions & 0 deletions packages/go_router/test/path_utils_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ void main() {
verify('/a/', '/a');
verify('/', '/');
verify('/a/b/', '/a/b');
verify('https://www.example.com/', 'https://www.example.com/');
verify('https://www.example.com/a', 'https://www.example.com/a');
verify('https://www.example.com/a/', 'https://www.example.com/a');
verify('https://www.example.com/a/b/', 'https://www.example.com/a/b');

expect(() => canonicalUri('::::'), throwsA(isA<FormatException>()));
expect(() => canonicalUri(''), throwsA(anything));
Expand Down