actr_web_protoc_codegen/
config.rs1use std::path::PathBuf;
4
5#[derive(Debug, Clone)]
7pub struct WebCodegenConfig {
8 pub proto_files: Vec<PathBuf>,
10
11 pub rust_output_dir: PathBuf,
13
14 pub ts_output_dir: PathBuf,
16
17 pub generate_react_hooks: bool,
19
20 pub includes: Vec<PathBuf>,
22
23 pub format_code: bool,
25
26 pub custom_templates_dir: Option<PathBuf>,
28}
29
30impl WebCodegenConfig {
31 pub fn builder() -> WebCodegenConfigBuilder {
33 WebCodegenConfigBuilder::default()
34 }
35
36 pub fn validate(&self) -> crate::Result<()> {
38 use crate::error::CodegenError;
39
40 if self.proto_files.is_empty() {
42 return Err(CodegenError::config("at least one proto file is required"));
43 }
44
45 for proto in &self.proto_files {
47 if !proto.exists() {
48 return Err(CodegenError::FileNotFound(proto.clone()));
49 }
50 }
51
52 for include in &self.includes {
54 if !include.exists() {
55 return Err(CodegenError::FileNotFound(include.clone()));
56 }
57 }
58
59 Ok(())
60 }
61}
62
63#[derive(Default)]
65pub struct WebCodegenConfigBuilder {
66 proto_files: Vec<PathBuf>,
67 rust_output_dir: Option<PathBuf>,
68 ts_output_dir: Option<PathBuf>,
69 generate_react_hooks: bool,
70 includes: Vec<PathBuf>,
71 format_code: bool,
72 custom_templates_dir: Option<PathBuf>,
73}
74
75impl WebCodegenConfigBuilder {
76 pub fn proto_file<P: Into<PathBuf>>(mut self, path: P) -> Self {
78 self.proto_files.push(path.into());
79 self
80 }
81
82 pub fn proto_files<I, P>(mut self, paths: I) -> Self
84 where
85 I: IntoIterator<Item = P>,
86 P: Into<PathBuf>,
87 {
88 self.proto_files.extend(paths.into_iter().map(Into::into));
89 self
90 }
91
92 pub fn rust_output<P: Into<PathBuf>>(mut self, dir: P) -> Self {
94 self.rust_output_dir = Some(dir.into());
95 self
96 }
97
98 pub fn ts_output<P: Into<PathBuf>>(mut self, dir: P) -> Self {
100 self.ts_output_dir = Some(dir.into());
101 self
102 }
103
104 pub fn with_react_hooks(mut self, enabled: bool) -> Self {
106 self.generate_react_hooks = enabled;
107 self
108 }
109
110 pub fn include<P: Into<PathBuf>>(mut self, path: P) -> Self {
112 self.includes.push(path.into());
113 self
114 }
115
116 pub fn includes<I, P>(mut self, paths: I) -> Self
118 where
119 I: IntoIterator<Item = P>,
120 P: Into<PathBuf>,
121 {
122 self.includes.extend(paths.into_iter().map(Into::into));
123 self
124 }
125
126 pub fn with_formatting(mut self, enabled: bool) -> Self {
128 self.format_code = enabled;
129 self
130 }
131
132 pub fn custom_templates<P: Into<PathBuf>>(mut self, dir: P) -> Self {
134 self.custom_templates_dir = Some(dir.into());
135 self
136 }
137
138 pub fn build(self) -> crate::Result<WebCodegenConfig> {
140 use crate::error::CodegenError;
141
142 let rust_output_dir = self
143 .rust_output_dir
144 .ok_or_else(|| CodegenError::config("missing rust_output_dir configuration"))?;
145
146 let ts_output_dir = self
147 .ts_output_dir
148 .ok_or_else(|| CodegenError::config("missing ts_output_dir configuration"))?;
149
150 let config = WebCodegenConfig {
151 proto_files: self.proto_files,
152 rust_output_dir,
153 ts_output_dir,
154 generate_react_hooks: self.generate_react_hooks,
155 includes: self.includes,
156 format_code: self.format_code,
157 custom_templates_dir: self.custom_templates_dir,
158 };
159
160 config.validate()?;
161
162 Ok(config)
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169
170 #[test]
171 fn test_builder() {
172 let config = WebCodegenConfig::builder()
173 .proto_file("test.proto")
174 .rust_output("src/generated")
175 .ts_output("src/types")
176 .with_react_hooks(true)
177 .include("proto")
178 .with_formatting(true);
179
180 assert!(config.generate_react_hooks);
182 assert!(config.format_code);
183 }
184}