Skip to content

Commit

Permalink
fix(dojo-bindgen): typescript code gen (dojoengine#1847)
Browse files Browse the repository at this point in the history
* fix: system arg types

* fix: handle arrays

* fmt

* fix: duplicate tokens

* feat: do same thing for unity plugin & support bytes31

* fix: casing for system names

* fix: ts return namoing
  • Loading branch information
Larkooo authored Apr 18, 2024
1 parent 9c47ba7 commit 9a18f4d
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 39 deletions.
47 changes: 26 additions & 21 deletions crates/dojo-bindgen/src/plugins/typescript/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ use std::collections::HashMap;
use std::path::{Path, PathBuf};

use async_trait::async_trait;
use cainome::parser::tokens::{Composite, CompositeType, Function};
use convert_case::Casing;
use cainome::parser::tokens::{Composite, CompositeType, Function, Token};

use crate::error::BindgenResult;
use crate::plugins::BuiltinPlugin;
Expand All @@ -28,6 +27,7 @@ impl TypescriptPlugin {
"u256" => "RecsType.BigInt".to_string(),
"usize" => "RecsType.Number".to_string(),
"felt252" => "RecsType.BigInt".to_string(),
"bytes31" => "RecsType.String".to_string(),
"ClassHash" => "RecsType.BigInt".to_string(),
"ContractAddress" => "RecsType.BigInt".to_string(),

Expand Down Expand Up @@ -211,6 +211,11 @@ export enum {} {{
});

for token in &structs {
if handled_tokens.iter().filter(|t| t.type_name() == token.type_name()).count() > 1
{
continue;
}

// first index is our model struct
if token.type_name() == model.name {
models_structs.push(token.to_composite().unwrap().clone());
Expand All @@ -222,6 +227,10 @@ export enum {} {{
}

for token in &tokens.enums {
if handled_tokens.iter().filter(|t| t.type_name() == token.type_name()).count() > 1
{
continue;
}
out += TypescriptPlugin::format_enum(token.to_composite().unwrap()).as_str();
}

Expand All @@ -247,20 +256,22 @@ export function defineContractComponents(world: World) {
// Handled tokens should be a list of all structs and enums used by the contract
// Such as a set of referenced tokens from a model
fn format_system(system: &Function, handled_tokens: &[Composite]) -> String {
fn map_type(token: &Token) -> String {
match token {
Token::CoreBasic(t) => TypescriptPlugin::map_type(&t.type_name())
.replace("RecsType.", "")
// types should be lowercased
.to_lowercase(),
Token::Composite(t) => format!("models.{}", t.type_name()),
Token::Array(t) => format!("{}[]", map_type(&t.inner)),
_ => panic!("Unsupported token type: {:?}", token),
}
}

let args = system
.inputs
.iter()
.map(|arg| {
format!(
"{}: {}",
arg.0,
if TypescriptPlugin::map_type(&arg.1.type_name()) == arg.1.type_name() {
format!("models.{}", arg.1.type_name())
} else {
TypescriptPlugin::map_type(&arg.1.type_name()).replace("RecsType.", "")
}
)
})
.map(|arg| format!("{}: {}", arg.0, map_type(&arg.1)))
.collect::<Vec<String>>()
.join(", ");

Expand Down Expand Up @@ -295,7 +306,7 @@ export function defineContractComponents(world: World) {
format!(
"
// Call the `{system_name}` system with the specified Account and calldata
const {pretty_system_name} = async (props: {{ account: Account{arg_sep}{args} }}) => {{
const {system_name} = async (props: {{ account: Account{arg_sep}{args} }}) => {{
try {{
return await provider.execute(
props.account,
Expand All @@ -311,10 +322,6 @@ export function defineContractComponents(world: World) {
",
// selector for execute
system_name = system.name,
// pretty system name
// snake case to camel case
// move_to -> moveTo
pretty_system_name = system.name.to_case(convert_case::Case::Camel),
// add comma if we have args
arg_sep = if !args.is_empty() { ", " } else { "" },
// formatted args to use our mapped types
Expand Down Expand Up @@ -384,9 +391,7 @@ export function defineContractComponents(world: World) {
contract
.systems
.iter()
.map(|system| {
system.to_function().unwrap().name.to_case(convert_case::Case::Camel)
})
.map(|system| { system.to_function().unwrap().name.to_string() })
.collect::<Vec<String>>()
.join(", ")
);
Expand Down
39 changes: 21 additions & 18 deletions crates/dojo-bindgen/src/plugins/unity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::collections::HashMap;
use std::path::{Path, PathBuf};

use async_trait::async_trait;
use cainome::parser::tokens::{Composite, CompositeType, Function};
use cainome::parser::tokens::{Composite, CompositeType, Function, Token};

use crate::error::BindgenResult;
use crate::plugins::BuiltinPlugin;
Expand All @@ -26,6 +26,7 @@ impl UnityPlugin {
"u256" => "BigInteger".to_string(),
"usize" => "uint".to_string(),
"felt252" => "FieldElement".to_string(),
"bytes31" => "string".to_string(),
"ClassHash" => "FieldElement".to_string(),
"ContractAddress" => "FieldElement".to_string(),

Expand Down Expand Up @@ -147,6 +148,10 @@ public class {} : ModelInstance {{
let mut model_struct: Option<&Composite> = None;
let tokens = &model.tokens;
for token in &tokens.structs {
if handled_tokens.iter().any(|t| t.type_name() == token.type_name()) {
continue;
}

handled_tokens.push(token.to_composite().unwrap().to_owned());

// first index is our model struct
Expand All @@ -159,6 +164,10 @@ public class {} : ModelInstance {{
}

for token in &tokens.enums {
if handled_tokens.iter().any(|t| t.type_name() == token.type_name()) {
continue;
}

handled_tokens.push(token.to_composite().unwrap().to_owned());
out += UnityPlugin::format_enum(token.to_composite().unwrap()).as_str();
}
Expand All @@ -174,10 +183,19 @@ public class {} : ModelInstance {{
// Handled tokens should be a list of all structs and enums used by the contract
// Such as a set of referenced tokens from a model
fn format_system(system: &Function, handled_tokens: &[Composite]) -> String {
fn map_type(token: &Token) -> String {
match token {
Token::CoreBasic(t) => UnityPlugin::map_type(&t.type_name()),
Token::Composite(t) => format!("{}", t.type_name()),
Token::Array(t) => format!("{}[]", map_type(&t.inner)),
_ => panic!("Unsupported token type: {:?}", token),
}
}

let args = system
.inputs
.iter()
.map(|arg| format!("{} {}", UnityPlugin::map_type(&arg.1.type_name()), arg.0,))
.map(|arg| format!("{} {}", map_type(&arg.1), &arg.0))
.collect::<Vec<String>>()
.join(", ");

Expand Down Expand Up @@ -222,7 +240,7 @@ public class {} : ModelInstance {{
// Call the `{system_name}` system with the specified Account and calldata
// Returns the transaction hash. Use `WaitForTransaction` to wait for the transaction to be \
confirmed.
public async Task<FieldElement> {pretty_system_name}(Account account{arg_sep}{args}) {{
public async Task<FieldElement> {system_name}(Account account{arg_sep}{args}) {{
return await account.ExecuteRaw(new dojo.Call[] {{
new dojo.Call{{
to = contractAddress,
Expand All @@ -236,21 +254,6 @@ public class {} : ModelInstance {{
",
// selector for execute
system_name = system.name,
// pretty system name
// snake case to camel case
// move_to -> MoveTo
pretty_system_name = system
.name
.split('_')
.map(|s| {
let mut c = s.chars();
match c.next() {
None => String::new(),
Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
}
})
.collect::<Vec<String>>()
.join(""),
// add comma if we have args
arg_sep = if !args.is_empty() { ", " } else { "" },
// formatted args to use our mapped types
Expand Down

0 comments on commit 9a18f4d

Please sign in to comment.