Repository: paritytech/ink
Pull request #1385 (2022-09-05 12:58:26)

remove single whitespace prefix from comments and docs
Closes #613 

Only a single white space is removed which comes under the assumption that the user uses the standard cargo formatting style.

# Example of trimming
```json
...
"docs": [
  "# Flips the current value of the Flipper's boolean.",
  "Let's try to use some code",
  "```rust",
  "fn main() {",
  "    \"Hello, World!\"",
  "}",
  "```"
],
...
```


Patch:
diff --git a/crates/metadata/src/specs.rs b/crates/metadata/src/specs.rs
index 437916cd56..ad599de8c4 100644
--- a/crates/metadata/src/specs.rs
+++ b/crates/metadata/src/specs.rs
@@ -14,7 +14,10 @@
 
 #![allow(clippy::new_ret_no_self)]
 
-use crate::serde_hex;
+use crate::{
+    serde_hex,
+    utils::trim_extra_whitespace,
+};
 #[cfg(not(feature = "std"))]
 use alloc::{
     format,
@@ -367,7 +370,10 @@ impl<S, P> ConstructorSpecBuilder<S, P> {
     {
         let mut this = self;
         debug_assert!(this.spec.docs.is_empty());
-        this.spec.docs = docs.into_iter().map(str::trim).collect::<Vec<_>>();
+        this.spec.docs = docs
+            .into_iter()
+            .map(trim_extra_whitespace)
+            .collect::<Vec<_>>();
         this
     }
 }
@@ -586,7 +592,10 @@ impl<S, M, P, R> MessageSpecBuilder<S, M, P, R> {
     {
         let mut this = self;
         debug_assert!(this.spec.docs.is_empty());
-        this.spec.docs = docs.into_iter().collect::<Vec<_>>();
+        this.spec.docs = docs
+            .into_iter()
+            .map(trim_extra_whitespace)
+            .collect::<Vec<_>>();
         this
     }
 }
diff --git a/crates/metadata/src/utils.rs b/crates/metadata/src/utils.rs
index e09458c3e1..225d532b98 100644
--- a/crates/metadata/src/utils.rs
+++ b/crates/metadata/src/utils.rs
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 use crate::serde_hex;
+use std::str;
 
 /// Serializes the given bytes as byte string.
 pub fn serialize_as_byte_str<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
@@ -56,3 +57,12 @@ where
 
     deserializer.deserialize_str(Visitor)
 }
+
+/// Strips a single whitespace at the start and removes trailing spaces
+pub fn trim_extra_whitespace(item: &str) -> &str {
+    if let Some(stripped) = item.strip_prefix(' ') {
+        stripped.trim_end()
+    } else {
+        item.trim_end()
+    }
+}


Test patch:
diff --git a/crates/metadata/src/tests.rs b/crates/metadata/src/tests.rs
index 44d5d8492d..6f78240726 100644
--- a/crates/metadata/src/tests.rs
+++ b/crates/metadata/src/tests.rs
@@ -176,6 +176,7 @@ fn spec_contract_json() {
     )
 }
 
+/// Tests correct trimming of a simple comment with extra spaces
 #[test]
 fn trim_docs() {
     // given
@@ -206,3 +207,49 @@ fn trim_docs() {
     );
     assert_eq!(deserialized.docs, compact_spec.docs);
 }
+
+/// Tests correct trimming of a complex comment with a code snippet
+#[test]
+fn trim_docs_with_code() {
+    // given
+    let label = "foo";
+    let cs = ConstructorSpec::from_label(label)
+        .selector(123_456_789u32.to_be_bytes())
+        .docs(vec![
+            " Example      ",
+            " ```",
+            " fn test() {",
+            "     \"Hello, World\"",
+            " }",
+            " ```",
+        ])
+        .payable(Default::default())
+        .done();
+    let mut registry = Registry::new();
+    let compact_spec = cs.into_portable(&mut registry);
+
+    // when
+    let json = serde_json::to_value(&compact_spec).unwrap();
+    let deserialized: ConstructorSpec<PortableForm> =
+        serde_json::from_value(json.clone()).unwrap();
+
+    // then
+    assert_eq!(
+        json,
+        json!({
+            "label": "foo",
+            "payable": false,
+            "selector": "0x075bcd15",
+            "args": [],
+            "docs": [
+                "Example",
+                "```",
+                "fn test() {",
+                "    \"Hello, World\"",
+                "}",
+                "```"
+            ]
+        })
+    );
+    assert_eq!(deserialized.docs, compact_spec.docs);
+}