@@ -8,265 +8,18 @@ import 'dart:async';
8
8
9
9
import 'package:analyzer/dart/element/element.dart' ;
10
10
import 'package:build/build.dart' ;
11
- import 'package:quiver/iterables .dart' show concat ;
11
+ import 'package:enum_class_generator/src/source_library .dart' ;
12
12
import 'package:source_gen/source_gen.dart' ;
13
13
14
14
/// Generator for Enum Classes.
15
15
///
16
16
/// See https://github.com/google/enum_class.dart/tree/master/example for how
17
17
/// to use it.
18
18
class EnumClassGenerator extends Generator {
19
- Set <String > _usedGeneratedIdentifiers = new Set <String >();
20
-
21
19
@override
22
20
Future <String > generate (Element element, BuildStep buildStep) async {
23
- if (element is ! ClassElement ) {
24
- return null ;
25
- }
26
- final classElement = element as ClassElement ;
27
- final enumName = classElement.displayName;
28
-
29
- if (classElement.supertype.displayName != 'EnumClass' ) {
30
- // Maybe they're trying to use EnumClass but forgot to import the library.
31
- if (classElement
32
- .computeNode ()
33
- .toSource ()
34
- .contains ('class ${classElement .displayName } extends EnumClass' )) {
35
- throw _makeError (
36
- ["Import EnumClass: import 'package:enum_class/enum_class.dart';" ]);
37
- } else {
38
- return null ;
39
- }
40
- }
41
-
42
- final libraryName = classElement.library.displayName;
43
- final fields = _getApplicableFields (classElement);
44
- final errors = concat ([
45
- _checkPart (classElement),
46
- _checkFields (libraryName, fields),
47
- _checkConstructor (classElement),
48
- _checkValuesGetter (libraryName, classElement),
49
- _checkValueOf (libraryName, classElement)
50
- ]).toList ();
51
-
52
- final mixinElement = classElement.library.getType (enumName + 'Mixin' );
53
- final shouldGenerateMixin = mixinElement != null ;
54
- if (shouldGenerateMixin) {
55
- final expectedCode =
56
- 'abstract class ${enumName }Mixin = Object with _\$ ${enumName }Mixin;' ;
57
- if (mixinElement.computeNode ().toString () != expectedCode) {
58
- errors.add ('Remove mixin or declare using exactly: $expectedCode ' );
59
- }
60
- }
61
-
62
- if (errors.isNotEmpty) {
63
- throw _makeError (errors);
64
- }
65
-
66
- return _generateCode (classElement, enumName, fields, shouldGenerateMixin);
67
- }
68
-
69
- Iterable <String > _checkPart (ClassElement classElement) {
70
- final fileName =
71
- classElement.library.source.shortName.replaceAll ('.dart' , '' );
72
- final expectedCode = "part '$fileName .g.dart';" ;
73
- final alternativeExpectedCode = 'part "$fileName .g.dart";' ;
74
- final source = classElement.library.source.contents.data;
75
- return source.contains (expectedCode) ||
76
- source.contains (alternativeExpectedCode)
77
- ? < String > []
78
- : < String > ['Import generated part: $expectedCode ' ];
79
- }
80
-
81
- Iterable <FieldElement > _getApplicableFields (ClassElement classElement) {
82
- final enumName = classElement.displayName;
83
- final result = < FieldElement > [];
84
- for (final field in classElement.fields) {
85
- final type = field.getter.returnType.displayName;
86
- if (! field.isSynthetic && (type == enumName || type == 'dynamic' )) {
87
- result.add (field);
88
- }
89
- }
90
- return result;
91
- }
92
-
93
- Iterable <String > _checkFields (
94
- String libraryName, Iterable <FieldElement > fields) {
95
- final result = < String > [];
96
- for (final field in fields) {
97
- final fieldName = field.displayName;
98
- if (field.getter.returnType.displayName == 'dynamic' ) {
99
- result.add ('Specify a type for field "$fieldName ".' );
100
- continue ;
101
- } else if (! field.isConst && ! field.isStatic) {
102
- result.add ('Make field "$fieldName " static const.' );
103
- continue ;
104
- } else if (! field.isConst) {
105
- result.add ('Make field "$fieldName " const.' );
106
- continue ;
107
- }
108
-
109
- if (! field.computeNode ().toString ().startsWith ('$fieldName = _\$ ' )) {
110
- result
111
- .add ('Initialize field "$fieldName " with a value starting "_\$ ".' );
112
- }
113
-
114
- final identifier = _getGeneratedIdentifier (field);
115
- result.addAll (
116
- _checkAndRegisterGeneratedIdentifier (libraryName, identifier));
117
- }
118
- return result;
119
- }
120
-
121
- Iterable <String > _checkConstructor (ClassElement classElement) {
122
- final enumName = classElement.displayName;
123
- final expectedCode = 'const $enumName ._(String name) : super(name);' ;
124
- return classElement.constructors.length == 1 &&
125
- classElement.constructors.single.computeNode ().toString () ==
126
- expectedCode
127
- ? < String > []
128
- : < String > ['Have exactly one constructor: $expectedCode ' ];
129
- }
130
-
131
- Iterable <String > _checkValuesGetter (
132
- String libraryName, ClassElement classElement) {
133
- final enumName = classElement.displayName;
134
- final valuesIdentifier = _getValuesIdentifier (classElement, enumName);
135
- final result = < String > [];
136
- if (valuesIdentifier == null ) {
137
- result.add (
138
- 'Add getter: static BuiltSet<$enumName > get values => _\$ values' );
139
- } else {
140
- result.addAll (
141
- _checkAndRegisterGeneratedIdentifier (libraryName, valuesIdentifier));
142
- }
143
- return result;
144
- }
145
-
146
- Iterable <String > _checkValueOf (
147
- String libraryName, ClassElement classElement) {
148
- final enumName = classElement.displayName;
149
- final valueOfIdentifier = _getValueOfIdentifier (classElement, enumName);
150
- final result = < String > [];
151
- if (valueOfIdentifier == null ) {
152
- result.add ('Add method: '
153
- 'static $enumName valueOf(String name) => _\$ valueOf(name)' );
154
- } else {
155
- result.addAll (
156
- _checkAndRegisterGeneratedIdentifier (libraryName, valueOfIdentifier));
157
- }
158
- return result;
159
- }
160
-
161
- Iterable <String > _checkAndRegisterGeneratedIdentifier (
162
- String libraryName, String identifier) {
163
- final result = < String > [];
164
- final scopedIdentifier = '$libraryName .$identifier ' ;
165
- if (_usedGeneratedIdentifiers.contains (scopedIdentifier)) {
166
- result
167
- .add ('Generated identifier "_\$ $identifier " is used multiple times in'
168
- ' $libraryName , change to something else.' );
169
- } else {
170
- _usedGeneratedIdentifiers.add (scopedIdentifier);
171
- }
172
- return result;
173
- }
174
-
175
- String _generateCode (ClassElement classElement, String enumName,
176
- Iterable <FieldElement > fields, bool generateMixin) {
177
- final result = new StringBuffer ();
178
-
179
- for (final field in fields) {
180
- final fieldName = field.displayName;
181
- result.writeln ('const $enumName _\$ ${_getGeneratedIdentifier (field )} = '
182
- 'const $enumName ._(\' $fieldName \' );' );
183
- }
184
-
185
- result.writeln ('' );
186
-
187
- final valueOf = _getValueOfIdentifier (classElement, enumName);
188
- result.writeln ('$enumName _\$ $valueOf (String name) {'
189
- 'switch (name) {' );
190
- for (final field in fields) {
191
- final fieldName = field.displayName;
192
- result.writeln (
193
- 'case \' $fieldName \' : return _\$ ${_getGeneratedIdentifier (field )};' );
194
- }
195
- result.writeln ('default: throw new ArgumentError(name);' );
196
- result.writeln ('}}' );
197
-
198
- result.writeln ('' );
199
-
200
- final values = _getValuesIdentifier (classElement, enumName);
201
- result.writeln ('final BuiltSet<$enumName > _\$ $values ='
202
- 'new BuiltSet<$enumName >(const [' );
203
- for (final field in fields) {
204
- result.writeln ('_\$ ${_getGeneratedIdentifier (field )},' );
205
- }
206
- result.writeln (']);' );
207
-
208
- if (generateMixin)
209
- result.write (_generateMixin (enumName, fields, valueOf, values));
210
-
211
- return result.toString ();
212
- }
213
-
214
- String _generateMixin (String enumName, Iterable <FieldElement > fields,
215
- String valueOfIdentifier, String valuesIdentifier) {
216
- final result = new StringBuffer ();
217
-
218
- result.writeln ('class _\$ ${enumName }Meta {' );
219
- result.writeln ('const _\$ ${enumName }Meta();' );
220
- for (final field in fields) {
221
- final fieldName = field.displayName;
222
- result.writeln ('$enumName get $fieldName => _\$ ${_getGeneratedIdentifier (
223
- field )};' );
224
- }
225
- result.writeln (
226
- '$enumName valueOf(String name) => _\$ $valueOfIdentifier (name);' );
227
- result.writeln ('BuiltSet<$enumName > get values => _\$ $valuesIdentifier ;' );
228
- result.writeln ('}' );
229
- result.writeln ('abstract class _\$ ${enumName }Mixin {' );
230
- result.writeln (
231
- '_\$ ${enumName }Meta get $enumName => const _\$ ${enumName }Meta();' );
232
- result.writeln ('}' );
233
-
234
- return result.toString ();
235
- }
236
-
237
- String _getGeneratedIdentifier (FieldElement field) {
238
- final fieldName = field.displayName;
239
- return field.computeNode ().toString ().substring ('$fieldName = _\$ ' .length);
240
- }
241
-
242
- String _getValueOfIdentifier (ClassElement classElement, String enumName) {
243
- final getter = classElement.getMethod ('valueOf' );
244
- if (getter == null ) return null ;
245
- final source = getter.computeNode ().toSource ();
246
- final matches = new RegExp (r'static ' +
247
- enumName +
248
- r' valueOf\(String name\) \=\> \_\$(\w+)\(name\)\;' )
249
- .allMatches (source);
250
- return matches.isEmpty ? null : matches.first.group (1 );
251
- }
252
-
253
- String _getValuesIdentifier (ClassElement classElement, String enumName) {
254
- final getter = classElement.getGetter ('values' );
255
- if (getter == null ) return null ;
256
- final source = getter.computeNode ().toSource ();
257
- final matches = new RegExp (
258
- r'static BuiltSet<' + enumName + r'> get values => _\$(\w+)\;' )
259
- .allMatches (source);
260
- return matches.isEmpty ? null : matches.first.group (1 );
261
- }
262
-
263
- InvalidGenerationSourceError _makeError (Iterable <String > todos) {
264
- final message = new StringBuffer (
265
- 'Please make the following changes to use EnumClass:\n ' );
266
- for (var i = 0 ; i != todos.length; ++ i) {
267
- message.write ('\n ${i + 1 }. ${todos .elementAt (i )}' );
268
- }
21
+ if (element is ! LibraryElement ) return null ;
269
22
270
- return new InvalidGenerationSourceError (message. toString () );
23
+ return new SourceLibrary . fromLibraryElement (element). generateCode ( );
271
24
}
272
25
}
0 commit comments