Skip to content

Commit f93d67c

Browse files
committed
WIP TypeScript codegen
1 parent f7f5672 commit f93d67c

File tree

9 files changed

+262
-9
lines changed

9 files changed

+262
-9
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/cw-schema-codegen/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ clap = { version = "4.5.18", features = ["derive"] }
1212
cw-schema = { version = "=2.2.0-rc.1", path = "../cw-schema" }
1313
either = "1.13.0"
1414
frunk = "0.4.3"
15+
frunk_core = "0.4.3"
1516
heck = "0.5.0"
1617
log = "0.4.22"
1718
serde_json = "1.0.128"

packages/cw-schema-codegen/src/main.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,14 @@ fn main() -> anyhow::Result<()> {
7979

8080
schema.definitions.iter().try_for_each(|node| {
8181
debug!("Processing node: {node:?}");
82-
cw_schema_codegen::rust::process_node(&mut output, &schema, node)
82+
83+
match opts.language {
84+
Language::Rust => cw_schema_codegen::rust::process_node(&mut output, &schema, node),
85+
Language::Typescript => {
86+
cw_schema_codegen::typescript::process_node(&mut output, &schema, node)
87+
}
88+
Language::Go | Language::Python => todo!(),
89+
}
8390
})?;
8491

8592
Ok(())
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,145 @@
1+
use self::template::{
2+
EnumTemplate, EnumVariantTemplate, FieldTemplate, StructTemplate, TypeTemplate,
3+
};
4+
use heck::ToPascalCase;
5+
use std::{borrow::Cow, io};
6+
17
pub mod template;
8+
9+
fn expand_node_name<'a>(
10+
schema: &'a cw_schema::SchemaV1,
11+
node: &'a cw_schema::Node,
12+
) -> Cow<'a, str> {
13+
match node.value {
14+
cw_schema::NodeType::Array { items } => {
15+
let items = &schema.definitions[items];
16+
format!("{}[]", expand_node_name(schema, items)).into()
17+
}
18+
cw_schema::NodeType::Float => "number".into(),
19+
cw_schema::NodeType::Double => "number".into(),
20+
cw_schema::NodeType::Boolean => "boolean".into(),
21+
cw_schema::NodeType::String => "string".into(),
22+
cw_schema::NodeType::Integer { signed, precision } => {
23+
"string".into()
24+
/*let ty = if signed { "i" } else { "u" };
25+
format!("{ty}{precision}").into()*/
26+
}
27+
cw_schema::NodeType::Binary => "Uint8Array".into(),
28+
cw_schema::NodeType::Optional { inner } => {
29+
let inner = &schema.definitions[inner];
30+
format!("{} | null", expand_node_name(schema, inner)).into()
31+
}
32+
cw_schema::NodeType::Struct(..) => node.name.as_ref().into(),
33+
cw_schema::NodeType::Tuple { ref items } => {
34+
let items = items
35+
.iter()
36+
.map(|item| expand_node_name(schema, &schema.definitions[*item]))
37+
.collect::<Vec<_>>()
38+
.join(", ");
39+
40+
format!("[{}]", items).into()
41+
}
42+
cw_schema::NodeType::Enum { .. } => node.name.as_ref().into(),
43+
44+
cw_schema::NodeType::Decimal { precision, signed } => todo!(),
45+
cw_schema::NodeType::Address => todo!(),
46+
cw_schema::NodeType::Checksum => todo!(),
47+
cw_schema::NodeType::HexBinary => todo!(),
48+
cw_schema::NodeType::Timestamp => todo!(),
49+
cw_schema::NodeType::Unit => Cow::Borrowed("void"),
50+
}
51+
}
52+
53+
fn prepare_docs(desc: Option<&str>) -> Cow<'_, [Cow<'_, str>]> {
54+
desc.map(|desc| {
55+
desc.lines()
56+
.map(|line| line.replace('"', "\\\"").into())
57+
.collect()
58+
})
59+
.unwrap_or(Cow::Borrowed(&[]))
60+
}
61+
62+
pub fn process_node<O>(
63+
output: &mut O,
64+
schema: &cw_schema::SchemaV1,
65+
node: &cw_schema::Node,
66+
) -> io::Result<()>
67+
where
68+
O: io::Write,
69+
{
70+
match node.value {
71+
cw_schema::NodeType::Struct(ref sty) => {
72+
let structt = StructTemplate {
73+
name: node.name.clone(),
74+
docs: prepare_docs(node.description.as_deref()),
75+
ty: match sty {
76+
cw_schema::StructType::Unit => TypeTemplate::Unit,
77+
cw_schema::StructType::Named { ref properties } => TypeTemplate::Named {
78+
fields: properties
79+
.iter()
80+
.map(|(name, prop)| FieldTemplate {
81+
name: Cow::Borrowed(name),
82+
docs: prepare_docs(prop.description.as_deref()),
83+
ty: expand_node_name(schema, &schema.definitions[prop.value]),
84+
})
85+
.collect(),
86+
},
87+
cw_schema::StructType::Tuple { ref items } => TypeTemplate::Tuple(
88+
items
89+
.iter()
90+
.map(|item| expand_node_name(schema, &schema.definitions[*item]))
91+
.collect(),
92+
),
93+
},
94+
};
95+
96+
writeln!(output, "{structt}")?;
97+
}
98+
cw_schema::NodeType::Enum { ref cases, .. } => {
99+
let enumm = EnumTemplate {
100+
name: node.name.clone(),
101+
docs: prepare_docs(node.description.as_deref()),
102+
variants: cases
103+
.iter()
104+
.map(|(name, case)| EnumVariantTemplate {
105+
name: name.clone(),
106+
docs: prepare_docs(case.description.as_deref()),
107+
ty: match case.value {
108+
cw_schema::EnumValue::Unit => TypeTemplate::Unit,
109+
cw_schema::EnumValue::Tuple { ref items } => {
110+
let items = items
111+
.iter()
112+
.map(|item| {
113+
expand_node_name(schema, &schema.definitions[*item])
114+
})
115+
.collect();
116+
117+
TypeTemplate::Tuple(items)
118+
}
119+
cw_schema::EnumValue::Named { ref properties, .. } => {
120+
TypeTemplate::Named {
121+
fields: properties
122+
.iter()
123+
.map(|(name, prop)| FieldTemplate {
124+
name: Cow::Borrowed(name),
125+
docs: prepare_docs(prop.description.as_deref()),
126+
ty: expand_node_name(
127+
schema,
128+
&schema.definitions[prop.value],
129+
),
130+
})
131+
.collect(),
132+
}
133+
}
134+
},
135+
})
136+
.collect(),
137+
};
138+
139+
writeln!(output, "{enumm}")?;
140+
}
141+
_ => (),
142+
}
143+
144+
Ok(())
145+
}
Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,41 @@
11
use askama::Template;
2+
use std::borrow::Cow;
3+
4+
#[derive(Clone)]
5+
pub struct EnumVariantTemplate<'a> {
6+
pub name: Cow<'a, str>,
7+
pub docs: Cow<'a, [Cow<'a, str>]>,
8+
pub ty: TypeTemplate<'a>,
9+
}
210

