From 3fa8a321a1bf4c34ed4fbc67daf5336cf307e1c2 Mon Sep 17 00:00:00 2001 From: Theo Lee Date: Fri, 20 Oct 2023 11:00:57 +0800 Subject: [PATCH 1/4] Add an option for generating http response --- swagger_parser/lib/src/config/yaml_config.dart | 10 ++++++++++ swagger_parser/lib/src/generator/generator.dart | 7 +++++++ .../lib/src/generator/models/universal_request.dart | 4 ++++ .../templates/dart_retrofit_client_template.dart | 5 ++++- swagger_parser/lib/src/parser/parser.dart | 4 ++++ 5 files changed, 29 insertions(+), 1 deletion(-) diff --git a/swagger_parser/lib/src/config/yaml_config.dart b/swagger_parser/lib/src/config/yaml_config.dart index 94274c44..6d1ec211 100644 --- a/swagger_parser/lib/src/config/yaml_config.dart +++ b/swagger_parser/lib/src/config/yaml_config.dart @@ -37,6 +37,7 @@ final class YamlConfig { this.enumsToJson, this.enumsPrefix, this.markFilesAsGenerated, + this.withHttpResponse, this.replacementRules = const [], }); @@ -209,6 +210,13 @@ final class YamlConfig { ); } + final withHttpResponse = yamlConfig['with_http_response']; + if (withHttpResponse is! bool?) { + throw const ConfigException( + "Config parameter 'with_http_response' must be bool.", + ); + } + final rawReplacementRules = yamlConfig['replacement_rules']; if (rawReplacementRules is! YamlList?) { throw const ConfigException( @@ -254,6 +262,7 @@ final class YamlConfig { putClientsInFolder: putClientsInFolder ?? rootConfig?.putClientsInFolder, squashClients: squashClients ?? rootConfig?.squashClients, pathMethodName: pathMethodName ?? rootConfig?.pathMethodName, + withHttpResponse: withHttpResponse ?? rootConfig?.withHttpResponse, enumsToJson: enumsToJson ?? rootConfig?.enumsToJson, enumsPrefix: enumsPrefix ?? rootConfig?.enumsPrefix, markFilesAsGenerated: @@ -352,5 +361,6 @@ final class YamlConfig { final bool? enumsToJson; final bool? enumsPrefix; final bool? markFilesAsGenerated; + final bool? withHttpResponse; final List replacementRules; } diff --git a/swagger_parser/lib/src/generator/generator.dart b/swagger_parser/lib/src/generator/generator.dart index ab13ef9d..38196d9c 100644 --- a/swagger_parser/lib/src/generator/generator.dart +++ b/swagger_parser/lib/src/generator/generator.dart @@ -40,6 +40,7 @@ final class Generator { String? rootClientName, bool? putClientsInFolder, bool? squashClients, + bool? withHttpResponse, bool? pathMethodName, bool? putInFolder, bool? enumsToJson, @@ -61,6 +62,7 @@ final class Generator { _clientPostfix = clientPostfix ?? 'Client', _putClientsInFolder = putClientsInFolder ?? false, _squashClients = squashClients ?? false, + _withHttpResponse = withHttpResponse ?? false, _pathMethodName = pathMethodName ?? false, _putInFolder = putInFolder ?? false, _enumsToJson = enumsToJson ?? false, @@ -84,6 +86,7 @@ final class Generator { clientPostfix: yamlConfig.clientPostfix, putClientsInFolder: yamlConfig.putClientsInFolder, squashClients: yamlConfig.squashClients, + withHttpResponse: yamlConfig.withHttpResponse, pathMethodName: yamlConfig.pathMethodName, putInFolder: yamlConfig.putInFolder, enumsToJson: yamlConfig.enumsToJson, @@ -138,6 +141,9 @@ final class Generator { /// Squash all clients in one client. final bool _squashClients; + /// Generate request methods with http response. + final bool _withHttpResponse; + /// If true, use the endpoint path for the method name, if false, use operationId final bool _pathMethodName; @@ -257,6 +263,7 @@ final class Generator { name: _name, squashClients: _squashClients, replacementRules: _replacementRules, + withHttpResponse: _withHttpResponse, ); _openApiInfo = parser.parseOpenApiInfo(); _restClients = parser.parseRestClients(); diff --git a/swagger_parser/lib/src/generator/models/universal_request.dart b/swagger_parser/lib/src/generator/models/universal_request.dart index db15ac31..f57c98ca 100644 --- a/swagger_parser/lib/src/generator/models/universal_request.dart +++ b/swagger_parser/lib/src/generator/models/universal_request.dart @@ -16,6 +16,7 @@ final class UniversalRequest { this.isMultiPart = false, this.isFormUrlEncoded = false, this.isDeprecated = false, + this.isWithHttpResponse = false, }); /// Request name @@ -45,6 +46,9 @@ final class UniversalRequest { /// Value indicating whether this request is deprecated final bool isDeprecated; + /// Wrap request return type with HttpResponse. + final bool isWithHttpResponse; + @override bool operator ==(Object other) => identical(this, other) || 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 3917839a..4488251b 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 @@ -35,11 +35,14 @@ abstract class $name { } String _toClientRequest(UniversalRequest request) { + final responseType = request.returnType == null + ? 'void' + : request.returnType!.toSuitableType(ProgrammingLanguage.dart); final sb = StringBuffer( ''' ${descriptionComment(request.description, tabForFirstLine: false, tab: ' ', end: ' ')}${request.isDeprecated ? "@Deprecated('This method is marked as deprecated')\n " : ''}${request.isMultiPart ? '@MultiPart()\n ' : ''}${request.isFormUrlEncoded ? '@FormUrlEncoded()\n ' : ''}@${request.requestType.name.toUpperCase()}('${request.route}') - Future<${request.returnType == null ? 'void' : request.returnType!.toSuitableType(ProgrammingLanguage.dart)}> ${request.name}(''', + Future<${request.isWithHttpResponse ? 'HttpResponse<$responseType>' : responseType}> ${request.name}(''', ); if (request.parameters.isNotEmpty) { sb.write('{\n'); diff --git a/swagger_parser/lib/src/parser/parser.dart b/swagger_parser/lib/src/parser/parser.dart index 919138ca..1db58990 100644 --- a/swagger_parser/lib/src/parser/parser.dart +++ b/swagger_parser/lib/src/parser/parser.dart @@ -29,11 +29,13 @@ class OpenApiParser { bool enumsPrefix = false, bool pathMethodName = false, bool squashClients = false, + bool withHttpResponse = false, List replacementRules = const [], }) : _name = name, _pathMethodName = pathMethodName, _enumsPrefix = enumsPrefix, _squashClients = squashClients, + _withHttpResponse = withHttpResponse, _replacementRules = replacementRules { _definitionFileContent = isYaml ? (loadYaml(fileContent) as YamlMap).toMap() @@ -62,6 +64,7 @@ class OpenApiParser { final bool _enumsPrefix; final String? _name; final bool _squashClients; + final bool _withHttpResponse; final List _replacementRules; late final Map _definitionFileContent; late final OAS _version; @@ -472,6 +475,7 @@ class OpenApiParser { route: path, isMultiPart: isMultiPart, isFormUrlEncoded: isFormUrlEncoded, + isWithHttpResponse: _withHttpResponse, returnType: returnType, parameters: parameters, isDeprecated: requestPath[_deprecatedConst].toString().toBool(), From 976b765f0525cbf1f6a6c878763f8dedc9619c00 Mon Sep 17 00:00:00 2001 From: Roman Laptev Date: Fri, 20 Oct 2023 09:22:44 +0300 Subject: [PATCH 2/4] Rename to `original_http_response` --- swagger_parser/CHANGELOG.md | 3 +++ swagger_parser/README.md | 3 +++ swagger_parser/lib/src/config/yaml_config.dart | 13 +++++++------ swagger_parser/lib/src/generator/generator.dart | 12 ++++++------ .../lib/src/generator/models/universal_request.dart | 6 +++--- .../templates/dart_retrofit_client_template.dart | 2 +- swagger_parser/lib/src/parser/parser.dart | 8 ++++---- swagger_parser/pubspec.yaml | 2 +- 8 files changed, 28 insertions(+), 21 deletions(-) diff --git a/swagger_parser/CHANGELOG.md b/swagger_parser/CHANGELOG.md index adb751a8..562be08b 100644 --- a/swagger_parser/CHANGELOG.md +++ b/swagger_parser/CHANGELOG.md @@ -1,3 +1,6 @@ +## 1.10.3 +- Add new config parameter `original_http_response`(only for dart) ([#115](https://github.com/Carapacik/swagger_parser/issues/115)) + ## 1.10.2 - Fix error in `body` with name in dart template diff --git a/swagger_parser/README.md b/swagger_parser/README.md index 500f488d..bd14dea9 100644 --- a/swagger_parser/README.md +++ b/swagger_parser/README.md @@ -110,6 +110,9 @@ swagger_parser: # Optional. Set 'false' to not put a comment at the beginning of the generated files. mark_files_as_generated: true + # Optional (dart only). Set 'true' to wrap all request return types with HttpResponse. + original_http_response: false + # Optional. Set regex replacement rules for the names of the generated classes/enums. # All rules are applied in order. replacement_rules: diff --git a/swagger_parser/lib/src/config/yaml_config.dart b/swagger_parser/lib/src/config/yaml_config.dart index 6d1ec211..2896bb2f 100644 --- a/swagger_parser/lib/src/config/yaml_config.dart +++ b/swagger_parser/lib/src/config/yaml_config.dart @@ -37,7 +37,7 @@ final class YamlConfig { this.enumsToJson, this.enumsPrefix, this.markFilesAsGenerated, - this.withHttpResponse, + this.originalHttpResponse, this.replacementRules = const [], }); @@ -210,10 +210,10 @@ final class YamlConfig { ); } - final withHttpResponse = yamlConfig['with_http_response']; - if (withHttpResponse is! bool?) { + final originalHttpResponse = yamlConfig['original_http_response']; + if (originalHttpResponse is! bool?) { throw const ConfigException( - "Config parameter 'with_http_response' must be bool.", + "Config parameter 'original_http_response' must be bool.", ); } @@ -262,7 +262,8 @@ final class YamlConfig { putClientsInFolder: putClientsInFolder ?? rootConfig?.putClientsInFolder, squashClients: squashClients ?? rootConfig?.squashClients, pathMethodName: pathMethodName ?? rootConfig?.pathMethodName, - withHttpResponse: withHttpResponse ?? rootConfig?.withHttpResponse, + originalHttpResponse: + originalHttpResponse ?? rootConfig?.originalHttpResponse, enumsToJson: enumsToJson ?? rootConfig?.enumsToJson, enumsPrefix: enumsPrefix ?? rootConfig?.enumsPrefix, markFilesAsGenerated: @@ -361,6 +362,6 @@ final class YamlConfig { final bool? enumsToJson; final bool? enumsPrefix; final bool? markFilesAsGenerated; - final bool? withHttpResponse; + final bool? originalHttpResponse; final List replacementRules; } diff --git a/swagger_parser/lib/src/generator/generator.dart b/swagger_parser/lib/src/generator/generator.dart index 38196d9c..de3f9c10 100644 --- a/swagger_parser/lib/src/generator/generator.dart +++ b/swagger_parser/lib/src/generator/generator.dart @@ -40,7 +40,7 @@ final class Generator { String? rootClientName, bool? putClientsInFolder, bool? squashClients, - bool? withHttpResponse, + bool? originalHttpResponse, bool? pathMethodName, bool? putInFolder, bool? enumsToJson, @@ -62,7 +62,7 @@ final class Generator { _clientPostfix = clientPostfix ?? 'Client', _putClientsInFolder = putClientsInFolder ?? false, _squashClients = squashClients ?? false, - _withHttpResponse = withHttpResponse ?? false, + _originalHttpResponse = originalHttpResponse ?? false, _pathMethodName = pathMethodName ?? false, _putInFolder = putInFolder ?? false, _enumsToJson = enumsToJson ?? false, @@ -86,7 +86,7 @@ final class Generator { clientPostfix: yamlConfig.clientPostfix, putClientsInFolder: yamlConfig.putClientsInFolder, squashClients: yamlConfig.squashClients, - withHttpResponse: yamlConfig.withHttpResponse, + originalHttpResponse: yamlConfig.originalHttpResponse, pathMethodName: yamlConfig.pathMethodName, putInFolder: yamlConfig.putInFolder, enumsToJson: yamlConfig.enumsToJson, @@ -141,8 +141,8 @@ final class Generator { /// Squash all clients in one client. final bool _squashClients; - /// Generate request methods with http response. - final bool _withHttpResponse; + /// Generate request methods with HttpResponse + final bool _originalHttpResponse; /// If true, use the endpoint path for the method name, if false, use operationId final bool _pathMethodName; @@ -263,7 +263,7 @@ final class Generator { name: _name, squashClients: _squashClients, replacementRules: _replacementRules, - withHttpResponse: _withHttpResponse, + originalHttpResponse: _originalHttpResponse, ); _openApiInfo = parser.parseOpenApiInfo(); _restClients = parser.parseRestClients(); diff --git a/swagger_parser/lib/src/generator/models/universal_request.dart b/swagger_parser/lib/src/generator/models/universal_request.dart index f57c98ca..d61894aa 100644 --- a/swagger_parser/lib/src/generator/models/universal_request.dart +++ b/swagger_parser/lib/src/generator/models/universal_request.dart @@ -16,7 +16,7 @@ final class UniversalRequest { this.isMultiPart = false, this.isFormUrlEncoded = false, this.isDeprecated = false, - this.isWithHttpResponse = false, + this.isOriginalHttpResponse = false, }); /// Request name @@ -46,8 +46,8 @@ final class UniversalRequest { /// Value indicating whether this request is deprecated final bool isDeprecated; - /// Wrap request return type with HttpResponse. - final bool isWithHttpResponse; + /// Wrap request return type with HttpResponse + final bool isOriginalHttpResponse; @override bool operator ==(Object other) => 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 4488251b..87a64bb5 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 @@ -42,7 +42,7 @@ String _toClientRequest(UniversalRequest request) { ''' ${descriptionComment(request.description, tabForFirstLine: false, tab: ' ', end: ' ')}${request.isDeprecated ? "@Deprecated('This method is marked as deprecated')\n " : ''}${request.isMultiPart ? '@MultiPart()\n ' : ''}${request.isFormUrlEncoded ? '@FormUrlEncoded()\n ' : ''}@${request.requestType.name.toUpperCase()}('${request.route}') - Future<${request.isWithHttpResponse ? 'HttpResponse<$responseType>' : responseType}> ${request.name}(''', + Future<${request.isOriginalHttpResponse ? 'HttpResponse<$responseType>' : responseType}> ${request.name}(''', ); if (request.parameters.isNotEmpty) { sb.write('{\n'); diff --git a/swagger_parser/lib/src/parser/parser.dart b/swagger_parser/lib/src/parser/parser.dart index 1db58990..04c2fff1 100644 --- a/swagger_parser/lib/src/parser/parser.dart +++ b/swagger_parser/lib/src/parser/parser.dart @@ -29,13 +29,13 @@ class OpenApiParser { bool enumsPrefix = false, bool pathMethodName = false, bool squashClients = false, - bool withHttpResponse = false, + bool originalHttpResponse = false, List replacementRules = const [], }) : _name = name, _pathMethodName = pathMethodName, _enumsPrefix = enumsPrefix, _squashClients = squashClients, - _withHttpResponse = withHttpResponse, + _originalHttpResponse = originalHttpResponse, _replacementRules = replacementRules { _definitionFileContent = isYaml ? (loadYaml(fileContent) as YamlMap).toMap() @@ -64,7 +64,7 @@ class OpenApiParser { final bool _enumsPrefix; final String? _name; final bool _squashClients; - final bool _withHttpResponse; + final bool _originalHttpResponse; final List _replacementRules; late final Map _definitionFileContent; late final OAS _version; @@ -475,7 +475,7 @@ class OpenApiParser { route: path, isMultiPart: isMultiPart, isFormUrlEncoded: isFormUrlEncoded, - isWithHttpResponse: _withHttpResponse, + isOriginalHttpResponse: _originalHttpResponse, returnType: returnType, parameters: parameters, isDeprecated: requestPath[_deprecatedConst].toString().toBool(), diff --git a/swagger_parser/pubspec.yaml b/swagger_parser/pubspec.yaml index 19e3839d..93fa70d6 100644 --- a/swagger_parser/pubspec.yaml +++ b/swagger_parser/pubspec.yaml @@ -1,6 +1,6 @@ name: swagger_parser description: Package that generates REST clients and data classes from OpenApi definition file -version: 1.10.2 +version: 1.10.3 repository: https://github.com/Carapacik/swagger_parser/tree/main/swagger_parser homepage: https://omega-r.com topics: From b4a4698fa1c3c351e256369e387680d77fae1463 Mon Sep 17 00:00:00 2001 From: Theo Lee Date: Fri, 20 Oct 2023 16:42:51 +0800 Subject: [PATCH 3/4] Fix bug when additionalProperties has ref. --- swagger_parser/lib/src/parser/parser.dart | 32 ++++++++++++++++------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/swagger_parser/lib/src/parser/parser.dart b/swagger_parser/lib/src/parser/parser.dart index 04c2fff1..75338cf2 100644 --- a/swagger_parser/lib/src/parser/parser.dart +++ b/swagger_parser/lib/src/parser/parser.dart @@ -793,6 +793,8 @@ class OpenApiParser { (map[_propertiesConst] as Map).isNotEmpty) || (map.containsKey(_additionalPropertiesConst) && (map[_additionalPropertiesConst] is Map) && + !(map[_additionalPropertiesConst] as Map) + .containsKey(_refConst) && (map[_additionalPropertiesConst] as Map) .isNotEmpty)) { // false positive result @@ -935,16 +937,26 @@ class OpenApiParser { } // Type or ref else { - var type = map.containsKey(_typeConst) - ? map.containsKey(_refConst) && - map[_typeConst].toString() == _objectConst - ? _formatRef(map) - : map[_typeConst].toString() - : map.containsKey(_refConst) - ? _formatRef(map) - : _objectConst; - - var import = map.containsKey(_refConst) ? _formatRef(map) : null; + String? import; + String type; + + if (map.containsKey(_refConst)) { + import = _formatRef(map); + } else if (map.containsKey(_additionalPropertiesConst) && + map[_additionalPropertiesConst] is Map && + (map[_additionalPropertiesConst] as Map) + .containsKey(_refConst)) { + import = + _formatRef(map[_additionalPropertiesConst] as Map); + } + + if (map.containsKey(_typeConst)) { + type = import != null && map[_typeConst].toString() == _objectConst + ? import + : map[_typeConst].toString(); + } else { + type = import ?? _objectConst; + } if (import != null) { for (final replacementRule in _replacementRules) { From 0b392eb6d314adde0e5dbffcf9b4a36f41a7f849 Mon Sep 17 00:00:00 2001 From: Roman Laptev Date: Fri, 20 Oct 2023 16:47:47 +0300 Subject: [PATCH 4/4] Version --- swagger_parser/CHANGELOG.md | 3 +++ swagger_parser/lib/src/parser/parser.dart | 15 +++++++-------- swagger_parser/pubspec.yaml | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/swagger_parser/CHANGELOG.md b/swagger_parser/CHANGELOG.md index 562be08b..e42d251e 100644 --- a/swagger_parser/CHANGELOG.md +++ b/swagger_parser/CHANGELOG.md @@ -1,3 +1,6 @@ +## 1.10.4 +- Fix bug with `additionalProperties` ([#114](https://github.com/Carapacik/swagger_parser/issues/114)) + ## 1.10.3 - Add new config parameter `original_http_response`(only for dart) ([#115](https://github.com/Carapacik/swagger_parser/issues/115)) diff --git a/swagger_parser/lib/src/parser/parser.dart b/swagger_parser/lib/src/parser/parser.dart index 75338cf2..441ea6d1 100644 --- a/swagger_parser/lib/src/parser/parser.dart +++ b/swagger_parser/lib/src/parser/parser.dart @@ -793,13 +793,12 @@ class OpenApiParser { (map[_propertiesConst] as Map).isNotEmpty) || (map.containsKey(_additionalPropertiesConst) && (map[_additionalPropertiesConst] is Map) && - !(map[_additionalPropertiesConst] as Map) - .containsKey(_refConst) && (map[_additionalPropertiesConst] as Map) - .isNotEmpty)) { + .isNotEmpty && + !(map[_additionalPropertiesConst] as Map) + .containsKey(_refConst))) { // false positive result - // ignore: unnecessary_null_checks - final (newName!, description) = protectName( + final (newName, description) = protectName( name ?? additionalName, uniqueIfNull: true, description: map[_descriptionConst]?.toString(), @@ -836,10 +835,10 @@ class OpenApiParser { ); } - if (_objectClasses.where((oc) => oc.name == newName.toPascal).isEmpty) { + if (_objectClasses.where((oc) => oc.name == newName!.toPascal).isEmpty) { _objectClasses.add( UniversalComponentClass( - name: newName.toPascal, + name: newName!.toPascal, imports: typeWithImports .where((e) => e.import != null) .map((e) => e.import!) @@ -851,7 +850,7 @@ class OpenApiParser { return ( type: UniversalType( - type: newName.toPascal, + type: newName!.toPascal, name: newName.toCamel, description: description, format: map.containsKey(_formatConst) diff --git a/swagger_parser/pubspec.yaml b/swagger_parser/pubspec.yaml index 93fa70d6..5a07a3e2 100644 --- a/swagger_parser/pubspec.yaml +++ b/swagger_parser/pubspec.yaml @@ -1,6 +1,6 @@ name: swagger_parser description: Package that generates REST clients and data classes from OpenApi definition file -version: 1.10.3 +version: 1.10.4 repository: https://github.com/Carapacik/swagger_parser/tree/main/swagger_parser homepage: https://omega-r.com topics: