1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
mod ast;
mod md;
use crate::ast::Document;
use md::{MdNodeRef, MdRoot, ToMarkdown};
use std::{
collections::{hash_map, HashSet},
iter::FromIterator,
};
pub trait Documentation {
fn to_md(&self) -> String;
}
fn parse_links<S: AsRef<str>>(text: S, existing_links: &HashSet<String>) -> String {
let text = text.as_ref();
let mut parsed_text = String::with_capacity(text.len());
let mut link = String::with_capacity(text.len());
let mut is_link = false;
for ch in text.chars() {
match (ch, is_link) {
('`', false) => {
is_link = true;
}
('`', true) => {
let md_link = link.replace("::", ".");
let expanded = if let Some(_) = existing_links.get(&md_link) {
format!("[`{}`](#{})", link, md_link)
} else {
log::warn!(
"Link [`{}`](#{}) could not be found in the document!",
link,
md_link
);
format!("`{}`", link)
};
parsed_text.push_str(&expanded);
link.drain(..);
is_link = false;
}
(ch, false) => parsed_text.push(ch),
(ch, true) => link.push(ch),
}
}
parsed_text
}
impl Documentation for Document {
fn to_md(&self) -> String {
let root = MdNodeRef::new(MdRoot::default());
self.generate(root.clone());
let children = root.borrow().children();
let existing_links: HashSet<String, hash_map::RandomState> = HashSet::from_iter(
children
.iter()
.filter_map(|x| x.any_ref().id().map(String::from)),
);
for child in children {
let docs_with_links = child
.any_ref()
.docs()
.map(|docs| parse_links(docs, &existing_links));
if let Some(docs) = docs_with_links {
child.any_ref_mut().set_docs(&docs);
}
}
format!("{}", root)
}
}