Skip to content

Commit

Permalink
Skip 1st line in path macro description expansion (#881)
Browse files Browse the repository at this point in the history
Previously, the entire doc comment was used as the description, in
addition to the summary using the first line of the doc comment,
resulting in duplicated text.

This commit changes the path macro doc comment extraction logic to split
the first line from the rest of the body, and skip all lines until the
first non-whitespace line. This results in the description no longer
containing the summary.

In degenerate cases, such as a doc comment consisting of new lines, this
will invoke a full linear search over all lines in the doc comment. This
should be relatively acceptable as most reasonable forms of doc comments
shouldn't have more than a couple of newlines between the first line and
subsequent body.

For testing and verification, I've tested this in a private project
using the `patch` override section in `Cargo.toml`, and tests needed to
be changed to account for this change.
  • Loading branch information
edward-shen committed May 1, 2024
1 parent 365469f commit 5aa9749
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 10 deletions.
4 changes: 2 additions & 2 deletions utoipa-gen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -657,12 +657,12 @@ pub fn derive_to_schema(input: TokenStream) -> TokenStream {
/// `#[deprecated = "There is better way to do this"]` the reason would not render in OpenAPI spec.
///
/// Doc comment at decorated function will be used for _`description`_ and _`summary`_ of the path.
/// First line of the doc comment will be used as the _`summary`_ and the whole doc comment will be
/// First line of the doc comment will be used as the _`summary`_ while the remaining lines will be
/// used as _`description`_.
/// ```rust
/// /// This is a summary of the operation
/// ///
/// /// All lines of the doc comment will be included to operation description.
/// /// The rest of the doc comment will be included to operation description.
/// #[utoipa::path(get, path = "/operation")]
/// fn operation() {}
/// ```
Expand Down
26 changes: 20 additions & 6 deletions utoipa-gen/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,14 +376,28 @@ impl<'p> ToTokens 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 operation: Operation = Operation {
deprecated: &self.deprecated,
operation_id,
summary: self
.doc_comments
.as_ref()
.and_then(|comments| comments.iter().next()),
description: self.doc_comments.as_ref(),
summary: split_comment.map(|(summary, _)| summary),
description: split_comment.map(|(_, description)| description),
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 @@ -427,7 +441,7 @@ impl<'p> ToTokens for Path<'p> {
struct Operation<'a> {
operation_id: Expr,
summary: Option<&'a String>,
description: Option<&'a Vec<String>>,
description: Option<&'a [String]>,
deprecated: &'a Option<bool>,
parameters: &'a Vec<Parameter<'a>>,
request_body: Option<&'a RequestBody<'a>>,
Expand Down
4 changes: 2 additions & 2 deletions utoipa-gen/tests/path_derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ 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#""This is test operation description\n\nAdditional info in long description""#, "Api fn description"
"description" = r#""Additional info in long description""#, "Api fn description"
"summary" = r#""This is test operation description""#, "Api fn summary"
"operationId" = r#""foo_bar_id""#, "Api fn operation_id"
"tags.[0]" = r#""custom_tag""#, "Api fn tag"
Expand Down Expand Up @@ -224,7 +224,7 @@ fn derive_path_with_extra_attributes_without_nested_module() {
common::assert_json_array_len(operation.pointer("/parameters").unwrap(), 2);
assert_value! {operation=>
"deprecated" = r#"null"#, "Api operation deprecated"
"description" = r#""This is test operation\n\nThis is long description for test operation""#, "Api operation description"
"description" = r#""This is long description for test operation""#, "Api operation description"
"operationId" = r#""get_foos_by_id_since""#, "Api operation operation_id"
"summary" = r#""This is test operation""#, "Api operation summary"
"tags.[0]" = r#""crate""#, "Api operation tag"
Expand Down

0 comments on commit 5aa9749

Please sign in to comment.