rs_web/markdown/
pipeline.rs

1use std::path::Path;
2
3use super::parser::{events_to_html, parse_markdown};
4use super::transforms::AstTransform;
5use crate::config::Config;
6
7/// Context passed to transforms (fields available for custom transforms)
8#[allow(dead_code)]
9pub struct TransformContext<'a> {
10    pub config: &'a Config,
11    pub current_path: &'a Path,
12    pub base_url: &'a str,
13}
14
15/// Markdown processing pipeline
16pub struct Pipeline {
17    transforms: Vec<Box<dyn AstTransform>>,
18}
19
20impl Pipeline {
21    pub fn new() -> Self {
22        Self {
23            transforms: Vec::new(),
24        }
25    }
26
27    /// Add a transform to the pipeline
28    pub fn with<T: AstTransform + 'static>(mut self, transform: T) -> Self {
29        self.transforms.push(Box::new(transform));
30        self
31    }
32
33    /// Build the pipeline (sorts by priority)
34    pub fn build(mut self) -> Self {
35        self.transforms.sort_by_key(|t| t.priority());
36        self
37    }
38
39    /// Process markdown content through the pipeline
40    pub fn process(&self, content: &str, ctx: &TransformContext<'_>) -> String {
41        // Strip frontmatter if present (delimited by ---)
42        let content = if let Some(stripped) = content.strip_prefix("---") {
43            if let Some(end) = stripped.find("---") {
44                &stripped[end + 3..]
45            } else {
46                content
47            }
48        } else {
49            content
50        };
51
52        let mut events = parse_markdown(content);
53
54        // Apply each transform
55        for transform in &self.transforms {
56            events = transform.transform(events, ctx);
57        }
58
59        // Convert to HTML
60        events_to_html(events.into_iter())
61    }
62}
63
64impl Pipeline {
65    /// Create pipeline with default transforms and configuration
66    pub fn from_config(_config: &Config) -> Self {
67        use super::transforms::*;
68
69        Self::new()
70            .with(LazyImagesTransform)
71            .with(HeadingAnchorsTransform::new())
72            .with(ExternalLinksTransform)
73            .build()
74    }
75}
76
77impl Default for Pipeline {
78    fn default() -> Self {
79        use super::transforms::*;
80
81        Self::new()
82            .with(LazyImagesTransform)
83            .with(HeadingAnchorsTransform::new())
84            .with(ExternalLinksTransform)
85            .build()
86    }
87}