oag_node_client/emitters/
types.rs1use minijinja::{Environment, context};
2use oag_core::ir::{IrObjectSchema, IrReturnType, IrSchema, IrSpec};
3
4use crate::type_mapper::ir_type_to_ts;
5
6fn escape_jsdoc(value: String) -> String {
8 value.replace("*/", "*\\/")
9}
10
11pub fn emit_types(ir: &IrSpec) -> String {
13 let mut env = Environment::new();
14 env.add_filter("escape_jsdoc", escape_jsdoc);
15 env.add_template("types.ts.j2", include_str!("../../templates/types.ts.j2"))
16 .expect("template should be valid");
17 let tmpl = env.get_template("types.ts.j2").unwrap();
18
19 let schemas: Vec<_> = ir.schemas.iter().map(schema_to_ctx).collect();
20 let sse_event_types = collect_sse_event_types(ir);
21
22 tmpl.render(context! {
23 schemas => schemas,
24 sse_event_types => sse_event_types,
25 })
26 .expect("render should succeed")
27}
28
29fn schema_to_ctx(schema: &IrSchema) -> minijinja::Value {
30 match schema {
31 IrSchema::Object(obj) => object_to_ctx(obj),
32 IrSchema::Enum(e) => {
33 let variants: Vec<String> = e.variants.iter().map(|v| format!("\"{v}\"")).collect();
34 context! {
35 kind => "enum",
36 name => e.name.pascal_case.clone(),
37 description => e.description.clone(),
38 variants => variants,
39 }
40 }
41 IrSchema::Alias(a) => {
42 context! {
43 kind => "alias",
44 name => a.name.pascal_case.clone(),
45 description => a.description.clone(),
46 target => ir_type_to_ts(&a.target),
47 }
48 }
49 IrSchema::Union(u) => {
50 let variants: Vec<String> = u.variants.iter().map(ir_type_to_ts).collect();
51 context! {
52 kind => "union",
53 name => u.name.pascal_case.clone(),
54 description => u.description.clone(),
55 variants => variants,
56 }
57 }
58 }
59}
60
61fn object_to_ctx(obj: &IrObjectSchema) -> minijinja::Value {
62 let fields: Vec<minijinja::Value> = obj
63 .fields
64 .iter()
65 .map(|f| {
66 context! {
67 name => f.name.camel_case.clone(),
68 original_name => f.original_name.clone(),
69 type => ir_type_to_ts(&f.field_type),
70 required => f.required,
71 description => f.description.clone(),
72 }
73 })
74 .collect();
75
76 let additional = obj.additional_properties.as_ref().map(ir_type_to_ts);
77
78 context! {
79 kind => "object",
80 name => obj.name.pascal_case.clone(),
81 description => obj.description.clone(),
82 fields => fields,
83 additional_properties => additional,
84 }
85}
86
87fn collect_sse_event_types(ir: &IrSpec) -> Vec<minijinja::Value> {
88 let mut event_types = Vec::new();
89 for op in &ir.operations {
90 if let IrReturnType::Sse(sse) = &op.return_type
91 && let Some(ref event_name) = sse.event_type_name
92 {
93 let variants: Vec<String> = sse.variants.iter().map(ir_type_to_ts).collect();
94 if !variants.is_empty() {
95 event_types.push(context! {
96 name => event_name.clone(),
97 variants => variants,
98 });
99 }
100 }
101 }
102 event_types
103}