diff --git a/swagger_parser/CHANGELOG.md b/swagger_parser/CHANGELOG.md index 706e00ea..6e8bbdb4 100644 --- a/swagger_parser/CHANGELOG.md +++ b/swagger_parser/CHANGELOG.md @@ -1,3 +1,6 @@ +## 1.11.2 +- Add description of request parameters to the code docs + ## 1.11.1 - Fixed ref component being wrongly labeled as map - Fixed map components being assigned an import despite not needing one diff --git a/swagger_parser/example/swagger_parser.yaml b/swagger_parser/example/swagger_parser.yaml index 32270f6c..d45d01d1 100644 --- a/swagger_parser/example/swagger_parser.yaml +++ b/swagger_parser/example/swagger_parser.yaml @@ -91,4 +91,4 @@ swagger_parser: - schema_path: schemas/pet_store.json schema_url: https://petstore.swagger.io/v2/swagger.json output_directory: lib/api/kotlin - language: kotlin + language: kotlin \ No newline at end of file diff --git a/swagger_parser/lib/src/generator/models/universal_request_type.dart b/swagger_parser/lib/src/generator/models/universal_request_type.dart index 491c677c..3bc6fff8 100644 --- a/swagger_parser/lib/src/generator/models/universal_request_type.dart +++ b/swagger_parser/lib/src/generator/models/universal_request_type.dart @@ -6,6 +6,7 @@ final class UniversalRequestType { const UniversalRequestType({ required this.parameterType, required this.type, + this.description, this.name, }); @@ -18,6 +19,9 @@ final class UniversalRequestType { /// Request parameter http type final HttpParameterType parameterType; + /// Request parameter description + final String? description; + @override bool operator ==(Object other) => identical(this, other) || diff --git a/swagger_parser/lib/src/parser/parser.dart b/swagger_parser/lib/src/parser/parser.dart index 01e4d166..6d9eff03 100644 --- a/swagger_parser/lib/src/parser/parser.dart +++ b/swagger_parser/lib/src/parser/parser.dart @@ -84,8 +84,8 @@ class OpenApiParser { static const _contentConst = 'content'; static const _defaultConst = 'default'; static const _definitionsConst = 'definitions'; - static const _deprecatedConst = 'deprecated'; static const _descriptionConst = 'description'; + static const _deprecatedConst = 'deprecated'; static const _enumConst = 'enum'; static const _formatConst = 'format'; static const _formUrlEncodedConst = 'application/x-www-form-urlencoded'; @@ -228,6 +228,7 @@ class OpenApiParser { UniversalRequestType( parameterType: parameterType, type: typeWithImport.type, + description: parameter[_descriptionConst]?.toString(), name: parameterType.isBody && parameter[_nameConst] == _bodyConst ? null : parameter[_nameConst].toString(), @@ -280,6 +281,7 @@ class OpenApiParser { types.add( UniversalRequestType( parameterType: HttpParameterType.part, + description: requestBody[_descriptionConst]?.toString(), type: UniversalType( type: currentType.type, name: 'file', @@ -310,6 +312,7 @@ class OpenApiParser { UniversalRequestType( parameterType: HttpParameterType.part, name: e.key, + description: requestBody[_descriptionConst]?.toString(), type: UniversalType( type: currentType.type, name: e.key, @@ -338,6 +341,7 @@ class OpenApiParser { types.add( UniversalRequestType( parameterType: HttpParameterType.body, + description: requestBody[_descriptionConst]?.toString(), type: UniversalType( type: currentType.type, name: _bodyConst, @@ -418,6 +422,7 @@ class OpenApiParser { UniversalRequestType( parameterType: parameterType, type: typeWithImport.type, + description: parameter[_descriptionConst]?.toString(), name: parameterType.isBody && parameter[_nameConst] == _bodyConst ? null : parameter[_nameConst].toString(), @@ -448,25 +453,37 @@ class OpenApiParser { ? parametersV2(requestPath) : parametersV3(requestPath); + // Build full description final summary = requestPath[_summaryConst]?.toString().trim(); var description = requestPath[_descriptionConst]?.toString().trim(); description = switch ((summary, description)) { - (null, null) => null, + (null, null) || ('', '') => null, (_, null) || (_, '') => summary, (null, _) || ('', _) => description, (_, _) => '$summary\n\n$description', }; + final parametersDescription = parameters + .where((e) => e.description != null) + .map((e) => '[${e.name?.toCamel ?? 'body'}] - ${e.description}') + .join('\n') + .trim(); + description = switch ((description, parametersDescription)) { + (null, '') || ('', '') => null, + (_, '') => description, + (null, _) || ('', _) => parametersDescription, + (_, _) => '$description\n\n$parametersDescription', + }; - final String requestName; + String requestName; if (_pathMethodName) { requestName = (key + path).toCamel; } else { final operationIdName = requestPath[_operationIdConst]?.toString().toCamel; - final (_, error) = protectName(operationIdName); - if (error != null) { - description = '$description\n\n$error'; + final (_, nameDescription) = protectName(operationIdName); + if (nameDescription != null) { + description = '$description\n\n$nameDescription'; requestName = (key + path).toCamel; } else { requestName = operationIdName ?? (key + path).toCamel; @@ -744,14 +761,15 @@ class OpenApiParser { } // Enum else if (map.containsKey(_enumConst)) { - final (variableName, description) = protectName( + // ignore: unnecessary_null_checks + final (variableName!, description) = protectName( name, isEnum: true, uniqueIfNull: true, description: map[_descriptionConst]?.toString(), ); - var newName = variableName!; + var newName = variableName; if (_enumsPrefix && additionalName != null) { newName = '$additionalName $newName'.toPascal; } @@ -871,10 +889,8 @@ class OpenApiParser { _objectClasses.add( UniversalComponentClass( name: newName.toPascal, - imports: typeWithImports - .where((e) => e.import != null) - .map((e) => e.import!) - .toSet(), + imports: + typeWithImports.map((e) => e.import).whereNotNull().toSet(), parameters: typeWithImports.map((e) => e.type).toList(), ), ); diff --git a/swagger_parser/lib/src/utils/utils.dart b/swagger_parser/lib/src/utils/utils.dart index 46935fe8..10d86a05 100644 --- a/swagger_parser/lib/src/utils/utils.dart +++ b/swagger_parser/lib/src/utils/utils.dart @@ -24,7 +24,7 @@ String dartImports({required Set imports, String? pathPrefix}) { return '\n${imports.map((import) => "import '${pathPrefix ?? ''}${import.toSnake}.dart';").join('\n')}\n'; } -/// Provides class description +/// Provides description String descriptionComment( String? description, { bool tabForFirstLine = true, @@ -36,14 +36,26 @@ String descriptionComment( } final lineStart = RegExp('^(.*)', multiLine: true); + final result = description.replaceAllMapped( lineStart, - (m) => '${!tabForFirstLine && m.start == 0 ? '' : tab}/// ${m[1]}', + (m) => + '${!tabForFirstLine && m.start == 0 ? '' : tab}/// ${m.start == 0 && m.end == description.length ? m[1] : addDot(m[1])}', ); return '$result\n$end'; } +/// RegExp for punctuation marks in the end of string +final _punctuationRegExp = RegExp(r'[.!?]$'); + +/// Add dot to string if not exist +/// https://dart.dev/effective-dart/documentation#do-format-comments-like-sentences +String? addDot(String? text) => + text != null && text.trim().isNotEmpty && !_punctuationRegExp.hasMatch(text) + ? '$text.' + : text; + /// Replace all not english letters in text String? replaceNotEnglishLetter(String? text) { if (text == null || text.isEmpty) { diff --git a/swagger_parser/test/generator/data_classes_test.dart b/swagger_parser/test/generator/data_classes_test.dart index 50d420fb..d8dd68da 100644 --- a/swagger_parser/test/generator/data_classes_test.dart +++ b/swagger_parser/test/generator/data_classes_test.dart @@ -2008,8 +2008,8 @@ class ClassName { final String megaMind; final Object emptyDescription; - /// List of data - /// This data is a list + /// List of data. + /// This data is a list. final List list; Map toJson() => _$ClassNameToJson(this); @@ -2084,8 +2084,8 @@ class ClassName with _$ClassName { required String megaMind, required Object emptyDescription, - /// List of data - /// This data is a list + /// List of data. + /// This data is a list. required List list, /// Default value