@@ -8,6 +8,7 @@ import '../constants.dart';
8
8
import '../shared_checkers.dart' ;
9
9
import '../type_helper.dart' ;
10
10
import '../utils.dart' ;
11
+ import 'to_from_string.dart' ;
11
12
12
13
const _keyParam = 'k' ;
13
14
@@ -28,15 +29,17 @@ class MapHelper extends TypeHelper<TypeHelperContextWithConfig> {
28
29
29
30
_checkSafeKeyType (expression, keyType);
30
31
32
+ final toFromString = _forType (keyType);
33
+
34
+ final subKeyValue = toFromString? .serialize (keyType, _keyParam, false ) ??
35
+ context.serialize (keyType, _keyParam);
31
36
final subFieldValue = context.serialize (valueType, closureArg);
32
- final subKeyValue = context.serialize (keyType, _keyParam);
33
37
34
38
if (closureArg == subFieldValue && _keyParam == subKeyValue) {
35
39
return expression;
36
40
}
37
41
38
42
final optionalQuestion = context.nullable ? '?' : '' ;
39
-
40
43
return '$expression $optionalQuestion '
41
44
'.map(($_keyParam , $closureArg ) => MapEntry($subKeyValue , $subFieldValue ))' ;
42
45
}
@@ -56,9 +59,9 @@ class MapHelper extends TypeHelper<TypeHelperContextWithConfig> {
56
59
_checkSafeKeyType (expression, keyArg);
57
60
58
61
final valueArgIsAny = _isObjectOrDynamic (valueArg);
59
- final isEnumKey = isEnum (keyArg);
62
+ final isKeyStringable = _isStringKeyable (keyArg);
60
63
61
- if (! isEnumKey ) {
64
+ if (! isKeyStringable ) {
62
65
if (valueArgIsAny) {
63
66
if (context.config.anyMap) {
64
67
if (_isObjectOrDynamic (keyArg)) {
@@ -90,30 +93,58 @@ class MapHelper extends TypeHelper<TypeHelperContextWithConfig> {
90
93
context.config.anyMap ? 'as Map' : 'as Map<String, dynamic>' ;
91
94
92
95
String keyUsage;
93
- if (isEnumKey) {
96
+
97
+ if (isEnum (keyArg)) {
94
98
keyUsage = context.deserialize (keyArg, _keyParam).toString ();
95
99
} else if (context.config.anyMap && ! _isObjectOrDynamic (keyArg)) {
96
100
keyUsage = '$_keyParam as String' ;
97
101
} else {
98
102
keyUsage = _keyParam;
99
103
}
100
104
105
+ final toFromString = _forType (keyArg);
106
+ if (toFromString != null ) {
107
+ keyUsage = toFromString.deserialize (keyArg, keyUsage, false , true );
108
+ }
109
+
101
110
return '($expression $mapCast )$optionalQuestion .map('
102
111
'($_keyParam , $closureArg ) => MapEntry($keyUsage , $itemSubVal ),)' ;
103
112
}
104
113
}
105
114
115
+ final _intString = ToFromStringHelper ('int.parse' , 'toString()' , 'int' );
116
+
117
+ final _instances = {
118
+ bigIntString,
119
+ dateTimeString,
120
+ _intString,
121
+ uriString,
122
+ };
123
+
124
+ Iterable <String > get _allowedTypeNames => const [
125
+ 'Object' ,
126
+ 'dynamic' ,
127
+ 'enum' ,
128
+ 'String'
129
+ ].followedBy (_instances.map ((i) => i.coreTypeName));
130
+
131
+ ToFromStringHelper _forType (DartType type) =>
132
+ _instances.singleWhere ((i) => i.matches (type), orElse: () => null );
133
+
106
134
bool _isObjectOrDynamic (DartType type) => type.isObject || type.isDynamic;
107
135
136
+ bool _isStringKeyable (DartType keyType) =>
137
+ isEnum (keyType) || _instances.any ((inst) => inst.matches (keyType));
138
+
108
139
void _checkSafeKeyType (String expression, DartType keyArg) {
109
140
// We're not going to handle converting key types at the moment
110
141
// So the only safe types for key are dynamic/Object/String/enum
111
142
final safeKey = _isObjectOrDynamic (keyArg) ||
112
143
coreStringTypeChecker.isExactlyType (keyArg) ||
113
- isEnum (keyArg);
144
+ _isStringKeyable (keyArg);
114
145
115
146
if (! safeKey) {
116
147
throw UnsupportedTypeError (keyArg, expression,
117
- 'Map keys must be of type `String`, enum, `Object` or `dynamic` .' );
148
+ 'Map keys must be one of: ${ _allowedTypeNames . join ( ', ' )} .' );
118
149
}
119
150
}
0 commit comments