From 354d7ec4e412c8cf20ce1a09d4ab734f6be2c7e5 Mon Sep 17 00:00:00 2001 From: Valentin Dosimont Date: Mon, 2 Dec 2024 12:00:16 +0100 Subject: [PATCH 1/5] bump: cainome-0.4.8 --- Cargo.lock | 154 +++++++++++++++++++++++++++++++++++++++++++---------- Cargo.toml | 6 +-- 2 files changed, 129 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d6f8d6883f..41ff1b29b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,7 +40,7 @@ dependencies = [ "serde-wasm-bindgen", "serde_cbor_2", "serde_json", - "serde_with 3.9.0", + "serde_with 3.11.0", "sha2 0.10.8", "starknet 0.12.0", "starknet-crypto 0.7.2", @@ -2448,7 +2448,7 @@ dependencies = [ "anyhow", "async-trait", "cainome-cairo-serde 0.1.0 (git+https://github.com/cartridge-gg/cainome?rev=5c2616c273faca7700d2ba565503fcefb5b9d720)", - "cainome-cairo-serde-derive", + "cainome-cairo-serde-derive 0.1.0 (git+https://github.com/cartridge-gg/cainome?rev=5c2616c273faca7700d2ba565503fcefb5b9d720)", "cainome-parser 0.1.0 (git+https://github.com/cartridge-gg/cainome?rev=5c2616c273faca7700d2ba565503fcefb5b9d720)", "cainome-rs 0.1.0 (git+https://github.com/cartridge-gg/cainome?rev=5c2616c273faca7700d2ba565503fcefb5b9d720)", "cainome-rs-macro 0.1.0 (git+https://github.com/cartridge-gg/cainome?rev=5c2616c273faca7700d2ba565503fcefb5b9d720)", @@ -2466,6 +2466,32 @@ dependencies = [ "url", ] +[[package]] +name = "cainome" +version = "0.4.8" +source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.8#53f989af513adc30c5576898c4a586bb3cd71d63" +dependencies = [ + "anyhow", + "async-trait", + "cainome-cairo-serde 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.8)", + "cainome-cairo-serde-derive 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.8)", + "cainome-parser 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.8)", + "cainome-rs 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.8)", + "cainome-rs-macro 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.8)", + "camino", + "clap", + "clap_complete", + "convert_case 0.6.0", + "serde", + "serde_json", + "starknet 0.12.0", + "starknet-types-core", + "thiserror", + "tracing", + "tracing-subscriber", + "url", +] + [[package]] name = "cainome-cairo-serde" version = "0.1.0" @@ -2476,6 +2502,18 @@ dependencies = [ "thiserror", ] +[[package]] +name = "cainome-cairo-serde" +version = "0.1.0" +source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.8#53f989af513adc30c5576898c4a586bb3cd71d63" +dependencies = [ + "num-bigint", + "serde", + "serde_with 3.11.0", + "starknet 0.12.0", + "thiserror", +] + [[package]] name = "cainome-cairo-serde" version = "0.1.0" @@ -2486,6 +2524,17 @@ dependencies = [ "thiserror", ] +[[package]] +name = "cainome-cairo-serde-derive" +version = "0.1.0" +source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.8#53f989af513adc30c5576898c4a586bb3cd71d63" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", + "unzip-n", +] + [[package]] name = "cainome-cairo-serde-derive" version = "0.1.0" @@ -2510,6 +2559,19 @@ dependencies = [ "thiserror", ] +[[package]] +name = "cainome-parser" +version = "0.1.0" +source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.8#53f989af513adc30c5576898c4a586bb3cd71d63" +dependencies = [ + "convert_case 0.6.0", + "quote", + "serde_json", + "starknet 0.12.0", + "syn 2.0.77", + "thiserror", +] + [[package]] name = "cainome-parser" version = "0.1.0" @@ -2541,6 +2603,24 @@ dependencies = [ "thiserror", ] +[[package]] +name = "cainome-rs" +version = "0.1.0" +source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.8#53f989af513adc30c5576898c4a586bb3cd71d63" +dependencies = [ + "anyhow", + "cainome-cairo-serde 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.8)", + "cainome-parser 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.8)", + "camino", + "prettyplease", + "proc-macro2", + "quote", + "serde_json", + "starknet 0.12.0", + "syn 2.0.77", + "thiserror", +] + [[package]] name = "cainome-rs" version = "0.1.0" @@ -2577,6 +2657,24 @@ dependencies = [ "thiserror", ] +[[package]] +name = "cainome-rs-macro" +version = "0.1.0" +source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.8#53f989af513adc30c5576898c4a586bb3cd71d63" +dependencies = [ + "anyhow", + "cainome-cairo-serde 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.8)", + "cainome-parser 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.8)", + "cainome-rs 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.8)", + "proc-macro-error", + "proc-macro2", + "quote", + "serde_json", + "starknet 0.12.0", + "syn 2.0.77", + "thiserror", +] + [[package]] name = "cainome-rs-macro" version = "0.1.0" @@ -3812,7 +3910,7 @@ dependencies = [ "ed25519-dalek", "serde", "serde_json", - "serde_with 3.9.0", + "serde_with 3.11.0", "starknet-types-core", ] @@ -4715,7 +4813,7 @@ dependencies = [ "anyhow", "assert_matches", "async-trait", - "cainome 0.4.6", + "cainome 0.4.8", "camino", "chrono", "convert_case 0.6.0", @@ -4767,7 +4865,7 @@ dependencies = [ "semver 1.0.23", "serde", "serde_json", - "serde_with 3.9.0", + "serde_with 3.11.0", "smol_str", "starknet 0.12.0", "starknet-crypto 0.7.2", @@ -4872,7 +4970,7 @@ name = "dojo-types" version = "1.0.2" dependencies = [ "anyhow", - "cainome 0.4.6", + "cainome 0.4.8", "crypto-bigint", "hex", "itertools 0.12.1", @@ -4911,7 +5009,7 @@ version = "1.0.2" dependencies = [ "anyhow", "async-trait", - "cainome 0.4.6", + "cainome 0.4.8", "cairo-lang-starknet-classes", "dojo-types 1.0.2", "hex", @@ -4921,7 +5019,7 @@ dependencies = [ "regex", "serde", "serde_json", - "serde_with 3.9.0", + "serde_with 3.11.0", "starknet 0.12.0", "starknet-crypto 0.7.2", "thiserror", @@ -4936,7 +5034,7 @@ name = "dojo-world-abigen" version = "1.0.2" dependencies = [ "anyhow", - "cainome 0.4.6", + "cainome 0.4.8", "cairo-lang-starknet", "cairo-lang-starknet-classes", "camino", @@ -8282,7 +8380,7 @@ dependencies = [ "alloy-primitives", "anyhow", "assert_matches", - "cainome-cairo-serde 0.1.0 (git+https://github.com/cartridge-gg/cainome?rev=5c2616c273faca7700d2ba565503fcefb5b9d720)", + "cainome-cairo-serde 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.8)", "clap", "console", "dojo-utils", @@ -8522,7 +8620,7 @@ dependencies = [ "serde", "serde_json", "serde_json_pythonic", - "serde_with 3.9.0", + "serde_with 3.11.0", "similar-asserts", "starknet 0.12.0", "starknet-crypto 0.7.2", @@ -8566,7 +8664,7 @@ dependencies = [ "alloy-primitives", "anyhow", "assert_matches", - "cainome 0.4.6", + "cainome 0.4.8", "dojo-metrics", "dojo-test-utils", "dojo-utils", @@ -8631,7 +8729,7 @@ dependencies = [ "serde", "serde_json", "serde_json_pythonic", - "serde_with 3.9.0", + "serde_with 3.11.0", "similar-asserts", "starknet 0.12.0", "thiserror", @@ -12760,7 +12858,7 @@ dependencies = [ "num-traits 0.2.19", "serde", "serde_json", - "serde_with 3.9.0", + "serde_with 3.11.0", "starknet 0.12.0", "thiserror", "tokio", @@ -13274,9 +13372,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" dependencies = [ "base64 0.22.1", "chrono", @@ -13286,7 +13384,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "serde_with_macros 3.9.0", + "serde_with_macros 3.11.0", "time", ] @@ -13304,9 +13402,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" dependencies = [ "darling 0.20.10", "proc-macro2", @@ -13662,7 +13760,7 @@ version = "1.0.2" dependencies = [ "anyhow", "async-trait", - "cainome 0.4.6", + "cainome 0.4.8", "cairo-lang-compiler", "cairo-lang-filesystem", "cairo-lang-project", @@ -13714,7 +13812,7 @@ dependencies = [ "anyhow", "assert_fs", "async-trait", - "cainome 0.4.6", + "cainome 0.4.8", "colored", "colored_json", "dojo-test-utils", @@ -13728,7 +13826,7 @@ dependencies = [ "scarb", "serde", "serde_json", - "serde_with 3.9.0", + "serde_with 3.11.0", "sozo-scarbext", "sozo-walnut", "spinoff", @@ -14133,7 +14231,7 @@ checksum = "bd6ee5762d24c4f06ab7e9406550925df406712e73719bd2de905c879c674a87" dependencies = [ "serde", "serde_json", - "serde_with 3.9.0", + "serde_with 3.11.0", "starknet-accounts 0.11.0", "starknet-core 0.12.0", "starknet-providers 0.12.0", @@ -14172,7 +14270,7 @@ dependencies = [ "serde", "serde_json", "serde_json_pythonic", - "serde_with 3.9.0", + "serde_with 3.11.0", "sha3", "starknet-crypto 0.7.2", "starknet-types-core", @@ -14335,7 +14433,7 @@ dependencies = [ "reqwest 0.11.27", "serde", "serde_json", - "serde_with 3.9.0", + "serde_with 3.11.0", "starknet-core 0.12.0", "thiserror", "url", @@ -15416,7 +15514,7 @@ dependencies = [ "async-trait", "base64 0.21.7", "bitflags 2.6.0", - "cainome 0.4.6", + "cainome 0.4.8", "chrono", "crypto-bigint", "data-url", @@ -15491,7 +15589,7 @@ dependencies = [ name = "torii-grpc" version = "1.0.2" dependencies = [ - "cainome 0.4.6", + "cainome 0.4.8", "camino", "crypto-bigint", "dojo-test-utils", @@ -15539,7 +15637,7 @@ name = "torii-relay" version = "1.0.2" dependencies = [ "anyhow", - "cainome 0.4.6", + "cainome 0.4.8", "chrono", "crypto-bigint", "dojo-types 1.0.2", diff --git a/Cargo.toml b/Cargo.toml index d2350365d1..eebf5294a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,8 +71,8 @@ debug = true inherits = "release" [workspace.dependencies] -cainome = { git = "https://github.com/cartridge-gg/cainome", rev = "5c2616c273faca7700d2ba565503fcefb5b9d720", features = [ "abigen-rs" ] } -cainome-cairo-serde = { git = "https://github.com/cartridge-gg/cainome", rev = "5c2616c273faca7700d2ba565503fcefb5b9d720" } +cainome = { git = "https://github.com/cartridge-gg/cainome", tag = "v0.4.8", features = [ "abigen-rs" ] } +cainome-cairo-serde = { git = "https://github.com/cartridge-gg/cainome", tag = "v0.4.8" } dojo-utils = { path = "crates/dojo/utils" } # metrics @@ -210,7 +210,7 @@ scarb-ui = { git = "https://github.com/dojoengine/scarb", rev = "7eac49b3e61236c semver = "1.0.5" serde = { version = "1.0", features = [ "derive" ] } serde_json = { version = "1.0", features = [ "arbitrary_precision" ] } -serde_with = "3.9.0" +serde_with = "3.11.0" similar-asserts = "1.5.0" smol_str = { version = "0.2.0", features = [ "serde" ] } spinoff = "0.8.0" From f0596373f7e33386117138fcd846b6b8a8be62a7 Mon Sep 17 00:00:00 2001 From: Valentin Dosimont Date: Mon, 2 Dec 2024 12:01:48 +0100 Subject: [PATCH 2/5] feat: add CairoOption and CairoCustomEnum type handling --- crates/dojo/bindgen/src/plugins/mod.rs | 9 ++ .../plugins/typescript/generator/constants.rs | 8 ++ .../src/plugins/typescript/generator/enum.rs | 67 +++++++++-- .../plugins/typescript/generator/interface.rs | 109 ++++++++++++++++-- .../src/plugins/typescript/generator/mod.rs | 104 ++++++++++++++++- .../bindgen/src/plugins/typescript/writer.rs | 3 + 6 files changed, 280 insertions(+), 20 deletions(-) diff --git a/crates/dojo/bindgen/src/plugins/mod.rs b/crates/dojo/bindgen/src/plugins/mod.rs index 3b1b481482..4470028a65 100644 --- a/crates/dojo/bindgen/src/plugins/mod.rs +++ b/crates/dojo/bindgen/src/plugins/mod.rs @@ -74,6 +74,15 @@ impl Buffer { } } + /// Inserts string at the specified index. + /// + /// * `s` - The string to insert. + /// * `pos` - The position to insert the string at. + /// * `idx` - The index of the string to insert at. + pub fn insert_at_index(&mut self, s: String, idx: usize) { + self.0.insert(idx, s); + } + /// Finds position of the given string in the inner vec. /// /// * `pos` - The string to search for. diff --git a/crates/dojo/bindgen/src/plugins/typescript/generator/constants.rs b/crates/dojo/bindgen/src/plugins/typescript/generator/constants.rs index 24f3dc3772..66efc4be29 100644 --- a/crates/dojo/bindgen/src/plugins/typescript/generator/constants.rs +++ b/crates/dojo/bindgen/src/plugins/typescript/generator/constants.rs @@ -14,3 +14,11 @@ pub const CAIRO_BOOL: &str = "bool"; pub const JS_BOOLEAN: &str = "boolean"; pub const JS_STRING: &str = "string"; pub const JS_BIGNUMBERISH: &str = "BigNumberish"; + +pub(crate) const BIGNUMNERISH_IMPORT: &str = "import type { BigNumberish } from 'starknet';\n"; +pub(crate) const CAIRO_OPTION_IMPORT: &str = "import type { CairoOption } from 'starknet';\n"; +pub(crate) const CAIRO_ENUM_IMPORT: &str = "import type { CairoCustomEnum } from 'starknet';\n"; +pub(crate) const CAIRO_OPTION_TYPE_PATH: &str = "core::option::Option"; +pub(crate) const SN_IMPORT_SEARCH: &str = "} from 'starknet';"; +pub(crate) const CAIRO_OPTION_TOKEN: &str = "CairoOption,"; +pub(crate) const CAIRO_ENUM_TOKEN: &str = "CairoCustomEnum,"; diff --git a/crates/dojo/bindgen/src/plugins/typescript/generator/enum.rs b/crates/dojo/bindgen/src/plugins/typescript/generator/enum.rs index ebbee65c47..c28a5fd37a 100644 --- a/crates/dojo/bindgen/src/plugins/typescript/generator/enum.rs +++ b/crates/dojo/bindgen/src/plugins/typescript/generator/enum.rs @@ -1,31 +1,76 @@ use cainome::parser::tokens::{Composite, CompositeType}; use crate::error::BindgenResult; +use crate::plugins::typescript::generator::JsType; use crate::plugins::{BindgenModelGenerator, Buffer}; +use super::constants::{CAIRO_ENUM_IMPORT, CAIRO_ENUM_TOKEN, SN_IMPORT_SEARCH}; +use super::token_is_custom_enum; + +const CAIRO_ENUM_TYPE_IMPL: &str = "export type TypedCairoEnum = CairoCustomEnum & {\n\tvariant: { [K in keyof T]: T[K] | undefined };\n\tunwrap(): T[keyof T];\n}\n"; + pub(crate) struct TsEnumGenerator; +impl TsEnumGenerator { + fn check_import(&self, token: &Composite, buffer: &mut Buffer) { + // type is Enum with type variants, need to import CairoEnum + // if enum has at least one inner that is a composite type + if token_is_custom_enum(token) { + if !buffer.has(SN_IMPORT_SEARCH) { + buffer.push(CAIRO_ENUM_IMPORT.to_owned()); + } else if !buffer.has(CAIRO_ENUM_TOKEN) { + // If 'starknet' import is present, we add CairoEnum to the imported types + buffer.insert_after(format!(" {CAIRO_ENUM_TOKEN}"), SN_IMPORT_SEARCH, "{", 1); + } + } + if !buffer.has(CAIRO_ENUM_TYPE_IMPL) { + let pos = buffer.pos(SN_IMPORT_SEARCH).unwrap(); + buffer.insert_at_index(CAIRO_ENUM_TYPE_IMPL.to_owned(), pos + 1); + } + } +} + impl BindgenModelGenerator for TsEnumGenerator { fn generate(&self, token: &Composite, buffer: &mut Buffer) -> BindgenResult { if token.r#type != CompositeType::Enum || token.inners.is_empty() { return Ok(String::new()); } - let gen = format!( - "// Type definition for `{path}` enum + let gen = if token_is_custom_enum(token) { + self.check_import(token, buffer); + format!( + "// Type definition for `{path}` enum +export type {name} = {{ +{variants} +}} +export type {name}Enum = TypedCairoEnum<{name}>; +", + path = token.type_path, + name = token.type_name(), + variants = token + .inners + .iter() + .map(|inner| { format!("\t{}: {};", inner.name, JsType::from(&inner.token)) }) + .collect::>() + .join("\n") + ) + } else { + format!( + "// Type definition for `{path}` enum export enum {name} {{ {variants} }} ", - path = token.type_path, - name = token.type_name(), - variants = token - .inners - .iter() - .map(|inner| format!("\t{},", inner.name)) - .collect::>() - .join("\n") - ); + path = token.type_path, + name = token.type_name(), + variants = token + .inners + .iter() + .map(|inner| format!("\t{},", inner.name)) + .collect::>() + .join("\n") + ) + }; if buffer.has(&gen) { return Ok(String::new()); diff --git a/crates/dojo/bindgen/src/plugins/typescript/generator/interface.rs b/crates/dojo/bindgen/src/plugins/typescript/generator/interface.rs index 111a082d3c..98dc866795 100644 --- a/crates/dojo/bindgen/src/plugins/typescript/generator/interface.rs +++ b/crates/dojo/bindgen/src/plugins/typescript/generator/interface.rs @@ -1,12 +1,31 @@ -use cainome::parser::tokens::{Composite, CompositeType}; +use cainome::parser::tokens::{Composite, CompositeType, Token}; -use super::JsType; +use super::constants::{BIGNUMNERISH_IMPORT, CAIRO_OPTION_IMPORT, SN_IMPORT_SEARCH}; +use super::{token_is_option, JsType}; use crate::error::BindgenResult; +use crate::plugins::typescript::generator::constants::CAIRO_OPTION_TOKEN; use crate::plugins::{BindgenModelGenerator, Buffer}; -const BIGNUMNERISH_IMPORT: &str = "import type { BigNumberish } from 'starknet';"; - pub(crate) struct TsInterfaceGenerator; +impl TsInterfaceGenerator { + fn check_import(&self, token: &Composite, buffer: &mut Buffer) { + // only search for end part of the import, as we append the other imports afterward + if !buffer.has("BigNumberish } from 'starknet';") { + buffer.push(BIGNUMNERISH_IMPORT.to_owned()); + } + + // type is Option, need to import CairoOption + if token_is_option(token) { + // we directly add import if 'starknet' import is not present + if !buffer.has(SN_IMPORT_SEARCH) { + buffer.push(CAIRO_OPTION_IMPORT.to_owned()); + } else if !buffer.has(CAIRO_OPTION_TOKEN) { + // If 'starknet' import is present, we add CairoOption to the imported types + buffer.insert_after(format!(" {CAIRO_OPTION_TOKEN}"), SN_IMPORT_SEARCH, "{", 1); + } + } + } +} impl BindgenModelGenerator for TsInterfaceGenerator { fn generate(&self, token: &Composite, buffer: &mut Buffer) -> BindgenResult { @@ -14,9 +33,7 @@ impl BindgenModelGenerator for TsInterfaceGenerator { return Ok(String::new()); } - if !buffer.has(BIGNUMNERISH_IMPORT) { - buffer.push(BIGNUMNERISH_IMPORT.to_owned()); - } + self.check_import(token, buffer); Ok(format!( "// Type definition for `{path}` struct @@ -30,7 +47,15 @@ export interface {name} {{ fields = token .inners .iter() - .map(|inner| { format!("\t{}: {};", inner.name, JsType::from(&inner.token)) }) + .map(|inner| { + if let Token::Composite(composite) = &inner.token { + if token_is_option(composite) { + self.check_import(composite, buffer); + } + } + + format!("\t{}: {};", inner.name, JsType::from(&inner.token)) + }) .collect::>() .join("\n") )) @@ -93,6 +118,21 @@ mod tests { ); } + #[test] + fn test_check_import() { + let mut buff = Buffer::new(); + let writer = TsInterfaceGenerator; + let token = create_test_struct_token(); + writer.check_import(&token, &mut buff); + assert_eq!(1, buff.len()); + let option = create_option_token(); + writer.check_import(&option, &mut buff); + assert_eq!(1, buff.len()); + let custom_enum = create_custom_enum_token(); + writer.check_import(&custom_enum, &mut buff); + assert_eq!(1, buff.len()); + } + fn create_test_struct_token() -> Composite { Composite { type_path: "core::test::TestStruct".to_owned(), @@ -122,4 +162,57 @@ mod tests { alias: None, } } + + fn create_option_token() -> Composite { + Composite { + type_path: "core::option::Option".to_owned(), + inners: vec![CompositeInner { + index: 0, + name: "value".to_owned(), + kind: CompositeInnerKind::Key, + token: Token::CoreBasic(CoreBasic { type_path: "core::felt252".to_owned() }), + }], + generic_args: vec![], + r#type: CompositeType::Struct, + is_event: false, + alias: None, + } + } + fn create_custom_enum_token() -> Composite { + Composite { + type_path: "core::test::CustomEnum".to_owned(), + inners: vec![ + CompositeInner { + index: 0, + name: "Variant1".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::CoreBasic(CoreBasic { type_path: "core::felt252".to_owned() }), + }, + CompositeInner { + index: 1, + name: "Variant2".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::Composite(Composite { + type_path: "core::test::NestedStruct".to_owned(), + inners: vec![CompositeInner { + index: 0, + name: "nested_field".to_owned(), + kind: CompositeInnerKind::Key, + token: Token::CoreBasic(CoreBasic { + type_path: "core::felt252".to_owned(), + }), + }], + generic_args: vec![], + r#type: CompositeType::Struct, + is_event: false, + alias: None, + }), + }, + ], + generic_args: vec![], + r#type: CompositeType::Enum, + is_event: false, + alias: None, + } + } } diff --git a/crates/dojo/bindgen/src/plugins/typescript/generator/mod.rs b/crates/dojo/bindgen/src/plugins/typescript/generator/mod.rs index 49978627fe..786d8d0380 100644 --- a/crates/dojo/bindgen/src/plugins/typescript/generator/mod.rs +++ b/crates/dojo/bindgen/src/plugins/typescript/generator/mod.rs @@ -1,4 +1,5 @@ -use cainome::parser::tokens::{Composite, Token}; +use crate::plugins::typescript::generator::constants::CAIRO_OPTION_TYPE_PATH; +use cainome::parser::tokens::{Composite, CompositeType, Token}; use constants::{ CAIRO_BOOL, CAIRO_BYTE_ARRAY, CAIRO_CONTRACT_ADDRESS, CAIRO_FELT252, CAIRO_I128, CAIRO_U128, CAIRO_U16, CAIRO_U256, CAIRO_U256_STRUCT, CAIRO_U32, CAIRO_U64, CAIRO_U8, JS_BIGNUMBERISH, @@ -55,6 +56,21 @@ pub(crate) fn generate_type_init(token: &Composite) -> String { ) } +/// Checks if Token::Composite is an Option +/// * token - The token to check +/// +pub(crate) fn token_is_option(token: &Composite) -> bool { + token.type_path.starts_with(CAIRO_OPTION_TYPE_PATH) +} + +/// Checks if Token::Composite is an custom enum (enum with nested Composite types) +/// * token - The token to check +/// +pub(crate) fn token_is_custom_enum(token: &Composite) -> bool { + token.r#type == CompositeType::Enum + && token.inners.iter().any(|inner| inner.token.to_composite().is_ok()) +} + #[derive(Debug)] pub(crate) struct JsType(String); impl From<&str> for JsType { @@ -93,6 +109,16 @@ impl From<&Token> for JsType { ) .as_str(), ), + Token::Composite(c) => { + if token_is_option(c) { + return JsType::from(format!("CairoOption<{}>", c.generic_args.iter().map(|(_, t)| JsType::from(t.type_name().as_str()).to_string()).collect::>().join(", ")).as_str()); + } + if token_is_custom_enum(c) { + // we defined a type wrapper with Enum suffix let's use it there + return JsType::from(format!("{}Enum", value.type_name()).as_str()); + } + return JsType::from(value.type_name().as_str()) + }, _ => JsType::from(value.type_name().as_str()), } } @@ -244,6 +270,82 @@ mod tests { ) } + #[test] + fn test_option_type() { + assert_eq!( + "CairoOption", + JsType::from(&Token::Composite(Composite { + type_path: "core::option::Option".to_owned(), + inners: vec![], + generic_args: vec![ + ( + "A".to_owned(), + Token::Composite( + Composite { + type_path: "tournament::ls15_components::models::tournament::GatedType".to_owned(), + inners: vec![ + CompositeInner { + index: 0, + name: "token".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::Composite( + Composite { + type_path: "tournament::ls15_components::models::tournament::GatedToken".to_owned(), + inners: vec![], + generic_args: vec![], + r#type: CompositeType::Unknown, + is_event: false, + alias: None, + }, + ), + }, + CompositeInner { + index: 1, + name: "tournament".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::Array( + Array { + type_path: "core::array::Span::".to_owned(), + inner: Box::new(Token::CoreBasic( + CoreBasic { + type_path: "core::integer::u64".to_owned(), + }, + )), + is_legacy: false, + }, + ), + }, + CompositeInner { + index: 2, + name: "address".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::Array( + Array { + type_path: "core::array::Span::".to_owned(), + inner: Box::new(Token::CoreBasic( + CoreBasic { + type_path: "core::starknet::contract_address::ContractAddress".to_owned(), + }, + )) , + is_legacy: false, + }, + ), + } + ], + generic_args: vec![], + r#type: CompositeType::Unknown, + is_event: false, + alias: None + } + ) + ), + ], + r#type: CompositeType::Unknown, + is_event: false, + alias: None })) + ) + } + #[test] fn test_default_value_basics() { assert_eq!( diff --git a/crates/dojo/bindgen/src/plugins/typescript/writer.rs b/crates/dojo/bindgen/src/plugins/typescript/writer.rs index b49bc580a6..e34313d994 100644 --- a/crates/dojo/bindgen/src/plugins/typescript/writer.rs +++ b/crates/dojo/bindgen/src/plugins/typescript/writer.rs @@ -51,6 +51,9 @@ impl BindgenWriter for TsFileWriter { .iter() .fold(Buffer::new(), |mut acc, g| { composites.iter().for_each(|c| { + // println!("Generating code for model {}", c.type_path); + // println!("{:#?}", c); + // println!("====================="); match g.generate(c, &mut acc) { Ok(code) => { if !code.is_empty() { From 85504a8231364768915bfb339300bc70d2257988 Mon Sep 17 00:00:00 2001 From: Valentin Dosimont Date: Mon, 2 Dec 2024 12:02:26 +0100 Subject: [PATCH 3/5] feat: merge schema in models.gen.ts --- .../plugins/typescript/generator/schema.rs | 142 +++++++++++++----- 1 file changed, 106 insertions(+), 36 deletions(-) diff --git a/crates/dojo/bindgen/src/plugins/typescript/generator/schema.rs b/crates/dojo/bindgen/src/plugins/typescript/generator/schema.rs index e906eb6cc3..2e2a6adf85 100644 --- a/crates/dojo/bindgen/src/plugins/typescript/generator/schema.rs +++ b/crates/dojo/bindgen/src/plugins/typescript/generator/schema.rs @@ -12,45 +12,59 @@ pub(crate) struct TsSchemaGenerator {} impl TsSchemaGenerator { /// Import only needs to be present once fn import_schema_type(&self, buffer: &mut Buffer) { - if !buffer.has("import type { SchemaType }") { - buffer.insert(0, "import type { SchemaType } from \"@dojoengine/sdk\";\n".to_owned()); + if !buffer.has("import type { SchemaType as ISchemaType }") { + buffer.insert( + 0, + "import type { SchemaType as ISchemaType } from \"@dojoengine/sdk\";\n".to_owned(), + ); } } /// Generates the type definition for the schema fn handle_schema_type(&self, token: &Composite, buffer: &mut Buffer) { - let (ns, namespace, type_name) = get_namespace_and_path(token); - let schema_type = format!("export interface {namespace}SchemaType extends SchemaType"); - if !buffer.has(&schema_type) { + let (ns, _namespace, type_name) = get_namespace_and_path(token); + let schema_type = "export interface SchemaType extends ISchemaType"; + if !buffer.has(schema_type) { buffer.push(format!( - "export interface {namespace}SchemaType extends SchemaType {{\n\t{ns}: \ + "export interface SchemaType extends ISchemaType {{\n\t{ns}: \ {{\n\t\t{}: {},\n\t}},\n}}", type_name, type_name )); return; } + // check if namespace is defined in interface. if not, add it. + // next, find where namespace was defined in interface and add property to it. + if !self.namespace_is_defined(buffer, &ns) { + let gen = format!("\n\t{ns}: {{\n\t\t{type_name}: {type_name},\n\t}},"); + buffer.insert_after(gen, schema_type, ",", 1); + return; + } + // type has already been initialized let gen = format!("\n\t\t{type_name}: {type_name},"); if buffer.has(&gen) { return; } - // fastest way to add a field to the interface is to search for the n-1 `,` and add the + let ns_def = format!("\n\t{ns}: {{\n\t\t"); + + // fastest way to add a field to the interface is to search for the n-1 + // `,` and add the // field directly after it. // to improve this logic, we would need to either have some kind of code parsing. // we could otherwise have some intermediate representation that we pass to this generator // function. - buffer.insert_after(gen, &schema_type, ",", 2); + buffer.insert_after(gen, &ns_def, ",", 2); } /// Generates the default values for the schema fn handle_schema_const(&self, token: &Composite, buffer: &mut Buffer) { - let (ns, namespace, type_name) = get_namespace_and_path(token); - let const_type = format!("export const schema: {namespace}SchemaType"); - if !buffer.has(&const_type) { + let (ns, _namespace, type_name) = get_namespace_and_path(token); + let const_type = "export const schema: SchemaType"; + if !buffer.has(const_type) { buffer.push(format!( - "export const schema: {namespace}SchemaType = {{\n\t{ns}: {{\n\t\t{}: \ + "export const schema: SchemaType = {{\n\t{ns}: {{\n\t\t{}: \ {},\n\t}},\n}};", type_name, generate_type_init(token) @@ -58,12 +72,27 @@ impl TsSchemaGenerator { return; } + // check if namespace is defined in interface. if not, add it. + // next, find where namespace was defined in interface and add property to it. + if !self.namespace_is_defined(buffer, &ns) { + let gen = + format!("\n\t{ns}: {{\n\t\t{}: {},\n\t}},", type_name, generate_type_init(token)); + buffer.insert_after(gen, const_type, ",", 1); + return; + } + // type has already been initialized let gen = format!("\n\t\t{type_name}: {},", generate_type_init(token)); if buffer.has(&gen) { return; } - buffer.insert_after(gen, &const_type, ",", 2); + + buffer.insert_after(gen, const_type, ",", 1); + } + + /// Check if namespace is defined in schema + fn namespace_is_defined(&self, buffer: &mut Buffer, ns: &str) -> bool { + buffer.has(format!("\n\t{ns}: {{\n\t\t").as_str()) } } @@ -74,12 +103,12 @@ impl BindgenModelGenerator for TsSchemaGenerator { } self.import_schema_type(buffer); - // in buffer search for interface named {pascal_case(namespace)}SchemaType extends - // SchemaType + // in buffer search for interface named SchemaType extends + // ISchemaType // this should be hold in a buffer item self.handle_schema_type(token, buffer); - // in buffer search for const schema: InterfaceName = named + // in buffer search for const schema: SchemaType = named // {pascal_case(namespace)}SchemaType extends SchemaType // this should be hold in a buffer item self.handle_schema_const(token, buffer); @@ -122,11 +151,14 @@ mod tests { let generator = TsSchemaGenerator {}; let mut buffer = Buffer::new(); - let token = create_test_struct_token("TestStruct"); + let token = create_test_struct_token("TestStruct", "onchain_dash"); let _result = generator.generate(&token, &mut buffer); // token is not empty, we should have an import - assert_eq!("import type { SchemaType } from \"@dojoengine/sdk\";\n", buffer[0]); + assert_eq!( + "import type { SchemaType as ISchemaType } from \"@dojoengine/sdk\";\n", + buffer[0] + ); } /// NOTE: For the following tests, we assume that the `enum.rs` and `interface.rs` generators @@ -136,10 +168,10 @@ mod tests { let generator = TsSchemaGenerator {}; let mut buffer = Buffer::new(); - let token = create_test_struct_token("TestStruct"); + let token = create_test_struct_token("TestStruct", "onchain_dash"); let _result = generator.generate(&token, &mut buffer); assert_eq!( - "export interface OnchainDashSchemaType extends SchemaType {\n\tonchain_dash: \ + "export interface SchemaType extends ISchemaType {\n\tonchain_dash: \ {\n\t\tTestStruct: TestStruct,\n\t},\n}", buffer[1] ); @@ -150,65 +182,103 @@ mod tests { let generator = TsSchemaGenerator {}; let mut buffer = Buffer::new(); - let token = create_test_struct_token("TestStruct"); + let token = create_test_struct_token("TestStruct", "onchain_dash"); generator.handle_schema_type(&token, &mut buffer); assert_ne!(0, buffer.len()); assert_eq!( - "export interface OnchainDashSchemaType extends SchemaType {\n\tonchain_dash: \ + "export interface SchemaType extends ISchemaType {\n\tonchain_dash: \ {\n\t\tTestStruct: TestStruct,\n\t},\n}", buffer[0] ); - let token_2 = create_test_struct_token("AvailableTheme"); + let token_2 = create_test_struct_token("AvailableTheme", "onchain_dash"); generator.handle_schema_type(&token_2, &mut buffer); assert_eq!( - "export interface OnchainDashSchemaType extends SchemaType {\n\tonchain_dash: \ + "export interface SchemaType extends ISchemaType {\n\tonchain_dash: \ {\n\t\tTestStruct: TestStruct,\n\t\tAvailableTheme: AvailableTheme,\n\t},\n}", buffer[0] ); + let token_3 = create_test_struct_token("Player", "combat"); + generator.handle_schema_type(&token_3, &mut buffer); + assert_eq!( + "export interface SchemaType extends ISchemaType {\n\tonchain_dash: \ + {\n\t\tTestStruct: TestStruct,\n\t\tAvailableTheme: AvailableTheme,\n\t},\n\tcombat: {\n\t\tPlayer: Player,\n\t},\n}", + buffer[0] + ); + let token_4 = create_test_struct_token("Position", "combat"); + generator.handle_schema_type(&token_4, &mut buffer); + assert_eq!( + "export interface SchemaType extends ISchemaType {\n\tonchain_dash: \ + {\n\t\tTestStruct: TestStruct,\n\t\tAvailableTheme: AvailableTheme,\n\t},\n\tcombat: {\n\t\tPlayer: Player,\n\t\tPosition: Position,\n\t},\n}", + buffer[0] + ); } #[test] fn test_handle_schema_const() { let generator = TsSchemaGenerator {}; let mut buffer = Buffer::new(); - let token = create_test_struct_token("TestStruct"); + let token = create_test_struct_token("TestStruct", "onchain_dash"); generator.handle_schema_const(&token, &mut buffer); assert_eq!(buffer.len(), 1); assert_eq!( buffer[0], - "export const schema: OnchainDashSchemaType = {\n\tonchain_dash: {\n\t\tTestStruct: \ + "export const schema: SchemaType = {\n\tonchain_dash: {\n\t\tTestStruct: \ {\n\t\t\tfieldOrder: ['field1', 'field2', 'field3'],\n\t\t\tfield1: \ 0,\n\t\t\tfield2: 0,\n\t\t\tfield3: 0,\n\t\t},\n\t},\n};" ); - let token_2 = create_test_struct_token("AvailableTheme"); + let token_2 = create_test_struct_token("AvailableTheme", "onchain_dash"); generator.handle_schema_const(&token_2, &mut buffer); assert_eq!(buffer.len(), 1); assert_eq!( buffer[0], - "export const schema: OnchainDashSchemaType = {\n\tonchain_dash: {\n\t\tTestStruct: \ + "export const schema: SchemaType = {\n\tonchain_dash: {\n\t\tTestStruct: \ {\n\t\t\tfieldOrder: ['field1', 'field2', 'field3'],\n\t\t\tfield1: \ 0,\n\t\t\tfield2: 0,\n\t\t\tfield3: 0,\n\t\t},\n\t\tAvailableTheme: \ {\n\t\t\tfieldOrder: ['field1', 'field2', 'field3'],\n\t\t\tfield1: \ 0,\n\t\t\tfield2: 0,\n\t\t\tfield3: 0,\n\t\t},\n\t},\n};" ); + + let token_3 = create_test_struct_token("Player", "combat"); + generator.handle_schema_const(&token_3, &mut buffer); + assert_eq!(buffer.len(), 1); + assert_eq!( + buffer[0], + "export const schema: SchemaType = {\n\tonchain_dash: {\n\t\tTestStruct: \ + {\n\t\t\tfieldOrder: ['field1', 'field2', 'field3'],\n\t\t\tfield1: \ + 0,\n\t\t\tfield2: 0,\n\t\t\tfield3: 0,\n\t\t},\n\t\tAvailableTheme: \ + {\n\t\t\tfieldOrder: ['field1', 'field2', 'field3'],\n\t\t\tfield1: \ + 0,\n\t\t\tfield2: 0,\n\t\t\tfield3: 0,\n\t\t},\n\t},\n\tcombat: {\n\t\tPlayer: {\n\t\t\tfieldOrder: ['field1', 'field2', 'field3'],\n\t\t\tfield1: 0,\n\t\t\tfield2: 0,\n\t\t\tfield3: 0,\n\t\t},\n\t},\n};" + ); + + let token_4 = create_test_struct_token("Position", "combat"); + generator.handle_schema_const(&token_4, &mut buffer); + assert_eq!(buffer.len(), 1); + assert_eq!( + buffer[0], + "export const schema: SchemaType = {\n\tonchain_dash: {\n\t\tTestStruct: \ + {\n\t\t\tfieldOrder: ['field1', 'field2', 'field3'],\n\t\t\tfield1: \ + 0,\n\t\t\tfield2: 0,\n\t\t\tfield3: 0,\n\t\t},\n\t\tAvailableTheme: \ + {\n\t\t\tfieldOrder: ['field1', 'field2', 'field3'],\n\t\t\tfield1: \ + 0,\n\t\t\tfield2: 0,\n\t\t\tfield3: 0,\n\t\t},\n\t},\n\tcombat: {\n\t\tPlayer: {\n\t\t\tfieldOrder: ['field1', 'field2', 'field3'],\n\t\t\tfield1: 0,\n\t\t\tfield2: 0,\n\t\t\tfield3: 0,\n\t\t},\n\t\tPosition: {\n\t\t\tfieldOrder: ['field1', 'field2', 'field3'],\n\t\t\tfield1: 0,\n\t\t\tfield2: 0,\n\t\t\tfield3: 0,\n\t\t},\n\t},\n};" + ); } #[test] fn test_handle_nested_struct() { let generator = TsSchemaGenerator {}; let mut buffer = Buffer::new(); - let nested_struct = create_test_nested_struct_token("TestNestedStruct"); + let nested_struct = create_test_nested_struct_token("TestNestedStruct", "onchain_dash"); let _res = generator.generate(&nested_struct, &mut buffer); assert_eq!(buffer.len(), 3); } - fn create_test_struct_token(name: &str) -> Composite { + fn create_test_struct_token(name: &str, namespace: &str) -> Composite { Composite { - type_path: format!("onchain_dash::{name}"), + type_path: format!("{namespace}::{name}"), inners: vec![ CompositeInner { index: 0, @@ -236,18 +306,18 @@ mod tests { } } - pub fn create_test_nested_struct_token(name: &str) -> Composite { + pub fn create_test_nested_struct_token(name: &str, namespace: &str) -> Composite { Composite { - type_path: format!("onchain_dash::{name}"), + type_path: format!("{namespace}::{name}"), inners: vec![ CompositeInner { index: 0, name: "field1".to_owned(), kind: CompositeInnerKind::Key, token: Token::Array(cainome::parser::tokens::Array { - type_path: "core::array::Array::".to_owned(), + type_path: format!("core::array::Array::<{namespace}::Direction>"), inner: Box::new(Token::Composite(Composite { - type_path: "onchain_dah::Direction".to_owned(), + type_path: format!("{namespace}::Direction"), inners: vec![ CompositeInner { index: 0, @@ -302,7 +372,7 @@ mod tests { index: 1, name: "field2".to_owned(), kind: CompositeInnerKind::Key, - token: Token::Composite(create_test_struct_token("Position")), + token: Token::Composite(create_test_struct_token("Position", namespace)), }, ], generic_args: vec![], From 6917660304585e12ced07140d62080787ded5ae5 Mon Sep 17 00:00:00 2001 From: Valentin Dosimont Date: Mon, 2 Dec 2024 15:26:08 +0100 Subject: [PATCH 4/5] feat: add Input type to omit fieldOrder field --- .../src/plugins/typescript/generator/constants.rs | 9 +++++++++ .../src/plugins/typescript/generator/function.rs | 9 +++++---- .../src/plugins/typescript/generator/interface.rs | 14 ++++++++++++-- .../src/plugins/typescript/generator/schema.rs | 2 +- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/crates/dojo/bindgen/src/plugins/typescript/generator/constants.rs b/crates/dojo/bindgen/src/plugins/typescript/generator/constants.rs index 66efc4be29..ce064ed6f9 100644 --- a/crates/dojo/bindgen/src/plugins/typescript/generator/constants.rs +++ b/crates/dojo/bindgen/src/plugins/typescript/generator/constants.rs @@ -22,3 +22,12 @@ pub(crate) const CAIRO_OPTION_TYPE_PATH: &str = "core::option::Option"; pub(crate) const SN_IMPORT_SEARCH: &str = "} from 'starknet';"; pub(crate) const CAIRO_OPTION_TOKEN: &str = "CairoOption,"; pub(crate) const CAIRO_ENUM_TOKEN: &str = "CairoCustomEnum,"; + +pub(crate) const REMOVE_FIELD_ORDER_TYPE_DEF: &str = "type RemoveFieldOrder = T extends object + ? Omit< + { + [K in keyof T]: T[K] extends object ? RemoveFieldOrder : T[K]; + }, + 'fieldOrder' + > + : T;"; diff --git a/crates/dojo/bindgen/src/plugins/typescript/generator/function.rs b/crates/dojo/bindgen/src/plugins/typescript/generator/function.rs index 2c09ad8e72..8161ab6a6b 100644 --- a/crates/dojo/bindgen/src/plugins/typescript/generator/function.rs +++ b/crates/dojo/bindgen/src/plugins/typescript/generator/function.rs @@ -88,11 +88,12 @@ impl TsFunctionGenerator { .fold(inputs, |mut acc, input| { let prefix = match &input.1 { Token::Composite(t) => { - if t.r#type == CompositeType::Enum - || (t.r#type == CompositeType::Struct - && !t.type_path.starts_with("core")) - { + if t.r#type == CompositeType::Enum { "models." + } else if t.r#type == CompositeType::Struct + && !t.type_path.starts_with("core") + { + "models.Input" } else { "" } diff --git a/crates/dojo/bindgen/src/plugins/typescript/generator/interface.rs b/crates/dojo/bindgen/src/plugins/typescript/generator/interface.rs index 98dc866795..e58b3f6d9c 100644 --- a/crates/dojo/bindgen/src/plugins/typescript/generator/interface.rs +++ b/crates/dojo/bindgen/src/plugins/typescript/generator/interface.rs @@ -1,6 +1,8 @@ use cainome::parser::tokens::{Composite, CompositeType, Token}; -use super::constants::{BIGNUMNERISH_IMPORT, CAIRO_OPTION_IMPORT, SN_IMPORT_SEARCH}; +use super::constants::{ + BIGNUMNERISH_IMPORT, CAIRO_OPTION_IMPORT, REMOVE_FIELD_ORDER_TYPE_DEF, SN_IMPORT_SEARCH, +}; use super::{token_is_option, JsType}; use crate::error::BindgenResult; use crate::plugins::typescript::generator::constants::CAIRO_OPTION_TOKEN; @@ -25,6 +27,12 @@ impl TsInterfaceGenerator { } } } + + fn add_input_type(&self, buffer: &mut Buffer) { + if !buffer.has(REMOVE_FIELD_ORDER_TYPE_DEF) { + buffer.push(REMOVE_FIELD_ORDER_TYPE_DEF.to_owned()); + } + } } impl BindgenModelGenerator for TsInterfaceGenerator { @@ -34,6 +42,7 @@ impl BindgenModelGenerator for TsInterfaceGenerator { } self.check_import(token, buffer); + self.add_input_type(buffer); Ok(format!( "// Type definition for `{path}` struct @@ -41,6 +50,7 @@ export interface {name} {{ \tfieldOrder: string[]; {fields} }} +export type Input{name} = RemoveFieldOrder<{name}>; ", path = token.type_path, name = token.type_name(), @@ -114,7 +124,7 @@ mod tests { result, "// Type definition for `core::test::TestStruct` struct\nexport interface TestStruct \ {\n\tfieldOrder: string[];\n\tfield1: BigNumberish;\n\tfield2: \ - BigNumberish;\n\tfield3: BigNumberish;\n}\n" + BigNumberish;\n\tfield3: BigNumberish;\n}\nexport type InputTestStruct = RemoveFieldOrder;\n" ); } diff --git a/crates/dojo/bindgen/src/plugins/typescript/generator/schema.rs b/crates/dojo/bindgen/src/plugins/typescript/generator/schema.rs index 2e2a6adf85..b25ba2d3dc 100644 --- a/crates/dojo/bindgen/src/plugins/typescript/generator/schema.rs +++ b/crates/dojo/bindgen/src/plugins/typescript/generator/schema.rs @@ -87,7 +87,7 @@ impl TsSchemaGenerator { return; } - buffer.insert_after(gen, const_type, ",", 1); + buffer.insert_after(gen, const_type, ",", 2); } /// Check if namespace is defined in schema From a5417687f5ef1efcbe007740c4bfea724fc56445 Mon Sep 17 00:00:00 2001 From: Valentin Dosimont Date: Thu, 5 Dec 2024 21:50:28 +0100 Subject: [PATCH 5/5] feat: recursive types in model definition --- Cargo.lock | 56 ++-- Cargo.toml | 4 +- .../src/plugins/typescript/generator/enum.rs | 9 +- .../plugins/typescript/generator/interface.rs | 8 +- .../src/plugins/typescript/generator/mod.rs | 260 +++++++++++++++++- .../plugins/typescript/generator/schema.rs | 23 +- 6 files changed, 308 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 41ff1b29b5..76312c16a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2469,15 +2469,15 @@ dependencies = [ [[package]] name = "cainome" version = "0.4.8" -source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.8#53f989af513adc30c5576898c4a586bb3cd71d63" +source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.10#6fefd8bf4370c77d8834d18a2ae3c59d3a5e8dd5" dependencies = [ "anyhow", "async-trait", - "cainome-cairo-serde 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.8)", - "cainome-cairo-serde-derive 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.8)", - "cainome-parser 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.8)", - "cainome-rs 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.8)", - "cainome-rs-macro 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.8)", + "cainome-cairo-serde 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.10)", + "cainome-cairo-serde-derive 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.10)", + "cainome-parser 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.10)", + "cainome-rs 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.10)", + "cainome-rs-macro 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.10)", "camino", "clap", "clap_complete", @@ -2495,9 +2495,11 @@ dependencies = [ [[package]] name = "cainome-cairo-serde" version = "0.1.0" -source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.2#4e3924fb82b7299d56d3619aa5d7b9863f581e0a" +source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.10#6fefd8bf4370c77d8834d18a2ae3c59d3a5e8dd5" dependencies = [ + "num-bigint", "serde", + "serde_with 3.11.0", "starknet 0.12.0", "thiserror", ] @@ -2505,11 +2507,9 @@ dependencies = [ [[package]] name = "cainome-cairo-serde" version = "0.1.0" -source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.8#53f989af513adc30c5576898c4a586bb3cd71d63" +source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.2#4e3924fb82b7299d56d3619aa5d7b9863f581e0a" dependencies = [ - "num-bigint", "serde", - "serde_with 3.11.0", "starknet 0.12.0", "thiserror", ] @@ -2527,7 +2527,7 @@ dependencies = [ [[package]] name = "cainome-cairo-serde-derive" version = "0.1.0" -source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.8#53f989af513adc30c5576898c4a586bb3cd71d63" +source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.10#6fefd8bf4370c77d8834d18a2ae3c59d3a5e8dd5" dependencies = [ "proc-macro2", "quote", @@ -2549,7 +2549,7 @@ dependencies = [ [[package]] name = "cainome-parser" version = "0.1.0" -source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.2#4e3924fb82b7299d56d3619aa5d7b9863f581e0a" +source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.10#6fefd8bf4370c77d8834d18a2ae3c59d3a5e8dd5" dependencies = [ "convert_case 0.6.0", "quote", @@ -2562,7 +2562,7 @@ dependencies = [ [[package]] name = "cainome-parser" version = "0.1.0" -source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.8#53f989af513adc30c5576898c4a586bb3cd71d63" +source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.2#4e3924fb82b7299d56d3619aa5d7b9863f581e0a" dependencies = [ "convert_case 0.6.0", "quote", @@ -2588,11 +2588,11 @@ dependencies = [ [[package]] name = "cainome-rs" version = "0.1.0" -source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.2#4e3924fb82b7299d56d3619aa5d7b9863f581e0a" +source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.10#6fefd8bf4370c77d8834d18a2ae3c59d3a5e8dd5" dependencies = [ "anyhow", - "cainome-cairo-serde 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.2)", - "cainome-parser 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.2)", + "cainome-cairo-serde 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.10)", + "cainome-parser 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.10)", "camino", "prettyplease", "proc-macro2", @@ -2606,11 +2606,11 @@ dependencies = [ [[package]] name = "cainome-rs" version = "0.1.0" -source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.8#53f989af513adc30c5576898c4a586bb3cd71d63" +source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.2#4e3924fb82b7299d56d3619aa5d7b9863f581e0a" dependencies = [ "anyhow", - "cainome-cairo-serde 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.8)", - "cainome-parser 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.8)", + "cainome-cairo-serde 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.2)", + "cainome-parser 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.2)", "camino", "prettyplease", "proc-macro2", @@ -2642,12 +2642,12 @@ dependencies = [ [[package]] name = "cainome-rs-macro" version = "0.1.0" -source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.2#4e3924fb82b7299d56d3619aa5d7b9863f581e0a" +source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.10#6fefd8bf4370c77d8834d18a2ae3c59d3a5e8dd5" dependencies = [ "anyhow", - "cainome-cairo-serde 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.2)", - "cainome-parser 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.2)", - "cainome-rs 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.2)", + "cainome-cairo-serde 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.10)", + "cainome-parser 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.10)", + "cainome-rs 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.10)", "proc-macro-error", "proc-macro2", "quote", @@ -2660,12 +2660,12 @@ dependencies = [ [[package]] name = "cainome-rs-macro" version = "0.1.0" -source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.8#53f989af513adc30c5576898c4a586bb3cd71d63" +source = "git+https://github.com/cartridge-gg/cainome?tag=v0.4.2#4e3924fb82b7299d56d3619aa5d7b9863f581e0a" dependencies = [ "anyhow", - "cainome-cairo-serde 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.8)", - "cainome-parser 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.8)", - "cainome-rs 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.8)", + "cainome-cairo-serde 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.2)", + "cainome-parser 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.2)", + "cainome-rs 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.2)", "proc-macro-error", "proc-macro2", "quote", @@ -8380,7 +8380,7 @@ dependencies = [ "alloy-primitives", "anyhow", "assert_matches", - "cainome-cairo-serde 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.8)", + "cainome-cairo-serde 0.1.0 (git+https://github.com/cartridge-gg/cainome?tag=v0.4.10)", "clap", "console", "dojo-utils", diff --git a/Cargo.toml b/Cargo.toml index eebf5294a5..d99ac8043e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,8 +71,8 @@ debug = true inherits = "release" [workspace.dependencies] -cainome = { git = "https://github.com/cartridge-gg/cainome", tag = "v0.4.8", features = [ "abigen-rs" ] } -cainome-cairo-serde = { git = "https://github.com/cartridge-gg/cainome", tag = "v0.4.8" } +cainome = { git = "https://github.com/cartridge-gg/cainome", tag = "v0.4.10", features = [ "abigen-rs" ] } +cainome-cairo-serde = { git = "https://github.com/cartridge-gg/cainome", tag = "v0.4.10" } dojo-utils = { path = "crates/dojo/utils" } # metrics diff --git a/crates/dojo/bindgen/src/plugins/typescript/generator/enum.rs b/crates/dojo/bindgen/src/plugins/typescript/generator/enum.rs index c28a5fd37a..a80df627c4 100644 --- a/crates/dojo/bindgen/src/plugins/typescript/generator/enum.rs +++ b/crates/dojo/bindgen/src/plugins/typescript/generator/enum.rs @@ -1,13 +1,14 @@ use cainome::parser::tokens::{Composite, CompositeType}; +use super::constants::{CAIRO_ENUM_IMPORT, CAIRO_ENUM_TOKEN, SN_IMPORT_SEARCH}; +use super::token_is_custom_enum; use crate::error::BindgenResult; use crate::plugins::typescript::generator::JsType; use crate::plugins::{BindgenModelGenerator, Buffer}; -use super::constants::{CAIRO_ENUM_IMPORT, CAIRO_ENUM_TOKEN, SN_IMPORT_SEARCH}; -use super::token_is_custom_enum; - -const CAIRO_ENUM_TYPE_IMPL: &str = "export type TypedCairoEnum = CairoCustomEnum & {\n\tvariant: { [K in keyof T]: T[K] | undefined };\n\tunwrap(): T[keyof T];\n}\n"; +const CAIRO_ENUM_TYPE_IMPL: &str = "export type TypedCairoEnum = CairoCustomEnum & \ + {\n\tvariant: { [K in keyof T]: T[K] | undefined \ + };\n\tunwrap(): T[keyof T];\n}\n"; pub(crate) struct TsEnumGenerator; diff --git a/crates/dojo/bindgen/src/plugins/typescript/generator/interface.rs b/crates/dojo/bindgen/src/plugins/typescript/generator/interface.rs index e58b3f6d9c..15defd7bcd 100644 --- a/crates/dojo/bindgen/src/plugins/typescript/generator/interface.rs +++ b/crates/dojo/bindgen/src/plugins/typescript/generator/interface.rs @@ -40,6 +40,11 @@ impl BindgenModelGenerator for TsInterfaceGenerator { if token.r#type != CompositeType::Struct || token.inners.is_empty() { return Ok(String::new()); } + if buffer + .has(format!("// Type definition for `{path}` struct", path = token.type_path).as_str()) + { + return Ok(String::new()); + } self.check_import(token, buffer); self.add_input_type(buffer); @@ -124,7 +129,8 @@ mod tests { result, "// Type definition for `core::test::TestStruct` struct\nexport interface TestStruct \ {\n\tfieldOrder: string[];\n\tfield1: BigNumberish;\n\tfield2: \ - BigNumberish;\n\tfield3: BigNumberish;\n}\nexport type InputTestStruct = RemoveFieldOrder;\n" + BigNumberish;\n\tfield3: BigNumberish;\n}\nexport type InputTestStruct = \ + RemoveFieldOrder;\n" ); } diff --git a/crates/dojo/bindgen/src/plugins/typescript/generator/mod.rs b/crates/dojo/bindgen/src/plugins/typescript/generator/mod.rs index 786d8d0380..9d080322c2 100644 --- a/crates/dojo/bindgen/src/plugins/typescript/generator/mod.rs +++ b/crates/dojo/bindgen/src/plugins/typescript/generator/mod.rs @@ -1,4 +1,3 @@ -use crate::plugins::typescript::generator::constants::CAIRO_OPTION_TYPE_PATH; use cainome::parser::tokens::{Composite, CompositeType, Token}; use constants::{ CAIRO_BOOL, CAIRO_BYTE_ARRAY, CAIRO_CONTRACT_ADDRESS, CAIRO_FELT252, CAIRO_I128, CAIRO_U128, @@ -7,6 +6,8 @@ use constants::{ }; use convert_case::{Case, Casing}; +use crate::plugins::typescript::generator::constants::CAIRO_OPTION_TYPE_PATH; + pub(crate) mod constants; pub(crate) mod r#enum; pub(crate) mod erc; @@ -58,14 +59,12 @@ pub(crate) fn generate_type_init(token: &Composite) -> String { /// Checks if Token::Composite is an Option /// * token - The token to check -/// pub(crate) fn token_is_option(token: &Composite) -> bool { token.type_path.starts_with(CAIRO_OPTION_TYPE_PATH) } /// Checks if Token::Composite is an custom enum (enum with nested Composite types) /// * token - The token to check -/// pub(crate) fn token_is_custom_enum(token: &Composite) -> bool { token.r#type == CompositeType::Enum && token.inners.iter().any(|inner| inner.token.to_composite().is_ok()) @@ -111,14 +110,24 @@ impl From<&Token> for JsType { ), Token::Composite(c) => { if token_is_option(c) { - return JsType::from(format!("CairoOption<{}>", c.generic_args.iter().map(|(_, t)| JsType::from(t.type_name().as_str()).to_string()).collect::>().join(", ")).as_str()); + return JsType::from( + format!( + "CairoOption<{}>", + c.generic_args + .iter() + .map(|(_, t)| JsType::from(t.type_name().as_str()).to_string()) + .collect::>() + .join(", ") + ) + .as_str(), + ); } if token_is_custom_enum(c) { // we defined a type wrapper with Enum suffix let's use it there return JsType::from(format!("{}Enum", value.type_name()).as_str()); } - return JsType::from(value.type_name().as_str()) - }, + return JsType::from(value.type_name().as_str()); + } _ => JsType::from(value.type_name().as_str()), } } @@ -155,7 +164,12 @@ impl From<&Composite> for JsDefaultValue { fn from(value: &Composite) -> Self { match value.r#type { cainome::parser::tokens::CompositeType::Enum => { - JsDefaultValue(format!("{}.{}", value.type_name(), value.inners[0].name)) + match value.inners[0].token.to_composite() { + Ok(c) => JsDefaultValue::from(c), + Err(_) => { + JsDefaultValue(format!("{}.{}", value.type_name(), value.inners[0].name)) + } + } } cainome::parser::tokens::CompositeType::Struct => JsDefaultValue(format!( "{{ fieldOrder: [{}], {} }}", @@ -163,7 +177,18 @@ impl From<&Composite> for JsDefaultValue { value .inners .iter() - .map(|i| format!("{}: {},", i.name, JsDefaultValue::from(&i.token))) + .map(|i| format!( + "{}: {},", + i.name, + match i.token.to_composite() { + Ok(c) => { + JsDefaultValue::from(c) + } + Err(_) => { + JsDefaultValue::from(&i.token) + } + } + )) .collect::>() .join(" ") )), @@ -281,7 +306,7 @@ mod tests { ( "A".to_owned(), Token::Composite( - Composite { + Composite { type_path: "tournament::ls15_components::models::tournament::GatedType".to_owned(), inners: vec![ CompositeInner { @@ -394,6 +419,223 @@ mod tests { ) } + #[test] + fn test_enum_default_value() { + assert_eq!( + "Direction.Up", + JsDefaultValue::from(&Token::Composite(Composite { + type_path: "dojo_starter::Direction".to_owned(), + inners: vec![ + CompositeInner { + index: 0, + name: "Up".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::CoreBasic(CoreBasic { type_path: "()".to_owned() }) + }, + CompositeInner { + index: 1, + name: "Down".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::CoreBasic(CoreBasic { type_path: "()".to_owned() }) + }, + CompositeInner { + index: 2, + name: "Left".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::CoreBasic(CoreBasic { type_path: "()".to_owned() }) + }, + CompositeInner { + index: 3, + name: "Right".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::CoreBasic(CoreBasic { type_path: "()".to_owned() }) + }, + ], + generic_args: vec![], + r#type: CompositeType::Enum, + is_event: false, + alias: None, + })) + ) + } + + #[test] + fn test_cairo_custom_enum_default_value() { + assert_eq!( + "{ fieldOrder: ['id', 'xp'], id: 0, xp: 0, }", + JsDefaultValue::from(&Token::Composite(Composite { + type_path: "dojo_starter::Direction".to_owned(), + inners: vec![ + CompositeInner { + index: 0, + name: "item".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::Composite(Composite { + type_path: "dojo_starter::Item".to_owned(), + inners: vec![ + CompositeInner { + index: 0, + name: "id".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::CoreBasic(CoreBasic { + type_path: "core::felt252".to_owned(), + }) + }, + CompositeInner { + index: 1, + name: "xp".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::CoreBasic(CoreBasic { + type_path: "core::felt252".to_owned(), + }) + }, + ], + generic_args: vec![], + r#type: CompositeType::Struct, + is_event: false, + alias: None, + }) + }, + CompositeInner { + index: 1, + name: "address".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::CoreBasic(CoreBasic { type_path: "()".to_owned() }) + }, + ], + generic_args: vec![], + r#type: CompositeType::Enum, + is_event: false, + alias: None, + })) + ) + } + + #[test] + fn test_composite_default_value() { + assert_eq!( + "{ fieldOrder: ['id', 'xp'], id: 0, xp: 0, }", + JsDefaultValue::from(&Token::Composite(Composite { + type_path: "dojo_starter::Item".to_owned(), + inners: vec![ + CompositeInner { + index: 0, + name: "id".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::CoreBasic(CoreBasic { + type_path: "core::felt252".to_owned(), + }) + }, + CompositeInner { + index: 1, + name: "xp".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::CoreBasic(CoreBasic { + type_path: "core::felt252".to_owned(), + }) + }, + ], + generic_args: vec![], + r#type: CompositeType::Struct, + is_event: false, + alias: None, + })) + ) + } + + #[test] + fn test_nested_composite_default_value() { + assert_eq!( + "{ fieldOrder: ['id', 'xp', 'item'], id: 0, xp: 0, item: { fieldOrder: ['id', 'xp', \ + 'item'], id: 0, xp: 0, item: { fieldOrder: ['id', 'xp'], id: 0, xp: 0, }, }, }", + JsDefaultValue::from(&Token::Composite(Composite { + type_path: "dojo_starter::Item".to_owned(), + inners: vec![ + CompositeInner { + index: 0, + name: "id".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::CoreBasic(CoreBasic { + type_path: "core::felt252".to_owned(), + }) + }, + CompositeInner { + index: 1, + name: "xp".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::CoreBasic(CoreBasic { + type_path: "core::felt252".to_owned(), + }) + }, + CompositeInner { + index: 1, + name: "item".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::Composite(Composite { + type_path: "dojo_starter::Item".to_owned(), + inners: vec![ + CompositeInner { + index: 0, + name: "id".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::CoreBasic(CoreBasic { + type_path: "core::felt252".to_owned(), + }) + }, + CompositeInner { + index: 1, + name: "xp".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::CoreBasic(CoreBasic { + type_path: "core::felt252".to_owned(), + }) + }, + CompositeInner { + index: 1, + name: "item".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::Composite(Composite { + type_path: "dojo_starter::Item".to_owned(), + inners: vec![ + CompositeInner { + index: 0, + name: "id".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::CoreBasic(CoreBasic { + type_path: "core::felt252".to_owned(), + }) + }, + CompositeInner { + index: 1, + name: "xp".to_owned(), + kind: CompositeInnerKind::NotUsed, + token: Token::CoreBasic(CoreBasic { + type_path: "core::felt252".to_owned(), + }) + }, + ], + generic_args: vec![], + r#type: CompositeType::Struct, + is_event: false, + alias: None, + }) + }, + ], + generic_args: vec![], + r#type: CompositeType::Struct, + is_event: false, + alias: None, + }) + }, + ], + generic_args: vec![], + r#type: CompositeType::Struct, + is_event: false, + alias: None, + })) + ) + } + #[test] fn test_generate_type_init() { let token = create_test_struct_token("TestStruct"); diff --git a/crates/dojo/bindgen/src/plugins/typescript/generator/schema.rs b/crates/dojo/bindgen/src/plugins/typescript/generator/schema.rs index b25ba2d3dc..91cc83b0f8 100644 --- a/crates/dojo/bindgen/src/plugins/typescript/generator/schema.rs +++ b/crates/dojo/bindgen/src/plugins/typescript/generator/schema.rs @@ -26,8 +26,8 @@ impl TsSchemaGenerator { let schema_type = "export interface SchemaType extends ISchemaType"; if !buffer.has(schema_type) { buffer.push(format!( - "export interface SchemaType extends ISchemaType {{\n\t{ns}: \ - {{\n\t\t{}: {},\n\t}},\n}}", + "export interface SchemaType extends ISchemaType {{\n\t{ns}: {{\n\t\t{}: \ + {},\n\t}},\n}}", type_name, type_name )); return; @@ -64,8 +64,7 @@ impl TsSchemaGenerator { let const_type = "export const schema: SchemaType"; if !buffer.has(const_type) { buffer.push(format!( - "export const schema: SchemaType = {{\n\t{ns}: {{\n\t\t{}: \ - {},\n\t}},\n}};", + "export const schema: SchemaType = {{\n\t{ns}: {{\n\t\t{}: {},\n\t}},\n}};", type_name, generate_type_init(token) )); @@ -203,14 +202,16 @@ mod tests { generator.handle_schema_type(&token_3, &mut buffer); assert_eq!( "export interface SchemaType extends ISchemaType {\n\tonchain_dash: \ - {\n\t\tTestStruct: TestStruct,\n\t\tAvailableTheme: AvailableTheme,\n\t},\n\tcombat: {\n\t\tPlayer: Player,\n\t},\n}", + {\n\t\tTestStruct: TestStruct,\n\t\tAvailableTheme: AvailableTheme,\n\t},\n\tcombat: \ + {\n\t\tPlayer: Player,\n\t},\n}", buffer[0] ); let token_4 = create_test_struct_token("Position", "combat"); generator.handle_schema_type(&token_4, &mut buffer); assert_eq!( "export interface SchemaType extends ISchemaType {\n\tonchain_dash: \ - {\n\t\tTestStruct: TestStruct,\n\t\tAvailableTheme: AvailableTheme,\n\t},\n\tcombat: {\n\t\tPlayer: Player,\n\t\tPosition: Position,\n\t},\n}", + {\n\t\tTestStruct: TestStruct,\n\t\tAvailableTheme: AvailableTheme,\n\t},\n\tcombat: \ + {\n\t\tPlayer: Player,\n\t\tPosition: Position,\n\t},\n}", buffer[0] ); } @@ -251,7 +252,9 @@ mod tests { {\n\t\t\tfieldOrder: ['field1', 'field2', 'field3'],\n\t\t\tfield1: \ 0,\n\t\t\tfield2: 0,\n\t\t\tfield3: 0,\n\t\t},\n\t\tAvailableTheme: \ {\n\t\t\tfieldOrder: ['field1', 'field2', 'field3'],\n\t\t\tfield1: \ - 0,\n\t\t\tfield2: 0,\n\t\t\tfield3: 0,\n\t\t},\n\t},\n\tcombat: {\n\t\tPlayer: {\n\t\t\tfieldOrder: ['field1', 'field2', 'field3'],\n\t\t\tfield1: 0,\n\t\t\tfield2: 0,\n\t\t\tfield3: 0,\n\t\t},\n\t},\n};" + 0,\n\t\t\tfield2: 0,\n\t\t\tfield3: 0,\n\t\t},\n\t},\n\tcombat: {\n\t\tPlayer: \ + {\n\t\t\tfieldOrder: ['field1', 'field2', 'field3'],\n\t\t\tfield1: \ + 0,\n\t\t\tfield2: 0,\n\t\t\tfield3: 0,\n\t\t},\n\t},\n};" ); let token_4 = create_test_struct_token("Position", "combat"); @@ -263,7 +266,11 @@ mod tests { {\n\t\t\tfieldOrder: ['field1', 'field2', 'field3'],\n\t\t\tfield1: \ 0,\n\t\t\tfield2: 0,\n\t\t\tfield3: 0,\n\t\t},\n\t\tAvailableTheme: \ {\n\t\t\tfieldOrder: ['field1', 'field2', 'field3'],\n\t\t\tfield1: \ - 0,\n\t\t\tfield2: 0,\n\t\t\tfield3: 0,\n\t\t},\n\t},\n\tcombat: {\n\t\tPlayer: {\n\t\t\tfieldOrder: ['field1', 'field2', 'field3'],\n\t\t\tfield1: 0,\n\t\t\tfield2: 0,\n\t\t\tfield3: 0,\n\t\t},\n\t\tPosition: {\n\t\t\tfieldOrder: ['field1', 'field2', 'field3'],\n\t\t\tfield1: 0,\n\t\t\tfield2: 0,\n\t\t\tfield3: 0,\n\t\t},\n\t},\n};" + 0,\n\t\t\tfield2: 0,\n\t\t\tfield3: 0,\n\t\t},\n\t},\n\tcombat: {\n\t\tPlayer: \ + {\n\t\t\tfieldOrder: ['field1', 'field2', 'field3'],\n\t\t\tfield1: \ + 0,\n\t\t\tfield2: 0,\n\t\t\tfield3: 0,\n\t\t},\n\t\tPosition: {\n\t\t\tfieldOrder: \ + ['field1', 'field2', 'field3'],\n\t\t\tfield1: 0,\n\t\t\tfield2: 0,\n\t\t\tfield3: \ + 0,\n\t\t},\n\t},\n};" ); }