Skip to main content

vbare_compiler/
lib.rs

1use indoc::formatdoc;
2use std::{fs, path::Path};
3
4/// Configuration for the vbare-compiler.
5///
6/// This allows callers to control how code generation behaves, including
7/// passing through configuration to `vbare_gen`.
8pub struct Config {
9    /// Configuration forwarded to `vbare_gen` for schema codegen.
10    pub vbare: vbare_gen::Config,
11}
12
13impl Default for Config {
14    fn default() -> Self {
15        Self {
16            vbare: vbare_gen::Config::default(),
17        }
18    }
19}
20
21/// Process BARE schema files and generate Rust code.
22pub fn process_schemas(schema_dir: &Path) -> Result<(), Box<dyn std::error::Error>> {
23    process_schemas_with_config(schema_dir, &Config::default())
24}
25
26/// Process BARE schema files and generate Rust code, using the provided config.
27pub fn process_schemas_with_config(
28    schema_dir: &Path,
29    config: &Config,
30) -> Result<(), Box<dyn std::error::Error>> {
31    let out_dir = std::env::var("OUT_DIR")?;
32    let out_path = Path::new(&out_dir);
33
34    println!("cargo:rerun-if-changed={}", schema_dir.display());
35
36    let mut all_names = Vec::new();
37
38    for entry in fs::read_dir(schema_dir)?.flatten() {
39        let path = entry.path();
40
41        if path.is_dir() {
42            continue;
43        }
44
45        let bare_name = path
46            .file_name()
47            .ok_or("No file name")?
48            .to_str()
49            .ok_or("Invalid UTF-8 in file name")?
50            .rsplit_once('.')
51            .ok_or("No file extension")?
52            .0;
53
54        let tokens = vbare_gen::bare_schema(&path, config.vbare);
55        let ast = syn::parse2(tokens)?;
56        let content = prettyplease::unparse(&ast);
57
58        fs::write(out_path.join(format!("{bare_name}_generated.rs")), content)?;
59
60        all_names.push(bare_name.to_string());
61    }
62
63    let mut mod_content = String::new();
64    mod_content.push_str("// Auto-generated module file for schemas\n\n");
65
66    for name in all_names {
67        let module_name = name.replace('.', "_");
68        mod_content.push_str(&formatdoc!(
69            r#"
70            pub mod {module_name} {{
71                include!(concat!(env!("OUT_DIR"), "/{name}_generated.rs"));
72            }}
73            "#,
74            name = name,
75            module_name = module_name,
76        ));
77    }
78
79    fs::write(out_path.join("combined_imports.rs"), mod_content)?;
80
81    Ok(())
82}