311
#[derive(Template)]
412
#[template(escape = "none", path = "typescript/enum.tpl.ts")]
5-
pub struct EnumTemplate {}
13+
pub struct EnumTemplate<'a> {
14+
pub name: Cow<'a, str>,
15+
pub docs: Cow<'a, [Cow<'a, str>]>,
16+
pub variants: Cow<'a, [EnumVariantTemplate<'a>]>,
17+
}
18+
19+
#[derive(Clone)]
20+
pub struct FieldTemplate<'a> {
21+
pub name: Cow<'a, str>,
22+
pub docs: Cow<'a, [Cow<'a, str>]>,
23+
pub ty: Cow<'a, str>,
24+
}
25+
26+
#[derive(Clone)]
27+
pub enum TypeTemplate<'a> {
28+
Unit,
29+
Tuple(Cow<'a, [Cow<'a, str>]>),
30+
Named {
31+
fields: Cow<'a, [FieldTemplate<'a>]>,
32+
},
33+
}
634

735
#[derive(Template)]
836
#[template(escape = "none", path = "typescript/struct.tpl.ts")]
9-
pub struct StructTemplate {}
37+
pub struct StructTemplate<'a> {
38+
pub name: Cow<'a, str>,
39+
pub docs: Cow<'a, [Cow<'a, str>]>,
40+
pub ty: TypeTemplate<'a>,
41+
}

