-
Notifications
You must be signed in to change notification settings - Fork 3.6k
[go_router_builder] Support extension types #9458
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
Merged
Merged
Changes from 9 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
688ec24
feat: Support extension type
koji-1009 bf334dc
chore: 3.0.2
koji-1009 8cf27d2
test: Remove nullable path case
koji-1009 af33a0b
refactor: Fix encode case
koji-1009 61901a3
feat: Clarify which extension types are supported
koji-1009 53e30bb
test: Update test cases
koji-1009 1a84b3a
Merge branch 'main' into feat/extension_type
koji-1009 9b9afeb
chore: Fix version
koji-1009 4a4d892
chore: fix
koji-1009 bcc5d26
chore: Add example
koji-1009 c57f3d0
fix: Fix typo
koji-1009 57cf662
Merge branch 'main' into feat/extension_type
koji-1009 5910235
feat: Element2 API
koji-1009 ffdb723
chore: 3.2.0
koji-1009 9fc1ec2
refactor: dart format
koji-1009 b8758e0
refactor: dart format (test_input)
koji-1009 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -43,6 +43,7 @@ const List<_TypeHelper> _helpers = <_TypeHelper>[ | |
| _TypeHelperDateTime(), | ||
| _TypeHelperDouble(), | ||
| _TypeHelperEnum(), | ||
| _TypeHelperExtensionType(), | ||
| _TypeHelperInt(), | ||
| _TypeHelperNum(), | ||
| _TypeHelperString(), | ||
|
|
@@ -263,6 +264,94 @@ class _TypeHelperEnum extends _TypeHelperWithHelper { | |
| bool _matchesType(DartType type) => type.isEnum; | ||
| } | ||
|
|
||
| /// A type helper for extension types. | ||
| /// Suppoted extension types are: | ||
|
||
| /// - [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(); | ||
|
|
||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
180 changes: 180 additions & 0 deletions
180
packages/go_router_builder/test_inputs/extension_type_parameter.dart
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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) {} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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