Skip to content

Commit 14f903b

Browse files
committed
Fix the issues of strip and merge desc for code block
1 parent 9415fcb commit 14f903b

File tree

6 files changed

+180
-17
lines changed

6 files changed

+180
-17
lines changed

schemars/tests/docs.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,59 @@ enum MyEnum {
5454
},
5555
}
5656

57+
#[allow(dead_code)]
58+
#[derive(JsonSchema)]
59+
/**
60+
*
61+
* # This is the struct's title
62+
*
63+
* This is the struct's description.
64+
*
65+
* This is example:
66+
* ```json
67+
* {
68+
* "value": 0,
69+
* "type": "msg"
70+
* }
71+
* ```
72+
*/
73+
struct MyStructWithInlineCode {
74+
/// # An integer
75+
my_int: i32,
76+
}
77+
78+
#[allow(dead_code)]
79+
#[derive(JsonSchema)]
80+
81+
/// This is example:
82+
/// ```json
83+
/// {
84+
/// "value": 0,
85+
/// "type": "msg"
86+
/// }
87+
/// ```
88+
struct MyStructWithInlineCodeNormal {
89+
/// # An integer
90+
my_int: i32,
91+
}
92+
93+
#[allow(dead_code)]
94+
#[derive(JsonSchema)]
95+
96+
/// This is example:
97+
///
98+
/// | A | B |
99+
/// |---|---|
100+
/// | 1 | 2 |
101+
/// | 3 | 4 |
102+
/// | 5 | 6 |
103+
/// this is last line
104+
///
105+
struct MyStructWithInlineCodeTable {
106+
/// # An integer
107+
my_int: i32,
108+
}
109+
57110
#[test]
58111
fn doc_comments_struct() -> TestResult {
59112
test_default_generated_schema::<MyStruct>("doc_comments_struct")
@@ -70,6 +123,23 @@ fn doc_comments_enum() -> TestResult {
70123
test_default_generated_schema::<MyEnum>("doc_comments_enum")
71124
}
72125

126+
#[test]
127+
fn doc_comments_with_inline_code() -> TestResult {
128+
test_default_generated_schema::<MyStructWithInlineCode>("doc_comments_with_inline_code")
129+
}
130+
131+
#[test]
132+
fn doc_comments_with_inline_code_normal() -> TestResult {
133+
test_default_generated_schema::<MyStructWithInlineCodeNormal>(
134+
"doc_comments_with_inline_code_normal",
135+
)
136+
}
137+
138+
#[test]
139+
fn doc_comments_with_inline_table() -> TestResult {
140+
test_default_generated_schema::<MyStructWithInlineCodeTable>("doc_comments_with_inline_table")
141+
}
142+
73143
/// # OverrideDocs struct
74144
/// This description should be overridden
75145
#[allow(dead_code)]
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"title": "This is the struct's title",
4+
"description": "This is the struct's description.\n\nThis is example:\n ```json\n {\n \"value\": 0,\n \"type\": \"msg\"\n }\n```",
5+
"type": "object",
6+
"required": [
7+
"my_int"
8+
],
9+
"properties": {
10+
"my_int": {
11+
"title": "An integer",
12+
"type": "integer",
13+
"format": "int32"
14+
}
15+
}
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"title": "MyStructWithInlineCodeNormal",
4+
"description": "This is example:\n ```json\n {\n \"value\": 0,\n \"type\": \"msg\"\n }\n```",
5+
"type": "object",
6+
"required": [
7+
"my_int"
8+
],
9+
"properties": {
10+
"my_int": {
11+
"title": "An integer",
12+
"type": "integer",
13+
"format": "int32"
14+
}
15+
}
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"title": "MyStructWithInlineCodeTable",
4+
"description": "This is example:\n\n| A | B |\n|---|---|\n| 1 | 2 |\n| 3 | 4 |\n| 5 | 6 | this is last line",
5+
"type": "object",
6+
"required": [
7+
"my_int"
8+
],
9+
"properties": {
10+
"my_int": {
11+
"title": "An integer",
12+
"type": "integer",
13+
"format": "int32"
14+
}
15+
}
16+
}

