use crate::generator::posts::parse::{parse_post, prepare_post, PostContent, PostMetadata}; use crate::generator::{content_path, HtmlContent, Post}; use compute_graph::rule::{Input, InputVisitable, Rule}; use std::fs; use std::path::PathBuf; pub fn list_post_files() -> anyhow::Result> { let posts_path = content_path("posts/"); let mut paths = vec![]; for ent in fs::read_dir(posts_path)? { let Ok(ent) = ent else { continue; }; let Ok(ty) = ent.file_type() else { continue; }; if ty.is_dir() { paths.push(find_index(ent.path()).expect("folder posts must have index file")); } else { paths.push(ent.path()); } } Ok(paths) } fn find_index(path: PathBuf) -> Option { let dir = fs::read_dir(path).ok()?; dir.flatten() .find(|e| e.path().file_stem().unwrap().eq_ignore_ascii_case("index")) .map(|e| e.path()) } #[derive(InputVisitable)] pub struct ParsePost(pub PathBuf); impl Rule for ParsePost { type Output = Post; fn evaluate(&mut self) -> Self::Output { match parse_post(self.0.clone()) { Ok(post) => prepare_post(post), Err(e) => { let path = self.0.to_string_lossy(); panic!("Failed to parse post {path}: {e}") } } } fn node_label(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.0.file_stem().unwrap().to_string_lossy()) } } #[derive(InputVisitable)] pub struct ExtractMetadata(pub Input>); impl Rule for ExtractMetadata { type Output = PostMetadata; fn evaluate(&mut self) -> Self::Output { self.input_0().metadata.clone() } }