Skip to content

Commit 72cc27c

Browse files
committed
fix: consistency improvements and more invalid config validations
1 parent f4407b0 commit 72cc27c

File tree

4 files changed

+53
-28
lines changed

4 files changed

+53
-28
lines changed

json_serializable/lib/src/decode_helper.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ mixin DecodeHelper implements HelperCore {
153153
String _createSealedFunctionExpressionBody() {
154154
assert(element.isSealed);
155155

156-
final implementations = sealedClassImplementations(element);
156+
final implementations = sealedSubClasses(element);
157157

158158
final discriminator = config.unionDiscriminator;
159159

json_serializable/lib/src/encoder_helper.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ mixin EncodeHelper implements HelperCore {
137137
String _createSealedFunctionExpressionBody() {
138138
assert(element.isSealed);
139139

140-
final implementations = sealedClassImplementations(element);
140+
final implementations = sealedSubClasses(element);
141141

142142
final discriminator = config.unionDiscriminator;
143143

json_serializable/lib/src/generator_helper.dart

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import 'package:analyzer/dart/element/element.dart';
66
import 'package:build/build.dart';
7+
import 'package:collection/collection.dart';
78
import 'package:source_gen/source_gen.dart';
89

910
import '../type_helper.dart';
@@ -51,13 +52,25 @@ class GeneratorHelper extends HelperCore with EncodeHelper, DecodeHelper {
5152
);
5253
}
5354

54-
final sealedSuperClassesOrEmpty = sealedSuperClasses(element);
55+
final sealedSupersAndConfigs = sealedSuperClasses(element).map(
56+
(superClass) => (
57+
classElement: superClass,
58+
config: jsonSerializableConfig(superClass, _generator),
59+
),
60+
);
5561

56-
final sealedDiscriminators = sealedSuperClassesOrEmpty
57-
.map((sealedClass) => jsonSerializableConfig(sealedClass, _generator))
58-
.map((config) => config?.unionDiscriminator);
62+
if (sealedSupersAndConfigs.isNotEmpty &&
63+
sealedSupersAndConfigs.any((e) => e.config == null)) {
64+
throw InvalidGenerationSourceError(
65+
'The class `${element.displayName}` is annotated '
66+
'with `JsonSerializable` but its superclass is not annotated '
67+
'with `JsonSerializable`.',
68+
todo: 'Add `@JsonSerializable` annotation to the sealed class.',
69+
element: element,
70+
);
71+
}
5972

60-
if ((sealedSuperClassesOrEmpty.isNotEmpty || element.isSealed) &&
73+
if ((sealedSupersAndConfigs.isNotEmpty || element.isSealed) &&
6174
config.genericArgumentFactories) {
6275
throw InvalidGenerationSourceError(
6376
'The class `${element.displayName}` is annotated '
@@ -70,31 +83,42 @@ class GeneratorHelper extends HelperCore with EncodeHelper, DecodeHelper {
7083
);
7184
}
7285

86+
if (sealedSupersAndConfigs.firstWhereOrNull(
87+
(e) => e.config?.unionDiscriminator == config.unionDiscriminator,
88+
)
89+
case final conflictingSuper? when element.isSealed) {
90+
throw InvalidGenerationSource(
91+
'The classes `${conflictingSuper.classElement.displayName}` and '
92+
'${element.displayName} are nested sealed classes, but they have '
93+
'the same discriminator ${config.unionDiscriminator}.',
94+
todo: 'Rename one of the discriminators with `unionDiscriminator` '
95+
'field of `@JsonSerializable`.',
96+
);
97+
}
98+
99+
if (sealedSupersAndConfigs.firstWhereOrNull(
100+
(e) => e.config?.createToJson != config.createToJson,
101+
)
102+
case final diffSuper?) {
103+
throw InvalidGenerationSourceError(
104+
'The class `${diffSuper.classElement.displayName}` is sealed but its '
105+
'subclass `${element.displayName}` has a different '
106+
'`createToJson` option than the base class.',
107+
element: element,
108+
);
109+
}
110+
73111
if (element.isSealed) {
74-
if (sealedDiscriminators.contains(config.unionDiscriminator)) {
75-
throw InvalidGenerationSource(
76-
'Nested sealed classes cannot have the same discriminator.',
77-
todo: 'Rename one of the discriminators with `unionDiscriminator` '
78-
'field in `@JsonSerializable`.',
79-
);
80-
}
81-
sealedClassImplementations(element).forEach((impl) {
82-
final annotationConfig = jsonSerializableConfig(impl, _generator);
112+
sealedSubClasses(element).forEach((sub) {
113+
final annotationConfig = jsonSerializableConfig(sub, _generator);
83114

84115
if (annotationConfig == null) {
85116
throw InvalidGenerationSourceError(
86117
'The class `${element.displayName}` is sealed but its '
87-
'implementation `${impl.displayName}` is not annotated with '
118+
'subclass `${sub.displayName}` is not annotated with '
88119
'`JsonSerializable`.',
89-
todo: 'Add `@JsonSerializable` annotation to ${impl.displayName}.',
90-
);
91-
}
92-
93-
if (annotationConfig.createToJson != config.createToJson) {
94-
throw InvalidGenerationSourceError(
95-
'The class `${element.displayName}` is sealed but its '
96-
'implementation `${impl.displayName}` has a different '
97-
'`createToJson` option than the base class.',
120+
todo: 'Add `@JsonSerializable` annotation to ${sub.displayName}.',
121+
element: sub,
98122
);
99123
}
100124
});
@@ -168,7 +192,8 @@ class GeneratorHelper extends HelperCore with EncodeHelper, DecodeHelper {
168192
(Set<String> set, fe) {
169193
final jsonKey = nameAccess(fe);
170194

171-
if (sealedDiscriminators.contains(jsonKey)) {
195+
if (sealedSupersAndConfigs
196+
.any((e) => e.config?.unionDiscriminator == jsonKey)) {
172197
throw InvalidGenerationSourceError(
173198
'The JSON key "$jsonKey" is conflicting with the discriminator '
174199
'of sealed superclass ',

json_serializable/lib/src/utils.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ ConstructorElement constructorByName(ClassElement classElement, String name) {
175175
/// indirect subclasses (ie. subclasses of subclasses).
176176
///
177177
/// Otherwise, returns an empty iterable.
178-
Iterable<ClassElement> sealedClassImplementations(
178+
Iterable<ClassElement> sealedSubClasses(
179179
ClassElement maybeSealedSuperClass,
180180
) {
181181
if (maybeSealedSuperClass case final sc when sc.isSealed) {

0 commit comments

Comments
 (0)