use std::path::PathBuf;
#[derive(Debug, Clone)]
pub struct WebCodegenConfig {
pub proto_files: Vec<PathBuf>,
pub rust_output_dir: PathBuf,
pub ts_output_dir: PathBuf,
pub generate_react_hooks: bool,
pub includes: Vec<PathBuf>,
pub format_code: bool,
pub custom_templates_dir: Option<PathBuf>,
}
impl WebCodegenConfig {
pub fn builder() -> WebCodegenConfigBuilder {
WebCodegenConfigBuilder::default()
}
pub fn validate(&self) -> crate::Result<()> {
use crate::error::CodegenError;
if self.proto_files.is_empty() {
return Err(CodegenError::config("at least one proto file is required"));
}
for proto in &self.proto_files {
if !proto.exists() {
return Err(CodegenError::FileNotFound(proto.clone()));
}
}
for include in &self.includes {
if !include.exists() {
return Err(CodegenError::FileNotFound(include.clone()));
}
}
Ok(())
}
}
#[derive(Default)]
pub struct WebCodegenConfigBuilder {
proto_files: Vec<PathBuf>,
rust_output_dir: Option<PathBuf>,
ts_output_dir: Option<PathBuf>,
generate_react_hooks: bool,
includes: Vec<PathBuf>,
format_code: bool,
custom_templates_dir: Option<PathBuf>,
}
impl WebCodegenConfigBuilder {
pub fn proto_file<P: Into<PathBuf>>(mut self, path: P) -> Self {
self.proto_files.push(path.into());
self
}
pub fn proto_files<I, P>(mut self, paths: I) -> Self
where
I: IntoIterator<Item = P>,
P: Into<PathBuf>,
{
self.proto_files.extend(paths.into_iter().map(Into::into));
self
}
pub fn rust_output<P: Into<PathBuf>>(mut self, dir: P) -> Self {
self.rust_output_dir = Some(dir.into());
self
}
pub fn ts_output<P: Into<PathBuf>>(mut self, dir: P) -> Self {
self.ts_output_dir = Some(dir.into());
self
}
pub fn with_react_hooks(mut self, enabled: bool) -> Self {
self.generate_react_hooks = enabled;
self
}
pub fn include<P: Into<PathBuf>>(mut self, path: P) -> Self {
self.includes.push(path.into());
self
}
pub fn includes<I, P>(mut self, paths: I) -> Self
where
I: IntoIterator<Item = P>,
P: Into<PathBuf>,
{
self.includes.extend(paths.into_iter().map(Into::into));
self
}
pub fn with_formatting(mut self, enabled: bool) -> Self {
self.format_code = enabled;
self
}
pub fn custom_templates<P: Into<PathBuf>>(mut self, dir: P) -> Self {
self.custom_templates_dir = Some(dir.into());
self
}
pub fn build(self) -> crate::Result<WebCodegenConfig> {
use crate::error::CodegenError;
let rust_output_dir = self
.rust_output_dir
.ok_or_else(|| CodegenError::config("missing rust_output_dir configuration"))?;
let ts_output_dir = self
.ts_output_dir
.ok_or_else(|| CodegenError::config("missing ts_output_dir configuration"))?;
let config = WebCodegenConfig {
proto_files: self.proto_files,
rust_output_dir,
ts_output_dir,
generate_react_hooks: self.generate_react_hooks,
includes: self.includes,
format_code: self.format_code,
custom_templates_dir: self.custom_templates_dir,
};
config.validate()?;
Ok(config)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_builder() {
let config = WebCodegenConfig::builder()
.proto_file("test.proto")
.rust_output("src/generated")
.ts_output("src/types")
.with_react_hooks(true)
.include("proto")
.with_formatting(true);
assert!(config.generate_react_hooks);
assert!(config.format_code);
}
}