lssg_lib/
lib.rs

1pub mod char_reader;
2pub mod lmarkdown;
3pub mod parse_error;
4pub mod renderer;
5pub mod sitetree;
6
7pub mod html;
8pub mod lssg_error;
9mod path_extension;
10mod tree;
11
12use std::{
13    fs::{create_dir, create_dir_all, remove_dir_all, write, File},
14    io::{self},
15    path::PathBuf,
16};
17
18use log::info;
19use lssg_error::LssgError;
20use renderer::{Renderer, RendererModule};
21use sitetree::Input;
22
23use crate::{
24    path_extension::PathExtension,
25    sitetree::{Relation, SiteNodeKind, SiteTree},
26};
27
28pub struct Lssg {
29    input: Input,
30    output_directory: PathBuf,
31    renderer: Renderer,
32}
33
34impl Lssg {
35    pub fn new(input: Input, output_directory: PathBuf) -> Lssg {
36        let renderer = Renderer::new();
37        Lssg {
38            input,
39            output_directory,
40            renderer,
41        }
42    }
43
44    pub fn add_module(&mut self, module: impl RendererModule + 'static) {
45        self.renderer.add_module(module)
46    }
47
48    pub fn render(&mut self) -> Result<(), LssgError> {
49        info!("Generating SiteTree");
50        let mut site_tree = SiteTree::from_input(self.input.clone())?;
51
52        self.renderer.init(&mut site_tree);
53        info!("SiteTree:\n{site_tree}");
54
55        // site_tree.minify();
56
57        self.renderer.after_init(&mut site_tree);
58
59        if self.output_directory.exists() {
60            info!(
61                "Removing {:?}",
62                self.output_directory.canonicalize_nonexistent_path()
63            );
64            remove_dir_all(&self.output_directory)?;
65        }
66        info!(
67            "Creating {:?}",
68            self.output_directory.canonicalize_nonexistent_path()
69        );
70        create_dir_all(&self.output_directory)?;
71
72        let mut queue: Vec<usize> = vec![site_tree.root()];
73        while let Some(site_id) = queue.pop() {
74            queue.append(&mut site_tree[site_id].children.clone());
75            let rel_path = site_tree.rel_path(site_tree.root(), site_id);
76            let path = self
77                .output_directory
78                .join(rel_path)
79                .canonicalize_nonexistent_path();
80            match &mut site_tree[site_id].kind {
81                SiteNodeKind::Stylesheet(stylesheet) => {
82                    let mut stylesheet = stylesheet.clone();
83
84                    // update resources to stylesheet sitenode path
85                    for link in site_tree.links_from(site_id) {
86                        if let Relation::Discovered { raw_path } = &link.relation {
87                            let updated_resource = site_tree.path(link.to);
88                            stylesheet.update_resource(raw_path, &updated_resource);
89                        }
90                    }
91
92                    stylesheet.write(&path)?;
93                }
94                SiteNodeKind::Resource(resource) => {
95                    resource.write(&path)?;
96                }
97                SiteNodeKind::Folder => {
98                    info!("Creating folder {path:?}",);
99                    create_dir(path)?;
100                }
101                SiteNodeKind::Page { .. } => {
102                    let html = self.renderer.render(&site_tree, site_id)?;
103                    create_dir_all(&path)?;
104                    let html_output_path = path.join("index.html").canonicalize_nonexistent_path();
105
106                    info!(
107                        "Writing to {:?}",
108                        (&html_output_path).canonicalize_nonexistent_path()
109                    );
110                    write(html_output_path, html)?;
111                }
112            }
113        }
114
115        info!("All files written");
116
117        Ok(())
118    }
119}