Skip to content

Commit 19aedeb

Browse files
dfdgsdfgclaude
andauthored
Support sealed classes on json_serializeble, dart_mappable (#383)
Co-authored-by: Claude <[email protected]>
1 parent ef2ad28 commit 19aedeb

File tree

178 files changed

+6108
-259
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

178 files changed

+6108
-259
lines changed

swagger_parser/CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
## 1.31.0
2+
- Add complete sealed classes(`oneOf`/`anyOf`) support for `json_serializeble` serializer
3+
- **WARNING**: Undiscriminated sealed classes use O(n) try-catch deserialization where n is the number of variants
4+
- **RECOMMENDED**: Add discriminator properties to your OpenAPI specification for O(1) performance
5+
- Add support for sealed classes fallback for failed decoding
6+
- Add complete sealed classes(`oneOf`/`anyOf`) support for `dart_mappable` serializer
7+
- **WARNING**: Undiscriminated sealed classes use O(n) try-catch deserialization where n is the number of variants
8+
- **RECOMMENDED**: Add discriminator properties to your OpenAPI specification for O(1) performance
9+
- Add support for sealed classes fallback for failed decoding
10+
- Add `dart_mappable_convenient_when` option to control union type generation for `dart_mappable` serializer
11+
- `dart_mappable_convenient_when: true` - generates legacy `when<T>, maybeWhen<T>` methods
12+
- `dart_mappable_convenient_when: false` (default) - generates sealed classes for better type safety
13+
- Add `@Deprecated()` annotation to `when<T>, maybeWhen<T>` method with dart_mappable. Use dart pattern matching
14+
- Fix creating duplicated `unknown` property enum with dart_mappable and `unknown_enum_value: true`
15+
116
## 1.30.1
217
- Fix resolve inline schemas nested within tagged operations
318

swagger_parser/README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,19 @@ swagger_parser:
148148
# Set 'false' to maintain compatibility with Freezed 2.x.
149149
use_freezed3: false
150150
151-
# Optional (dart & freezed only). Set string value to use fallbackUnion parameter when using Freezed annotation.
152-
# When set to a string value, adds fallbackUnion: <value> to the @Freezed annotation.
153-
# When not set (null) or empty, the @Freezed annotation has no fallbackUnion parameter.
151+
# Optional (dart & freezed/dart_mappable). Set string value to use fallbackUnion parameter.
152+
# For freezed: adds fallbackUnion: <value> to the @Freezed annotation.
153+
# For dart_mappable: creates additional fallback variant for unknown discriminator values.
154+
# When not set (null) or empty, no fallback union is generated.
154155
# Examples: "unknown"
155156
# Default: "" (no fallbackUnion parameter)
156157
fallback_union: ""
157158
159+
# Optional (dart_mappable only). Set false to generate sealed classes for union types.
160+
# Set true to generate when/maybeWhen convenience methods for legacy support of deprecated union features from versions prior to 3.31.
161+
# Default: false
162+
dart_mappable_convenient_when: false
163+
158164
# DART ONLY
159165
# Optional. Set `true` to use MultipartFile instead of File as argument type for file parameters.
160166
use_multipart_file: false

swagger_parser/lib/src/config/swp_config.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class SWPConfig {
3939
this.useFreezed3 = false,
4040
this.useMultipartFile = false,
4141
this.fallbackUnion,
42+
this.dartMappableConvenientWhen = false,
4243
this.excludeTags = const <String>[],
4344
this.includeTags = const <String>[],
4445
this.fallbackClient = 'fallback',
@@ -78,6 +79,7 @@ class SWPConfig {
7879
required this.includeTags,
7980
required this.fallbackClient,
8081
required this.mergeOutputs,
82+
required this.dartMappableConvenientWhen,
8183
this.fallbackUnion,
8284
});
8385

@@ -233,6 +235,11 @@ class SWPConfig {
233235
final fallbackUnion =
234236
yamlMap['fallback_union'] as String? ?? rootConfig?.fallbackUnion;
235237

238+
final dartMappableConvenientWhen =
239+
yamlMap['dart_mappable_convenient_when'] as bool? ??
240+
rootConfig?.dartMappableConvenientWhen ??
241+
true;
242+
236243
final excludedTagsYaml = yamlMap['exclude_tags'] as YamlList?;
237244
List<String>? excludedTags;
238245
if (excludedTagsYaml != null) {
@@ -309,6 +316,7 @@ class SWPConfig {
309316
includeTags: includedTags ?? dc.includeTags,
310317
fallbackClient: fallbackClient ?? dc.fallbackClient,
311318
mergeOutputs: mergeOutputs ?? dc.mergeOutputs,
319+
dartMappableConvenientWhen: dartMappableConvenientWhen,
312320
);
313321
}
314322

@@ -458,6 +466,11 @@ class SWPConfig {
458466
/// Optional. Set fallback consctructor name to use fallbackUnion parameter when using Freezed annotation.
459467
final String? fallbackUnion;
460468

469+
/// DART ONLY
470+
/// Optional. Set 'true' to generate when/maybeWhen convenience methods for dart_mappable unions.
471+
/// Set 'false' to use only native Dart pattern matching.
472+
final bool dartMappableConvenientWhen;
473+
461474
/// DART ONLY
462475
/// Optional. Set excluded tags.
463476
///
@@ -507,6 +520,7 @@ class SWPConfig {
507520
useFreezed3: useFreezed3,
508521
useMultipartFile: useMultipartFile,
509522
fallbackUnion: fallbackUnion,
523+
dartMappableConvenientWhen: dartMappableConvenientWhen,
510524
mergeOutputs: mergeOutputs,
511525
);
512526
}

swagger_parser/lib/src/generator/config/generator_config.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class GeneratorConfig {
2727
this.useFreezed3 = false,
2828
this.useMultipartFile = false,
2929
this.fallbackUnion,
30+
this.dartMappableConvenientWhen = true,
3031
this.mergeOutputs = false,
3132
});
3233

@@ -126,6 +127,11 @@ class GeneratorConfig {
126127
/// Optional. Set fallback constructor name to use fallbackUnion parameter when using Freezed annotation.
127128
final String? fallbackUnion;
128129

130+
/// DART ONLY
131+
/// Optional. Set 'true' to generate when/maybeWhen convenience methods for dart_mappable unions.
132+
/// Set 'false' to use only native Dart pattern matching.
133+
final bool dartMappableConvenientWhen;
134+
129135
/// Optional. Set to true to merge all generated code into a single file.
130136
///
131137
/// This is useful when using swagger_parser together with build_runner, which needs to map

swagger_parser/lib/src/generator/generator/fill_controller.dart

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import '../../parser/swagger_parser_core.dart';
33
import '../../utils/base_utils.dart';
44
import '../config/generator_config.dart';
55
import '../model/generated_file.dart';
6+
import '../model/json_serializer.dart';
67
import '../model/programming_language.dart';
78

89
/// Handles generating files
@@ -21,9 +22,8 @@ final class FillController {
2122

2223
/// Return [GeneratedFile] generated from given [UniversalDataClass]
2324
GeneratedFile fillDtoContent(UniversalDataClass dataClass) => GeneratedFile(
24-
name: 'models/'
25-
'${config.language == ProgrammingLanguage.dart ? dataClass.name.toSnake : dataClass.name.toPascal}'
26-
'.${config.language.fileExtension}',
25+
name:
26+
'models/${_resolveDtoFileBaseName(dataClass)}.${config.language.fileExtension}',
2727
content: config.language.dtoFileContent(
2828
dataClass,
2929
jsonSerializer: config.jsonSerializer,
@@ -33,10 +33,45 @@ final class FillController {
3333
generateValidator: config.generateValidator,
3434
useFreezed3: config.useFreezed3,
3535
useMultipartFile: config.useMultipartFile,
36+
dartMappableConvenientWhen: config.dartMappableConvenientWhen,
3637
fallbackUnion: config.fallbackUnion,
3738
),
3839
);
3940

41+
String _resolveDtoFileBaseName(UniversalDataClass dataClass) {
42+
if (config.language != ProgrammingLanguage.dart) {
43+
return dataClass.name.toPascal;
44+
}
45+
46+
var baseName = dataClass.name;
47+
48+
if (config.jsonSerializer != JsonSerializer.freezed &&
49+
dataClass is UniversalComponentClass) {
50+
final isUnion = dataClass.discriminator != null ||
51+
(dataClass.undiscriminatedUnionVariants?.isNotEmpty ?? false);
52+
if (isUnion) {
53+
baseName = _applySealedNaming(baseName);
54+
}
55+
}
56+
57+
return baseName.toSnake;
58+
}
59+
60+
String _applySealedNaming(String name) {
61+
const unionSuffix = 'Union';
62+
const sealedSuffix = 'Sealed';
63+
64+
if (name.endsWith(sealedSuffix)) {
65+
return name;
66+
}
67+
68+
if (name.endsWith(unionSuffix)) {
69+
return '${name.substring(0, name.length - unionSuffix.length)}$sealedSuffix';
70+
}
71+
72+
return name;
73+
}
74+
4075
/// Return [GeneratedFile] generated from given [UniversalRestClient]
4176
GeneratedFile fillRestClientContent(UniversalRestClient restClient) {
4277
final postfix = config.clientPostfix ?? 'Client';

swagger_parser/lib/src/generator/model/programming_language.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ enum ProgrammingLanguage {
4949
required bool generateValidator,
5050
required bool useFreezed3,
5151
required bool useMultipartFile,
52+
required bool dartMappableConvenientWhen,
5253
String? fallbackUnion,
5354
}) {
5455
switch (this) {
@@ -78,11 +79,14 @@ enum ProgrammingLanguage {
7879
dataClass,
7980
markFileAsGenerated: markFilesAsGenerated,
8081
useMultipartFile: useMultipartFile,
82+
fallbackUnion: fallbackUnion,
8183
),
8284
JsonSerializer.dartMappable => dartDartMappableDtoTemplate(
8385
dataClass,
8486
markFileAsGenerated: markFilesAsGenerated,
8587
useMultipartFile: useMultipartFile,
88+
fallbackUnion: fallbackUnion,
89+
dartMappableConvenientWhen: dartMappableConvenientWhen,
8690
),
8791
};
8892
}

0 commit comments

Comments
 (0)