1#![deny(missing_docs)]
20#![deny(rust_2018_idioms)]
21#![doc(html_playground_url = "https://play.rust-lang.org/")]
22mod build_book;
26mod dependencies;
27mod fs;
28mod gen;
29mod link;
30pub mod markdown;
31mod parser;
32mod sitemap;
33pub mod test_markdown;
34mod write_from_parser;
35
36use std::fs::File;
37use std::io::BufWriter;
38use std::io::Write;
39use std::path::Path;
40
41use anyhow::bail;
42use anyhow::Context;
43use anyhow::Result;
44use pulldown_cmark::LinkType;
45use pulldown_cmark::Parser;
46
47fn helper<P1, P2, F>(src_dir_path: P1, dest_file_path: P2, func: F) -> Result<()>
55where
56 P1: AsRef<Path>,
57 P2: AsRef<Path>,
58 F: for<'a, 'b> FnOnce(&'a mut Parser<'a>, &'b mut File) -> Result<()>,
59{
60 let src_dir_path = fs::check_is_dir(src_dir_path)?;
61
62 fs::create_parent_dir_for(dest_file_path.as_ref())?;
63
64 let mut f = File::create(dest_file_path.as_ref()).with_context(|| {
65 format!(
66 "[helper] Could not create file {}",
67 dest_file_path.as_ref().display()
68 )
69 })?;
70
71 let all_markdown = fs::read_to_string_all_markdown_files_in(src_dir_path)?;
72 let mut parser = parser::get_parser(all_markdown.as_ref());
73
74 func(&mut parser, &mut f)?;
75 Ok(())
76}
77
78pub fn debug_parse_to<P1, P2>(src_dir_path: P1, dest_file_path: P2) -> Result<()>
89where
90 P1: AsRef<Path>,
91 P2: AsRef<Path>,
92{
93 helper(
94 src_dir_path,
95 dest_file_path,
96 write_from_parser::write_raw_to,
97 )?;
98 Ok(())
99}
100
101pub fn test() -> Result<()> {
103 fs::create_dir("./book/temp/")?;
104
105 let dest_file_path = "./book/temp/test.log";
106 let mut f = BufWriter::new(File::create(dest_file_path).context(
107 "[test] Failed to create the destination file. Does the full directory path exist?",
108 )?);
109
110 let test_markdown = test_markdown::get_test_markdown();
111 let mut parser = parser::get_parser(test_markdown.as_ref());
112 write_from_parser::write_raw_to(&mut parser, &mut f)?;
113 f.flush()
114 .context("Not all bytes could be written due to I/O errors or EOF being reached.")?;
115 Ok(())
116}
117
118pub fn write_refdefs_to<P1, P2>(src_dir_path: P1, dest_file_path: P2) -> Result<()>
127where
128 P1: AsRef<Path>,
129 P2: AsRef<Path>,
130{
131 helper(
132 src_dir_path,
133 dest_file_path,
134 write_from_parser::write_refdefs_to,
135 )?;
136 Ok(())
137}
138
139pub fn generate_badges<P1, P2>(src_dir_path: P1, dest_file_path: P2) -> Result<()>
149where
150 P1: AsRef<Path>,
151 P2: AsRef<Path>,
152{
153 helper(
154 src_dir_path,
155 dest_file_path,
156 write_from_parser::write_github_repo_badge_refdefs,
157 )?;
158 Ok(())
159}
160
161pub fn write_inline_links<P1, P2>(src_dir_path: P1, dest_file_path: P2) -> Result<()>
173where
174 P1: AsRef<Path>,
175 P2: AsRef<Path>,
176{
177 helper(src_dir_path, dest_file_path, |parser, f| {
178 let links: Vec<link::Link<'_>> = parser::extract_links(parser);
179 let links: Vec<_> = links
180 .into_iter()
181 .filter(|l| {
182 [LinkType::Inline, LinkType::Autolink]
183 .iter()
184 .any(|&x| l.get_link_type().unwrap() == x)
185 })
186 .collect();
187 link::write_reference_style_links_to(links, f)?;
188 Ok(())
189 })?;
190
191 Ok(())
192}
193
194pub fn write_all_links<P1, P2>(src_dir_path: P1, dest_file_path: P2) -> Result<()>
201where
202 P1: AsRef<Path>,
203 P2: AsRef<Path>,
204{
205 helper(src_dir_path, dest_file_path, |parser, f| {
206 let links: Vec<link::Link<'_>> = parser::extract_links(parser);
207 link::write_reference_style_links_to(links, f)?;
208 Ok(())
209 })?;
210
211 Ok(())
212}
213
214pub fn write_duplicate_links<P1, P2>(src_dir_path: P1, dest_file_path: P2) -> Result<()>
221where
222 P1: AsRef<Path>,
223 P2: AsRef<Path>,
224{
225 helper(src_dir_path, dest_file_path, |parser, _f| {
226 let _links: Vec<link::Link<'_>> = parser::extract_links(parser);
227 println!("NOT IMPLEMENTED!");
229 Ok(())
230 })?;
231
232 Ok(())
233}
234
235pub fn write_broken_links<P1, P2>(src_dir_path: P1, dest_file_path: P2) -> Result<()>
242where
243 P1: AsRef<Path>,
244 P2: AsRef<Path>,
245{
246 helper(src_dir_path, dest_file_path, |parser, _f| {
247 let _links: Vec<link::Link<'_>> = parser::extract_links(parser);
248 println!("NOT IMPLEMENTED!");
250 Ok(())
251 })?;
252
253 Ok(())
254}
255
256pub fn generate_refdefs_to<P1, P2, P3>(
269 cargo_toml_dir_path: P1,
270 markdown_dir_path: P2,
271 refdef_dest_file_path: P3,
272) -> Result<()>
273where
274 P1: AsRef<Path>,
275 P2: AsRef<Path>,
276 P3: AsRef<Path>,
277{
278 let deps = dependencies::get_dependencies(&cargo_toml_dir_path)?;
280 let mut new_links = gen::generate_refdefs_from(deps);
284
285 helper(markdown_dir_path, refdef_dest_file_path, |parser, f| {
287 let _sorted_linkdefs: std::collections::BTreeMap<_, _> =
289 parser.reference_definitions().iter().collect();
290 println!("NOT IMPLEMENTED!");
292 let existing_links = Vec::new();
293
294 let links = gen::merge_links(existing_links, &mut new_links);
295 link::write_refdefs_to(links, f)?;
296 Ok(())
297 })?;
298 Ok(())
299}
300
301pub fn generate_sitemap<P1, P2>(
313 markdown_src_dir_path: P1,
314 base_url: url::Url,
315 sitemap_dest_file_path: P2,
316) -> Result<()>
317where
318 P1: AsRef<Path>,
319 P2: AsRef<Path>,
320{
321 if base_url.cannot_be_a_base() {
325 bail!("Invalid URL - cannot be a base: {}", base_url);
326 }
327
328 let markdown_src_dir_path = fs::check_is_dir(markdown_src_dir_path)?;
330
331 fs::create_parent_dir_for(sitemap_dest_file_path.as_ref())?;
333
334 let mut f = File::create(sitemap_dest_file_path.as_ref()).with_context(|| {
338 format!(
339 "Failed to create the sitemap file {}. The full directory path may not exist or required permissions may be missing.",
340 sitemap_dest_file_path.as_ref().display()
341 )
342 })?;
343
344 let summary_md_path = markdown_src_dir_path.join("SUMMARY.md");
345 tracing::debug!("SUMMARY.md path: {}", summary_md_path.display());
346 let markdown = std::fs::read_to_string(summary_md_path.clone()).with_context(|| {
347 format!(
348 "[generate_sitemap] Could not read {}. Does the file exist?",
349 summary_md_path.display()
350 )
351 })?;
352 let mut parser = parser::get_parser(markdown.as_str());
353 let links: Vec<link::Link<'_>> = parser::extract_links(&mut parser);
354
355 sitemap::generate_sitemap(links, base_url, &mut f)?;
356
357 Ok(())
358}
359
360#[cfg(test)]
361mod test {
362 }