From a0a8bde78ec08ddd85eafe773cde166203b0cf83 Mon Sep 17 00:00:00 2001 From: samooyo Date: Thu, 6 Mar 2025 14:14:51 +0100 Subject: [PATCH 1/4] feat(forge): add params natspec for enums --- crates/doc/src/parser/comment.rs | 12 +++++-- crates/doc/src/writer/as_doc.rs | 11 ++++++- crates/doc/src/writer/buf_writer.rs | 51 +++++++++++++++++++++++++++-- 3 files changed, 68 insertions(+), 6 deletions(-) diff --git a/crates/doc/src/parser/comment.rs b/crates/doc/src/parser/comment.rs index bf2b0ad7b4f0d..cba7f32df2767 100644 --- a/crates/doc/src/parser/comment.rs +++ b/crates/doc/src/parser/comment.rs @@ -46,7 +46,7 @@ impl CommentTag { } _ => { warn!(target: "forge::doc", tag=trimmed, "unknown comment tag. custom tags must be preceded by `custom:`"); - return None + return None; } }; Some(tag) @@ -157,6 +157,12 @@ impl From> for Comments { } } +impl From> for Comments { + fn from(value: Vec) -> Self { + Self(value) + } +} + /// The collection of references to natspec [Comment] items. #[derive(Debug, Default, PartialEq, Deref)] pub struct CommentsRef<'a>(Vec<&'a Comment>); @@ -184,8 +190,8 @@ impl<'a> CommentsRef<'a> { self.iter().any(|c| match (&c.tag, &target.tag) { (CommentTag::Inheritdoc, CommentTag::Inheritdoc) => c.value == target.value, (CommentTag::Param, CommentTag::Param) | (CommentTag::Return, CommentTag::Return) => { - c.split_first_word().map(|(name, _)| name) == - target.split_first_word().map(|(name, _)| name) + c.split_first_word().map(|(name, _)| name) + == target.split_first_word().map(|(name, _)| name) } (tag1, tag2) => tag1 == tag2, }) diff --git a/crates/doc/src/writer/as_doc.rs b/crates/doc/src/writer/as_doc.rs index 56a0a4026c504..98fe8f668eca0 100644 --- a/crates/doc/src/writer/as_doc.rs +++ b/crates/doc/src/writer/as_doc.rs @@ -229,7 +229,16 @@ impl AsDoc for Document { writer.write_subtitle("Enums")?; enums.into_iter().try_for_each(|(item, comments, code)| { writer.write_heading(&item.name.safe_unwrap().name)?; - writer.write_section(comments, code) + + let filtered_comments: Comments = (*comments) + .iter() + .cloned() + .filter(|c| c.tag != CommentTag::Custom("variant".to_string())) + .collect::>() + .into(); + + writer.write_section(&filtered_comments, code)?; + writer.try_write_variant_table(&item, comments) })?; } } diff --git a/crates/doc/src/writer/buf_writer.rs b/crates/doc/src/writer/buf_writer.rs index e6109c338c03f..152f29dc61345 100644 --- a/crates/doc/src/writer/buf_writer.rs +++ b/crates/doc/src/writer/buf_writer.rs @@ -1,6 +1,8 @@ use crate::{writer::traits::ParamLike, AsDoc, CommentTag, Comments, Deployment, Markdown}; use itertools::Itertools; -use solang_parser::pt::{ErrorParameter, EventParameter, Parameter, VariableDeclaration}; +use solang_parser::pt::{ + EnumDefinition, ErrorParameter, EventParameter, Parameter, VariableDeclaration, +}; use std::{ fmt::{self, Display, Write}, sync::LazyLock, @@ -19,6 +21,11 @@ const DEPLOYMENTS_TABLE_HEADERS: &[&str] = &["Network", "Address"]; static DEPLOYMENTS_TABLE_SEPARATOR: LazyLock = LazyLock::new(|| DEPLOYMENTS_TABLE_HEADERS.iter().map(|h| "-".repeat(h.len())).join("|")); +/// Headers and separator for rendering the variants table. +const VARIANTS_TABLE_HEADERS: &[&str] = &["Name", "Description"]; +const VARIANTS_TABLE_SEPARATOR: LazyLock = + LazyLock::new(|| VARIANTS_TABLE_HEADERS.iter().map(|h| "-".repeat(h.len())).join("|")); + /// The buffered writer. /// Writes various display items into the internal buffer. #[derive(Debug, Default)] @@ -132,7 +139,7 @@ impl BufWriter { // There is nothing to write. if params.is_empty() || comments.is_empty() { - return Ok(()) + return Ok(()); } self.write_bold(heading)?; @@ -177,6 +184,46 @@ impl BufWriter { self.try_write_table(CommentTag::Param, params, comments, "Properties") } + /// Tries to write the variant table to the buffer. + /// Doesn't write anything if either params or comments are empty. + pub fn try_write_variant_table( + &mut self, + params: &EnumDefinition, + comments: &Comments, + ) -> fmt::Result { + let comments = + comments.include_tags(&[CommentTag::Param, CommentTag::Custom("variant".to_string())]); + + // There is nothing to write. + if comments.is_empty() { + return Ok(()); + } + + self.write_bold("Variants")?; + self.writeln()?; + + self.write_piped(&VARIANTS_TABLE_HEADERS.join("|"))?; + self.write_piped(&VARIANTS_TABLE_SEPARATOR)?; + + for value in params.values.iter() { + let param_name = value.as_ref().map(|v| v.name.clone()); + + let comment = param_name.as_ref().and_then(|name| { + comments.iter().find_map(|comment| comment.match_first_word(name)) + }); + + let row = [ + Markdown::Code(¶m_name.unwrap_or("".to_string())).as_doc()?, + comment.unwrap_or_default().replace('\n', " "), + ]; + self.write_piped(&row.join("|"))?; + } + + self.writeln()?; + + Ok(()) + } + /// Tries to write the parameters table to the buffer. /// Doesn't write anything if either params or comments are empty. pub fn try_write_events_table( From c0b572530bad0202ee38f95f05988273b6ffda02 Mon Sep 17 00:00:00 2001 From: samooyo Date: Thu, 6 Mar 2025 14:15:45 +0100 Subject: [PATCH 2/4] chore: cargo fmt --- crates/doc/src/parser/comment.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/doc/src/parser/comment.rs b/crates/doc/src/parser/comment.rs index cba7f32df2767..5dc6c17f98890 100644 --- a/crates/doc/src/parser/comment.rs +++ b/crates/doc/src/parser/comment.rs @@ -190,8 +190,8 @@ impl<'a> CommentsRef<'a> { self.iter().any(|c| match (&c.tag, &target.tag) { (CommentTag::Inheritdoc, CommentTag::Inheritdoc) => c.value == target.value, (CommentTag::Param, CommentTag::Param) | (CommentTag::Return, CommentTag::Return) => { - c.split_first_word().map(|(name, _)| name) - == target.split_first_word().map(|(name, _)| name) + c.split_first_word().map(|(name, _)| name) == + target.split_first_word().map(|(name, _)| name) } (tag1, tag2) => tag1 == tag2, }) From d6033484b6f75de82b51eec87e1d0f36745898ac Mon Sep 17 00:00:00 2001 From: samooyo Date: Thu, 6 Mar 2025 14:23:16 +0100 Subject: [PATCH 3/4] fix: clippy errors --- crates/doc/src/writer/as_doc.rs | 4 ++-- crates/doc/src/writer/buf_writer.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/doc/src/writer/as_doc.rs b/crates/doc/src/writer/as_doc.rs index 98fe8f668eca0..d38f880ed8693 100644 --- a/crates/doc/src/writer/as_doc.rs +++ b/crates/doc/src/writer/as_doc.rs @@ -232,13 +232,13 @@ impl AsDoc for Document { let filtered_comments: Comments = (*comments) .iter() - .cloned() .filter(|c| c.tag != CommentTag::Custom("variant".to_string())) + .cloned() .collect::>() .into(); writer.write_section(&filtered_comments, code)?; - writer.try_write_variant_table(&item, comments) + writer.try_write_variant_table(item, comments) })?; } } diff --git a/crates/doc/src/writer/buf_writer.rs b/crates/doc/src/writer/buf_writer.rs index 152f29dc61345..7fb657ba1d7a4 100644 --- a/crates/doc/src/writer/buf_writer.rs +++ b/crates/doc/src/writer/buf_writer.rs @@ -23,7 +23,7 @@ static DEPLOYMENTS_TABLE_SEPARATOR: LazyLock = /// Headers and separator for rendering the variants table. const VARIANTS_TABLE_HEADERS: &[&str] = &["Name", "Description"]; -const VARIANTS_TABLE_SEPARATOR: LazyLock = +static VARIANTS_TABLE_SEPARATOR: LazyLock = LazyLock::new(|| VARIANTS_TABLE_HEADERS.iter().map(|h| "-".repeat(h.len())).join("|")); /// The buffered writer. From 4cae0e34a3da13bbd8f6f4ce5236624b8f59d11d Mon Sep 17 00:00:00 2001 From: zerosnacks Date: Fri, 7 Mar 2025 16:33:09 +0100 Subject: [PATCH 4/4] add @gregorsternat as co-author given their earlier work on https://github.com/foundry-rs/foundry/pull/9905 Co-authored-by: gregorsternat