use std::path::PathBuf;
use forge_core::schema::SchemaRegistry;
use super::Error;
pub struct TypeGenerator {
#[allow(dead_code)]
output_dir: PathBuf,
}
impl TypeGenerator {
pub fn new(output_dir: impl Into<PathBuf>) -> Self {
Self {
output_dir: output_dir.into(),
}
}
pub fn generate(&self, registry: &SchemaRegistry) -> Result<String, Error> {
let mut output = String::new();
output.push_str("// Auto-generated by FORGE - DO NOT EDIT\n\n");
for table in registry.all_tables() {
output.push_str(&format!("export interface {} {{\n", table.struct_name));
for field in &table.fields {
output.push_str(&field.to_typescript());
output.push('\n');
}
output.push_str("}\n\n");
}
for enum_def in registry.all_enums() {
output.push_str(&enum_def.to_typescript());
output.push_str("\n\n");
}
output.push_str(&self.generate_common_types());
Ok(output)
}
fn generate_common_types(&self) -> String {
r#"
// Common Types
export interface Paginated<T> {
data: T[];
total: number;
page: number;
pageSize: number;
hasMore: boolean;
}
export interface Page {
page: number;
pageSize: number;
}
export interface SortOrder {
field: string;
direction: 'asc' | 'desc';
}
export interface QueryResult<T> {
loading: boolean;
data: T | null;
error: ForgeError | null;
}
export interface SubscriptionResult<T> extends QueryResult<T> {
stale: boolean;
}
export interface ForgeError {
code: string;
message: string;
details?: Record<string, unknown>;
}
"#
.to_string()
}
}
#[cfg(test)]
mod tests {
use super::*;
use forge_core::schema::{EnumDef, EnumVariant, FieldDef, RustType, TableDef};
#[test]
fn test_generator_creation() {
let gen = TypeGenerator::new("/tmp");
assert_eq!(gen.output_dir, PathBuf::from("/tmp"));
}
#[test]
fn test_generate_with_table() {
let gen = TypeGenerator::new("/tmp");
let registry = SchemaRegistry::new();
let mut table = TableDef::new("users", "User");
table.fields.push(FieldDef::new("id", RustType::Uuid));
table.fields.push(FieldDef::new("email", RustType::String));
table.fields.push(FieldDef::new(
"avatar_url",
RustType::Option(Box::new(RustType::String)),
));
registry.register_table(table);
let output = gen.generate(®istry).unwrap();
assert!(output.contains("export interface User {"));
assert!(output.contains("id: string;"));
assert!(output.contains("email: string;"));
assert!(output.contains("avatarUrl?: string | null;"));
}
#[test]
fn test_generate_with_enum() {
let gen = TypeGenerator::new("/tmp");
let registry = SchemaRegistry::new();
let mut enum_def = EnumDef::new("ProjectStatus");
enum_def.variants.push(EnumVariant::new("Draft"));
enum_def.variants.push(EnumVariant::new("Active"));
registry.register_enum(enum_def);
let output = gen.generate(®istry).unwrap();
assert!(output.contains("export type ProjectStatus"));
assert!(output.contains("'draft'"));
assert!(output.contains("'active'"));
}
#[test]
fn test_generate_common_types() {
let gen = TypeGenerator::new("/tmp");
let result = gen.generate_common_types();
assert!(result.contains("export interface Paginated<T>"));
assert!(result.contains("export interface ForgeError"));
}
}