@@ -6,9 +6,9 @@ import 'package:flutter/widgets.dart';
6
6
7
7
import 'configuration.dart' ;
8
8
import 'logging.dart' ;
9
+ import 'misc/errors.dart' ;
9
10
import 'path_utils.dart' ;
10
11
import 'typedefs.dart' ;
11
-
12
12
export 'route.dart' ;
13
13
export 'state.dart' ;
14
14
@@ -20,74 +20,95 @@ class RouteConfiguration {
20
20
required this .redirectLimit,
21
21
required this .topRedirect,
22
22
required this .navigatorKey,
23
- }) {
23
+ }) : assert (_debugCheckPath (routes, true )),
24
+ assert (
25
+ _debugVerifyNoDuplicatePathParameter (routes, < String , GoRoute > {})),
26
+ assert (_debugCheckParentNavigatorKeys (
27
+ routes, < GlobalKey <NavigatorState >> [navigatorKey])) {
24
28
_cacheNameToPath ('' , routes);
25
-
26
29
log.info (_debugKnownRoutes ());
30
+ }
27
31
28
- assert (() {
29
- for (final RouteBase route in routes) {
30
- if (route is GoRoute && ! route.path.startsWith ('/' )) {
32
+ static bool _debugCheckPath (List <RouteBase > routes, bool isTopLevel) {
33
+ for (final RouteBase route in routes) {
34
+ late bool subRouteIsTopLevel;
35
+ if (route is GoRoute ) {
36
+ if (isTopLevel) {
31
37
assert (route.path.startsWith ('/' ),
32
- 'top-level path must start with "/": ${route .path }' );
33
- } else if (route is ShellRoute ) {
34
- for (final RouteBase route in routes) {
35
- if (route is GoRoute ) {
36
- assert (route.path.startsWith ('/' ),
37
- 'top-level path must start with "/": ${route .path }' );
38
- }
39
- }
38
+ 'top-level path must start with "/": $route ' );
39
+ } else {
40
+ assert (! route.path.startsWith ('/' ) && ! route.path.endsWith ('/' ),
41
+ 'sub-route path may not start or end with /: $route ' );
40
42
}
43
+ subRouteIsTopLevel = false ;
44
+ } else if (route is ShellRoute ) {
45
+ subRouteIsTopLevel = isTopLevel;
41
46
}
47
+ _debugCheckPath (route.routes, subRouteIsTopLevel);
48
+ }
49
+ return true ;
50
+ }
42
51
43
- // Check that each parentNavigatorKey refers to either a ShellRoute's
44
- // navigatorKey or the root navigator key.
45
- void checkParentNavigatorKeys (
46
- List <RouteBase > routes, List <GlobalKey <NavigatorState >> allowedKeys) {
47
- for (final RouteBase route in routes) {
48
- if (route is GoRoute ) {
49
- final GlobalKey <NavigatorState >? parentKey =
50
- route.parentNavigatorKey;
51
- if (parentKey != null ) {
52
- // Verify that the root navigator or a ShellRoute ancestor has a
53
- // matching navigator key.
54
- assert (
55
- allowedKeys.contains (parentKey),
56
- 'parentNavigatorKey $parentKey must refer to'
57
- " an ancestor ShellRoute's navigatorKey or GoRouter's"
58
- ' navigatorKey' );
59
-
60
- checkParentNavigatorKeys (
61
- route.routes,
62
- < GlobalKey <NavigatorState >> [
63
- // Once a parentNavigatorKey is used, only that navigator key
64
- // or keys above it can be used.
65
- ...allowedKeys.sublist (0 , allowedKeys.indexOf (parentKey) + 1 ),
66
- ],
67
- );
68
- } else {
69
- checkParentNavigatorKeys (
70
- route.routes,
71
- < GlobalKey <NavigatorState >> [
72
- ...allowedKeys,
73
- ],
74
- );
75
- }
76
- } else if (route is ShellRoute && route.navigatorKey != null ) {
77
- checkParentNavigatorKeys (
78
- route.routes,
79
- < GlobalKey <NavigatorState >> [
80
- ...allowedKeys..add (route.navigatorKey)
81
- ],
82
- );
83
- }
52
+ // Check that each parentNavigatorKey refers to either a ShellRoute's
53
+ // navigatorKey or the root navigator key.
54
+ static bool _debugCheckParentNavigatorKeys (
55
+ List <RouteBase > routes, List <GlobalKey <NavigatorState >> allowedKeys) {
56
+ for (final RouteBase route in routes) {
57
+ if (route is GoRoute ) {
58
+ final GlobalKey <NavigatorState >? parentKey = route.parentNavigatorKey;
59
+ if (parentKey != null ) {
60
+ // Verify that the root navigator or a ShellRoute ancestor has a
61
+ // matching navigator key.
62
+ assert (
63
+ allowedKeys.contains (parentKey),
64
+ 'parentNavigatorKey $parentKey must refer to'
65
+ " an ancestor ShellRoute's navigatorKey or GoRouter's"
66
+ ' navigatorKey' );
67
+
68
+ _debugCheckParentNavigatorKeys (
69
+ route.routes,
70
+ < GlobalKey <NavigatorState >> [
71
+ // Once a parentNavigatorKey is used, only that navigator key
72
+ // or keys above it can be used.
73
+ ...allowedKeys.sublist (0 , allowedKeys.indexOf (parentKey) + 1 ),
74
+ ],
75
+ );
76
+ } else {
77
+ _debugCheckParentNavigatorKeys (
78
+ route.routes,
79
+ < GlobalKey <NavigatorState >> [
80
+ ...allowedKeys,
81
+ ],
82
+ );
84
83
}
84
+ } else if (route is ShellRoute && route.navigatorKey != null ) {
85
+ _debugCheckParentNavigatorKeys (
86
+ route.routes,
87
+ < GlobalKey <NavigatorState >> [...allowedKeys..add (route.navigatorKey)],
88
+ );
85
89
}
90
+ }
91
+ return true ;
92
+ }
86
93
87
- checkParentNavigatorKeys (
88
- routes, < GlobalKey <NavigatorState >> [navigatorKey]);
89
- return true ;
90
- }());
94
+ static bool _debugVerifyNoDuplicatePathParameter (
95
+ List <RouteBase > routes, Map <String , GoRoute > usedPathParams) {
96
+ for (final RouteBase route in routes) {
97
+ if (route is ! GoRoute ) {
98
+ continue ;
99
+ }
100
+ for (final String pathParam in route.pathParams) {
101
+ if (usedPathParams.containsKey (pathParam)) {
102
+ final bool sameRoute = usedPathParams[pathParam] == route;
103
+ throw GoError (
104
+ "duplicate path parameter, '$pathParam ' found in ${sameRoute ? '$route ' : '${usedPathParams [pathParam ]}, and $route ' }" );
105
+ }
106
+ usedPathParams[pathParam] = route;
107
+ }
108
+ _debugVerifyNoDuplicatePathParameter (route.routes, usedPathParams);
109
+ route.pathParams.forEach (usedPathParams.remove);
110
+ }
111
+ return true ;
91
112
}
92
113
93
114
/// The list of top level routes used by [GoRouterDelegate] .
0 commit comments