codegenr_lib/
lib.rs

1use serde::Deserialize;
2use serde_json::Value;
3use std::{collections::HashMap, rc::Rc};
4use tracing::{error, info};
5
6pub mod custom;
7pub mod errors;
8pub(crate) mod filesystem;
9pub mod helpers;
10pub mod loader;
11#[cfg(feature = "bin")]
12pub mod opt;
13pub mod processor;
14pub mod render;
15pub mod resolver;
16
17use filesystem::save_file_content;
18use handlebars::Handlebars;
19use thiserror::Error;
20
21type OptionsMap = HashMap<String, Options>;
22
23type OriginalDocumentsHash = HashMap<loader::DocumentPath, Rc<Value>>;
24type ResolvedDocumentsHash = HashMap<loader::DocumentPath, Rc<Value>>;
25type HandlebarsHash<'a> = HashMap<HandlebarsReusableConf, (String, Handlebars<'a>)>;
26
27#[derive(Debug, PartialEq, Eq, Hash)]
28struct HandlebarsReusableConf {
29  pub templates: Vec<String>,
30  pub custom_helpers: Vec<String>,
31}
32
33#[derive(Error, Debug)]
34pub enum SaverError {
35  #[error("Io Error: `{0}`.")]
36  Io(#[from] std::io::Error),
37}
38
39#[derive(Debug, Deserialize)]
40pub struct Options {
41  pub source: String,
42  pub output: String,
43  pub templates: Vec<String>,
44  pub intermediate: Option<String>,
45  pub custom_helpers: Vec<String>,
46  pub global_parameters: HashMap<String, serde_json::Value>,
47}
48
49#[::tracing::instrument(level = "trace")]
50pub fn run_all_codegenr(options_map: OptionsMap) -> Result<(), errors::CodegenrError> {
51  let mut original_cache = Default::default();
52  let mut resolved_cache = Default::default();
53  let mut reusables = Default::default();
54  for (name, options) in options_map {
55    info!("Running code generation section `{}`", name);
56    if let Err(e) = run_codegenr(options, &mut original_cache, &mut resolved_cache, &mut reusables) {
57      error!("Error while executing the `{}` section: `{}`.", name, e);
58    }
59  }
60  Ok(())
61}
62
63#[::tracing::instrument(level = "trace")]
64pub fn run_one_codegenr(options: Options) -> Result<(), errors::CodegenrError> {
65  let mut original_cache = Default::default();
66  let mut resolved_cache = Default::default();
67  let mut reusables = Default::default();
68  run_codegenr(options, &mut original_cache, &mut resolved_cache, &mut reusables)
69}
70
71#[::tracing::instrument(level = "trace")]
72fn run_codegenr(
73  options: Options,
74  original_cache: &mut OriginalDocumentsHash,
75  resolved_cache: &mut ResolvedDocumentsHash,
76  reusables: &mut HandlebarsHash,
77) -> Result<(), errors::CodegenrError> {
78  let document = loader::DocumentPath::parse(&options.source)?;
79  let json = resolver::resolve_refs(document, original_cache, resolved_cache)?;
80
81  if options.intermediate.is_some() {
82    save_intermediate(&options.intermediate, "resolved.json", &format!("{:#}", json))?;
83  }
84
85  let (main_template_name, mut handlebars) = reusables
86    .entry(HandlebarsReusableConf {
87      custom_helpers: options.custom_helpers,
88      templates: options.templates,
89    })
90    .or_insert_with_key(|conf| {
91      let mut all_templates = vec![];
92      for t in conf.templates.iter() {
93        let templates = render::get_templates_from_directory(t).unwrap(); //?;
94        all_templates.extend(templates);
95      }
96      let templates = render::TemplateCollection::from_list(all_templates).unwrap(); //?;
97
98      let mut handlebars = Handlebars::new();
99      templates.setup_handlebars(&mut handlebars).unwrap(); // todo?;
100      custom::handlebars_setup(&mut handlebars, &conf.custom_helpers).unwrap(); //?;
101      (templates.main_template_name().to_owned(), handlebars)
102    })
103    .clone();
104
105  helpers::handlebars_setup(&mut handlebars, options.global_parameters);
106
107  let rendered = handlebars.render(&main_template_name, &(*json))?;
108
109  save_intermediate(&options.intermediate, "rendered.txt", &rendered)?;
110
111  processor::process(&rendered, options.output)?;
112  Ok(())
113}
114
115fn save_intermediate(file: &Option<String>, extension: &str, content: &str) -> Result<(), SaverError> {
116  if let Some(s) = file {
117    let full_file_name = format!("{}.{}", s, extension);
118    save_file_content(".", &full_file_name, content)?;
119  }
120  Ok(())
121}