pub struct TypeInfo {
pub get_type: fn() -> crate::GearMeshType,
pub type_name: &'static str,
}
inventory::collect!(TypeInfo);
pub fn generate_types(output_path: impl AsRef<std::path::Path>) -> std::io::Result<()> {
use crate::{GeneratorConfig, TypeScriptGenerator};
use std::fs;
let types: Vec<_> = inventory::iter::<TypeInfo>()
.map(|info| (info.get_type)())
.collect();
if types.is_empty() {
eprintln!(
"⚠️ Warning: No types found. Make sure you have #[derive(GearMesh)] on your types."
);
}
let config = GeneratorConfig::new().with_zod(true).with_validation(true);
let mut generator = TypeScriptGenerator::new(config);
let output_content = generator.generate(&types);
let output_path = output_path.as_ref();
if let Some(parent) = output_path.parent() {
fs::create_dir_all(parent)?;
}
fs::write(output_path, output_content)?;
println!("✅ Generated TypeScript types: {}", output_path.display());
println!(" {} types exported", types.len());
Ok(())
}
pub fn generate_types_to_dir(output_dir: impl AsRef<std::path::Path>) -> std::io::Result<()> {
use crate::{GeneratorConfig, TypeScriptGenerator};
use std::fs;
let output_dir = output_dir.as_ref();
let types: Vec<_> = inventory::iter::<TypeInfo>()
.map(|info| (info.get_type)())
.collect();
if types.is_empty() {
eprintln!(
"⚠️ Warning: No types found. Make sure you have #[derive(GearMesh)] on your types."
);
return Ok(());
}
fs::create_dir_all(output_dir)?;
let config = GeneratorConfig::new().with_zod(true).with_validation(true);
let validator = crate::ValidationGenerator::new(config.clone());
let mut exports = Vec::new();
for ty in &types {
let file_name = format!("{}.ts", ty.name);
let file_path = output_dir.join(&file_name);
let mut content = String::new();
if config.generate_zod {
content.push_str("import { z } from 'zod';\n");
}
let deps = crate::extract_type_dependencies(ty);
let mut sorted_deps: Vec<_> = deps.iter().collect();
sorted_deps.sort();
for dep in sorted_deps {
if dep != &ty.name {
if config.generate_zod {
content.push_str(&format!(
"import type {{ {} }} from './{}';\nimport {{ {}Schema }} from './{}';\n",
dep, dep, dep, dep
));
} else {
content.push_str(&format!("import type {{ {} }} from './{}';\n", dep, dep));
}
}
}
if !deps.is_empty() {
content.push('\n');
}
if config.generate_branded && ty.attributes.branded {
content.push_str("\n// Branded Type helper\n");
content.push_str("type Brand<T, B> = T & { readonly __brand: B };\n");
}
content.push('\n');
let mut generator = TypeScriptGenerator::new(config.clone());
generator.generate_type(ty);
content.push_str(&generator.output);
if config.generate_zod {
if ty.attributes.branded {
let branded_gen = crate::BrandedTypeGenerator::new(config.clone());
if let Some(schema) = branded_gen.generate_zod_schema(ty) {
content.push_str("\n// Zod Schema\n\n");
content.push_str(&schema);
}
} else if let Some(schema) = validator.generate_zod_schema(ty) {
content.push_str("\n// Zod Schema\n\n");
content.push_str(&schema);
}
}
fs::write(&file_path, content)?;
exports.push(ty.name.clone());
println!(" ✓ {}", file_name);
}
let mut index_content = String::new();
index_content.push_str("// Auto-generated index file\n");
index_content.push_str("// Re-exports all types\n\n");
for type_name in &exports {
index_content.push_str(&format!("export * from './{}';\n", type_name));
}
fs::write(output_dir.join("index.ts"), index_content)?;
println!("✅ Generated TypeScript types to: {}", output_dir.display());
println!(" {} types exported", types.len());
println!(" 📄 index.ts created");
Ok(())
}