1pub mod char_reader;
19pub mod lmarkdown;
20pub mod parse_error;
21pub mod renderer;
22pub mod sitetree;
23
24mod domnode_to_token;
25pub mod lssg_error;
26mod path_extension;
27mod tree;
28
29use std::{
30 fs::{create_dir, create_dir_all, remove_dir_all, write},
31 path::PathBuf,
32};
33
34use log::info;
35use lssg_error::LssgError;
36use renderer::{Renderer, RendererModule};
37use sitetree::Input;
38
39use crate::{
40 path_extension::PathExtension,
41 sitetree::{Relation, SiteId, SiteNodeKind, SiteTree},
42};
43
44pub struct Lssg {
45 input: Input,
46 output_directory: PathBuf,
47 renderer: Renderer,
48}
49
50impl Lssg {
51 pub fn new(input: Input, output_directory: PathBuf) -> Lssg {
52 let renderer = Renderer::default();
53 Lssg {
54 input,
55 output_directory,
56 renderer,
57 }
58 }
59
60 pub fn add_module(&mut self, module: impl RendererModule + 'static) {
61 self.renderer.add_module(module)
62 }
63
64 pub fn render(&mut self) -> Result<(), LssgError> {
65 info!("Generating SiteTree");
66 let mut site_tree = SiteTree::from_input(self.input.clone())?;
67
68 self.renderer.init(&mut site_tree);
69 info!("SiteTree:\n{site_tree}");
70
71 self.renderer.after_init(&site_tree);
74
75 if self.output_directory.exists() {
76 info!(
77 "Removing {:?}",
78 self.output_directory.canonicalize_nonexistent_path()
79 );
80 remove_dir_all(&self.output_directory)?;
81 }
82 info!(
83 "Creating {:?}",
84 self.output_directory.canonicalize_nonexistent_path()
85 );
86 create_dir_all(&self.output_directory)?;
87
88 let mut queue: Vec<SiteId> = vec![site_tree.root()];
89 while let Some(site_id) = queue.pop() {
90 queue.append(&mut site_tree[site_id].children.clone());
91 let rel_path = site_tree.rel_path(site_tree.root(), site_id);
92 let path = self
93 .output_directory
94 .join(rel_path)
95 .canonicalize_nonexistent_path();
96 match &mut site_tree[site_id].kind {
97 SiteNodeKind::Stylesheet(stylesheet) => {
98 let mut stylesheet = stylesheet.clone();
99
100 for link in site_tree.links_from(site_id) {
102 if let Relation::Discovered { raw_path } = &link.relation {
103 let updated_resource = site_tree.rel_path(
104 site_tree[site_id]
105 .parent
106 .expect("stylesheet must have parent"),
107 link.to,
108 );
109 stylesheet.update_resource(raw_path, &updated_resource);
110 }
111 }
112
113 stylesheet.write(&path)?;
114 }
115 SiteNodeKind::Resource(resource) => {
116 resource.write(&path)?;
117 }
118 SiteNodeKind::Folder => {
119 info!("Creating folder {path:?}",);
120 create_dir(path)?;
121 }
122 SiteNodeKind::Page { .. } => {
123 let html = self.renderer.render(&site_tree, site_id)?;
124 create_dir_all(&path)?;
125 let html_output_path = path.join("index.html").canonicalize_nonexistent_path();
126
127 info!(
128 "Writing to {:?}",
129 html_output_path.canonicalize_nonexistent_path()
130 );
131 write(html_output_path, html)?;
132 }
133 }
134 }
135
136 info!("All files written");
137
138 Ok(())
139 }
140}