diff --git a/swagger_parser/README.md b/swagger_parser/README.md index 2b424fc3..19ccb206 100644 --- a/swagger_parser/README.md +++ b/swagger_parser/README.md @@ -206,6 +206,24 @@ swagger_parser: # Default: false dart_mappable_convenient_when: false + # Optional (dart_mappable only). + # Set to true to use the standard `toMap` and `fromMap` serialization from dart_mappable. + # The default implementation requires you to rename the serialization methods in the `build.yaml` to + # ensure compatibility between retrofit and dart_mappable + # ```yaml + # global_options: + # dart_mappable_builder: + # runs_before: + # - retrofit_generator + # options: + # renameMethods: + # toJson: toJsonString + # toMap: toJson + # ``` + # + # Default: false + use_dart_mappable_naming: false + # DART ONLY # Optional. Set `true` to use MultipartFile instead of File as argument type for file parameters. use_multipart_file: false @@ -398,6 +416,85 @@ To run the code generation with build_runner, execute the following command: dart run build_runner build -d ``` +### (Only for dart_mappable) Generate files using [dart_mappable](https://pub.dev/packages/build_runner) for retrofit and dart_mappable + +While most JSON serializer stick to the convention of naming the serializers `fromJson` and `toJson`, `dart_mappable` names these methods +according to the used data type `Map`. Therefore these serializing methods are called `toMap` and `fromMap`. This conflicted with `retrofit`. + +#### Default settings + +In the default settings the parameter `use_dart_mappable_naming` is set to `false` in the `swagger_parser.yaml`. +`retrofit` will therefore expect a `fromJson` and `toJson` method to be provided. In order to achieve that, set the following options +in the `build.yaml`: + +```yaml +global_options: + dart_mappable_builder: + runs_before: + - retrofit_generator + options: + renameMethods: + toJson: toJsonString + toMap: toJson +``` + +This will result in the following code usage: + +```dart + +@MappableClass() +class Foo with FooMappable { + final String name; + + const Foo(this.name); + + static Foo fromJson(Map json); +} + +void main() { + final Foo foo = Foo('Dave'); + // parse to JSON + final Map serializedFoo = foo.toJson(); + // parse from JSON + final Foo deserializedFoo = Foo.fromJson(serializedFoo); +} +``` + +This has been made default as `retrofit` prior to version `retrofit: 4.9.2`, did not support `dart_mappable`. +The `retrofit` package was expecting the `toJson` method being able to handle objects of type +`Map`. Therefore the standard naming convention in dart_mappable had to be overriden using the `build.yaml`. +To avoid breaking changes, this behaviour has been made default and may be changed in a future major release. + +#### use `dart_mappable` standard naming + +In order to use the default namings of `dart_mappable` set the `use_dart_mappable_naming` to `true`. + +This will result in the following code usage: + +```dart + +@MappableClass() +class Foo with FooMappable { + final String name; + + const Foo(this.name); + + static Foo fromMap(Map json); +} + +void main() { + final Foo foo = Foo('Dave'); + // parse to JSON + final Map serializedFoo = foo.toMap(); + // parse from JSON + final Foo deserializedFoo = Foo.fromMap(serializedFoo); +} +``` + +**NOTE:** If you want to migrate existing projects that have been using the renaming options, do not forget to remove these +options from the `build.yaml`. + + ## Contributing Contributions are welcome! diff --git a/swagger_parser/lib/src/config/swp_config.dart b/swagger_parser/lib/src/config/swp_config.dart index f3bc934e..ce7cad9c 100644 --- a/swagger_parser/lib/src/config/swp_config.dart +++ b/swagger_parser/lib/src/config/swp_config.dart @@ -42,6 +42,7 @@ class SWPConfig { this.useMultipartFile = false, this.fallbackUnion, this.dartMappableConvenientWhen = false, + this.useDartMappableNaming = false, this.excludeTags = const [], this.includeTags = const [], this.includePaths, @@ -91,6 +92,7 @@ class SWPConfig { required this.fallbackClient, required this.mergeOutputs, required this.dartMappableConvenientWhen, + required this.useDartMappableNaming, required this.includeIfNull, required this.inferRequiredFromNullable, required this.useFlutterCompute, @@ -284,6 +286,10 @@ class SWPConfig { rootConfig?.dartMappableConvenientWhen ?? true; + final useDartMappableNaming = + yamlMap['use_dart_mappable_naming'] as bool? ?? + rootConfig?.useDartMappableNaming; + final excludedTagsYaml = yamlMap['exclude_tags'] as YamlList?; List? excludedTags; if (excludedTagsYaml != null) { @@ -419,6 +425,7 @@ class SWPConfig { fallbackClient: fallbackClient ?? dc.fallbackClient, mergeOutputs: mergeOutputs ?? dc.mergeOutputs, dartMappableConvenientWhen: dartMappableConvenientWhen, + useDartMappableNaming: useDartMappableNaming ?? dc.useDartMappableNaming, includeIfNull: includeIfNull ?? dc.includeIfNull, inferRequiredFromNullable: inferRequiredFromNullable ?? dc.inferRequiredFromNullable, @@ -476,6 +483,18 @@ class SWPConfig { /// Optional. Current available serializers are: json_serializable, freezed, dart_mappable. final JsonSerializer jsonSerializer; + /// DART ONLY + /// Optional, defaults to false. Set to true to use the standard `toMap` and `fromMap` serialization from + /// dart_mappable. This is a new feature introduced in Retrofit 4.9.2. Prior to this + /// it was required to rename these methods in the build.yaml to `fromJson` and `toJson` + /// to make dart_mappable compatible with retrofit. To avoid breaking changes for existing + /// dart_mappable implementations, this flag must be explicitely set to true + /// + /// This flag exists to avoid making dart_mappable serialization the default behavior. + // TODO(carapacik): This flag can be removed in the next major version to make the standard + // dart_mappable serialization the default behavior. + final bool useDartMappableNaming; + /// Optional. Set postfix for client classes and files. final String? clientPostfix; @@ -681,6 +700,7 @@ class SWPConfig { useMultipartFile: useMultipartFile, fallbackUnion: fallbackUnion, dartMappableConvenientWhen: dartMappableConvenientWhen, + useDartMappableNaming: useDartMappableNaming, mergeOutputs: mergeOutputs, includeIfNull: includeIfNull, useFlutterCompute: useFlutterCompute, diff --git a/swagger_parser/lib/src/generator/config/generator_config.dart b/swagger_parser/lib/src/generator/config/generator_config.dart index 9dc19e2d..021b34b5 100644 --- a/swagger_parser/lib/src/generator/config/generator_config.dart +++ b/swagger_parser/lib/src/generator/config/generator_config.dart @@ -30,6 +30,7 @@ class GeneratorConfig { this.useMultipartFile = false, this.fallbackUnion, this.dartMappableConvenientWhen = true, + this.useDartMappableNaming = false, this.mergeOutputs = false, this.includeIfNull = false, this.useFlutterCompute = false, @@ -142,6 +143,18 @@ class GeneratorConfig { /// Set 'false' to use only native Dart pattern matching. final bool dartMappableConvenientWhen; + /// DART ONLY + /// Optional, defaults to false. Set to true to use the standard `toMap` and `fromMap` serialization from + /// dart_mappable. This is a new feature introduced in Retrofit 4.9.2. Prior to this + /// it was required to rename these methods in the build.yaml to `fromJson` and `toJson` + /// to make dart_mappable compatible with retrofit. To avoid breaking changes for existing + /// dart_mappable implementations, this flag must be explicitely set to true + /// + /// This flag exists to avoid making dart_mappable serialization the default behavior. + // TODO(carapacik): This flag can be removed in the next major version to make the standard + // dart_mappable serialization the default behavior. + final bool useDartMappableNaming; + /// Optional. Set to true to merge all generated code into a single file. /// /// This is useful when using swagger_parser together with build_runner, which needs to map diff --git a/swagger_parser/lib/src/generator/generator/fill_controller.dart b/swagger_parser/lib/src/generator/generator/fill_controller.dart index edd8e1f4..13dcfa19 100644 --- a/swagger_parser/lib/src/generator/generator/fill_controller.dart +++ b/swagger_parser/lib/src/generator/generator/fill_controller.dart @@ -35,6 +35,7 @@ final class FillController { useFreezed3: config.useFreezed3, useMultipartFile: config.useMultipartFile, dartMappableConvenientWhen: config.dartMappableConvenientWhen, + useDartMappableNaming: config.useDartMappableNaming, includeIfNull: config.includeIfNull, useFlutterCompute: config.useFlutterCompute, fallbackUnion: config.fallbackUnion, @@ -100,6 +101,7 @@ final class FillController { fileName: fileName, jsonSerializer: config.jsonSerializer, generateUrlsConstants: config.generateUrlsConstants, + useDartMappableNaming: config.useDartMappableNaming, ), ); } diff --git a/swagger_parser/lib/src/generator/model/programming_language.dart b/swagger_parser/lib/src/generator/model/programming_language.dart index fbe3ff20..02eee2c0 100644 --- a/swagger_parser/lib/src/generator/model/programming_language.dart +++ b/swagger_parser/lib/src/generator/model/programming_language.dart @@ -51,6 +51,7 @@ enum ProgrammingLanguage { required bool useFreezed3, required bool useMultipartFile, required bool dartMappableConvenientWhen, + required bool useDartMappableNaming, required bool includeIfNull, required List fieldParsers, bool useFlutterCompute = false, @@ -97,6 +98,7 @@ enum ProgrammingLanguage { useMultipartFile: useMultipartFile, fallbackUnion: fallbackUnion, dartMappableConvenientWhen: dartMappableConvenientWhen, + useDartMappableNaming: useDartMappableNaming, useFlutterCompute: useFlutterCompute, ), }; @@ -122,6 +124,7 @@ enum ProgrammingLanguage { required String defaultContentType, required bool useMultipartFile, required bool generateUrlsConstants, + bool useDartMappableNaming = false, bool extrasParameterByDefault = false, bool dioOptionsParameterByDefault = false, bool addOpenApiMetadata = false, @@ -144,6 +147,7 @@ enum ProgrammingLanguage { generateUrlsConstants: generateUrlsConstants, fileName: fileName, jsonSerializer: jsonSerializer, + useDartMappableNaming: useDartMappableNaming, ), kotlin => kotlinRetrofitClientTemplate(restClient: restClient, name: name), diff --git a/swagger_parser/lib/src/generator/templates/dart_dart_mappable_dto_template.dart b/swagger_parser/lib/src/generator/templates/dart_dart_mappable_dto_template.dart index 1eb69c07..38f91998 100644 --- a/swagger_parser/lib/src/generator/templates/dart_dart_mappable_dto_template.dart +++ b/swagger_parser/lib/src/generator/templates/dart_dart_mappable_dto_template.dart @@ -12,6 +12,7 @@ String dartDartMappableDtoTemplate( required bool markFileAsGenerated, required bool useMultipartFile, required bool dartMappableConvenientWhen, + required bool useDartMappableNaming, bool useFlutterCompute = false, String? fallbackUnion, }) { @@ -53,7 +54,11 @@ String dartDartMappableDtoTemplate( // Generate additional classes for undiscriminated unions or discriminated unions with complete mapping final additionalClasses = shouldUseWrapperPattern ? _generateWrapperClasses( - dataClass, className, useMultipartFile, effectiveFallbackUnion) + dataClass: dataClass, + className: className, + useMultipartFile: useMultipartFile, + fallbackUnion: effectiveFallbackUnion, + useDartMappableNaming: useDartMappableNaming) : ''; final serializerClass = @@ -67,7 +72,7 @@ part '$classNameSnake.mapper.dart'; ${descriptionComment(dataClass.description)}@MappableClass(${_getMappableClassAnnotation(dataClass, className, effectiveFallbackUnion)}) ${_classModifier(isUnion: isUnion)}class $className ${parent != null ? "extends $parent " : ""}with ${className}Mappable { -${_generateClassBody(dataClass, className, useMultipartFile, isUnion, dartMappableConvenientWhen, isSimpleDataClass, effectiveFallbackUnion)} +${_generateClassBody(dataClass: dataClass, className: className, useMultipartFile: useMultipartFile, isUnion: isUnion, dartMappableConvenientWhen: dartMappableConvenientWhen, isSimpleDataClass: isSimpleDataClass, useDartMappableNaming: useDartMappableNaming, fallbackUnion: effectiveFallbackUnion)} } $additionalClasses$serializerClass'''; @@ -228,29 +233,36 @@ String _classModifier({required bool isUnion}) { return isUnion ? 'sealed ' : ''; } -String _generateClassBody( - UniversalComponentClass dataClass, - String className, - bool useMultipartFile, - bool isUnion, - bool dartMappableConvenientWhen, - bool isSimpleDataClass, - [String? fallbackUnion]) { +String _generateClassBody({ + required UniversalComponentClass dataClass, + required String className, + required bool useMultipartFile, + required bool isUnion, + required bool dartMappableConvenientWhen, + required bool isSimpleDataClass, + required bool useDartMappableNaming, + String? fallbackUnion, +}) { if (!isUnion) { // Regular class generation return ''' ${indentation(2)}const $className(${getParameters(dataClass)}); ${getFields(dataClass, useMultipartFile: useMultipartFile, isSimpleDataClass: isSimpleDataClass)} ${dartMappableConvenientWhen ? getDiscriminatorConvenienceMethods(dataClass, className, fallbackUnion) : ''} -${indentation(2)}static $className fromJson(Map json) => ${className}Mapper.ensureInitialized().decodeMap<$className>(json); +${indentation(2)}static $className ${useDartMappableNaming ? 'fromMap' : 'fromJson'}(Map json) => ${className}Mapper.ensureInitialized().decodeMap<$className>(json); '''; } // Union class generation if (dataClass.undiscriminatedUnionVariants case final variants? when variants.isNotEmpty) { - return _generateUndiscriminatedUnionBody(className, variants, - useMultipartFile, dartMappableConvenientWhen, fallbackUnion); + return _generateUndiscriminatedUnionBody( + className: className, + variants: variants, + useMultipartFile: useMultipartFile, + dartMappableConvenientWhen: dartMappableConvenientWhen, + useDartMappableNaming: useDartMappableNaming, + fallbackUnion: fallbackUnion); } // Discriminated unions with complete mapping use wrapper pattern @@ -261,7 +273,7 @@ ${indentation(2)}static $className fromJson(Map json) => ${clas ${indentation(2)}const $className(); ${dartMappableConvenientWhen ? getDiscriminatorConvenienceMethods(dataClass, className, fallbackUnion) : ''} -${indentation(2)}static $className fromJson(Map json) { +${indentation(2)}static $className ${useDartMappableNaming ? 'fromMap' : 'fromJson'}(Map json) { ${indentation(4)}return ${_deserializerExtensionName(className)}.tryDeserialize(json); ${indentation(2)}} '''; @@ -272,32 +284,38 @@ ${indentation(2)}} ${indentation(2)}const $className(); ${dartMappableConvenientWhen ? getDiscriminatorConvenienceMethods(dataClass, className, fallbackUnion) : ''} -${indentation(2)}static $className fromJson(Map json) => ${className}Mapper.ensureInitialized().decodeMap<$className>(json); +${indentation(2)}static $className ${useDartMappableNaming ? 'fromMap' : 'fromJson'}(Map json) => ${className}Mapper.ensureInitialized().decodeMap<$className>(json); '''; } -String _generateUndiscriminatedUnionBody( - String className, - Map> variants, - bool useMultipartFile, - bool dartMappableConvenientWhen, - [String? fallbackUnion]) { +String _generateUndiscriminatedUnionBody({ + required String className, + required Map> variants, + required bool useMultipartFile, + required bool dartMappableConvenientWhen, + required bool useDartMappableNaming, + String? fallbackUnion, +}) { return ''' ${indentation(2)}const $className(); ${dartMappableConvenientWhen ? '\n${_generateUndiscriminatedUnionConvenienceMethods(className, variants, fallbackUnion)}' : ''} -${indentation(2)}static $className fromJson(Map json) { +${indentation(2)}static $className ${useDartMappableNaming ? 'fromMap' : 'fromJson'}(Map json) { ${indentation(4)}return ${_deserializerExtensionName(className)}.tryDeserialize(json); ${indentation(2)}} '''; } -String _generateUndiscriminatedUnionClasses(String className, - Map> variants, bool useMultipartFile, - [String? fallbackUnion]) { +String _generateUndiscriminatedUnionClasses({ + required String className, + required Map> variants, + required bool useMultipartFile, + required bool useDartMappableNaming, + String? fallbackUnion, +}) { return ''' -${_generateUndiscriminatedMappableExtension(className, variants, fallbackUnion)} +${_generateUndiscriminatedMappableExtension(className: className, variants: variants, useMultipartFile: useMultipartFile, useDartMappableNaming: useDartMappableNaming, fallbackUnion: fallbackUnion)} -${_generateVariantWrappers(className, variants, useMultipartFile, fallbackUnion)}'''; +${_generateVariantWrappers(className: className, variants: variants, useMultipartFile: useMultipartFile, useDartMappableNaming: useDartMappableNaming, fallbackUnion: fallbackUnion)}'''; } String _generateUndiscriminatedUnionConvenienceMethods( @@ -364,9 +382,13 @@ ${indentation(2)}} '''; } -String _generateUndiscriminatedMappableExtension( - String className, Map> variants, - [String? fallbackUnion]) { +String _generateUndiscriminatedMappableExtension({ + required String className, + required Map> variants, + required bool useMultipartFile, + required bool useDartMappableNaming, + String? fallbackUnion, +}) { final tryBlocks = variants.keys .map( (variantName) => ''' @@ -496,9 +518,13 @@ String _deserializerExtensionName(String className) => ? '${className}Deserializer' : '${className}SealedDeserializer'; -String _generateVariantWrappers(String className, - Map> variants, bool useMultipartFile, - [String? fallbackUnion]) { +String _generateVariantWrappers({ + required String className, + required Map> variants, + required bool useMultipartFile, + required bool useDartMappableNaming, + String? fallbackUnion, +}) { final regularWrappers = variants.entries.map((entry) { final variantName = entry.key; final properties = entry.value; @@ -548,7 +574,7 @@ ${indentation(2)}const $className${fallbackUnion.toPascal}(this._json); ${indentation(2)}/// Access raw JSON data for unknown union variant ${indentation(2)}Map get json => _json; -${indentation(2)}static $className${fallbackUnion.toPascal} fromJson(Map json) => +${indentation(2)}static $className${fallbackUnion.toPascal} ${useDartMappableNaming ? 'fromMap' : 'fromJson'}(Map json) => ${indentation(6)}$className${fallbackUnion.toPascal}(json); } ''' @@ -668,30 +694,45 @@ bool _isCompleteDiscriminatorMapping(Discriminator discriminator) { return discriminator.discriminatorValueToRefMapping.isNotEmpty; } -String _generateWrapperClasses(UniversalComponentClass dataClass, - String className, bool useMultipartFile, String? fallbackUnion) { +String _generateWrapperClasses({ + required UniversalComponentClass dataClass, + required String className, + required bool useMultipartFile, + required bool useDartMappableNaming, + String? fallbackUnion, +}) { // Handle undiscriminated unions if (dataClass.undiscriminatedUnionVariants?.isNotEmpty ?? false) { return _generateUndiscriminatedUnionClasses( - className, - dataClass.undiscriminatedUnionVariants!, - useMultipartFile, - fallbackUnion); + className: className, + variants: dataClass.undiscriminatedUnionVariants!, + useMultipartFile: useMultipartFile, + useDartMappableNaming: useDartMappableNaming, + fallbackUnion: fallbackUnion); } // Handle discriminated unions with complete mapping using wrapper pattern if (dataClass.discriminator != null && _isCompleteDiscriminatorMapping(dataClass.discriminator!)) { final wrappers = _generateDiscriminatedWrapperClasses( - dataClass, className, useMultipartFile, fallbackUnion); + dataClass: dataClass, + className: className, + useMultipartFile: useMultipartFile, + useDartMappableNaming: useDartMappableNaming, + fallbackUnion: fallbackUnion); return wrappers; } return ''; } -String _generateDiscriminatedWrapperClasses(UniversalComponentClass dataClass, - String className, bool useMultipartFile, String? fallbackUnion) { +String _generateDiscriminatedWrapperClasses({ + required UniversalComponentClass dataClass, + required String className, + required bool useMultipartFile, + required bool useDartMappableNaming, + String? fallbackUnion, +}) { final discriminator = dataClass.discriminator!; final wrappers = []; @@ -747,7 +788,7 @@ ${indentation(2)}const $className${fallbackUnion.toPascal}(this._json); ${indentation(2)}/// Access raw JSON data for unknown union variant ${indentation(2)}Map get json => _json; -${indentation(2)}static $className${fallbackUnion.toPascal} fromJson(Map json) => +${indentation(2)}static $className${fallbackUnion.toPascal} ${useDartMappableNaming ? 'fromMap' : 'fromJson'}(Map json) => ${indentation(6)}$className${fallbackUnion.toPascal}(json); }'''); } diff --git a/swagger_parser/lib/src/generator/templates/dart_retrofit_client_template.dart b/swagger_parser/lib/src/generator/templates/dart_retrofit_client_template.dart index 3368e677..f78b6f0b 100644 --- a/swagger_parser/lib/src/generator/templates/dart_retrofit_client_template.dart +++ b/swagger_parser/lib/src/generator/templates/dart_retrofit_client_template.dart @@ -15,6 +15,7 @@ String dartRetrofitClientTemplate({ required String defaultContentType, required bool useMultipartFile, required bool generateUrlsConstants, + bool useDartMappableNaming = false, bool extrasParameterByDefault = false, bool dioOptionsParameterByDefault = false, bool addOpenApiMetadata = false, @@ -35,7 +36,9 @@ String dartRetrofitClientTemplate({ // Determine @RestApi annotation final restApiAnnotation = useFlutterCompute ? '@RestApi(parser: Parser.FlutterCompute)' - : '@RestApi()'; + : jsonSerializer == JsonSerializer.dartMappable && useDartMappableNaming + ? '@RestApi(parser: Parser.DartMappable)' + : '@RestApi()'; // Flutter foundation import for compute function final flutterComputeImport = useFlutterCompute diff --git a/swagger_parser/test/generator/data_classes_test.dart b/swagger_parser/test/generator/data_classes_test.dart index 2320bd32..0cbf1036 100644 --- a/swagger_parser/test/generator/data_classes_test.dart +++ b/swagger_parser/test/generator/data_classes_test.dart @@ -461,6 +461,37 @@ class ClassName with ClassNameMappable { expect(filledContent.content, equalsIgnoringWhitespace(expectedContents)); }); + test('dart + dart_mappable + useDartMappableNaming: true', () async { + const dataClass = UniversalComponentClass( + name: 'ClassName', + imports: {}, + parameters: {}, + ); + const fillController = FillController( + config: GeneratorConfig( + name: '', + outputDirectory: '', + jsonSerializer: JsonSerializer.dartMappable, + useDartMappableNaming: true, + ), + ); + final filledContent = fillController.fillDtoContent(dataClass); + const expectedContents = ''' +import 'package:dart_mappable/dart_mappable.dart'; + +part 'class_name.mapper.dart'; + +@MappableClass() +class ClassName with ClassNameMappable { + + const ClassName(); + + static ClassName fromMap(Map json) => ClassNameMapper.ensureInitialized().decodeMap(json); +} +'''; + expect(filledContent.content, equalsIgnoringWhitespace(expectedContents)); + }); + test('dart + dart_mappable with custom json key', () async { final dataClass = UniversalComponentClass( name: 'ClassName', diff --git a/swagger_parser/test/generator/rest_clients_test.dart b/swagger_parser/test/generator/rest_clients_test.dart index 42a5b7df..1e470b24 100644 --- a/swagger_parser/test/generator/rest_clients_test.dart +++ b/swagger_parser/test/generator/rest_clients_test.dart @@ -1,7 +1,4 @@ -import 'package:swagger_parser/src/generator/config/generator_config.dart'; -import 'package:swagger_parser/src/generator/generator/fill_controller.dart'; -import 'package:swagger_parser/src/generator/model/programming_language.dart'; -import 'package:swagger_parser/src/parser/swagger_parser_core.dart'; +import 'package:swagger_parser/swagger_parser.dart'; import 'package:test/test.dart'; void main() { @@ -22,6 +19,62 @@ import 'package:retrofit/retrofit.dart'; part 'some_client.g.dart'; +@RestApi() +abstract class SomeClient { + factory SomeClient(Dio dio, {String? baseUrl}) = _SomeClient; +} +'''; + expect(filledContent.content, expectedContents); + }); + + test('dart + retrofit + use_dart_mappable_naming: true', () async { + const restClient = UniversalRestClient( + name: 'Some', + imports: {}, + requests: [], + ); + const fillController = FillController( + config: GeneratorConfig( + name: '', + outputDirectory: '', + jsonSerializer: JsonSerializer.dartMappable, + useDartMappableNaming: true), + ); + final filledContent = fillController.fillRestClientContent(restClient); + const expectedContents = ''' +import 'package:dio/dio.dart'; +import 'package:retrofit/retrofit.dart'; + +part 'some_client.g.dart'; + +@RestApi(parser: Parser.DartMappable) +abstract class SomeClient { + factory SomeClient(Dio dio, {String? baseUrl}) = _SomeClient; +} +'''; + expect(filledContent.content, expectedContents); + }); + + test('dart + retrofit + use_dart_mappable_naming: false', () async { + const restClient = UniversalRestClient( + name: 'Some', + imports: {}, + requests: [], + ); + const fillController = FillController( + config: GeneratorConfig( + name: '', + outputDirectory: '', + jsonSerializer: JsonSerializer.dartMappable, + ), + ); + final filledContent = fillController.fillRestClientContent(restClient); + const expectedContents = ''' +import 'package:dio/dio.dart'; +import 'package:retrofit/retrofit.dart'; + +part 'some_client.g.dart'; + @RestApi() abstract class SomeClient { factory SomeClient(Dio dio, {String? baseUrl}) = _SomeClient;