Skip to content

[go_router_builder] Add support for caseSensitive #9134

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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_builder/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.9.0

- Adds support for `caseSensitive` for go routes.

## 2.8.2

- Fixes an issue when enum params are not required
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// 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.

// ignore_for_file: public_member_api_docs, unreachable_from_main

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

part 'case_sensitive_example.g.dart';

void main() => runApp(CaseSensitivityApp());

class CaseSensitivityApp extends StatelessWidget {
CaseSensitivityApp({super.key});

@override
Widget build(BuildContext context) => MaterialApp.router(
routerConfig: _router,
);

final GoRouter _router = GoRouter(
initialLocation: '/case-sensitive',
routes: $appRoutes,
);
}

@TypedGoRoute<CaseSensitiveRoute>(
path: '/case-sensitive',
)
class CaseSensitiveRoute extends GoRouteData {
const CaseSensitiveRoute();

@override
Widget build(BuildContext context, GoRouterState state) => const Screen(
title: 'Case Sensitive',
);
}

@TypedGoRoute<NotCaseSensitiveRoute>(
path: '/not-case-sensitive',
caseSensitive: false,
)
class NotCaseSensitiveRoute extends GoRouteData {
const NotCaseSensitiveRoute();

@override
Widget build(BuildContext context, GoRouterState state) => const Screen(
title: 'Not Case Sensitive',
);
}

class Screen extends StatelessWidget {
const Screen({required this.title, super.key});

final String title;
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: Text(title),
),
body: ListView(
children: <Widget>[
ListTile(
title: const Text('Case Sensitive'),
onTap: () => context.go('/case-sensitive'),
),
ListTile(
title: const Text('Not Case Sensitive'),
onTap: () => context.go('/not-case-sensitive'),
),
],
),
);
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/go_router_builder/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ dependencies:
collection: ^1.15.0
flutter:
sdk: flutter
go_router: ^14.1.1
go_router: ^15.1.1
provider: 6.0.5

dev_dependencies:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// 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:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:go_router_builder_example/case_sensitive_example.dart';

void main() {
testWidgets(
'It should navigate to the correct screen when the route is case sensitive and the path matches exactly',
(WidgetTester tester) async {
tester.platformDispatcher.defaultRouteNameTestValue = '/case-sensitive';
await tester.pumpWidget(CaseSensitivityApp());

expect(find.widgetWithText(AppBar, 'Case Sensitive'), findsOne);
});

testWidgets(
'It should navigate to the correct screen when the route is not case sensitive and the path matches exactly',
(WidgetTester tester) async {
tester.platformDispatcher.defaultRouteNameTestValue = '/not-case-sensitive';
await tester.pumpWidget(CaseSensitivityApp());

expect(find.widgetWithText(AppBar, 'Not Case Sensitive'), findsOne);
});

testWidgets(
'It should throw an error when the route is case sensitive and the path does not match',
(WidgetTester tester) async {
final FlutterExceptionHandler? oldFlutterError = FlutterError.onError;
addTearDown(() => FlutterError.onError = oldFlutterError);
final List<FlutterErrorDetails> errors = <FlutterErrorDetails>[];
FlutterError.onError = (FlutterErrorDetails details) {
errors.add(details);
};

tester.platformDispatcher.defaultRouteNameTestValue = '/CASE-sensitive';
await tester.pumpWidget(CaseSensitivityApp());

expect(find.widgetWithText(AppBar, 'Case Sensitive'), findsNothing);
expect(errors, hasLength(1));
expect(
errors.single.exception,
isAssertionError,
reason: 'The path is case sensitive',
);
});

testWidgets(
'It should navigate to the correct screen when the route is not case sensitive and the path case does not match',
(WidgetTester tester) async {
tester.platformDispatcher.defaultRouteNameTestValue = '/NOT-case-sensitive';
await tester.pumpWidget(CaseSensitivityApp());

expect(find.widgetWithText(AppBar, 'Not Case Sensitive'), findsOne);
});
}
7 changes: 7 additions & 0 deletions packages/go_router_builder/lib/src/route_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ class GoRouteConfig extends RouteBaseConfig {
GoRouteConfig._({
required this.path,
required this.name,
required this.caseSensitive,
required this.parentNavigatorKey,
required super.routeDataClass,
required super.parent,
Expand All @@ -203,6 +204,9 @@ class GoRouteConfig extends RouteBaseConfig {
/// The name of the GoRoute to be created by this configuration.
final String? name;

/// The case sensitivity of the GoRoute to be created by this configuration.
final bool caseSensitive;

/// The parent navigator key.
final String? parentNavigatorKey;

Expand Down Expand Up @@ -422,6 +426,7 @@ extension $_extensionName on $_className {
String get routeConstructorParameters => '''
path: ${escapeDartString(path)},
${name != null ? 'name: ${escapeDartString(name!)},' : ''}
${caseSensitive ? '' : 'caseSensitive: $caseSensitive,'}
${parentNavigatorKey == null ? '' : 'parentNavigatorKey: $parentNavigatorKey,'}
''';

Expand Down Expand Up @@ -552,9 +557,11 @@ abstract class RouteBaseConfig {
);
}
final ConstantReader nameValue = reader.read('name');
final ConstantReader caseSensitiveValue = reader.read('caseSensitive');
value = GoRouteConfig._(
path: pathValue.stringValue,
name: nameValue.isNull ? null : nameValue.stringValue,
caseSensitive: caseSensitiveValue.boolValue,
routeDataClass: classElement,
parent: parent,
parentNavigatorKey: _generateParameterGetterCode(
Expand Down
4 changes: 2 additions & 2 deletions packages/go_router_builder/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: go_router_builder
description: >-
A builder that supports generated strongly-typed route helpers for
package:go_router
version: 2.8.2
version: 2.9.0
repository: https://github.com/flutter/packages/tree/main/packages/go_router_builder
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+go_router_builder%22

Expand All @@ -26,7 +26,7 @@ dev_dependencies:
dart_style: '>=2.3.7 <4.0.0'
flutter:
sdk: flutter
go_router: ^14.8.0
go_router: ^15.1.0
leak_tracker_flutter_testing: ">=3.0.0"
package_config: ^2.1.1
pub_semver: ^2.1.5
Expand Down
14 changes: 14 additions & 0 deletions packages/go_router_builder/test_inputs/case_sensitivity.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// 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';

@TypedGoRoute<CaseSensitiveRoute>(path: '/case-sensitive-route')
class CaseSensitiveRoute extends GoRouteData {}

@TypedGoRoute<NotCaseSensitiveRoute>(
path: '/not-case-sensitive-route',
caseSensitive: false,
)
class NotCaseSensitiveRoute extends GoRouteData {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
RouteBase get $caseSensitiveRoute => GoRouteData.$route(
path: '/case-sensitive-route',
factory: $CaseSensitiveRouteExtension._fromState,
);

extension $CaseSensitiveRouteExtension on CaseSensitiveRoute {
static CaseSensitiveRoute _fromState(GoRouterState state) =>
CaseSensitiveRoute();

String get location => GoRouteData.$location(
'/case-sensitive-route',
);

void go(BuildContext context) => context.go(location);

Future<T?> push<T>(BuildContext context) => context.push<T>(location);

void pushReplacement(BuildContext context) =>
context.pushReplacement(location);

void replace(BuildContext context) => context.replace(location);
}

RouteBase get $notCaseSensitiveRoute => GoRouteData.$route(
path: '/not-case-sensitive-route',
caseSensitive: false,
factory: $NotCaseSensitiveRouteExtension._fromState,
);

extension $NotCaseSensitiveRouteExtension on NotCaseSensitiveRoute {
static NotCaseSensitiveRoute _fromState(GoRouterState state) =>
NotCaseSensitiveRoute();

String get location => GoRouteData.$location(
'/not-case-sensitive-route',
);

void go(BuildContext context) => context.go(location);

Future<T?> push<T>(BuildContext context) => context.push<T>(location);

void pushReplacement(BuildContext context) =>
context.pushReplacement(location);

void replace(BuildContext context) => context.replace(location);
}