Skip to main content

forge_codegen/
compiler.rs

1//! Compile Forge templates to Askama templates. Driven from `build.rs`.
2
3use std::fs;
4use std::path::{Path, PathBuf};
5
6use walkdir::WalkDir;
7
8use crate::lower::lower;
9use crate::parser::tokenize;
10
11pub fn compile_source(source: &str) -> String {
12    let tokens = tokenize(source);
13    lower(&tokens)
14}
15
16pub fn compile_file(input: &Path, output: &Path) -> std::io::Result<()> {
17    let raw = fs::read_to_string(input)?;
18    let lowered = compile_source(&raw);
19    if let Some(parent) = output.parent() {
20        fs::create_dir_all(parent)?;
21    }
22    fs::write(output, lowered)?;
23    Ok(())
24}
25
26/// Walk `input_dir` for `*.forge.html` and write Askama-compatible `*.html`
27/// files into `output_dir`, preserving the relative layout.
28pub fn compile_dir(input_dir: &Path, output_dir: &Path) -> std::io::Result<Vec<PathBuf>> {
29    let mut written = Vec::new();
30    if !input_dir.exists() {
31        return Ok(written);
32    }
33    for entry in WalkDir::new(input_dir).into_iter().filter_map(|e| e.ok()) {
34        if !entry.file_type().is_file() {
35            continue;
36        }
37        let path = entry.path();
38        let Some(file_name) = path.file_name().and_then(|n| n.to_str()) else {
39            continue;
40        };
41        if !file_name.ends_with(".forge.html") && !file_name.ends_with(".forge") {
42            continue;
43        }
44        let rel = path.strip_prefix(input_dir).unwrap_or(path);
45        let out_name = file_name
46            .replace(".forge.html", ".html")
47            .replace(".forge", ".html");
48        let mut out_path = output_dir.to_path_buf();
49        if let Some(parent) = rel.parent() {
50            out_path.push(parent);
51        }
52        out_path.push(out_name);
53        compile_file(path, &out_path)?;
54        written.push(out_path);
55    }
56    Ok(written)
57}