Skip to content

Commit 8e041d8

Browse files
authored
Add include_if_null (#333)
1 parent a695d8d commit 8e041d8

File tree

110 files changed

+844
-206
lines changed

Some content is hidden

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

110 files changed

+844
-206
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
.vscode
1+
.vscode
2+
.idea/

swagger_parser/.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
.packages
33
build/
44
pubspec.lock
5-
.idea/
5+
.idea
66
swagger_parser.yaml
77
!example/swagger_parser.yaml
88
**/generated_files/**

swagger_parser/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## 1.34.0
2+
- includeIfNull handling, turned off by default, use include_if_null=true to enable
3+
14
## 1.33.0
25
- Support correct processing of nested allOf classes
36

swagger_parser/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,11 @@ swagger_parser:
195195
# This is useful when using swagger_parser together with build_runner, which needs to map
196196
# input files to output files 1-to-1.
197197
merge_outputs: false
198+
199+
# DART ONLY
200+
# Optional. Set `true` to generate includeIfNull annotations for nullable fields.
201+
# If set to `false`, includeIfNull annotations will not be generated.
202+
include_if_null: false
198203
```
199204
200205
For multiple schemes:

swagger_parser/lib/src/config/swp_config.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class SWPConfig {
4343
this.includeTags = const <String>[],
4444
this.fallbackClient = 'fallback',
4545
this.mergeOutputs = false,
46+
this.includeIfNull = false,
4647
});
4748

4849
/// Internal constructor of [SWPConfig]
@@ -79,6 +80,7 @@ class SWPConfig {
7980
required this.fallbackClient,
8081
required this.mergeOutputs,
8182
required this.dartMappableConvenientWhen,
83+
required this.includeIfNull,
8284
this.fallbackUnion,
8385
});
8486

@@ -277,6 +279,9 @@ class SWPConfig {
277279
final mergeOutputs =
278280
yamlMap['merge_outputs'] as bool? ?? rootConfig?.mergeOutputs;
279281

282+
final includeIfNull =
283+
yamlMap['include_if_null'] as bool? ?? rootConfig?.includeIfNull;
284+
280285
// Default config
281286
final dc = SWPConfig(name: name, outputDirectory: outputDirectory);
282287

@@ -316,6 +321,7 @@ class SWPConfig {
316321
fallbackClient: fallbackClient ?? dc.fallbackClient,
317322
mergeOutputs: mergeOutputs ?? dc.mergeOutputs,
318323
dartMappableConvenientWhen: dartMappableConvenientWhen,
324+
includeIfNull: includeIfNull ?? dc.includeIfNull,
319325
);
320326
}
321327

@@ -495,6 +501,11 @@ class SWPConfig {
495501
/// input files to output files 1-to-1.
496502
final bool mergeOutputs;
497503

504+
/// DART ONLY
505+
/// Optional. Set `true` to generate includeIfNull annotations for nullable fields.
506+
/// If set to `false`, includeIfNull annotations will not be generated.
507+
final bool includeIfNull;
508+
498509
/// Convert [SWPConfig] to [GeneratorConfig]
499510
GeneratorConfig toGeneratorConfig() {
500511
return GeneratorConfig(
@@ -521,6 +532,7 @@ class SWPConfig {
521532
fallbackUnion: fallbackUnion,
522533
dartMappableConvenientWhen: dartMappableConvenientWhen,
523534
mergeOutputs: mergeOutputs,
535+
includeIfNull: includeIfNull,
524536
);
525537
}
526538

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class GeneratorConfig {
2929
this.fallbackUnion,
3030
this.dartMappableConvenientWhen = true,
3131
this.mergeOutputs = false,
32+
this.includeIfNull = false,
3233
});
3334

3435
/// Optional. Set API name for folder and export file or merged output file
@@ -137,4 +138,9 @@ class GeneratorConfig {
137138
/// This is useful when using swagger_parser together with build_runner, which needs to map
138139
/// input files to output files 1-to-1.
139140
final bool mergeOutputs;
141+
142+
/// DART ONLY
143+
/// Optional. Set `true` to generate includeIfNull annotations for nullable fields.
144+
/// If set to `false`, includeIfNull annotations will not be generated.
145+
final bool includeIfNull;
140146
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ final class FillController {
3434
useFreezed3: config.useFreezed3,
3535
useMultipartFile: config.useMultipartFile,
3636
dartMappableConvenientWhen: config.dartMappableConvenientWhen,
37+
includeIfNull: config.includeIfNull,
3738
fallbackUnion: config.fallbackUnion,
3839
),
3940
);

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ enum ProgrammingLanguage {
5050
required bool useFreezed3,
5151
required bool useMultipartFile,
5252
required bool dartMappableConvenientWhen,
53+
required bool includeIfNull,
5354
String? fallbackUnion,
5455
}) {
5556
switch (this) {
@@ -73,12 +74,14 @@ enum ProgrammingLanguage {
7374
generateValidator: generateValidator,
7475
isV3: useFreezed3,
7576
useMultipartFile: useMultipartFile,
77+
includeIfNull: includeIfNull,
7678
fallbackUnion: fallbackUnion,
7779
),
7880
JsonSerializer.jsonSerializable => dartJsonSerializableDtoTemplate(
7981
dataClass,
8082
markFileAsGenerated: markFilesAsGenerated,
8183
useMultipartFile: useMultipartFile,
84+
includeIfNull: includeIfNull,
8285
fallbackUnion: fallbackUnion,
8386
),
8487
JsonSerializer.dartMappable => dartDartMappableDtoTemplate(

swagger_parser/lib/src/generator/templates/dart_freezed_dto_template.dart

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'package:swagger_parser/src/utils/type_utils.dart';
99
String dartFreezedDtoTemplate(
1010
UniversalComponentClass dataClass, {
1111
required bool useMultipartFile,
12+
required bool includeIfNull,
1213
bool generateValidator = false,
1314
bool isV3 = false,
1415
String? fallbackUnion,
@@ -32,7 +33,7 @@ ${descriptionComment(dataClass.description)}@Freezed(${[
3233
"fallbackUnion: '$fallbackUnion'",
3334
].join(', ')})
3435
${_classModifier(isUnion: isUnion, isV3: isV3)}class $className with _\$$className {
35-
${_factories(dataClass, className, useMultipartFile, fallbackUnion, isUnion: isUnion)}
36+
${_factories(dataClass, className, useMultipartFile, includeIfNull, fallbackUnion, isUnion: isUnion)}
3637
${_jsonFactories(className, dataClass.undiscriminatedUnionVariants)}
3738
${generateValidator ? dataClass.parameters.map(_validationString).nonNulls.join() : ''}}
3839
${generateValidator ? _validateMethod(className, dataClass.parameters) : ''}''';
@@ -170,11 +171,11 @@ String _validateMethod(String className, Set<UniversalType> types) {
170171
}
171172

172173
String _factories(UniversalComponentClass dataClass, String className,
173-
bool useMultipartFile, String? fallbackUnion,
174+
bool useMultipartFile, bool includeIfNull, String? fallbackUnion,
174175
{required bool isUnion}) {
175176
if (!isUnion) {
176177
return '''
177-
const factory $className(${dataClass.parameters.isNotEmpty ? '{' : ''}${_parametersToString(dataClass.parameters, useMultipartFile)}${dataClass.parameters.isNotEmpty ? '\n }' : ''}) = _$className;''';
178+
const factory $className(${dataClass.parameters.isNotEmpty ? '{' : ''}${_parametersToString(dataClass.parameters, useMultipartFile, includeIfNull)}${dataClass.parameters.isNotEmpty ? '\n }' : ''}) = _$className;''';
178179
}
179180

180181
if (dataClass.undiscriminatedUnionVariants case final variants?
@@ -183,6 +184,7 @@ String _factories(UniversalComponentClass dataClass, String className,
183184
className,
184185
variants,
185186
useMultipartFile,
187+
includeIfNull,
186188
);
187189
}
188190

@@ -198,7 +200,7 @@ String _factories(UniversalComponentClass dataClass, String className,
198200

199201
factories.add('''
200202
@FreezedUnionValue('$discriminatorValue')
201-
const factory $className.$factoryName(${factoryParameters.isNotEmpty ? '{' : ''}${_parametersToString(factoryParameters, useMultipartFile)}${factoryParameters.isNotEmpty ? '\n }' : ''}) = $unionItemClassName;
203+
const factory $className.$factoryName(${factoryParameters.isNotEmpty ? '{' : ''}${_parametersToString(factoryParameters, useMultipartFile, includeIfNull)}${factoryParameters.isNotEmpty ? '\n }' : ''}) = $unionItemClassName;
202204
''');
203205
}
204206

@@ -212,16 +214,19 @@ String _factories(UniversalComponentClass dataClass, String className,
212214
return factories.join('\n');
213215
}
214216

215-
String _createFactoriesForUndiscriminatedUnion(String className,
216-
Map<String, Set<UniversalType>> variants, bool useMultipartFile) {
217+
String _createFactoriesForUndiscriminatedUnion(
218+
String className,
219+
Map<String, Set<UniversalType>> variants,
220+
bool useMultipartFile,
221+
bool includeIfNull) {
217222
final factories = <String>[];
218223
for (final MapEntry(key: variantName, value: factoryParameters)
219224
in variants.entries) {
220225
final factoryName = variantName.toCamel;
221226
final unionItemClassName = className + variantName.toPascal;
222227
factories.add('''
223228
@JsonSerializable()
224-
const factory $className.$factoryName(${factoryParameters.isNotEmpty ? '{' : ''}${_parametersToString(factoryParameters, useMultipartFile)}${factoryParameters.isNotEmpty ? '\n }' : ''}) = $unionItemClassName;
229+
const factory $className.$factoryName(${factoryParameters.isNotEmpty ? '{' : ''}${_parametersToString(factoryParameters, useMultipartFile, includeIfNull)}${factoryParameters.isNotEmpty ? '\n }' : ''}) = $unionItemClassName;
225230
''');
226231
}
227232
return factories.join('\n');
@@ -307,37 +312,49 @@ String? _validationString(UniversalType type) {
307312
}
308313

309314
String _parametersToString(
310-
Set<UniversalType> parameters, bool useMultipartFile) {
315+
Set<UniversalType> parameters, bool useMultipartFile, bool includeIfNull) {
311316
final sortedByRequired = Set<UniversalType>.from(
312317
parameters.sorted((a, b) => a.compareTo(b)),
313318
);
314319
return sortedByRequired
315320
.mapIndexed(
316321
(i, e) =>
317322
'\n${i != 0 && (e.description?.isNotEmpty ?? false) ? '\n' : ''}${descriptionComment(e.description, tab: ' ')}'
318-
'${_jsonKey(e)} ${_required(e)}'
323+
'${_jsonKey(e, includeIfNull)} ${_required(e)}'
319324
'${e.toSuitableType(ProgrammingLanguage.dart, useMultipartFile: useMultipartFile)} ${e.name},',
320325
)
321326
.join();
322327
}
323328

324-
String _jsonKey(UniversalType t) {
329+
String _jsonKey(UniversalType t, bool includeIfNull) {
325330
final sb = StringBuffer();
326-
if ((t.jsonKey == null || t.name == t.jsonKey) &&
327-
t.defaultValue == null &&
328-
!t.deprecated) {
329-
return '';
330-
}
331-
if (t.deprecated) {
332-
sb.write(" @Deprecated('This is marked as deprecated')\n");
331+
final jsonKeyParams = <String, String?>{};
332+
333+
if (includeIfNull) {
334+
if (t.isRequired && (t.nullable || t.referencedNullable)) {
335+
jsonKeyParams['includeIfNull'] = 'true';
336+
} else if (!t.isRequired && (t.nullable || t.referencedNullable)) {
337+
jsonKeyParams['includeIfNull'] = 'false';
338+
}
333339
}
340+
334341
if (t.jsonKey != null && t.name != t.jsonKey) {
335-
sb.write(" @JsonKey(name: '${protectJsonKey(t.jsonKey)}')\n");
342+
jsonKeyParams['name'] = "'${protectJsonKey(t.jsonKey)}'";
336343
}
344+
345+
if (jsonKeyParams.isNotEmpty) {
346+
sb.write(
347+
" @JsonKey(${jsonKeyParams.entries.map((e) => '${e.key}: ${e.value}').join(',')})\n");
348+
}
349+
337350
if (t.defaultValue != null) {
338351
sb.write(' @Default(${_defaultValue(t)})\n');
339352
}
340353

354+
if (t.deprecated) {
355+
sb.write(" @Deprecated('This is marked as deprecated')\n");
356+
}
357+
341358
return sb.toString();
342359
}
343360

0 commit comments

Comments
 (0)