diff --git a/packages/cw-schema-codegen/src/go/mod.rs b/packages/cw-schema-codegen/src/go/mod.rs index 612b5b95f..c7f129b94 100644 --- a/packages/cw-schema-codegen/src/go/mod.rs +++ b/packages/cw-schema-codegen/src/go/mod.rs @@ -1 +1,160 @@ +use self::template::{ + EnumTemplate, EnumVariantTemplate, FieldTemplate, StructTemplate, TypeTemplate, +}; +use heck::ToPascalCase; +use std::{borrow::Cow, io}; + pub mod template; + +fn expand_node_name<'a>( + schema: &'a cw_schema::SchemaV1, + node: &'a cw_schema::Node, +) -> Cow<'a, str> { + match node.value { + cw_schema::NodeType::Array { items } => { + let items = &schema.definitions[items]; + format!("[]{}", expand_node_name(schema, items)).into() + } + cw_schema::NodeType::Float => "float32".into(), + cw_schema::NodeType::Double => "float64".into(), + cw_schema::NodeType::Boolean => "bool".into(), + cw_schema::NodeType::String => "string".into(), + cw_schema::NodeType::Integer { signed, precision } => { + let ty = if signed { "int" } else { "uint" }; + format!("{ty}{precision}").into() + } + cw_schema::NodeType::Binary => "[]byte".into(), + cw_schema::NodeType::Optional { inner } => { + let inner = &schema.definitions[inner]; + format!("{}", expand_node_name(schema, inner)).into() + } + cw_schema::NodeType::Struct(..) => node.name.as_ref().into(), + cw_schema::NodeType::Tuple { items: _ } => { + /*let items = items + .iter() + .map(|item| expand_node_name(schema, &schema.definitions[*item])) + .collect::>() + .join(", "); + + format!("({})", items).into()*/ + "[]interface{}".into() + } + cw_schema::NodeType::Enum { .. } => node.name.as_ref().into(), + + cw_schema::NodeType::Decimal { + precision: _, + signed: _, + } => { + // ToDo: Actually use a decimal type here + "string".into() + } + cw_schema::NodeType::Address => "Address".into(), + cw_schema::NodeType::Checksum => "string".into(), + cw_schema::NodeType::HexBinary => { + // ToDo: Actually use a hex-encoded binary type here + "string".into() + } + cw_schema::NodeType::Timestamp => "string".into(), + cw_schema::NodeType::Unit => "struct{}".into(), + } +} + +fn prepare_docs(desc: Option<&str>) -> Cow<'_, [Cow<'_, str>]> { + desc.map(|desc| { + desc.lines() + .map(|line| line.replace('"', "\\\"").into()) + .collect() + }) + .unwrap_or(Cow::Borrowed(&[])) +} + +pub fn process_node( + output: &mut O, + schema: &cw_schema::SchemaV1, + node: &cw_schema::Node, + add_package: bool, +) -> io::Result<()> +where + O: io::Write, +{ + match node.value { + cw_schema::NodeType::Struct(ref sty) => { + let structt = StructTemplate { + add_package, + name: node.name.clone(), + docs: prepare_docs(node.description.as_deref()), + ty: match sty { + cw_schema::StructType::Unit => TypeTemplate::Unit, + cw_schema::StructType::Named { ref properties } => TypeTemplate::Named { + fields: properties + .iter() + .map(|(name, prop)| FieldTemplate { + name: Cow::Owned(name.to_pascal_case()), + rename: Cow::Borrowed(name), + docs: prepare_docs(prop.description.as_deref()), + ty: expand_node_name(schema, &schema.definitions[prop.value]), + }) + .collect(), + }, + cw_schema::StructType::Tuple { ref items } => TypeTemplate::Tuple( + items + .iter() + .map(|item| expand_node_name(schema, &schema.definitions[*item])) + .collect(), + ), + }, + }; + + writeln!(output, "{structt}")?; + } + cw_schema::NodeType::Enum { ref cases, .. } => { + let enumm = EnumTemplate { + add_package, + name: node.name.clone(), + docs: prepare_docs(node.description.as_deref()), + variants: cases + .iter() + .map(|(name, case)| EnumVariantTemplate { + name: name.to_pascal_case().into(), + rename: Cow::Borrowed(name), + docs: prepare_docs(case.description.as_deref()), + ty: match case.value { + cw_schema::EnumValue::Unit => TypeTemplate::Unit, + cw_schema::EnumValue::Tuple { ref items } => { + let items = items + .iter() + .map(|item| { + expand_node_name(schema, &schema.definitions[*item]) + }) + .collect(); + + TypeTemplate::Tuple(items) + } + cw_schema::EnumValue::Named { ref properties, .. } => { + TypeTemplate::Named { + fields: properties + .iter() + .map(|(name, prop)| FieldTemplate { + name: Cow::Owned(name.to_pascal_case()), + rename: Cow::Borrowed(name), + docs: prepare_docs(prop.description.as_deref()), + ty: expand_node_name( + schema, + &schema.definitions[prop.value], + ), + }) + .collect(), + } + } + }, + }) + .collect(), + }; + + writeln!(output, "{enumm}")?; + } + _ => (), + } + + Ok(()) +} diff --git a/packages/cw-schema-codegen/src/go/template.rs b/packages/cw-schema-codegen/src/go/template.rs index 90c02e1b2..cfdf50a45 100644 --- a/packages/cw-schema-codegen/src/go/template.rs +++ b/packages/cw-schema-codegen/src/go/template.rs @@ -4,6 +4,7 @@ use std::borrow::Cow; #[derive(Clone)] pub struct EnumVariantTemplate<'a> { pub name: Cow<'a, str>, + pub rename: Cow<'a, str>, pub docs: Cow<'a, [Cow<'a, str>]>, pub ty: TypeTemplate<'a>, } @@ -11,6 +12,7 @@ pub struct EnumVariantTemplate<'a> { #[derive(Template)] #[template(escape = "none", path = "go/enum.tpl.go")] pub struct EnumTemplate<'a> { + pub add_package: bool, pub name: Cow<'a, str>, pub docs: Cow<'a, [Cow<'a, str>]>, pub variants: Cow<'a, [EnumVariantTemplate<'a>]>, @@ -19,6 +21,7 @@ pub struct EnumTemplate<'a> { #[derive(Clone)] pub struct FieldTemplate<'a> { pub name: Cow<'a, str>, + pub rename: Cow<'a, str>, pub docs: Cow<'a, [Cow<'a, str>]>, pub ty: Cow<'a, str>, } @@ -35,6 +38,7 @@ pub enum TypeTemplate<'a> { #[derive(Template)] #[template(escape = "none", path = "go/struct.tpl.go")] pub struct StructTemplate<'a> { + pub add_package: bool, pub name: Cow<'a, str>, pub docs: Cow<'a, [Cow<'a, str>]>, pub ty: TypeTemplate<'a>, diff --git a/packages/cw-schema-codegen/src/main.rs b/packages/cw-schema-codegen/src/main.rs index e01f8bff3..2677ea717 100644 --- a/packages/cw-schema-codegen/src/main.rs +++ b/packages/cw-schema-codegen/src/main.rs @@ -57,7 +57,7 @@ fn generate_defs( output: &mut W, language: Language, schema: &cw_schema::Schema, - add_imports: bool, + add_imports_or_package: bool, ) -> anyhow::Result<()> where W: io::Write, @@ -72,10 +72,10 @@ where match language { Language::Rust => cw_schema_codegen::rust::process_node(output, schema, node), Language::Typescript => { - cw_schema_codegen::typescript::process_node(output, schema, node, add_imports) + cw_schema_codegen::typescript::process_node(output, schema, node, add_imports_or_package) } Language::Python => cw_schema_codegen::python::process_node(output, schema, node), - Language::Go => todo!(), + Language::Go => cw_schema_codegen::go::process_node(output, schema, node, add_imports_or_package), } })?; diff --git a/packages/cw-schema-codegen/src/python/mod.rs b/packages/cw-schema-codegen/src/python/mod.rs index b60d0e0c0..07ac50a31 100644 --- a/packages/cw-schema-codegen/src/python/mod.rs +++ b/packages/cw-schema-codegen/src/python/mod.rs @@ -42,7 +42,6 @@ fn expand_node_name<'a>( cw_schema::NodeType::HexBinary => todo!(), cw_schema::NodeType::Timestamp => todo!(), cw_schema::NodeType::Unit => "None".into(), - _ => todo!(), } } @@ -82,7 +81,6 @@ where .map(|item| expand_node_name(schema, &schema.definitions[*item])) .collect(), ), - _ => todo!(), }, }; @@ -124,7 +122,6 @@ where .collect(), } } - _ => todo!(), }, }) .collect(), diff --git a/packages/cw-schema-codegen/templates/go/enum.tpl.go b/packages/cw-schema-codegen/templates/go/enum.tpl.go index ec0d54cc8..ac8df8c3f 100644 --- a/packages/cw-schema-codegen/templates/go/enum.tpl.go +++ b/packages/cw-schema-codegen/templates/go/enum.tpl.go @@ -1,2 +1,39 @@ // This code is @generated by cw-schema-codegen. Do not modify this manually. +{% if add_package %} +package cwcodegen + +import ( + "github.com/cosmos/cosmos-sdk/types/address" +) +{% endif %} + +{% for variant in variants %} +{% match variant.ty %} +{% when TypeTemplate::Unit %} +type {{ name }}{{ variant.name }} struct{} +{% when TypeTemplate::Tuple(types) %} +type {{ name }}{{ variant.name }} []interface{} +{% when TypeTemplate::Named { fields } %} +type {{ name }}{{ variant.name }} struct { + {% for field in fields %} + {% for doc in docs %} + // {{ doc }} + {% endfor %} + {{ field.name }} {{ field.ty }} `json:"{{ field.rename }}"` + {% endfor %} +} +{% endmatch %} +{% endfor %} + +{% for doc in docs %} + // {{ doc }} +{% endfor %} +type {{ name }} struct { +{% for variant in variants %} +{% for doc in docs %} + // {{ doc }} +{% endfor %} + {{ variant.name}} {{ name }}{{ variant.name }} `json:"{{ variant.rename }}"` +{% endfor %} +} diff --git a/packages/cw-schema-codegen/templates/go/struct.tpl.go b/packages/cw-schema-codegen/templates/go/struct.tpl.go index 48b420e7f..0a405140e 100644 --- a/packages/cw-schema-codegen/templates/go/struct.tpl.go +++ b/packages/cw-schema-codegen/templates/go/struct.tpl.go @@ -1,21 +1,28 @@ // This code is @generated by cw-schema-codegen. Do not modify this manually. +{% if add_package %} package cwcodegen +import ( + "github.com/cosmos/cosmos-sdk/types" +) +{% endif %} + {% for doc in docs %} // {{ doc }} {% endfor %} +{% match ty %} +{% when TypeTemplate::Unit %} +type {{ name }} struct{} +{% when TypeTemplate::Tuple with (types) %} +type {{ name }} []interface{} /* todo: replace with true tuples if i can think of it */ +{% when TypeTemplate::Named with { fields } %} type {{ name }} struct { - {% match ty %} - {% when TypeTemplate::Unit %} - {% when TypeTemplate::Tuple with (types) %} - {{ todo!() }} - {% when TypeTemplate::Named with { fields } %} - {% for field in fields %} - {% for doc in docs %} - // {{ doc }} - {% endfor %} - {{ field.name|capitalize }} {{ field.ty }} `json:"{{ field.name }}"` - {% endfor %} - {% endmatch %} +{% for field in fields %} +{% for doc in docs %} + // {{ doc }} +{% endfor %} + {{ field.name }} {{ field.ty }} `json:"{{ field.rename }}"` +{% endfor %} } +{% endmatch %} diff --git a/packages/cw-schema-codegen/templates/rust/enum.tpl.rs b/packages/cw-schema-codegen/templates/rust/enum.tpl.rs index 6898de1af..9f3d66dc9 100644 --- a/packages/cw-schema-codegen/templates/rust/enum.tpl.rs +++ b/packages/cw-schema-codegen/templates/rust/enum.tpl.rs @@ -6,35 +6,34 @@ #[cosmwasm_schema::cw_serde] pub enum {{ name }} { - {% for variant in variants %} - {% for doc in variant.docs %} - #[doc = "{{ doc }}"] - {% endfor %} - - {% match variant.serde_rename %} - {% when Some with (rename) %} - #[serde(rename = "{{ rename }}")] - {% when None %} - {% endmatch %} +{% for variant in variants %} +{% for doc in variant.docs %} + #[doc = "{{ doc }}"] +{% endfor %} - {{ variant.name }} - {% match variant.ty %} - {% when TypeTemplate::Unit %} - {% when TypeTemplate::Tuple with (types) %} - ( - {{ types|join(", ") }} - ) - {% when TypeTemplate::Named with { fields } %} - { - {% for field in fields %} - {% for doc in field.docs %} - #[doc = "{{ doc }}"] - {% endfor %} +{% match variant.serde_rename %} +{% when Some with (rename) %} + #[serde(rename = "{{ rename }}")] +{% when None %} +{% endmatch %} - {{ field.name }}: {{ field.ty }}, - {% endfor %} - } - {% endmatch %} + {{ variant.name }} +{% match variant.ty %} +{% when TypeTemplate::Unit %} +{% when TypeTemplate::Tuple with (types) %} + ( + {{ types|join(", ") }} + ) +{% when TypeTemplate::Named with { fields } %} + { + {% for field in fields %} + {% for doc in field.docs %} + #[doc = "{{ doc }}"] + {% endfor %} + {{ field.name }}: {{ field.ty }}, + {% endfor %} + } +{% endmatch %} , - {% endfor %} +{% endfor %} } \ No newline at end of file diff --git a/packages/cw-schema-codegen/templates/rust/struct.tpl.rs b/packages/cw-schema-codegen/templates/rust/struct.tpl.rs index 3d2f8a005..e25615739 100644 --- a/packages/cw-schema-codegen/templates/rust/struct.tpl.rs +++ b/packages/cw-schema-codegen/templates/rust/struct.tpl.rs @@ -1,27 +1,27 @@ // This code is @generated by cw-schema-codegen. Do not modify this manually. {% for doc in docs %} - #[doc = "{{ doc }}"] +#[doc = "{{ doc }}"] {% endfor %} #[cosmwasm_schema::cw_serde] pub struct {{ name }} {% match ty %} - {% when TypeTemplate::Unit %} - ; - {% when TypeTemplate::Tuple with (types) %} - ( - {{ types|join(", ") }} - ); - {% when TypeTemplate::Named with { fields } %} - { - {% for field in fields %} - {% for doc in field.docs %} - #[doc = "{{ doc }}"] - {% endfor %} +{% when TypeTemplate::Unit %} +; +{% when TypeTemplate::Tuple with (types) %} +( + {{ types|join(", ") }} +); +{% when TypeTemplate::Named with { fields } %} +{ +{% for field in fields %} +{% for doc in field.docs %} + #[doc = "{{ doc }}"] +{% endfor %} - {{ field.name }}: {{ field.ty }}, - {% endfor %} - } + {{ field.name }}: {{ field.ty }}, +{% endfor %} +} {% endmatch %} diff --git a/packages/cw-schema-codegen/templates/typescript/enum.tpl.ts b/packages/cw-schema-codegen/templates/typescript/enum.tpl.ts index 92b826914..8d794509a 100644 --- a/packages/cw-schema-codegen/templates/typescript/enum.tpl.ts +++ b/packages/cw-schema-codegen/templates/typescript/enum.tpl.ts @@ -18,28 +18,28 @@ const {{ name }}Schema = z.union([ {% endfor %} */ - {% match variant.ty %} - {% when TypeTemplate::Unit %} - z.object({ "{{ variant.name }}": z.null() }).or(z.literal("{{ variant.name }}")), - {% when TypeTemplate::Tuple with (types) %} - z.object({ "{{ variant.name }}": z.tuple([{{ types|join(", ") }}]) }), - {% when TypeTemplate::Named with { fields } %} - z.object({ "{{ variant.name }}": z.object({ - {% for field in fields %} - /** - {% for doc in field.docs %} - * {{ doc }} - {% endfor %} - */ - - {{ field.name }}: {{ field.ty }}, - {% endfor %} - }) }), - {% endmatch %} +{% match variant.ty %} +{% when TypeTemplate::Unit %} + z.object({ "{{ variant.name }}": z.null() }).or(z.literal("{{ variant.name }}")), +{% when TypeTemplate::Tuple with (types) %} + z.object({ "{{ variant.name }}": z.tuple([{{ types|join(", ") }}]) }), +{% when TypeTemplate::Named with { fields } %} + z.object({ "{{ variant.name }}": z.object({ +{% for field in fields %} + /** + {% for doc in field.docs %} + * {{ doc }} + {% endfor %} + */ + + {{ field.name }}: {{ field.ty }}, +{% endfor %} +}) }), +{% endmatch %} {% endfor %} {% if variants.len() == 0 %} - never; +never; {% endif %} ]); diff --git a/packages/cw-schema-codegen/templates/typescript/struct.tpl.ts b/packages/cw-schema-codegen/templates/typescript/struct.tpl.ts index 7b98afb51..a6bd159cb 100644 --- a/packages/cw-schema-codegen/templates/typescript/struct.tpl.ts +++ b/packages/cw-schema-codegen/templates/typescript/struct.tpl.ts @@ -12,22 +12,22 @@ import { z } from 'zod'; const {{ name }}Schema = {% match ty %} - {% when TypeTemplate::Unit %} - z.null() - {% when TypeTemplate::Tuple with (types) %} - z.tuple([{{ types|join(", ") }}]) - {% when TypeTemplate::Named with { fields } %} - z.object({ - {% for field in fields %} - /** - {% for doc in field.docs %} - * {{ doc }} - {% endfor %} - */ +{% when TypeTemplate::Unit %} + z.null() +{% when TypeTemplate::Tuple with (types) %} + z.tuple([{{ types|join(", ") }}]) +{% when TypeTemplate::Named with { fields } %} + z.object({ +{% for field in fields %} + /** + {% for doc in field.docs %} + * {{ doc }} + {% endfor %} + */ - {{ field.name }}: {{ field.ty }}, - {% endfor %} - }) + {{ field.name }}: {{ field.ty }}, +{% endfor %} +}) {% endmatch %} ;