oag_node_client/
type_mapper.rs1use oag_core::ir::IrType;
2
3pub fn ir_type_to_ts(ir_type: &IrType) -> String {
5 match ir_type {
6 IrType::String => "string".to_string(),
7 IrType::StringLiteral(s) => format!("\"{s}\""),
8 IrType::Number => "number".to_string(),
9 IrType::Integer => "number".to_string(),
10 IrType::Boolean => "boolean".to_string(),
11 IrType::Null => "null".to_string(),
12 IrType::DateTime => "string".to_string(),
13 IrType::Binary => "Blob".to_string(),
14 IrType::Any => "unknown".to_string(),
15 IrType::Void => "void".to_string(),
16 IrType::Ref(name) => name.clone(),
17 IrType::Array(inner) => {
18 let inner_ts = ir_type_to_ts(inner);
19 if inner_ts.contains('|') {
20 format!("({inner_ts})[]")
21 } else {
22 format!("{inner_ts}[]")
23 }
24 }
25 IrType::Map(value_type) => {
26 let value_ts = ir_type_to_ts(value_type);
27 format!("Record<string, {value_ts}>")
28 }
29 IrType::Object(fields) => {
30 if fields.is_empty() {
31 return "Record<string, unknown>".to_string();
32 }
33 let field_strs: Vec<String> = fields
34 .iter()
35 .map(|(name, ty, required)| {
36 let ts_type = ir_type_to_ts(ty);
37 if *required {
38 format!("{name}: {ts_type}")
39 } else {
40 format!("{name}?: {ts_type}")
41 }
42 })
43 .collect();
44 format!("{{ {} }}", field_strs.join("; "))
45 }
46 IrType::Union(variants) => {
47 let variant_strs: Vec<String> = variants.iter().map(ir_type_to_ts).collect();
48 variant_strs.join(" | ")
49 }
50 IrType::Intersection(parts) => {
51 let part_strs: Vec<String> = parts.iter().map(ir_type_to_ts).collect();
52 part_strs.join(" & ")
53 }
54 }
55}
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60
61 #[test]
62 fn test_primitives() {
63 assert_eq!(ir_type_to_ts(&IrType::String), "string");
64 assert_eq!(ir_type_to_ts(&IrType::Number), "number");
65 assert_eq!(ir_type_to_ts(&IrType::Integer), "number");
66 assert_eq!(ir_type_to_ts(&IrType::Boolean), "boolean");
67 assert_eq!(ir_type_to_ts(&IrType::Null), "null");
68 assert_eq!(ir_type_to_ts(&IrType::Any), "unknown");
69 assert_eq!(ir_type_to_ts(&IrType::Void), "void");
70 }
71
72 #[test]
73 fn test_array() {
74 assert_eq!(
75 ir_type_to_ts(&IrType::Array(Box::new(IrType::String))),
76 "string[]"
77 );
78 assert_eq!(
79 ir_type_to_ts(&IrType::Array(Box::new(IrType::Union(vec![
80 IrType::String,
81 IrType::Number,
82 ])))),
83 "(string | number)[]"
84 );
85 }
86
87 #[test]
88 fn test_map() {
89 assert_eq!(
90 ir_type_to_ts(&IrType::Map(Box::new(IrType::String))),
91 "Record<string, string>"
92 );
93 }
94
95 #[test]
96 fn test_ref() {
97 assert_eq!(ir_type_to_ts(&IrType::Ref("Pet".to_string())), "Pet");
98 }
99
100 #[test]
101 fn test_union() {
102 assert_eq!(
103 ir_type_to_ts(&IrType::Union(vec![IrType::String, IrType::Number])),
104 "string | number"
105 );
106 }
107}