Add a build for regular non-blog-post pages from org source.
This commit is contained in:
		
							parent
							
								
									424a970014
								
							
						
					
					
						commit
						8905c9356b
					
				| @ -13,9 +13,11 @@ use crate::context::RenderBlogPostPageInput; | ||||
| use crate::context::RenderBlogStream; | ||||
| use crate::context::RenderBlogStreamInput; | ||||
| use crate::context::RenderContext; | ||||
| use crate::context::RenderPage; | ||||
| use crate::error::CustomError; | ||||
| use crate::intermediate::get_web_path; | ||||
| use crate::intermediate::BlogPost; | ||||
| use crate::intermediate::IPage; | ||||
| use crate::render::DusterRenderer; | ||||
| use crate::render::RendererIntegration; | ||||
| 
 | ||||
| @ -27,6 +29,7 @@ pub(crate) struct SiteRenderer { | ||||
|     output_directory: PathBuf, | ||||
|     blog_posts: Vec<BlogPost>, | ||||
|     stylesheets: Vec<Stylesheet>, | ||||
|     pages: Vec<IPage>, | ||||
| } | ||||
| 
 | ||||
| impl SiteRenderer { | ||||
| @ -34,11 +37,13 @@ impl SiteRenderer { | ||||
|         output_directory: P, | ||||
|         blog_posts: Vec<BlogPost>, | ||||
|         stylesheets: Vec<Stylesheet>, | ||||
|         pages: Vec<IPage>, | ||||
|     ) -> SiteRenderer { | ||||
|         SiteRenderer { | ||||
|             output_directory: output_directory.into(), | ||||
|             blog_posts, | ||||
|             stylesheets, | ||||
|             pages, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -73,6 +78,29 @@ impl SiteRenderer { | ||||
|         Ok(renderer_integration) | ||||
|     } | ||||
| 
 | ||||
|     pub(crate) async fn render_pages(&self, config: &Config) -> Result<(), CustomError> { | ||||
|         let renderer_integration = self.init_renderer_integration()?; | ||||
| 
 | ||||
|         for page in &self.pages { | ||||
|             let output_path = self.output_directory.join(page.get_output_path()); | ||||
|             let render_context = RenderContext::new( | ||||
|                 config, | ||||
|                 self.output_directory.as_path(), | ||||
|                 output_path.as_path(), | ||||
|                 None, | ||||
|             )?; | ||||
|             let render_context = RenderPage::new(render_context, page)?; | ||||
|             let rendered_output = renderer_integration.render(render_context)?; | ||||
|             let parent_directory = output_path | ||||
|                 .parent() | ||||
|                 .ok_or("Output file should have a containing directory.")?; | ||||
|             tokio::fs::create_dir_all(parent_directory).await?; | ||||
|             tokio::fs::write(output_path, rendered_output).await?; | ||||
|         } | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     pub(crate) async fn render_blog_posts(&self, config: &Config) -> Result<(), CustomError> { | ||||
|         let renderer_integration = self.init_renderer_integration()?; | ||||
| 
 | ||||
|  | ||||
| @ -1,12 +1,19 @@ | ||||
| use std::ffi::OsStr; | ||||
| use std::path::PathBuf; | ||||
| use std::sync::Arc; | ||||
| use std::sync::Mutex; | ||||
| 
 | ||||
| use super::stylesheet::Stylesheet; | ||||
| use crate::cli::parameters::BuildArgs; | ||||
| use crate::command::build::render::SiteRenderer; | ||||
| use crate::config::Config; | ||||
| use crate::error::CustomError; | ||||
| use crate::intermediate::get_org_files; | ||||
| use crate::intermediate::BlogPost; | ||||
| use crate::intermediate::IPage; | ||||
| use crate::intermediate::IntermediateContext; | ||||
| use crate::intermediate::PageInput; | ||||
| use crate::intermediate::Registry; | ||||
| use include_dir::include_dir; | ||||
| use include_dir::Dir; | ||||
| 
 | ||||
| @ -17,13 +24,16 @@ pub(crate) async fn build_site(args: BuildArgs) -> Result<(), CustomError> { | ||||
|     let config = Config::load_from_file(args.config).await?; | ||||
|     let blog_posts = load_blog_posts(&config).await?; | ||||
|     let stylesheets = load_stylesheets().await?; | ||||
|     let pages = load_pages(&config).await?; | ||||
|     let renderer = SiteRenderer::new( | ||||
|         get_output_directory(&config).await?, | ||||
|         blog_posts, | ||||
|         stylesheets, | ||||
|         pages, | ||||
|     ); | ||||
|     renderer.render_blog_posts(&config).await?; | ||||
|     renderer.render_blog_stream(&config).await?; | ||||
|     renderer.render_pages(&config).await?; | ||||
|     renderer.render_stylesheets().await?; | ||||
|     renderer.copy_static_files(&config).await?; | ||||
| 
 | ||||
| @ -74,6 +84,62 @@ async fn load_blog_posts(config: &Config) -> Result<Vec<BlogPost>, CustomError> | ||||
|     Ok(blog_posts) | ||||
| } | ||||
| 
 | ||||
| async fn load_pages(config: &Config) -> Result<Vec<IPage>, CustomError> { | ||||
|     let pages_source = config | ||||
|         .get_root_directory() | ||||
|         .join(config.get_relative_path_to_pages()); | ||||
|     if !pages_source.exists() { | ||||
|         return Ok(Vec::new()); | ||||
|     } | ||||
|     let page_files = get_org_files(&pages_source)?; | ||||
|     let org_files = { | ||||
|         let mut ret = Vec::new(); | ||||
|         for page in page_files { | ||||
|             ret.push(page.await??); | ||||
|         } | ||||
|         ret | ||||
|     }; | ||||
|     let parsed_org_files = { | ||||
|         let mut ret = Vec::new(); | ||||
|         for (path, contents) in org_files.iter() { | ||||
|             let parsed = organic::parser::parse_file(contents.as_str(), Some(path)) | ||||
|                 .map_err(|_| CustomError::Static("Failed to parse org-mode document."))?; | ||||
|             ret.push((path, contents, parsed)); | ||||
|         } | ||||
|         ret | ||||
|     }; | ||||
| 
 | ||||
|     let pages = { | ||||
|         let mut ret = Vec::new(); | ||||
|         for (real_path, _contents, parsed_document) in parsed_org_files.iter() { | ||||
|             let mut registry = Registry::new(); | ||||
| 
 | ||||
|             // Assign IDs to the targets
 | ||||
|             organic::types::AstNode::from(parsed_document) | ||||
|                 .iter_all_ast_nodes() | ||||
|                 .for_each(|node| { | ||||
|                     if let organic::types::AstNode::Target(target) = node { | ||||
|                         registry.get_target(target.value); | ||||
|                     } | ||||
|                 }); | ||||
| 
 | ||||
|             let registry = Arc::new(Mutex::new(registry)); | ||||
|             let intermediate_context = IntermediateContext::new(registry)?; | ||||
|             let relative_to_pages_dir_path = real_path.strip_prefix(&pages_source)?; | ||||
|             ret.push( | ||||
|                 IPage::new( | ||||
|                     intermediate_context, | ||||
|                     PageInput::new(relative_to_pages_dir_path, parsed_document), | ||||
|                 ) | ||||
|                 .await?, | ||||
|             ); | ||||
|         } | ||||
|         ret | ||||
|     }; | ||||
| 
 | ||||
|     Ok(pages) | ||||
| } | ||||
| 
 | ||||
| async fn load_stylesheets() -> Result<Vec<Stylesheet>, CustomError> { | ||||
|     let sources: Vec<_> = DEFAULT_STYLESHEETS | ||||
|         .files() | ||||
|  | ||||
| @ -92,4 +92,8 @@ impl Config { | ||||
|     pub(crate) fn get_relative_path_to_static_files(&self) -> PathBuf { | ||||
|         Path::new("static").into() | ||||
|     } | ||||
| 
 | ||||
|     pub(crate) fn get_relative_path_to_pages(&self) -> PathBuf { | ||||
|         Path::new("pages").into() | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -36,6 +36,7 @@ mod line_break; | ||||
| mod macros; | ||||
| mod object; | ||||
| mod org_macro; | ||||
| mod page; | ||||
| mod page_header; | ||||
| mod paragraph; | ||||
| mod plain_link; | ||||
| @ -77,6 +78,7 @@ pub(crate) use footnote_definition::RenderRealFootnoteDefinition; | ||||
| pub(crate) use global_settings::GlobalSettings; | ||||
| pub(crate) use heading::RenderHeading; | ||||
| pub(crate) use object::RenderObject; | ||||
| pub(crate) use page::RenderPage; | ||||
| pub(crate) use page_header::PageHeader; | ||||
| pub(crate) use render_context::RenderContext; | ||||
| pub(crate) use section::RenderSection; | ||||
|  | ||||
							
								
								
									
										102
									
								
								src/context/page.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								src/context/page.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,102 @@ | ||||
| use super::footnote_definition::RenderRealFootnoteDefinition; | ||||
| use super::macros::render; | ||||
| use super::render_context::RenderContext; | ||||
| use super::GlobalSettings; | ||||
| use super::PageHeader; | ||||
| use super::RenderDocumentElement; | ||||
| use crate::error::CustomError; | ||||
| use crate::intermediate::get_web_path; | ||||
| use crate::intermediate::IPage; | ||||
| use serde::Serialize; | ||||
| 
 | ||||
| #[derive(Debug, Serialize)] | ||||
| #[serde(tag = "type")] | ||||
| #[serde(rename = "page")] | ||||
| pub(crate) struct RenderPage { | ||||
|     global_settings: GlobalSettings, | ||||
| 
 | ||||
|     page_header: Option<PageHeader>, | ||||
| 
 | ||||
|     /// The title that will be shown visibly on the page.
 | ||||
|     title: Option<String>, | ||||
| 
 | ||||
|     self_link: Option<String>, | ||||
| 
 | ||||
|     children: Vec<RenderDocumentElement>, | ||||
| 
 | ||||
|     footnotes: Vec<RenderRealFootnoteDefinition>, | ||||
| } | ||||
| 
 | ||||
| render!(RenderPage, IPage, original, render_context, { | ||||
|     let css_files = vec![ | ||||
|         get_web_path( | ||||
|             render_context.config, | ||||
|             render_context.output_root_directory, | ||||
|             render_context.output_file, | ||||
|             "stylesheet/reset.css", | ||||
|         )?, | ||||
|         get_web_path( | ||||
|             render_context.config, | ||||
|             render_context.output_root_directory, | ||||
|             render_context.output_file, | ||||
|             "stylesheet/main.css", | ||||
|         )?, | ||||
|     ]; | ||||
|     let js_files = vec![get_web_path( | ||||
|         render_context.config, | ||||
|         render_context.output_root_directory, | ||||
|         render_context.output_file, | ||||
|         "blog_post.js", | ||||
|     )?]; | ||||
|     let global_settings = GlobalSettings::new(original.title.clone(), css_files, js_files); | ||||
|     let page_header = PageHeader::new( | ||||
|         render_context.config.get_site_title().map(str::to_string), | ||||
|         Some(get_web_path( | ||||
|             render_context.config, | ||||
|             render_context.output_root_directory, | ||||
|             render_context.output_file, | ||||
|             "", | ||||
|         )?), | ||||
|     ); | ||||
|     let link_to_blog_post = get_web_path( | ||||
|         render_context.config, | ||||
|         render_context.output_root_directory, | ||||
|         render_context.output_file, | ||||
|         render_context | ||||
|             .output_file | ||||
|             .strip_prefix(render_context.output_root_directory)?, | ||||
|     )?; | ||||
| 
 | ||||
|     let children = { | ||||
|         let mut children = Vec::new(); | ||||
| 
 | ||||
|         for child in original.children.iter() { | ||||
|             children.push(RenderDocumentElement::new(render_context.clone(), child)?); | ||||
|         } | ||||
| 
 | ||||
|         children | ||||
|     }; | ||||
| 
 | ||||
|     let footnotes = { | ||||
|         let mut ret = Vec::new(); | ||||
| 
 | ||||
|         for footnote in original.footnotes.iter() { | ||||
|             ret.push(RenderRealFootnoteDefinition::new( | ||||
|                 render_context.clone(), | ||||
|                 footnote, | ||||
|             )?); | ||||
|         } | ||||
| 
 | ||||
|         ret | ||||
|     }; | ||||
| 
 | ||||
|     let ret = RenderPage { | ||||
|         global_settings, | ||||
|         page_header: Some(page_header), | ||||
|         title: original.title.clone(), | ||||
|         self_link: Some(link_to_blog_post), | ||||
|         children, | ||||
|         footnotes, | ||||
|     }; | ||||
|     Ok(ret) | ||||
| }); | ||||
| @ -7,7 +7,7 @@ use tokio::task::JoinHandle; | ||||
| use walkdir::WalkDir; | ||||
| 
 | ||||
| use crate::error::CustomError; | ||||
| use crate::intermediate::page::BlogPostPageInput; | ||||
| use crate::intermediate::blog_post_page::BlogPostPageInput; | ||||
| use crate::intermediate::registry::Registry; | ||||
| use crate::intermediate::IntermediateContext; | ||||
| 
 | ||||
| @ -119,7 +119,7 @@ async fn read_file(path: PathBuf) -> std::io::Result<(PathBuf, String)> { | ||||
|     Ok((path, contents)) | ||||
| } | ||||
| 
 | ||||
| fn get_org_files<P: AsRef<Path>>( | ||||
| pub(crate) fn get_org_files<P: AsRef<Path>>( | ||||
|     root_dir: P, | ||||
| ) -> Result<impl Iterator<Item = JoinHandle<std::io::Result<(PathBuf, String)>>>, walkdir::Error> { | ||||
|     let org_files = WalkDir::new(root_dir) | ||||
|  | ||||
							
								
								
									
										121
									
								
								src/intermediate/blog_post_page.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								src/intermediate/blog_post_page.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,121 @@ | ||||
| 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<P: Into<PathBuf>>( | ||||
|         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<String>, | ||||
| 
 | ||||
|     pub(crate) date: Option<String>, | ||||
| 
 | ||||
|     pub(crate) children: Vec<IDocumentElement>, | ||||
| 
 | ||||
|     pub(crate) footnotes: Vec<IRealFootnoteDefinition>, | ||||
| } | ||||
| 
 | ||||
| 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 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub(crate) fn get_title(document: &organic::types::Document<'_>) -> Option<String> { | ||||
|     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()) | ||||
| } | ||||
| 
 | ||||
| pub(crate) fn get_date(document: &organic::types::Document<'_>) -> Option<String> { | ||||
|     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()) | ||||
| } | ||||
| @ -2,6 +2,7 @@ mod angle_link; | ||||
| mod ast_node; | ||||
| mod babel_call; | ||||
| mod blog_post; | ||||
| mod blog_post_page; | ||||
| mod bold; | ||||
| mod center_block; | ||||
| mod citation; | ||||
| @ -70,7 +71,9 @@ mod verse_block; | ||||
| pub(crate) use angle_link::IAngleLink; | ||||
| pub(crate) use ast_node::IAstNode; | ||||
| pub(crate) use babel_call::IBabelCall; | ||||
| pub(crate) use blog_post::get_org_files; | ||||
| pub(crate) use blog_post::BlogPost; | ||||
| pub(crate) use blog_post_page::BlogPostPage; | ||||
| pub(crate) use bold::IBold; | ||||
| pub(crate) use center_block::ICenterBlock; | ||||
| pub(crate) use citation::ICitation; | ||||
| @ -105,7 +108,8 @@ pub(crate) use latex_fragment::ILatexFragment; | ||||
| pub(crate) use line_break::ILineBreak; | ||||
| pub(crate) use object::IObject; | ||||
| pub(crate) use org_macro::IOrgMacro; | ||||
| pub(crate) use page::BlogPostPage; | ||||
| pub(crate) use page::IPage; | ||||
| pub(crate) use page::PageInput; | ||||
| pub(crate) use paragraph::IParagraph; | ||||
| pub(crate) use plain_link::IPlainLink; | ||||
| pub(crate) use plain_list::IPlainList; | ||||
| @ -117,6 +121,7 @@ pub(crate) use property_drawer::IPropertyDrawer; | ||||
| pub(crate) use quote_block::IQuoteBlock; | ||||
| pub(crate) use radio_link::IRadioLink; | ||||
| pub(crate) use radio_target::IRadioTarget; | ||||
| pub(crate) use registry::Registry; | ||||
| pub(crate) use regular_link::IRegularLink; | ||||
| pub(crate) use section::ISection; | ||||
| pub(crate) use special_block::ISpecialBlock; | ||||
|  | ||||
| @ -1,39 +1,21 @@ | ||||
| use std::path::PathBuf; | ||||
| 
 | ||||
| use crate::error::CustomError; | ||||
| 
 | ||||
| use super::blog_post_page::get_date; | ||||
| use super::blog_post_page::get_title; | ||||
| use super::footnote_definition::IRealFootnoteDefinition; | ||||
| 
 | ||||
| use super::macros::intermediate; | ||||
| use super::IDocumentElement; | ||||
| use super::IHeading; | ||||
| use super::ISection; | ||||
| use crate::error::CustomError; | ||||
| use std::path::PathBuf; | ||||
| 
 | ||||
| #[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<P: Into<PathBuf>>( | ||||
|         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) struct IPage { | ||||
|     /// Relative path from the root of the pages directory.
 | ||||
|     pub(crate) path: PathBuf, | ||||
| 
 | ||||
|     pub(crate) title: Option<String>, | ||||
| 
 | ||||
|     #[allow(dead_code)] | ||||
|     pub(crate) date: Option<String>, | ||||
| 
 | ||||
|     pub(crate) children: Vec<IDocumentElement>, | ||||
| @ -42,8 +24,8 @@ pub(crate) struct BlogPostPage { | ||||
| } | ||||
| 
 | ||||
| intermediate!( | ||||
|     BlogPostPage, | ||||
|     BlogPostPageInput<'orig, 'parse>, | ||||
|     IPage, | ||||
|     PageInput<'orig, 'parse>, | ||||
|     original, | ||||
|     intermediate_context, | ||||
|     { | ||||
| @ -77,7 +59,7 @@ intermediate!( | ||||
|             ret | ||||
|         }; | ||||
| 
 | ||||
|         Ok(BlogPostPage { | ||||
|         Ok(IPage { | ||||
|             path: original.path, | ||||
|             title: get_title(original.document), | ||||
|             date: get_date(original.document), | ||||
| @ -87,8 +69,8 @@ intermediate!( | ||||
|     } | ||||
| ); | ||||
| 
 | ||||
| impl BlogPostPage { | ||||
|     /// Get the output path relative to the post directory.
 | ||||
| impl IPage { | ||||
|     /// Get the output path relative to the pages directory.
 | ||||
|     pub(crate) fn get_output_path(&self) -> PathBuf { | ||||
|         let mut ret = self.path.clone(); | ||||
|         ret.set_extension("html"); | ||||
| @ -96,26 +78,20 @@ impl BlogPostPage { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn get_title(document: &organic::types::Document<'_>) -> Option<String> { | ||||
|     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()) | ||||
| #[derive(Debug)] | ||||
| pub(crate) struct PageInput<'b, 'parse> { | ||||
|     path: PathBuf, | ||||
|     document: &'b organic::types::Document<'parse>, | ||||
| } | ||||
| 
 | ||||
| fn get_date(document: &organic::types::Document<'_>) -> Option<String> { | ||||
|     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()) | ||||
| impl<'b, 'parse> PageInput<'b, 'parse> { | ||||
|     pub(crate) fn new<P: Into<PathBuf>>( | ||||
|         path: P, | ||||
|         document: &'b organic::types::Document<'parse>, | ||||
|     ) -> PageInput<'b, 'parse> { | ||||
|         PageInput { | ||||
|             path: path.into(), | ||||
|             document, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Tom Alexander
						Tom Alexander