Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix multipart requests generation #155

Merged
merged 7 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.vscode
3 changes: 2 additions & 1 deletion swagger_parser/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
.packages
build/
pubspec.lock
.idea/
.idea/
swagger_parser.yaml
6 changes: 3 additions & 3 deletions swagger_parser/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ swagger_parser:
prefer_schema_source: url

# Optional (dart only).
# Current available serializers are: 'json_serializable', 'freezed' and 'dart_mappable'.
# Current available serializers are: json_serializable, freezed, dart_mappable.
json_serializer: json_serializable

# Optional (dart only). Set 'true' to generate root client
Expand Down Expand Up @@ -155,13 +155,13 @@ swagger_parser:
schemas:
- schema_path: schemas/openapi.json
root_client_name: ApiMicroservice
jsonSerializer: "freezed"
json_serializer: freezed
put_in_folder: true
replacement_rules: []

- schema_url: https://petstore.swagger.io/v2/swagger.json
name: pet_service_dart_mappable
jsonSerializer: "dart_mappable"
json_serializer: dart_mappable
client_postfix: Service
put_clients_in_folder: true
put_in_folder: true
Expand Down
2 changes: 2 additions & 0 deletions swagger_parser/example/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
lib/**

schemas/debug.json
6 changes: 3 additions & 3 deletions swagger_parser/example/swagger_parser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ swagger_parser:
prefer_schema_source: url

# Optional (dart only).
# Current available serializers are: 'json_serializable', 'freezed' and 'dart_mappable'.
# Current available serializers are: json_serializable, freezed, dart_mappable.
json_serializer: json_serializable

# Optional (dart only). Set 'true' to generate root client
Expand Down Expand Up @@ -81,13 +81,13 @@ swagger_parser:
schemas:
- schema_path: schemas/openapi.json
root_client_name: ApiMicroservice
jsonSerializer: "freezed"
json_serializer: freezed
put_in_folder: true
replacement_rules: []

- schema_url: https://petstore.swagger.io/v2/swagger.json
name: pet_service_dart_mappable
jsonSerializer: "dart_mappable"
json_serializer: dart_mappable
client_postfix: Service
put_clients_in_folder: true
put_in_folder: true
Expand Down
17 changes: 13 additions & 4 deletions swagger_parser/lib/src/generator/models/universal_type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ final class UniversalType {
this.isRequired = true,
this.nullable = false,
this.arrayDepth = 0,
this.arrayValueNullable = false,
this.enumType,
this.mapType,
});
Expand Down Expand Up @@ -52,6 +53,9 @@ final class UniversalType {
/// List<List<Object>>
final int arrayDepth;

/// Whether or not this field is nullable
final bool arrayValueNullable;

/// Whether or not this field is nullable
final bool nullable;

Expand All @@ -71,6 +75,7 @@ final class UniversalType {
int? arrayDepth,
bool? nullable,
String? mapType,
bool? arrayValueNullable,
}) {
return UniversalType(
type: type ?? this.type,
Expand All @@ -84,6 +89,7 @@ final class UniversalType {
arrayDepth: arrayDepth ?? this.arrayDepth,
nullable: nullable ?? this.nullable,
mapType: mapType ?? this.mapType,
arrayValueNullable: arrayValueNullable ?? this.arrayValueNullable,
);
}

Expand Down Expand Up @@ -113,7 +119,8 @@ final class UniversalType {
enumType == other.enumType &&
arrayDepth == other.arrayDepth &&
nullable == other.nullable &&
mapType == other.mapType;
mapType == other.mapType &&
arrayValueNullable == other.arrayValueNullable;

@override
int get hashCode =>
Expand All @@ -127,11 +134,12 @@ final class UniversalType {
enumType.hashCode ^
arrayDepth.hashCode ^
nullable.hashCode ^
mapType.hashCode;
mapType.hashCode ^
arrayValueNullable.hashCode;

@override
String toString() =>
'UniversalType(\ntype: $type,\nname: $name,\ndescription: $description,\nformat: $format,\njsonKey: $jsonKey,\ndefaultValue: $defaultValue,\nisRequired: $isRequired,\nenumType: $enumType,\narrayDepth: $arrayDepth,\nnullable: $nullable\n, mapType: $mapType\n)';
'UniversalType(\ntype: $type,\nname: $name,\ndescription: $description,\nformat: $format,\njsonKey: $jsonKey,\ndefaultValue: $defaultValue,\nisRequired: $isRequired,\nenumType: $enumType,\narrayDepth: $arrayDepth,\nnullable: $nullable\n, mapType: $mapType\n, arrayValueNullable: $arrayValueNullable\n)';
}

/// Converts [UniversalType] to type from specified language
Expand Down Expand Up @@ -163,7 +171,8 @@ extension UniversalTypeX on UniversalType {

String _questionMark(ProgrammingLanguage lang) {
final questionMark =
isRequired && !nullable || arrayDepth > 0 || defaultValue != null
(isRequired && !nullable || arrayDepth > 0 || defaultValue != null) &&
!arrayValueNullable
? ''
: '?';
switch (lang) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ String dartRetrofitClientTemplate({
}) {
final sb = StringBuffer(
'''
${generatedFileComment(markFileAsGenerated: markFileAsGenerated)}${_fileImport(restClient)}import 'package:dio/dio.dart'${_hideHeaders(restClient, defaultContentType)};
${generatedFileComment(markFileAsGenerated: markFileAsGenerated)}${_convertImport(restClient)}${_fileImport(restClient)}import 'package:dio/dio.dart'${_hideHeaders(restClient, defaultContentType)};
import 'package:retrofit/retrofit.dart';
${dartImports(imports: restClient.imports, pathPrefix: '../models/')}
part '${name.toSnake}.g.dart';
Expand Down Expand Up @@ -62,15 +62,18 @@ String _toClientRequest(UniversalRequest request, String defaultContentType) {
return sb.toString();
}

String _convertImport(UniversalRestClient restClient) =>
restClient.requests.any(
(r) => r.parameters.any(
(e) => e.parameterType.isPart,
),
)
? "import 'dart:convert';\n"
: '';

String _fileImport(UniversalRestClient restClient) => restClient.requests.any(
(r) => r.parameters.any(
(e) =>
e.type
.toSuitableType(ProgrammingLanguage.dart)
.startsWith('File') ||
e.type
.toSuitableType(ProgrammingLanguage.dart)
.startsWith('List<File'),
(e) => e.type.toSuitableType(ProgrammingLanguage.dart).contains('File'),
),
)
? "import 'dart:io';\n\n"
Expand Down
30 changes: 23 additions & 7 deletions swagger_parser/lib/src/parser/parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ class OpenApiParser {
return UniversalType(
type: typeWithImport.type.type,
arrayDepth: typeWithImport.type.arrayDepth,
arrayValueNullable: typeWithImport.type.arrayValueNullable,
);
}

Expand Down Expand Up @@ -324,7 +325,7 @@ class OpenApiParser {
types.add(
UniversalRequestType(
parameterType: HttpParameterType.part,
description: requestBody[_descriptionConst]?.toString(),
description: currentType.description,
type: UniversalType(
type: currentType.type,
name: 'file',
Expand All @@ -334,18 +335,26 @@ class OpenApiParser {
isRequired: currentType.isRequired,
nullable: currentType.nullable,
arrayDepth: currentType.arrayDepth,
arrayValueNullable: currentType.arrayValueNullable,
),
),
);
}
final schemaContent =
contentType[_schemaConst] as Map<String, dynamic>;
if (schemaContent.containsKey(_propertiesConst)) {
final requiredParameters =
(schemaContent[_requiredConst] as List<dynamic>?)
?.map((e) => e.toString())
.toList() ??
[];

for (final e
in (schemaContent[_propertiesConst] as Map<String, dynamic>)
.entries) {
final typeWithImport = _findType(
e.value as Map<String, dynamic>,
isRequired: requiredParameters.contains(e.key),
);
final currentType = typeWithImport.type;
if (typeWithImport.import != null) {
Expand All @@ -355,7 +364,7 @@ class OpenApiParser {
UniversalRequestType(
parameterType: HttpParameterType.part,
name: e.key,
description: requestBody[_descriptionConst]?.toString(),
description: currentType.description,
type: UniversalType(
type: currentType.type,
name: e.key,
Expand All @@ -365,6 +374,7 @@ class OpenApiParser {
isRequired: currentType.isRequired,
nullable: currentType.nullable,
arrayDepth: currentType.arrayDepth,
arrayValueNullable: currentType.arrayValueNullable,
),
),
);
Expand All @@ -384,7 +394,7 @@ class OpenApiParser {
types.add(
UniversalRequestType(
parameterType: HttpParameterType.body,
description: requestBody[_descriptionConst]?.toString(),
description: currentType.description,
type: UniversalType(
type: currentType.type,
name: _bodyConst,
Expand All @@ -394,6 +404,7 @@ class OpenApiParser {
isRequired: currentType.isRequired,
nullable: currentType.nullable,
arrayDepth: currentType.arrayDepth,
arrayValueNullable: currentType.arrayValueNullable,
),
),
);
Expand Down Expand Up @@ -422,6 +433,7 @@ class OpenApiParser {
return UniversalType(
type: typeWithImport.type.type,
arrayDepth: typeWithImport.type.arrayDepth,
arrayValueNullable: typeWithImport.type.arrayValueNullable,
);
}

Expand Down Expand Up @@ -535,14 +547,15 @@ class OpenApiParser {
final parametersDescription = parameters
.where((e) => e.description != null)
.map((e) => '[${e.name?.toCamel ?? 'body'}] - ${e.description}')
.join('\n')
.join('\n\n')
.trim();
description = switch ((description, parametersDescription)) {
(null, '') || ('', '') => null,
(_, '') => description,
(null, _) || ('', _) => parametersDescription,
(_, _) => '$description\n\n$parametersDescription',
};
// End build full description

String requestName;

Expand Down Expand Up @@ -811,14 +824,13 @@ class OpenApiParser {
root: false,
);
final arrayValueNullable = arrayItems[_nullableConst].toString().toBool();
final type = '${arrayType.type.type}${arrayValueNullable ? '?' : ''}';

final (newName, description) =
protectName(name, description: map[_descriptionConst]?.toString());

return (
type: UniversalType(
type: type,
type: arrayType.type.type,
name: newName?.toCamel,
description: description,
format: arrayType.type.format,
Expand All @@ -828,6 +840,7 @@ class OpenApiParser {
isRequired: isRequired,
nullable: map[_nullableConst].toString().toBool(),
arrayDepth: arrayType.type.arrayDepth + 1,
arrayValueNullable: arrayValueNullable,
),
import: arrayType.import,
);
Expand Down Expand Up @@ -939,7 +952,9 @@ class OpenApiParser {
}

// Interception of objectClass creation when Map construction is expected
if (typeWithImports.length == 1 && typeWithImports[0].import == null) {
if (mapType != null &&
typeWithImports.length == 1 &&
typeWithImports[0].import == null) {
return (
type: UniversalType(
type: map[_typeConst] as String,
Expand Down Expand Up @@ -1048,6 +1063,7 @@ class OpenApiParser {
enumType: enumType,
isRequired: isRequired,
arrayDepth: ofType?.arrayDepth ?? 0,
arrayValueNullable: ofType?.arrayValueNullable ?? false,
nullable: root &&
map.containsKey(_nullableConst) &&
map[_nullableConst].toString().toBool() ||
Expand Down
2 changes: 1 addition & 1 deletion swagger_parser/lib/src/utils/type_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ final _nameRegExp = RegExp(r'^[a-zA-Z_][a-zA-Z\d_]*$');
(null, null) => null,
(null, _) => error,
(_, null) => description,
(_, _) => '$description\n\n$error',
(_, _) => '$description\n$error',
},
);
}
2 changes: 1 addition & 1 deletion swagger_parser/lib/src/utils/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ const _generatedCodeComment = '''
''';

const _ignoreLintsComment = '''
// ignore_for_file: type=lint
// ignore_for_file: type=lint, unused_import
Carapacik marked this conversation as resolved.
Show resolved Hide resolved
''';

void introMessage() {
Expand Down
1 change: 1 addition & 0 deletions swagger_parser/test/generator/rest_clients_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,7 @@ interface ClassNameClient {
const fillController = FillController();
final filledContent = fillController.fillRestClientContent(restClient);
const expectedContents = '''
import 'dart:convert';
import 'dart:io';

import 'package:dio/dio.dart';
Expand Down