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_builder/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

- Restricts `build` to versions less than 2.5.0.

## 3.1.0

- Adds support for`extension type`.

## 3.0.1

- Updates README.md to use the mixin `with _$RouteName`.
Expand Down
2 changes: 1 addition & 1 deletion packages/go_router_builder/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ class RedirectRoute extends GoRouteData {

## Type conversions

The code generator can convert simple types like `int` and `enum` to/from the
The code generator can convert simple types like `int`, `enum`, and `extension type` to/from the
Copy link
Contributor

Choose a reason for hiding this comment

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

We should add a new example in example/ folder

`String` type of the underlying pathParameters:

<?code-excerpt "example/lib/readme_excerpts.dart (BookKind)"?>
Expand Down
6 changes: 6 additions & 0 deletions packages/go_router_builder/lib/src/route_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,12 @@ mixin $_mixinName on GoRouteData {
if (potentialEnumType.isEnum) {
enumParamTypes.add(potentialEnumType as InterfaceType);
}

// Support for enum extension types
final DartType representedType = potentialEnumType.extensionTypeErasure;
if (potentialEnumType != representedType && representedType.isEnum) {
enumParamTypes.add(representedType as InterfaceType);
}
}
return enumParamTypes.map<String>(_enumMapConst);
}
Expand Down
89 changes: 89 additions & 0 deletions packages/go_router_builder/lib/src/type_helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const List<_TypeHelper> _helpers = <_TypeHelper>[
_TypeHelperDateTime(),
_TypeHelperDouble(),
_TypeHelperEnum(),
_TypeHelperExtensionType(),
_TypeHelperInt(),
_TypeHelperNum(),
_TypeHelperString(),
Expand Down Expand Up @@ -263,6 +264,94 @@ class _TypeHelperEnum extends _TypeHelperWithHelper {
bool _matchesType(DartType type) => type.isEnum;
}

/// A type helper for extension types.
/// Suppoted extension types are:
Copy link
Member

Choose a reason for hiding this comment

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

nit: Suppoted-> Supported

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, I fixed! c57f3d0

/// - [String]
/// - [int]
/// - [double]
/// - [num]
/// - [bool]
/// - [Enum]
/// - [BigInt]
/// - [DateTime]
/// - [Uri]
class _TypeHelperExtensionType extends _TypeHelper {
const _TypeHelperExtensionType();

@override
String _decode(
ParameterElement parameterElement, Set<String> pathParameters) {
final DartType paramType = parameterElement.type;
if (paramType.isNullableType && parameterElement.hasDefaultValue) {
throw NullableDefaultValueError(parameterElement);
}

final String stateValue =
'state.${_stateValueAccess(parameterElement, pathParameters)}';
final String castType;
if (paramType.isNullableType || parameterElement.hasDefaultValue) {
castType = '$paramType${paramType.isNullableType ? '' : '?'}';
} else {
castType = '$paramType';
}

final DartType representationType = paramType.extensionTypeErasure;
if (representationType.isDartCoreString) {
return '$stateValue as $castType';
}

if (representationType.isEnum) {
return '${enumMapName(representationType as InterfaceType)}'
'.$enumExtensionHelperName($stateValue) as $castType';
}

final String representationTypeName =
withoutNullability(representationType.getDisplayString());
if (paramType.isNullableType || parameterElement.hasDefaultValue) {
return "$representationTypeName.tryParse($stateValue ?? '') as $castType";
} else {
return '$representationTypeName.parse($stateValue) as $castType';
}
}

@override
String _encode(String fieldName, DartType type) {
final DartType representationType = type.extensionTypeErasure;
if (representationType.isDartCoreString) {
return '$fieldName${type.ensureNotNull} as String';
}

if (representationType.isEnum) {
return '${enumMapName(representationType as InterfaceType)}'
'[$fieldName${type.ensureNotNull} as ${withoutNullability(representationType.getDisplayString())}]!';
}

return '$fieldName${representationType.ensureNotNull}.toString()';
}

@override
bool _matchesType(DartType type) {
final DartType representationType = type.extensionTypeErasure;
if (type == representationType) {
// `type` is not an extension type.
return false;
}

return representationType.isDartCoreString ||
representationType.isDartCoreInt ||
representationType.isDartCoreDouble ||
representationType.isDartCoreNum ||
representationType.isDartCoreBool ||
representationType.isEnum ||
const TypeChecker.fromRuntime(BigInt)
.isAssignableFromType(representationType) ||
const TypeChecker.fromRuntime(DateTime)
.isAssignableFromType(representationType) ||
const TypeChecker.fromRuntime(Uri)
.isAssignableFromType(representationType);
}
}

class _TypeHelperInt extends _TypeHelperWithHelper {
const _TypeHelperInt();

Expand Down
2 changes: 1 addition & 1 deletion 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: 3.0.1
version: 3.1.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 Down
180 changes: 180 additions & 0 deletions packages/go_router_builder/test_inputs/extension_type_parameter.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
// 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';

mixin _$ExtensionTypeParam {}
mixin _$ExtensionTypeStringParam {}
mixin _$ExtensionTypeStringDefaultParam {}
mixin _$ExtensionTypeIntParam {}
mixin _$ExtensionTypeIntDefaultParam {}
mixin _$ExtensionTypeDoubleParam {}
mixin _$ExtensionTypeNumParam {}
mixin _$ExtensionTypeBoolParam {}
mixin _$ExtensionTypeEnumType {}
mixin _$ExtensionTypeBigIntParam {}
mixin _$ExtensionTypeDateTimeParam {}
mixin _$ExtensionTypeUriType {}

@TypedGoRoute<ExtensionTypeParam>(path: '/', routes: <TypedRoute<RouteData>>[
TypedGoRoute<ExtensionTypeStringParam>(path: 'string/:s'),
TypedGoRoute<ExtensionTypeStringDefaultParam>(path: 'string_default/:s'),
TypedGoRoute<ExtensionTypeIntParam>(path: 'int/:x'),
TypedGoRoute<ExtensionTypeIntDefaultParam>(path: 'int_default/:x'),
TypedGoRoute<ExtensionTypeDoubleParam>(path: 'double/:d'),
TypedGoRoute<ExtensionTypeNumParam>(path: 'num/:n'),
TypedGoRoute<ExtensionTypeBoolParam>(path: 'bool/:b'),
TypedGoRoute<ExtensionTypeEnumType>(path: 'enum/:value'),
TypedGoRoute<ExtensionTypeBigIntParam>(path: 'bigint/:bi'),
TypedGoRoute<ExtensionTypeDateTimeParam>(path: 'datetime/:dt'),
TypedGoRoute<ExtensionTypeUriType>(path: 'uri/:uri'),
])
class ExtensionTypeParam extends GoRouteData with _$ExtensionTypeParam {
ExtensionTypeParam();
}

class ExtensionTypeStringParam extends GoRouteData
with _$ExtensionTypeStringParam {
ExtensionTypeStringParam({
required this.s,
required this.requiredValue,
this.optionalNullableValue,
this.optionalDefaultValue = const StringExtensionType('default'),
});
final StringExtensionType s;
final StringExtensionType requiredValue;
final StringExtensionType? optionalNullableValue;
final StringExtensionType optionalDefaultValue;
}

class ExtensionTypeStringDefaultParam extends GoRouteData
with _$ExtensionTypeStringDefaultParam {
ExtensionTypeStringDefaultParam({
this.s = const StringExtensionType('default'),
});
final StringExtensionType s;
}

class ExtensionTypeIntParam extends GoRouteData with _$ExtensionTypeIntParam {
ExtensionTypeIntParam({
required this.x,
required this.requiredValue,
this.optionalNullableValue,
this.optionalDefaultValue = const IntExtensionType(42),
});
final IntExtensionType x;
final IntExtensionType requiredValue;
final IntExtensionType? optionalNullableValue;
final IntExtensionType optionalDefaultValue;
}

class ExtensionTypeIntDefaultParam extends GoRouteData
with _$ExtensionTypeIntDefaultParam {
ExtensionTypeIntDefaultParam({
this.x = const IntExtensionType(42),
});
final IntExtensionType x;
}

class ExtensionTypeDoubleParam extends GoRouteData
with _$ExtensionTypeDoubleParam {
ExtensionTypeDoubleParam({
required this.d,
required this.requiredValue,
this.optionalNullableValue,
this.optionalDefaultValue = const DoubleExtensionType(3.14),
});
final DoubleExtensionType d;
final DoubleExtensionType requiredValue;
final DoubleExtensionType? optionalNullableValue;
final DoubleExtensionType optionalDefaultValue;
}

class ExtensionTypeNumParam extends GoRouteData with _$ExtensionTypeNumParam {
ExtensionTypeNumParam({
required this.n,
required this.requiredValue,
this.optionalNullableValue,
this.optionalDefaultValue = const NumExtensionType(3.14),
});
final NumExtensionType n;
final NumExtensionType requiredValue;
final NumExtensionType? optionalNullableValue;
final NumExtensionType optionalDefaultValue;
}

class ExtensionTypeBoolParam extends GoRouteData with _$ExtensionTypeBoolParam {
ExtensionTypeBoolParam({
required this.b,
required this.requiredValue,
this.optionalNullableValue,
this.optionalDefaultValue = const BoolExtensionType(true),
});
final BoolExtensionType b;
final BoolExtensionType requiredValue;
final BoolExtensionType? optionalNullableValue;
final BoolExtensionType optionalDefaultValue;
}

enum MyEnum { value1, value2, value3 }

class ExtensionTypeEnumType extends GoRouteData with _$ExtensionTypeEnumType {
ExtensionTypeEnumType({
required this.value,
required this.requiredValue,
this.optionalNullableValue,
this.optionalDefaultValue = const EnumExtensionType(MyEnum.value1),
});
final EnumExtensionType value;
final EnumExtensionType requiredValue;
final EnumExtensionType? optionalNullableValue;
final EnumExtensionType optionalDefaultValue;
}

class ExtensionTypeBigIntParam extends GoRouteData
with _$ExtensionTypeBigIntParam {
ExtensionTypeBigIntParam({
required this.bi,
required this.requiredValue,
this.optionalValue,
this.optionalNullableValue,
});
final BigIntExtensionType bi;
final BigIntExtensionType requiredValue;
final BigIntExtensionType? optionalValue;
final BigIntExtensionType? optionalNullableValue;
}

class ExtensionTypeDateTimeParam extends GoRouteData
with _$ExtensionTypeDateTimeParam {
ExtensionTypeDateTimeParam({
required this.dt,
required this.optionalValue,
this.optionalNullableValue,
});
final DateTimeExtensionType dt;
final DateTimeExtensionType optionalValue;
final DateTimeExtensionType? optionalNullableValue;
}

class ExtensionTypeUriType extends GoRouteData with _$ExtensionTypeUriType {
ExtensionTypeUriType({
required this.uri,
required this.requiredValue,
this.optionalNullableValue,
});
final UriExtensionType uri;
final UriExtensionType requiredValue;
final UriExtensionType? optionalNullableValue;
}

extension type const StringExtensionType(String value) {}
extension type const IntExtensionType(int value) {}
extension type const DoubleExtensionType(double value) {}
extension type const NumExtensionType(num value) {}
extension type const BoolExtensionType(bool value) {}
extension type const EnumExtensionType(MyEnum value) {}
extension type const BigIntExtensionType(BigInt value) {}
extension type const DateTimeExtensionType(DateTime value) {}
extension type const UriExtensionType(Uri value) {}
Loading