use std::path::PathBuf; use crate::error::CustomError; use super::footnote_definition::IRealFootnoteDefinition; use super::macros::intermediate; use super::IDocumentElement; use super::IHeading; use super::ISection; #[derive(Debug)] pub(crate) struct BlogPostPageInput<'b, 'parse> { path: PathBuf, document: &'b organic::types::Document<'parse>, } impl<'b, 'parse> BlogPostPageInput<'b, 'parse> { pub(crate) fn new>( path: P, document: &'b organic::types::Document<'parse>, ) -> BlogPostPageInput<'b, 'parse> { BlogPostPageInput { path: path.into(), document, } } } #[derive(Debug)] pub(crate) struct BlogPostPage { /// Relative path from the root of the blog post. pub(crate) path: PathBuf, pub(crate) title: Option, pub(crate) date: Option, pub(crate) children: Vec, pub(crate) footnotes: Vec, } intermediate!( BlogPostPage, BlogPostPageInput<'orig, 'parse>, original, intermediate_context, { let mut children = Vec::new(); if let Some(section) = original.document.zeroth_section.as_ref() { children.push(IDocumentElement::Section( ISection::new(intermediate_context.clone(), section).await?, )); } for heading in original.document.children.iter() { children.push(IDocumentElement::Heading( IHeading::new(intermediate_context.clone(), heading).await?, )); } let footnotes = { let footnote_definitions: Vec<_> = { let registry = intermediate_context.registry.lock().unwrap(); let ret = registry .get_footnote_ids() .map(|(id, def)| (id, def.clone())) .collect(); ret }; let mut ret = Vec::new(); for (id, def) in footnote_definitions.into_iter() { ret.push( IRealFootnoteDefinition::new(intermediate_context.clone(), id, def).await?, ); } ret }; Ok(BlogPostPage { path: original.path, title: get_title(original.document), date: get_date(original.document), children, footnotes, }) } ); impl BlogPostPage { /// Get the output path relative to the post directory. pub(crate) fn get_output_path(&self) -> PathBuf { let mut ret = self.path.clone(); ret.set_extension("html"); ret } } fn get_title(document: &organic::types::Document<'_>) -> Option { organic::types::AstNode::from(document) .iter_all_ast_nodes() .filter_map(|node| match node { organic::types::AstNode::Keyword(kw) if kw.key.eq_ignore_ascii_case("title") => { Some(kw) } _ => None, }) .last() .map(|kw| kw.value.to_owned()) } fn get_date(document: &organic::types::Document<'_>) -> Option { organic::types::AstNode::from(document) .iter_all_ast_nodes() .filter_map(|node| match node { organic::types::AstNode::Keyword(kw) if kw.key.eq_ignore_ascii_case("date") => Some(kw), _ => None, }) .last() .map(|kw| kw.value.to_owned()) }