forked from google/json_serializable.dart
-
Notifications
You must be signed in to change notification settings - Fork 1
/
generator_helper.dart
121 lines (103 loc) · 3.71 KB
/
generator_helper.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// for details. 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:analyzer/dart/element/element.dart';
import 'package:build/build.dart';
import 'package:source_gen/source_gen.dart';
import 'decode_helper.dart';
import 'encoder_helper.dart';
import 'field_helpers.dart';
import 'helper_core.dart';
import 'settings.dart';
import 'type_helper.dart';
import 'utils.dart';
class GeneratorHelper extends HelperCore with EncodeHelper, DecodeHelper {
final Settings _generator;
final _addedMembers = <String>{};
GeneratorHelper(
this._generator,
ClassElement element,
ConstantReader annotation,
) : super(
element,
mergeConfig(
_generator.config,
annotation,
classElement: element,
));
@override
void addMember(String memberContent) {
_addedMembers.add(memberContent);
}
@override
Iterable<TypeHelper> get allTypeHelpers => _generator.allHelpers;
Iterable<String> generate() sync* {
assert(_addedMembers.isEmpty);
if (config.genericArgumentFactories && element.typeParameters.isEmpty) {
log.warning(
'The class `${element.displayName}` is annotated '
'with `JsonSerializable` field `genericArgumentFactories: true`. '
'`genericArgumentFactories: true` only affects classes with type '
'parameters. For classes without type parameters, the option is '
'ignored.',
);
}
final sortedFields = createSortedFieldSet(element);
// Used to keep track of why a field is ignored. Useful for providing
// helpful errors when generating constructor calls that try to use one of
// these fields.
final unavailableReasons = <String, String>{};
final accessibleFields = sortedFields.fold<Map<String, FieldElement>>(
<String, FieldElement>{},
(map, field) {
if (!field.isPublic) {
unavailableReasons[field.name] = 'It is assigned to a private field.';
} else if (field.getter == null) {
assert(field.setter != null);
unavailableReasons[field.name] =
'Setter-only properties are not supported.';
log.warning('Setters are ignored: ${element.name}.${field.name}');
} else if (jsonKeyFor(field).ignore) {
unavailableReasons[field.name] =
'It is assigned to an ignored field.';
} else {
assert(!map.containsKey(field.name));
map[field.name] = field;
}
return map;
},
);
var accessibleFieldSet = accessibleFields.values.toSet();
if (config.createFactory) {
final createResult = createFactory(accessibleFields, unavailableReasons);
yield createResult.output;
accessibleFieldSet = accessibleFields.entries
.where((e) => createResult.usedFields.contains(e.key))
.map((e) => e.value)
.toSet();
}
// Check for duplicate JSON keys due to colliding annotations.
// We do this now, since we have a final field list after any pruning done
// by `_writeCtor`.
accessibleFieldSet.fold(
<String>{},
(Set<String> set, fe) {
final jsonKey = nameAccess(fe);
if (!set.add(jsonKey)) {
throw InvalidGenerationSourceError(
'More than one field has the JSON key for name "$jsonKey".',
element: fe,
);
}
return set;
},
);
if (config.createFieldMap) {
yield createFieldMap(accessibleFieldSet);
}
if (config.createToJson) {
yield* createToJson(accessibleFieldSet);
}
yield* _addedMembers;
}
}