Store item type for items

Previously, we assumed that we only have to differentiate between items
(= elements with their own documentation file) and members (= elements
described in the documentation file of their parent).  But this model
was too simple.  For example, there are big differences in the structure
of a module and a struct documentation file.

Therefore we introduce a new enum, ItemType, that stores the type of an
item.  This allows us to drop the member field of the Item struct and to
add the name of the member to the full name of the item.
This commit is contained in:
Robin Krahl 2020-07-21 13:41:00 +02:00
parent 9613235ccc
commit 60cb034c5a
No known key found for this signature in database
GPG Key ID: 8E9B0870524F69D8
2 changed files with 43 additions and 27 deletions

View File

@ -21,6 +21,14 @@ pub struct Name {
#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
pub struct Fqn(Name);
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ItemType {
Crate,
Module,
Item,
Member,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Crate {
pub name: String,
@ -29,9 +37,9 @@ pub struct Crate {
#[derive(Clone, Debug, PartialEq)]
pub struct Item {
pub path: path::PathBuf,
pub name: Fqn,
pub member: Option<String>,
pub ty: ItemType,
pub path: path::PathBuf,
}
#[derive(Clone, Debug, Default)]
@ -135,6 +143,10 @@ impl Fqn {
self.first()
}
pub fn is_crate(&self) -> bool {
self.0.is_singleton()
}
pub fn parent(&self) -> Option<Self> {
self.0.parent().map(From::from)
}
@ -186,7 +198,11 @@ impl Crate {
if let Some(local_name) = name.rest() {
if let Some(path) = parser::find_item(self.path.join("all.html"), local_name)? {
let path = path::PathBuf::from(path);
return Ok(Some(Item::new(name.clone(), self.path.join(path), None)));
return Ok(Some(Item::new(
name.clone(),
self.path.join(path),
ItemType::Item,
)));
}
}
}
@ -205,7 +221,12 @@ impl Crate {
};
let path = self.path.join(module_path).join("index.html");
if path.is_file() {
Some(Item::new(name.clone(), path, None))
let item_type = if name.is_crate() {
ItemType::Crate
} else {
ItemType::Module
};
Some(Item::new(name.clone(), path, item_type))
} else {
None
}
@ -215,15 +236,11 @@ impl Crate {
}
pub fn find_member(&self, name: &Fqn) -> Option<Item> {
if self.name == name.krate() {
if let Some(parent) = name.parent() {
// TODO: error
self.find_item(&parent)
.unwrap()
.and_then(|i| i.find_member(name.last()))
} else {
None
}
if let Some(parent) = name.parent() {
// TODO: error
self.find_item(&parent)
.unwrap()
.and_then(|i| i.find_member(name.last()))
} else {
None
}
@ -231,13 +248,13 @@ impl Crate {
}
impl Item {
pub fn new(name: Fqn, path: path::PathBuf, member: Option<String>) -> Self {
Item { path, member, name }
pub fn new(name: Fqn, path: path::PathBuf, ty: ItemType) -> Self {
Item { name, ty, path }
}
pub fn load_doc(&self) -> anyhow::Result<Doc> {
if let Some(member) = &self.member {
parser::parse_member_doc(&self.path, &self.name, member)
if self.ty == ItemType::Member {
parser::parse_member_doc(&self.path, &self.name)
} else {
parser::parse_item_doc(&self.path, &self.name)
}
@ -247,9 +264,9 @@ impl Item {
// TODO: error handling
if parser::find_member(&self.path, name).unwrap() {
Some(Item::new(
self.name.clone(),
self.name.child(name),
self.path.clone(),
Some(name.to_owned()),
ItemType::Member,
))
} else {
None

View File

@ -96,19 +96,18 @@ pub fn parse_item_doc<P: AsRef<path::Path>>(path: P, name: &doc::Fqn) -> anyhow:
pub fn parse_member_doc<P: AsRef<path::Path>>(
path: P,
item: &doc::Fqn,
name: &str,
name: &doc::Fqn,
) -> anyhow::Result<doc::Doc> {
let document = parse_file(path)?;
let member =
get_member(&document, name)?.with_context(|| format!("Could not find member {}", name))?;
let member = get_member(&document, name.last())?
.with_context(|| format!("Could not find member {}", name))?;
let heading = member
.as_node()
.parent()
.with_context(|| format!("The member {} does not have a parent", name))?;
let docblock = heading.next_sibling();
let mut doc = doc::Doc::new(item.child(name));
let mut doc = doc::Doc::new(name.clone());
doc.definition = Some(get_html(member.as_node())?);
doc.description = docblock.map(|n| get_html(&n)).transpose()?;
Ok(doc)
@ -190,10 +189,10 @@ mod tests {
fn test_parse_member_doc() {
let path = crate::tests::ensure_docs();
let path = path.join("kuchiki").join("struct.NodeDataRef.html");
let name: doc::Fqn = "kuchiki::NodeDataRef".to_owned().into();
let doc = super::parse_member_doc(&path, &name, "as_node").unwrap();
let name: doc::Fqn = "kuchiki::NodeDataRef::as_node".to_owned().into();
let doc = super::parse_member_doc(&path, &name).unwrap();
assert_eq!(name.child("as_node"), doc.name);
assert_eq!(name, doc.name);
assert!(doc.title.is_none());
assert_eq!(
"<code id=\"as_node.v\">\