packages/cw-schema-codegen/templates/rust/enum.tpl.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// This code is @generated by cw-schema-codegen. Do not modify this manually.
2+
13
{% for doc in docs %}
24
#[doc = "{{ doc }}"]
35
{% endfor %}
@@ -20,9 +22,7 @@ pub enum {{ name }} {
2022
{% when TypeTemplate::Unit %}
2123
{% when TypeTemplate::Tuple with (types) %}
2224
(
23-
{% for ty in types %}
24-
{{ ty }},
25-
{% endfor %}
25+
{{ types|join(", ") }}
2626
)
2727
{% when TypeTemplate::Named with { fields } %}
2828
{

packages/cw-schema-codegen/templates/rust/struct.tpl.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// This code is @generated by cw-schema-codegen. Do not modify this manually.
2+
13
{% for doc in docs %}
24
#[doc = "{{ doc }}"]
35
{% endfor %}
@@ -10,9 +12,7 @@ pub struct {{ name }}
1012
;
1113
{% when TypeTemplate::Tuple with (types) %}
1214
(
13-
{% for ty in types %}
14-
{{ ty }},
15-
{% endfor %}
15+
{{ types|join(", ") }}
1616
);
1717
{% when TypeTemplate::Named with { fields } %}
1818
{
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// This code is @generated by cw-schema-codegen. Do not modify this manually.
2+
3+
/**
4+
{% for doc in docs %}
5+
* {{ doc }}
6+
{% endfor %}
7+
*/
8+
9+
type {{ name }} =
10+
{% for variant in variants %}
11+
|
12+
13+
/**
14+
{% for doc in variant.docs %}
15+
* {{ doc }}
16+
{% endfor %}
17+
*/
18+
19+
{% match variant.ty %}
20+
{% when TypeTemplate::Unit %}
21+
{ "{{ variant.name }}": {} }
22+
{% when TypeTemplate::Tuple with (types) %}
23+
{ "{{ variant.name }}": [{{ types|join(", ") }}] }
24+
{% when TypeTemplate::Named with { fields } %}
25+
{ "{{ variant.name }}": {
26+
{% for field in fields %}
27+
/**
28+
{% for doc in field.docs %}
29+
* {{ doc }}
30+
{% endfor %}
31+
*/
32+
33+
{{ field.name }}: {{ field.ty }};
34+
{% endfor %}
35+
} }
36+
{% endmatch %}
37+
{% endfor %}
38+
;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// This code is @generated by cw-schema-codegen. Do not modify this manually.
2+
3+
/**
4+
{% for doc in docs %}
5+
* {{ doc }}
6+
{% endfor %}
7+
*/
8+
9+
type {{ name }} =
10+
{% match ty %}
11+
{% when TypeTemplate::Unit %}
12+
void
13+
{% when TypeTemplate::Tuple with (types) %}
14+
[{{ types|join(", ") }}]
15+
{% when TypeTemplate::Named with { fields } %}
16+
{
17+
{% for field in fields %}
18+
/**
19+
{% for doc in field.docs %}
20+
* {{ doc }}
21+
{% endfor %}
22+
*/
23+
24+
{{ field.name }}: {{ field.ty }};
25+
{% endfor %}
26+
}
27+
{% endmatch %}
28+
;
29+
30+
export { {{ name }} };

0 commit comments

Comments
 (0)