gear_mesh/
inventory_collect.rs1pub struct TypeInfo {
3 pub get_type: fn() -> crate::GearMeshType,
4 pub type_name: &'static str,
5}
6
7inventory::collect!(TypeInfo);
8
9pub fn generate_types(output_path: impl AsRef<std::path::Path>) -> std::io::Result<()> {
23 use crate::{GeneratorConfig, TypeScriptGenerator};
24 use std::fs;
25
26 let types: Vec<_> = inventory::iter::<TypeInfo>()
28 .map(|info| (info.get_type)())
29 .collect();
30
31 if types.is_empty() {
32 eprintln!(
33 "⚠️ Warning: No types found. Make sure you have #[derive(GearMesh)] on your types."
34 );
35 }
36
37 let config = GeneratorConfig::new().with_zod(true).with_validation(true);
39 let mut generator = TypeScriptGenerator::new(config);
40 let output_content = generator.generate(&types);
41
42 let output_path = output_path.as_ref();
44 if let Some(parent) = output_path.parent() {
45 fs::create_dir_all(parent)?;
46 }
47
48 fs::write(output_path, output_content)?;
50
51 println!("✅ Generated TypeScript types: {}", output_path.display());
52 println!(" {} types exported", types.len());
53
54 Ok(())
55}
56
57pub fn generate_types_to_dir(output_dir: impl AsRef<std::path::Path>) -> std::io::Result<()> {
70 use crate::{GeneratorConfig, TypeScriptGenerator};
71 use std::fs;
72
73 let output_dir = output_dir.as_ref();
74
75 let types: Vec<_> = inventory::iter::<TypeInfo>()
77 .map(|info| (info.get_type)())
78 .collect();
79
80 if types.is_empty() {
81 eprintln!(
82 "⚠️ Warning: No types found. Make sure you have #[derive(GearMesh)] on your types."
83 );
84 return Ok(());
85 }
86
87 fs::create_dir_all(output_dir)?;
89
90 let config = GeneratorConfig::new().with_zod(true).with_validation(true);
92
93 let validator = crate::ValidationGenerator::new(config.clone());
94 let mut exports = Vec::new();
95
96 for ty in &types {
97 let file_name = format!("{}.ts", ty.name);
98 let file_path = output_dir.join(&file_name);
99
100 let mut content = String::new();
101
102 if config.generate_zod {
104 content.push_str("import { z } from 'zod';\n");
105 }
106
107 let deps = crate::extract_type_dependencies(ty);
109 let mut sorted_deps: Vec<_> = deps.iter().collect();
110 sorted_deps.sort();
111
112 for dep in sorted_deps {
113 if dep != &ty.name {
115 if config.generate_zod {
117 content.push_str(&format!(
118 "import type {{ {} }} from './{}';\nimport {{ {}Schema }} from './{}';\n",
119 dep, dep, dep, dep
120 ));
121 } else {
122 content.push_str(&format!("import type {{ {} }} from './{}';\n", dep, dep));
123 }
124 }
125 }
126
127 if !deps.is_empty() {
128 content.push('\n');
129 }
130
131 if config.generate_branded && ty.attributes.branded {
133 content.push_str("\n// Branded Type helper\n");
134 content.push_str("type Brand<T, B> = T & { readonly __brand: B };\n");
135 }
136
137 content.push('\n');
138
139 let mut generator = TypeScriptGenerator::new(config.clone());
141 generator.generate_type(ty);
142 content.push_str(&generator.output);
143
144 if config.generate_zod {
146 if ty.attributes.branded {
148 let branded_gen = crate::BrandedTypeGenerator::new(config.clone());
149 if let Some(schema) = branded_gen.generate_zod_schema(ty) {
150 content.push_str("\n// Zod Schema\n\n");
151 content.push_str(&schema);
152 }
153 } else if let Some(schema) = validator.generate_zod_schema(ty) {
154 content.push_str("\n// Zod Schema\n\n");
155 content.push_str(&schema);
156 }
157 }
158
159 fs::write(&file_path, content)?;
160 exports.push(ty.name.clone());
161 println!(" ✓ {}", file_name);
162 }
163
164 let mut index_content = String::new();
166 index_content.push_str("// Auto-generated index file\n");
167 index_content.push_str("// Re-exports all types\n\n");
168
169 for type_name in &exports {
170 index_content.push_str(&format!("export * from './{}';\n", type_name));
171 }
172
173 fs::write(output_dir.join("index.ts"), index_content)?;
174
175 println!("✅ Generated TypeScript types to: {}", output_dir.display());
176 println!(" {} types exported", types.len());
177 println!(" 📄 index.ts created");
178
179 Ok(())
180}