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)
}
}