schemars/tests/validate_inner.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub struct Struct<'a> {
1212
#[schemars(inner(length(min = 5, max = 100)))]
1313
array_str_length: [&'a str; 2],
1414
#[schemars(inner(contains(pattern = "substring...")))]
15-
slice_str_contains: &'a[&'a str],
15+
slice_str_contains: &'a [&'a str],
1616
#[schemars(inner(regex = "STARTS_WITH_HELLO"))]
1717
vec_str_regex: Vec<String>,
1818
#[schemars(inner(length(min = 1, max = 100)))]

schemars_derive/src/attr/doc.rs

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,13 @@ fn merge_description_lines(doc: &str) -> Option<String> {
2525
let desc = doc
2626
.trim()
2727
.split("\n\n")
28-
.filter_map(|line| none_if_empty(line.trim().replace('\n', " ")))
28+
.map(|s| s.to_string())
29+
.collect::<Vec<_>>();
30+
31+
let desc = desc
32+
.iter()
33+
.map(|paragrah| merge_without_codeblock(paragrah))
34+
.filter_map(|line| none_if_empty(line.to_string()))
2935
.collect::<Vec<_>>()
3036
.join("\n\n");
3137
none_if_empty(desc)
@@ -47,30 +53,22 @@ fn get_doc(attrs: &[Attribute]) -> Option<String> {
4753
None
4854
})
4955
.collect::<Vec<_>>();
50-
51-
let mut lines = attrs
56+
let lines = attrs
5257
.iter()
5358
.flat_map(|a| a.split('\n'))
54-
.map(str::trim)
5559
.skip_while(|s| s.is_empty())
60+
.map(|l| l.to_string())
5661
.collect::<Vec<_>>();
5762

58-
if let Some(&"") = lines.last() {
59-
lines.pop();
60-
}
61-
63+
let mut res = strip_without_codeblock(&lines, |l| l.trim().to_string());
6264
// Added for backward-compatibility, but perhaps we shouldn't do this
6365
// https://github.com/rust-lang/rust/issues/32088
64-
if lines.iter().all(|l| l.starts_with('*')) {
65-
for line in lines.iter_mut() {
66-
*line = line[1..].trim()
67-
}
68-
while let Some(&"") = lines.first() {
69-
lines.remove(0);
70-
}
66+
if res.iter().all(|l| l.trim().starts_with('*')) {
67+
res = res.iter().map(|l| l[1..].to_string()).collect::<Vec<_>>();
68+
res = strip_without_codeblock(&res, |l| l.trim().to_string());
7169
};
7270

73-
none_if_empty(lines.join("\n"))
71+
none_if_empty(res.join("\n"))
7472
}
7573

7674
fn none_if_empty(s: String) -> Option<String> {
@@ -80,3 +78,50 @@ fn none_if_empty(s: String) -> Option<String> {
8078
Some(s)
8179
}
8280
}
81+
82+
fn strip_without_codeblock(lines: &Vec<String>, func: fn(&str) -> String) -> Vec<String> {
83+
let mut res = vec![];
84+
let mut in_codeblock = false;
85+
for line in lines {
86+
if line.trim().starts_with("```") {
87+
in_codeblock = !in_codeblock;
88+
}
89+
let l = if in_codeblock {
90+
line.to_string()
91+
} else {
92+
func(line)
93+
};
94+
res.push(l);
95+
}
96+
while let Some("") = res.first().map(|s| s.as_str()) {
97+
res.remove(0);
98+
}
99+
while let Some("") = res.last().map(|s| s.as_str()) {
100+
res.pop();
101+
}
102+
res
103+
}
104+
105+
fn merge_without_codeblock(content: &str) -> String {
106+
let lines = content.lines();
107+
let mut res = String::new();
108+
let mut in_codeblock = false;
109+
for line in lines {
110+
let flag = line.trim().starts_with("```");
111+
if flag {
112+
in_codeblock = !in_codeblock;
113+
}
114+
// other possible Markdown prefix characters
115+
let maybe_markdown = ["#", "-", ">", "|", "*", "["]
116+
.iter()
117+
.any(|p| line.trim().starts_with(p))
118+
|| line.trim().chars().next().map(char::is_numeric) == Some(true);
119+
let prefix = if in_codeblock || flag || maybe_markdown {
120+
"\n"
121+
} else {
122+
" "
123+
};
124+
res += &(format!("{}{}", prefix, line));
125+
}
126+
res.trim().to_string()
127+
}

0 commit comments

Comments
 (0)