1#![deny(unsafe_code)]
13
14pub mod cli;
15pub mod components;
16pub mod config;
17pub mod dev;
18pub mod discovery;
19pub mod error;
20pub mod models;
21pub mod parser;
22pub mod scaffold;
23pub mod template;
24pub mod writer;
25
26use std::path::Path;
27use std::time::Instant;
28
29use rayon::prelude::*;
30
31use crate::components::ComponentRegistry;
32use crate::config::Config;
33use crate::discovery::discover_pages;
34use crate::error::{OrbitError, PageError};
35use crate::models::RenderedPage;
36use crate::parser::{compile_all, compile_markdown};
37use crate::template::{TemplateEngine, render_all};
38use crate::writer::{clean_output_dir, write_all};
39
40#[derive(Debug, Clone, PartialEq, Eq)]
42pub struct BuildReport {
43 pub pages_written: usize,
45 pub elapsed_ms: u128,
47}
48
49pub fn build(config: &Config) -> Result<BuildReport, OrbitError> {
55 let started = Instant::now();
56
57 let components = ComponentRegistry::from_config(config)?;
58 let engine = TemplateEngine::from_config(config)?;
59 clean_output_dir(&config.output_dir).map_err(OrbitError::from)?;
60
61 let uncompiled = discover_pages(&config.source_dir).map_err(OrbitError::from)?;
62 let compiled = compile_all(uncompiled, &components).map_err(OrbitError::from)?;
63 let rendered = render_all(&engine, compiled, &config.output_dir).map_err(OrbitError::from)?;
64
65 let count = rendered.len();
66 write_all(&rendered).map_err(OrbitError::from)?;
67
68 Ok(BuildReport {
69 pages_written: count,
70 elapsed_ms: started.elapsed().as_millis(),
71 })
72}
73
74pub fn compile_pipeline(
78 config: &Config,
79 content_root: &Path,
80) -> Result<Vec<RenderedPage>, PageError> {
81 let components = ComponentRegistry::from_config(config)
82 .map_err(|err| PageError::new(content_root, err.to_string()))?;
83 let engine = TemplateEngine::from_config(config)
84 .map_err(|err| PageError::new(content_root, err.to_string()))?;
85
86 let uncompiled = discover_pages(content_root)?;
87 let compiled = compile_all(uncompiled, &components)?;
88 render_all(&engine, compiled, &config.output_dir)
89}
90
91pub fn compile_markdown_batch(
93 pages: Vec<crate::models::UncompiledPage>,
94 registry: &ComponentRegistry,
95) -> Result<usize, PageError> {
96 let count = pages
97 .into_par_iter()
98 .map(|page| compile_markdown(page, registry))
99 .collect::<Result<Vec<_>, _>>()?
100 .len();
101 Ok(count)
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107 use crate::models::{FrontMatter, SourcePage, UncompiledPage};
108 use std::path::PathBuf;
109
110 #[test]
111 fn compile_markdown_batch_parallel() {
112 let registry = ComponentRegistry::from_config(&Config::default()).unwrap();
113 let pages: Vec<_> = (0..32)
114 .map(|i| {
115 UncompiledPage::new(SourcePage {
116 source_path: PathBuf::from(format!("content/{i}.md")),
117 relative_path: PathBuf::from(format!("{i}.md")),
118 front_matter: FrontMatter::default(),
119 body: format!("# Post {i}\n\nParagraph."),
120 })
121 })
122 .collect();
123
124 let count = compile_markdown_batch(pages, ®istry).unwrap();
125 assert_eq!(count, 32);
126 }
127}