Skip to content

Commit

Permalink
Fix summary / description split on empty lines (#947)
Browse files Browse the repository at this point in the history
Priot to this PR the summary and description was blindly split by the
first line of the doc comment of path operaiton. This caused long
multi line summaries to be split from illogically bleeding part of the
summary to the description. More context can be found from issue #942.

This commit fixes this as from now one comments as follows will be
correctly split by paragraph. Where first paragraph will resolve to
summary and rest will become the description.
```rust
 /// This is test operation long multiline
 /// summary. That need to be correctly split.
 ///
 /// Additional info in long description
 ///
 /// With more info on separate lines
 /// containing text.
 ///
 /// Yeah
```

Follow up for #881 and #439

Fixes #942
  • Loading branch information
juhaku authored May 23, 2024
1 parent 68172bf commit 403d716
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 35 deletions.
42 changes: 23 additions & 19 deletions utoipa-gen/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,28 +389,31 @@ impl<'p> ToTokensDiagnostics for Path<'p> {
}
});

let split_comment = self
.doc_comments
.as_ref()
.and_then(|comments| comments.split_first())
.map(|(summary, description)| {
// Skip all whitespace lines
let start_pos = description
.iter()
.position(|s| !s.chars().all(char::is_whitespace));

let trimmed = start_pos
.and_then(|pos| description.get(pos..))
.unwrap_or(description);

(summary, trimmed)
});
let split_comment = self.doc_comments.as_ref().map(|comments| {
let mut split = comments.split(|comment| comment.trim().is_empty());
let summary = split
.by_ref()
.next()
.map(|summary| summary.join("\n"))
.unwrap_or_default();
let description = split.map(|lines| lines.join("\n")).collect::<Vec<_>>();

(summary, description)
});

let operation: Operation = Operation {
deprecated: &self.deprecated,
operation_id,
summary: split_comment.map(|(summary, _)| summary),
description: split_comment.map(|(_, description)| description),
summary: split_comment.as_ref().and_then(|(summary, _)| {
if summary.is_empty() {
None
} else {
Some(summary)
}
}),
description: split_comment
.as_ref()
.map(|(_, description)| description.as_ref()),
parameters: self.path_attr.params.as_ref(),
request_body: self.path_attr.request_body.as_ref(),
responses: self.path_attr.responses.as_ref(),
Expand Down Expand Up @@ -514,7 +517,7 @@ impl ToTokensDiagnostics for Operation<'_> {
}

if let Some(description) = self.description {
let description = description.join("\n");
let description = description.join("\n\n");

if !description.is_empty() {
tokens.extend(quote! {
Expand Down Expand Up @@ -603,6 +606,7 @@ pub trait PathTypeTree {
/// Resolve default content type based on current [`Type`].
fn get_default_content_type(&self) -> &str;

#[allow(unused)]
/// Check whether [`TypeTree`] an option
fn is_option(&self) -> bool;

Expand Down
38 changes: 22 additions & 16 deletions utoipa-gen/tests/path_derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,20 +101,6 @@ test_path_operation! {
derive_path_connect: connect
}

test_api_fn! {
name: test_operation2,
module: derive_path_with_all_info,
operation: post,
path: "/foo/bar/{id}",
params: (("id", description = "Foo bar id")),
operation_id: "foo_bar_id",
tag: "custom_tag";
/// This is test operation description
///
/// Additional info in long description
#[deprecated]
}

macro_rules! api_fn_doc_with_params {
( $method:ident: $path:literal => $( #[$attr:meta] )* $key:ident $name:ident $body:tt ) => {{
#[allow(dead_code)]
Expand Down Expand Up @@ -147,6 +133,26 @@ macro_rules! api_fn_doc_with_params {
}};
}

test_api_fn! {
name: test_operation2,
module: derive_path_with_all_info,
operation: post,
path: "/foo/bar/{id}",
params: (("id", description = "Foo bar id")),
operation_id: "foo_bar_id",
tag: "custom_tag";
/// This is test operation long multiline
/// summary. That need to be correctly split.
///
/// Additional info in long description
///
/// With more info on separate lines
/// containing text.
///
/// Yeah
#[deprecated]
}

#[test]
fn derive_path_with_all_info_success() {
let operation = test_api_fn_doc! {
Expand All @@ -158,8 +164,8 @@ fn derive_path_with_all_info_success() {
common::assert_json_array_len(operation.pointer("/parameters").unwrap(), 1);
assert_value! {operation=>
"deprecated" = r#"true"#, "Api fn deprecated status"
"description" = r#""Additional info in long description""#, "Api fn description"
"summary" = r#""This is test operation description""#, "Api fn summary"
"description" = r#""Additional info in long description\n\nWith more info on separate lines\ncontaining text.\n\nYeah""#, "Api fn description"
"summary" = r#""This is test operation long multiline\nsummary. That need to be correctly split.""#, "Api fn summary"
"operationId" = r#""foo_bar_id""#, "Api fn operation_id"
"tags.[0]" = r#""custom_tag""#, "Api fn tag"

Expand Down

0 comments on commit 403d716

Please sign in to comment.