ruitl 0.2.2

Template compiler for type-safe, server-rendered HTML components in Rust
Documentation
//! Build script for the RUITL runtime crate.
//!
//! Compiles every `.ruitl` template found under `templates/` or `src/templates/`
//! into a sibling `*_ruitl.rs` file using the shared `ruitl_compiler` crate.
//! The CLI (`ruitl compile`) uses the same crate — there is no second parser.

use std::env;
use std::path::{Path, PathBuf};
use std::process;

fn main() {
    // docs.rs mounts the crate source read-only while building, and the
    // committed sibling `*_ruitl.rs` files already match what we'd emit —
    // so there is nothing to do there. Ditto any host that explicitly
    // opts out via `RUITL_SKIP_BUILD=1`.
    if env::var_os("DOCS_RS").is_some() || env::var_os("RUITL_SKIP_BUILD").is_some() {
        return;
    }

    let manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
    let manifest_root = PathBuf::from(&manifest_dir);

    let candidates = [
        manifest_root.join("templates"),
        manifest_root.join("src").join("templates"),
        // `examples/demo_templates/` hosts compilable templates used by
        // `examples/server_integration.rs` to demonstrate real sibling-file
        // integration. `examples/syntax_showcase/` (deliberately NOT in this
        // list) holds hand-written reference templates that exercise every
        // feature but depend on notional user-defined types — read-only
        // material for users learning the syntax.
        manifest_root.join("examples").join("demo_templates"),
    ];

    let mut compiled: Vec<PathBuf> = Vec::new();
    let mut errors: Vec<String> = Vec::new();

    for dir in &candidates {
        if !dir.exists() {
            continue;
        }

        // Rerun on any change under the templates dir.
        println!("cargo:rerun-if-changed={}", dir.display());
        emit_rerun_for_ruitl_files(dir);

        match ruitl_compiler::compile_dir_sibling(dir) {
            Ok(paths) => compiled.extend(paths),
            Err(e) => errors.push(format!("{}: {}", dir.display(), e)),
        }
    }

    if !errors.is_empty() {
        eprintln!("RUITL template compilation failed:");
        for err in &errors {
            eprintln!("  {}", err);
        }
        process::exit(1);
    }

    if !compiled.is_empty() {
        println!(
            "cargo:warning=Compiled {} RUITL templates (sibling *_ruitl.rs files)",
            compiled.len()
        );
    }
}

fn emit_rerun_for_ruitl_files(dir: &Path) {
    for entry in walkdir::WalkDir::new(dir).into_iter().filter_map(|e| e.ok()) {
        let path = entry.path();
        if path.is_file() && path.extension().map(|e| e == "ruitl").unwrap_or(false) {
            println!("cargo:rerun-if-changed={}", path.display());
        }
    }
}