Skip to content
This repository was archived by the owner on May 25, 2022. It is now read-only.

Commit c117e70

Browse files
committed
Merge pull request #8 from dave26199/multi-enum
Support multiple enums in one file by allowing arbitrary generated identifiers.
2 parents 1e0f685 + 64920e3 commit c117e70

File tree

8 files changed

+286
-46
lines changed

8 files changed

+286
-46
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 0.0.3
4+
5+
- Support multiple enums in one file by allowing arbitrary generated identifiers.
6+
37
## 0.0.2
48

59
- Add accurate dependencies on SDK, analyzer.

enum_class/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: enum_class
2-
version: 0.0.2
2+
version: 0.0.3
33
description: >
44
Dart classes as enums. This library is the runtime dependency.
55
authors:

enum_class_generator/lib/enum_class_generator.dart

Lines changed: 98 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import 'package:source_gen/source_gen.dart';
1515
/// See https://github.com/google/enum_class.dart/tree/master/example for how
1616
/// to use it.
1717
class EnumClassGenerator extends Generator {
18+
Set<String> _usedGeneratedIdentifiers = new Set<String>();
19+
1820
Future<String> generate(Element element) async {
1921
if (element is! ClassElement) {
2022
return null;
@@ -27,13 +29,13 @@ class EnumClassGenerator extends Generator {
2729
.where((i) => i.displayName == 'EnumClass')
2830
.isEmpty) return null;
2931

30-
final fields = getApplicableFields(classElement);
32+
final fields = _getApplicableFields(classElement);
3133
final errors = concat([
32-
checkPart(classElement),
33-
checkFields(fields),
34-
checkConstructor(classElement),
35-
checkValuesGetter(classElement),
36-
checkValueOf(classElement)
34+
_checkPart(classElement),
35+
_checkFields(fields),
36+
_checkConstructor(classElement),
37+
_checkValuesGetter(classElement),
38+
_checkValueOf(classElement)
3739
]);
3840

3941
if (errors.isNotEmpty) {
@@ -42,10 +44,10 @@ class EnumClassGenerator extends Generator {
4244
todo: errors.join(' '));
4345
}
4446

45-
return generateCode(enumName, fields.map((field) => field.displayName));
47+
return _generateCode(classElement, enumName, fields);
4648
}
4749

48-
Iterable<String> checkPart(ClassElement classElement) {
50+
Iterable<String> _checkPart(ClassElement classElement) {
4951
final fileName =
5052
classElement.library.source.shortName.replaceAll('.dart', '');
5153
final expectedCode = "part '$fileName.g.dart';";
@@ -54,7 +56,7 @@ class EnumClassGenerator extends Generator {
5456
: <String>['Import generated part: $expectedCode'];
5557
}
5658

57-
Iterable<FieldElement> getApplicableFields(ClassElement classElement) {
59+
Iterable<FieldElement> _getApplicableFields(ClassElement classElement) {
5860
final enumName = classElement.displayName;
5961
final result = <FieldElement>[];
6062
for (final field in classElement.fields) {
@@ -64,7 +66,7 @@ class EnumClassGenerator extends Generator {
6466
return result;
6567
}
6668

67-
Iterable<String> checkFields(Iterable<FieldElement> fields) {
69+
Iterable<String> _checkFields(Iterable<FieldElement> fields) {
6870
final result = <String>[];
6971
for (final field in fields) {
7072
final fieldName = field.displayName;
@@ -76,66 +78,128 @@ class EnumClassGenerator extends Generator {
7678
continue;
7779
}
7880

79-
if (field.computeNode().toString() != '$fieldName = _\$$fieldName') {
80-
result.add(
81-
'Initialize field "$fieldName" with generated value "_\$$fieldName".');
81+
if (!field.computeNode().toString().startsWith('$fieldName = _\$')) {
82+
result
83+
.add('Initialize field "$fieldName" with a value starting "_\$".');
84+
}
85+
86+
final identifier = _getGeneratedIdentifier(field);
87+
if (_usedGeneratedIdentifiers.contains(identifier)) {
88+
result
89+
.add('Generated identifier "_\$$identifier" is used multiple times,'
90+
' change to something else.');
8291
}
92+
_usedGeneratedIdentifiers.add(identifier);
8393
}
8494
return result;
8595
}
8696

87-
Iterable<String> checkConstructor(ClassElement classElement) {
97+
Iterable<String> _checkConstructor(ClassElement classElement) {
8898
final enumName = classElement.displayName;
8999
final expectedCode = 'const $enumName._(String name) : super(name);';
90100
return classElement.constructors.length == 1 &&
91101
classElement.constructors.single.computeNode().toString() ==
92102
expectedCode ? <String>[] : <String>['Constructor: $expectedCode'];
93103
}
94104

95-
Iterable<String> checkValuesGetter(ClassElement classElement) {
105+
Iterable<String> _checkValuesGetter(ClassElement classElement) {
96106
// TODO(davidmorgan): do this without reading the whole source.
97107
final enumName = classElement.displayName;
98-
final expectedCode = 'static BuiltSet<$enumName> get values => _\$values;';
99-
return classElement.source.contents.data.contains(expectedCode)
100-
? <String>[]
101-
: <String>['Getter: $expectedCode'];
108+
final valuesIdentifier =
109+
_getValuesIdentifier(classElement.source.contents.data, enumName);
110+
if (valuesIdentifier == null) {
111+
return <String>[
112+
'Getter: static BuiltSet<$enumName> get values => _\$values'
113+
];
114+
} else {
115+
if (_usedGeneratedIdentifiers.contains(valuesIdentifier)) {
116+
return <String>[
117+
'Generated identifier "_\$$valuesIdentifier" is used multiple times,'
118+
' change to something else.'
119+
];
120+
} else {
121+
return <String>[];
122+
}
123+
}
102124
}
103125

104-
Iterable<String> checkValueOf(ClassElement classElement) {
126+
Iterable<String> _checkValueOf(ClassElement classElement) {
105127
// TODO(davidmorgan): do this without reading the whole source.
106128
final enumName = classElement.displayName;
107-
final expectedCode =
108-
'static $enumName valueOf(String name) => _\$valueOf(name);';
109-
return classElement.source.contents.data.contains(expectedCode)
110-
? <String>[]
111-
: <String>['Method: $expectedCode'];
129+
130+
final valueOfIdentifier =
131+
_getValueOfIdentifier(classElement.source.contents.data, enumName);
132+
133+
if (valueOfIdentifier == null) {
134+
return <String>[
135+
'Method: static $enumName valueOf(String name) => _\$valueOf(name)'
136+
];
137+
} else {
138+
if (_usedGeneratedIdentifiers.contains(valueOfIdentifier)) {
139+
return <String>[
140+
'Generated identifier "_\$$valueOfIdentifier" is used multiple times,'
141+
' change to something else.'
142+
];
143+
} else {
144+
return <String>[];
145+
}
146+
}
112147
}
113148

114-
String generateCode(String enumName, Iterable<String> fieldNames) {
149+
String _generateCode(ClassElement classElement, String enumName,
150+
Iterable<FieldElement> fields) {
115151
final result = new StringBuffer();
116152

117-
for (final fieldName in fieldNames) {
118-
result.writeln('const $enumName _\$$fieldName = '
153+
for (final field in fields) {
154+
final fieldName = field.displayName;
155+
result.writeln('const $enumName _\$${_getGeneratedIdentifier(field)} = '
119156
'const $enumName._(\'$fieldName\');');
120157
}
121158

122159
result.writeln('');
123-
result.writeln('$enumName _\$valueOf(String name) {'
160+
161+
final valueOf =
162+
_getValueOfIdentifier(classElement.source.contents.data, enumName);
163+
result.writeln('$enumName _\$$valueOf(String name) {'
124164
'switch (name) {');
125-
for (final fieldName in fieldNames) {
126-
result.writeln('case \'$fieldName\': return _\$$fieldName;');
165+
for (final field in fields) {
166+
final fieldName = field.displayName;
167+
result.writeln(
168+
'case \'$fieldName\': return _\$${_getGeneratedIdentifier(field)};');
127169
}
128170
result.writeln('default: throw new ArgumentError(name);');
129171
result.writeln('}}');
130172

131173
result.writeln('');
132-
result.writeln('final BuiltSet<$enumName> _\$values ='
174+
175+
final values =
176+
_getValuesIdentifier(classElement.source.contents.data, enumName);
177+
result.writeln('final BuiltSet<$enumName> _\$$values ='
133178
'new BuiltSet<$enumName>(const [');
134-
for (final fieldName in fieldNames) {
135-
result.writeln('_\$$fieldName,');
179+
for (final field in fields) {
180+
result.writeln('_\$${_getGeneratedIdentifier(field)},');
136181
}
137182
result.writeln(']);');
138183

139184
return result.toString();
140185
}
186+
187+
String _getGeneratedIdentifier(FieldElement field) {
188+
final fieldName = field.displayName;
189+
return field.computeNode().toString().substring('$fieldName = _\$'.length);
190+
}
191+
192+
String _getValueOfIdentifier(String source, String enumName) {
193+
final matches = new RegExp(r'static ' +
194+
enumName +
195+
r' valueOf\(String name\) \=\> \_\$(\w+)\(name\)\;').allMatches(source);
196+
return matches.isEmpty ? null : matches.first.group(1);
197+
}
198+
199+
String _getValuesIdentifier(String source, String enumName) {
200+
final matches = new RegExp(
201+
r'static BuiltSet<' + enumName + r'> get values => _\$(\w+)\;')
202+
.allMatches(source);
203+
return matches.isEmpty ? null : matches.first.group(1);
204+
}
141205
}

enum_class_generator/pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: enum_class_generator
2-
version: 0.0.2
2+
version: 0.0.3
33
description: >
44
Dart classes as enums. This library is the dev dependency.
55
authors:
@@ -12,7 +12,7 @@ environment:
1212
dependencies:
1313
analyzer: '>=0.26.1 <1.0.0'
1414
built_collection: '^1.0.0'
15-
enum_class: '^0.0.2'
15+
enum_class: '^0.0.3'
1616
source_gen: '>=0.4.3 <1.0.0'
1717
quiver: '>=0.21.0 <0.22.0'
1818

0 commit comments

Comments
 (0)