diff --git a/Cargo.lock b/Cargo.lock index 1e5ce5ae1a..79cb2c0674 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2023,6 +2023,7 @@ dependencies = [ "cairo-lang-test-utils", "cairo-lang-utils", "camino", + "convert_case 0.6.0", "dojo-test-utils", "dojo-world", "env_logger 0.10.0", @@ -2111,6 +2112,7 @@ dependencies = [ "cairo-lang-project", "cairo-lang-starknet", "camino", + "convert_case 0.6.0", "dojo-lang", "dojo-test-utils", "reqwest", diff --git a/Cargo.toml b/Cargo.toml index 07912550a5..214a2ec057 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,7 @@ chrono = { version = "0.4.24", features = [ "serde" ] } clap = { version = "4.2", features = [ "derive" ] } colored = "2" console = "0.15.7" +convert_case = "0.6.0" env_logger = "0.10.0" flate2 = "1.0.24" indoc = "1.0.7" diff --git a/crates/dojo-core/src/world.cairo b/crates/dojo-core/src/world.cairo index 4832db66f9..ee37b660f9 100644 --- a/crates/dojo-core/src/world.cairo +++ b/crates/dojo-core/src/world.cairo @@ -480,7 +480,7 @@ mod World { } #[system] -mod LibraryCall { +mod library_call { fn execute( class_hash: starknet::ClassHash, entrypoint: felt252, calladata: Span ) -> Span { diff --git a/crates/dojo-core/tests/src/world.cairo b/crates/dojo-core/tests/src/world.cairo index a7aa1505ea..b84380189b 100644 --- a/crates/dojo-core/tests/src/world.cairo +++ b/crates/dojo-core/tests/src/world.cairo @@ -15,7 +15,7 @@ use dojo::interfaces::IWorldDispatcher; use dojo::interfaces::IWorldDispatcherTrait; use dojo::executor::Executor; use dojo::world::World; -use dojo::world::LibraryCall; +use dojo::world::library_call; // Components and Systems @@ -74,7 +74,7 @@ fn test_component() { let name = 'Foo'.into(); let world = deploy_world(); - world.register_component(FooComponent::TEST_CLASS_HASH.try_into().unwrap()); + world.register_component(foo::TEST_CLASS_HASH.try_into().unwrap()); let mut data = ArrayTrait::new(); data.append(1337); let id = world.uuid(); @@ -89,7 +89,7 @@ fn test_component_with_partition() { let name = 'Foo'.into(); let world = deploy_world(); - world.register_component(FooComponent::TEST_CLASS_HASH.try_into().unwrap()); + world.register_component(foo::TEST_CLASS_HASH.try_into().unwrap()); let mut data = ArrayTrait::new(); data.append(1337); let id = world.uuid(); @@ -107,7 +107,7 @@ fn test_system() { let world = spawn_empty_world(); world.register_system(Bar::TEST_CLASS_HASH.try_into().unwrap()); - world.register_component(FooComponent::TEST_CLASS_HASH.try_into().unwrap()); + world.register_component(foo::TEST_CLASS_HASH.try_into().unwrap()); let mut data = ArrayTrait::new(); data.append(1337); data.append(1337); @@ -135,7 +135,7 @@ fn test_set_entity_admin() { let world = spawn_empty_world(); world.register_system(Bar::TEST_CLASS_HASH.try_into().unwrap()); - world.register_component(FooComponent::TEST_CLASS_HASH.try_into().unwrap()); + world.register_component(foo::TEST_CLASS_HASH.try_into().unwrap()); let alice = starknet::contract_address_const::<0x1337>(); starknet::testing::set_contract_address(alice); @@ -158,7 +158,7 @@ fn test_set_entity_unauthorized() { let world = spawn_empty_world(); world.register_system(Bar::TEST_CLASS_HASH.try_into().unwrap()); - world.register_component(FooComponent::TEST_CLASS_HASH.try_into().unwrap()); + world.register_component(foo::TEST_CLASS_HASH.try_into().unwrap()); let caller = starknet::contract_address_const::<0x1337>(); starknet::testing::set_account_contract_address(caller); @@ -178,7 +178,7 @@ fn test_set_entity_directly() { let world = spawn_empty_world(); world.register_system(Bar::TEST_CLASS_HASH.try_into().unwrap()); - world.register_component(FooComponent::TEST_CLASS_HASH.try_into().unwrap()); + world.register_component(foo::TEST_CLASS_HASH.try_into().unwrap()); // Change Foo component directly let id = world.uuid(); @@ -218,12 +218,12 @@ fn test_library_call_system() { // Spawn empty world let world = spawn_empty_world(); - world.register_system(LibraryCall::TEST_CLASS_HASH.try_into().unwrap()); + world.register_system(library_call::TEST_CLASS_HASH.try_into().unwrap()); let mut calldata = ArrayTrait::new(); - calldata.append(FooComponent::TEST_CLASS_HASH); + calldata.append(foo::TEST_CLASS_HASH); calldata.append(0x011efd13169e3bceace525b23b7f968b3cc611248271e35f04c5c917311fc7f7); calldata.append(0); - world.execute('LibraryCall'.into(), calldata.span()); + world.execute('library_call'.into(), calldata.span()); } #[test] diff --git a/crates/dojo-core/tests/src/world_factory.cairo b/crates/dojo-core/tests/src/world_factory.cairo index 4ce1a8cabf..720b606242 100644 --- a/crates/dojo-core/tests/src/world_factory.cairo +++ b/crates/dojo-core/tests/src/world_factory.cairo @@ -25,7 +25,7 @@ struct Foo { } #[system] -mod Bar { +mod bar { use super::Foo; fn execute(foo: Foo) -> Foo { @@ -80,10 +80,10 @@ fn test_spawn_world() { // Prepare components and systems let mut systems: Array = array::ArrayTrait::new(); - systems.append(Bar::TEST_CLASS_HASH.try_into().unwrap()); + systems.append(bar::TEST_CLASS_HASH.try_into().unwrap()); let mut components: Array = array::ArrayTrait::new(); - components.append(FooComponent::TEST_CLASS_HASH.try_into().unwrap()); + components.append(foo::TEST_CLASS_HASH.try_into().unwrap()); // Spawn World from WorldFactory let world_address = factory.spawn(components, systems); @@ -92,9 +92,9 @@ fn test_spawn_world() { // Check Foo component and Bar system are registered let foo_hash = world.component('Foo'.into()); assert( - foo_hash == FooComponent::TEST_CLASS_HASH.try_into().unwrap(), 'component not registered' + foo_hash == foo::TEST_CLASS_HASH.try_into().unwrap(), 'component not registered' ); - let bar_hash = world.system('Bar'.into()); - assert(bar_hash == Bar::TEST_CLASS_HASH.try_into().unwrap(), 'system not registered'); + let bar_hash = world.system('bar'.into()); + assert(bar_hash == bar::TEST_CLASS_HASH.try_into().unwrap(), 'system not registered'); } diff --git a/crates/dojo-lang/Cargo.toml b/crates/dojo-lang/Cargo.toml index 4a2c489c3e..0455cd8dc5 100644 --- a/crates/dojo-lang/Cargo.toml +++ b/crates/dojo-lang/Cargo.toml @@ -26,6 +26,7 @@ cairo-lang-sierra-generator.workspace = true cairo-lang-syntax.workspace = true cairo-lang-starknet.workspace = true cairo-lang-utils.workspace = true +convert_case.workspace = true dojo-world = { path = "../dojo-world" } itertools.workspace = true scarb.workspace = true diff --git a/crates/dojo-lang/src/compiler.rs b/crates/dojo-lang/src/compiler.rs index dfed5b226a..267008a13e 100644 --- a/crates/dojo-lang/src/compiler.rs +++ b/crates/dojo-lang/src/compiler.rs @@ -61,7 +61,7 @@ impl Compiler for DojoCompiler { for (decl, class) in zip(contracts, classes) { let target_name = &unit.target().name; let contract_name = decl.submodule_id.name(db.upcast_mut()); - let file_name = format!("{target_name}_{contract_name}.json"); + let file_name = format!("{target_name}-{contract_name}.json"); let mut file = target_dir.open_rw(file_name.clone(), "output file", ws.config())?; serde_json::to_writer_pretty(file.deref_mut(), &class) diff --git a/crates/dojo-lang/src/component.rs b/crates/dojo-lang/src/component.rs index eb523b7d83..044a358d0b 100644 --- a/crates/dojo-lang/src/component.rs +++ b/crates/dojo-lang/src/component.rs @@ -7,6 +7,7 @@ use cairo_lang_syntax::node::db::SyntaxGroup; use cairo_lang_syntax::node::helpers::QueryAttrs; use cairo_lang_syntax::node::{ast, Terminal, TypedSyntaxNode}; use cairo_lang_utils::unordered_hash_map::UnorderedHashMap; +use convert_case::{Case, Casing}; use dojo_world::manifest::Member; use crate::plugin::{Component, DojoAuxData}; @@ -105,7 +106,7 @@ pub fn handle_component_struct( } #[starknet::contract] - mod $type_name$Component { + mod $contract_name$ { use super::$type_name$; #[storage] @@ -122,6 +123,7 @@ pub fn handle_component_struct( } ", UnorderedHashMap::from([ + ("contract_name".to_string(), RewriteNode::Text(name.to_case(Case::Snake))), ( "type_name".to_string(), RewriteNode::new_trimmed(struct_ast.name(db).as_syntax_node()), diff --git a/crates/dojo-lang/src/manifest.rs b/crates/dojo-lang/src/manifest.rs index 4d4aecd0dc..5b53ca43c5 100644 --- a/crates/dojo-lang/src/manifest.rs +++ b/crates/dojo-lang/src/manifest.rs @@ -5,6 +5,7 @@ use cairo_lang_defs::ids::{ModuleId, ModuleItemId}; use cairo_lang_filesystem::ids::CrateId; use cairo_lang_semantic::db::SemanticGroup; use cairo_lang_semantic::plugin::DynPluginAuxData; +use convert_case::{Case, Casing}; use dojo_world::manifest::{Contract, Input, Output, System}; use itertools::Itertools; use serde::Serialize; @@ -75,8 +76,8 @@ impl Manifest { // It needs the `Component` suffix because we are // searching from the compiled contracts. let class_hash = compiled_classes - .get(format!("{name}Component").as_str()) - .with_context(|| format!("Contract {name} not found in target.")) + .get(name.to_case(Case::Snake).as_str()) + .with_context(|| format!("Component {name} not found in target.")) .unwrap(); self.0.components.push(dojo_world::manifest::Component { @@ -130,7 +131,7 @@ impl Manifest { let class_hash = compiled_classes .get(name.as_str()) - .with_context(|| format!("Contract {name} not found in target.")) + .with_context(|| format!("System {name} not found in target.")) .unwrap(); self.0.systems.push(System { diff --git a/crates/dojo-lang/src/plugin_test_data/component b/crates/dojo-lang/src/plugin_test_data/component index d267231bd2..929a82b4c0 100644 --- a/crates/dojo-lang/src/plugin_test_data/component +++ b/crates/dojo-lang/src/plugin_test_data/component @@ -73,7 +73,7 @@ trait IPosition { } #[starknet::contract] -mod PositionComponent { +mod position { use super::Position; #[storage] @@ -116,7 +116,7 @@ trait IRoles { } #[starknet::contract] -mod RolesComponent { +mod roles { use super::Roles; #[storage] @@ -158,7 +158,7 @@ trait IPlayer { } #[starknet::contract] -mod PlayerComponent { +mod player { use super::Player; #[storage] diff --git a/crates/dojo-lang/src/plugin_test_data/system b/crates/dojo-lang/src/plugin_test_data/system index 4bbfc44600..e069cb5196 100644 --- a/crates/dojo-lang/src/plugin_test_data/system +++ b/crates/dojo-lang/src/plugin_test_data/system @@ -20,7 +20,7 @@ struct Player { } #[system] -mod Spawn { +mod spawn { use traits::Into; use dojo::world::Context; use super::Position; @@ -67,7 +67,7 @@ mod Spawn { } #[system] -mod Move { +mod move { use traits::Into; use array::ArrayTrait; use dojo::world::Context; @@ -136,7 +136,7 @@ mod Move { let mut calldata = ArrayTrait::new(); calldata.append('name'); - execute!(ctx.world, SpawnSystem, 'PositionPlayerWriter'.into(), calldata.span()); + execute!(ctx.world, spawn, 'PositionPlayerWriter'.into(), calldata.span()); // move_inner(@positions_query, 0_u32, positions_query.len()); @@ -162,7 +162,7 @@ mod Move { } #[system] -mod Proxy { +mod proxy { fn execute(value: felt252) -> felt252 { value } @@ -185,7 +185,7 @@ trait IPosition { } #[starknet::contract] -mod PositionComponent { +mod position { use super::Position; #[storage] @@ -228,7 +228,7 @@ trait IPlayer { } #[starknet::contract] -mod PlayerComponent { +mod player { use super::Player; #[storage] @@ -260,7 +260,7 @@ mod PlayerComponent { } #[starknet::contract] -mod Spawn { +mod spawn { use option::OptionTrait; use array::SpanTrait; @@ -281,7 +281,7 @@ mod Spawn { #[external(v0)] fn name(self: @ContractState) -> felt252 { - 'Spawn' + 'spawn' } #[external(v0)] @@ -400,7 +400,7 @@ mod Spawn { } #[starknet::contract] -mod Move { +mod move { use option::OptionTrait; use array::SpanTrait; @@ -421,7 +421,7 @@ mod Move { #[external(v0)] fn name(self: @ContractState) -> felt252 { - 'Move' + 'move' } #[external(v0)] @@ -901,7 +901,7 @@ mod Move { let mut calldata = ArrayTrait::new(); calldata.append('name'); - ctx.world.execute('SpawnSystem', calldata.span()); + ctx.world.execute('spawn', calldata.span()); let mut i = 0; loop { @@ -939,7 +939,7 @@ mod Move { } #[starknet::contract] -mod Proxy { +mod proxy { use option::OptionTrait; use array::SpanTrait; @@ -960,7 +960,7 @@ mod Proxy { #[external(v0)] fn name(self: @ContractState) -> felt252 { - 'Proxy' + 'proxy' } #[external(v0)] diff --git a/crates/dojo-world/Cargo.toml b/crates/dojo-world/Cargo.toml index f7ec3508dc..54da12af2c 100644 --- a/crates/dojo-world/Cargo.toml +++ b/crates/dojo-world/Cargo.toml @@ -13,6 +13,7 @@ cairo-lang-filesystem.workspace = true cairo-lang-project.workspace = true cairo-lang-starknet.workspace = true camino.workspace = true +convert_case.workspace = true reqwest = { version = "0.11.18", default-features = false, features = [ "rustls-tls", ] } diff --git a/crates/dojo-world/src/component.rs b/crates/dojo-world/src/component.rs index 16268d4f17..2ec47bc04e 100644 --- a/crates/dojo-world/src/component.rs +++ b/crates/dojo-world/src/component.rs @@ -72,7 +72,7 @@ impl<'a, P: Provider + Sync> ComponentReader<'a, P> { let res = self .world .call( - "LibraryCall", + "library_call", vec![FieldElement::THREE, self.class_hash, entrypoint, FieldElement::ZERO], block_id, ) diff --git a/crates/dojo-world/src/component_test.rs b/crates/dojo-world/src/component_test.rs index 3307399ae6..d4c9c1dd74 100644 --- a/crates/dojo-world/src/component_test.rs +++ b/crates/dojo-world/src/component_test.rs @@ -25,7 +25,7 @@ async fn test_component() { assert_eq!( component.class_hash(), FieldElement::from_hex_be( - "0x03a51494efe5416272b29bee6a95d21c2742d9a8a132fd98216f6b2c00f8304d" + "0x0669ea11a6f52d1330f76322e0c2393fb72a73e0cbc05359854f2a539743d000" ) .unwrap() ); diff --git a/crates/dojo-world/src/migration/strategy.rs b/crates/dojo-world/src/migration/strategy.rs index aac9b8159f..54cc102789 100644 --- a/crates/dojo-world/src/migration/strategy.rs +++ b/crates/dojo-world/src/migration/strategy.rs @@ -3,6 +3,7 @@ use std::fs; use std::path::{Path, PathBuf}; use anyhow::{anyhow, Context, Result}; +use convert_case::{Case, Casing}; use starknet::core::types::FieldElement; use super::class::{ClassDiff, ClassMigration}; @@ -96,7 +97,7 @@ where continue; } - let name = file_name_str.split('_').last().unwrap().trim_end_matches(".json").to_string(); + let name = file_name_str.split('-').last().unwrap().trim_end_matches(".json").to_string(); artifact_paths.insert(name, entry.path()); } @@ -147,7 +148,8 @@ fn evaluate_components_to_migrate( match c.remote { Some(remote) if remote == c.local && !world_contract_will_migrate => continue, _ => { - let path = find_artifact_path(&format!("{}Component", c.name), artifact_paths)?; + let path = + find_artifact_path(c.name.to_case(Case::Snake).as_str(), artifact_paths)?; comps_to_migrate .push(ClassMigration { diff: c.clone(), artifact_path: path.clone() }); } diff --git a/crates/dojo-world/src/system.rs b/crates/dojo-world/src/system.rs index a3110dc554..496f02883a 100644 --- a/crates/dojo-world/src/system.rs +++ b/crates/dojo-world/src/system.rs @@ -156,7 +156,7 @@ impl<'a, P: Provider + Sync> SystemReader<'a, P> { let res = self .world .call( - "LibraryCall", + "library_call", vec![FieldElement::THREE, self.class_hash, entrypoint, FieldElement::ZERO], block_id, ) diff --git a/crates/dojo-world/src/system_test.rs b/crates/dojo-world/src/system_test.rs index 08c53bc478..f617037cda 100644 --- a/crates/dojo-world/src/system_test.rs +++ b/crates/dojo-world/src/system_test.rs @@ -20,7 +20,7 @@ async fn test_system() { let block_id: BlockId = BlockId::Tag(BlockTag::Latest); let world = WorldContract::new(world_address, &account); - let spawn = world.system("Spawn", block_id).await.unwrap(); + let spawn = world.system("spawn", block_id).await.unwrap(); let dependencies = spawn.dependencies(block_id).await.unwrap(); assert_eq!( dependencies, @@ -38,7 +38,7 @@ async fn test_system() { assert_eq!(moves, vec![10_u8.into()]); - let move_system = world.system("Move", block_id).await.unwrap(); + let move_system = world.system("move", block_id).await.unwrap(); let _ = move_system.execute(vec![FieldElement::ONE]).await.unwrap(); let _ = move_system.execute(vec![FieldElement::THREE]).await.unwrap(); diff --git a/examples/ecs/README.md b/examples/ecs/README.md index a388714b03..d0e9cb13d7 100644 --- a/examples/ecs/README.md +++ b/examples/ecs/README.md @@ -29,7 +29,7 @@ sozo component entity --world 0xeb752067993e3e1903ba501267664b4ef2f1e40f629a17a0 # The returned value is 0 since we haven't spawned yet. Let's spawn # a player for the caller -sozo execute --world 0xeb752067993e3e1903ba501267664b4ef2f1e40f629a17a0180367e4f68428 Spawn +sozo execute --world 0xeb752067993e3e1903ba501267664b4ef2f1e40f629a17a0180367e4f68428 spawn # Fetch the updated entity sozo component entity --world 0xeb752067993e3e1903ba501267664b4ef2f1e40f629a17a0180367e4f68428 Moves 0x3ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0 diff --git a/examples/ecs/src/systems.cairo b/examples/ecs/src/systems.cairo index c9834f7c07..8893a88005 100644 --- a/examples/ecs/src/systems.cairo +++ b/examples/ecs/src/systems.cairo @@ -1,5 +1,5 @@ #[system] -mod Spawn { +mod spawn { use array::ArrayTrait; use box::BoxTrait; use traits::Into; @@ -17,7 +17,7 @@ mod Spawn { } #[system] -mod Move { +mod move { use array::ArrayTrait; use box::BoxTrait; use traits::Into; @@ -83,10 +83,10 @@ mod tests { use dojo::test_utils::spawn_test_world; - use dojo_examples::components::PositionComponent; - use dojo_examples::components::MovesComponent; - use dojo_examples::systems::Spawn; - use dojo_examples::systems::Move; + use dojo_examples::components::position; + use dojo_examples::components::moves; + use dojo_examples::systems::spawn; + use dojo_examples::systems::move; #[test] #[available_gas(30000000)] @@ -95,27 +95,27 @@ mod tests { // components let mut components = array::ArrayTrait::new(); - components.append(PositionComponent::TEST_CLASS_HASH); - components.append(MovesComponent::TEST_CLASS_HASH); + components.append(position::TEST_CLASS_HASH); + components.append(moves::TEST_CLASS_HASH); // systems let mut systems = array::ArrayTrait::new(); - systems.append(Spawn::TEST_CLASS_HASH); - systems.append(Move::TEST_CLASS_HASH); + systems.append(spawn::TEST_CLASS_HASH); + systems.append(move::TEST_CLASS_HASH); // deploy executor, world and register components/systems let world = spawn_test_world(components, systems); let spawn_call_data = array::ArrayTrait::new(); - world.execute('Spawn'.into(), spawn_call_data.span()); + world.execute('spawn'.into(), spawn_call_data.span()); let mut move_calldata = array::ArrayTrait::new(); - move_calldata.append(Move::Direction::Right(()).into()); - world.execute('Move'.into(), move_calldata.span()); + move_calldata.append(move::Direction::Right(()).into()); + world.execute('move'.into(), move_calldata.span()); let moves = world.entity('Moves'.into(), caller.into(), 0, 0); assert(*moves[0] == 9, 'moves is wrong'); - // let new_position = world.entity('Position'.into(), caller.into(), 0, 0); - // assert(*new_position[0] == 1, 'position x is wrong'); - // assert(*new_position[1] == 0, 'position y is wrong'); + let new_position = world.entity('Position'.into(), caller.into(), 0, 0); + assert(*new_position[0] == 1, 'position x is wrong'); + assert(*new_position[1] == 0, 'position y is wrong'); } } diff --git a/packages/core/src/types/index.ts b/packages/core/src/types/index.ts index 56f289f914..59fb7d8e4d 100644 --- a/packages/core/src/types/index.ts +++ b/packages/core/src/types/index.ts @@ -39,7 +39,7 @@ export interface ICommands { // examples types - TODO: These should be codegen'd from the manifest export type ComponentNames = "" | "Moves" | "Position" | "AuthStatus" | "AuthRole"; -export type SystemNames = "" | "SpawnSystem" | "MoveSystem" | "RouteAuthSystem" | "IsAccountAdminSystem" | "IsAuthorizedSystem" | "GrantAuthRoleSystem" | "GrantScopedAuthRoleSystem" | "GrantResourceSystem" | "RevokeAuthRoleSystem" | "RevokeScopedAuthRoleSystem" | "RevokeResourceSystem"; +export type SystemNames = "" | "spawn" | "move"; export type ExecuteState = 'idle' | 'loading' | 'done' | 'error' diff --git a/packages/examples/react-example/src/dojo/createSystemCalls.ts b/packages/examples/react-example/src/dojo/createSystemCalls.ts index 6826678be0..5a244198c9 100644 --- a/packages/examples/react-example/src/dojo/createSystemCalls.ts +++ b/packages/examples/react-example/src/dojo/createSystemCalls.ts @@ -13,7 +13,7 @@ export function createSystemCalls( { execute, syncWorker }: SetupNetworkResult, ) { const spawn = async () => { - const tx = await execute("Spawn", []); + const tx = await execute("spawn", []); // await awaitStreamValue(txReduced$, (txHash) => txHash === tx.transaction_hash); syncWorker.sync(tx.transaction_hash); @@ -21,7 +21,7 @@ export function createSystemCalls( const move = async (direction: Direction) => { // execute from core - const tx = await execute("Move", [direction]); + const tx = await execute("move", [direction]); // awaitStreamValue(txReduced$, (txHash) => txHash === tx.transaction_hash); syncWorker.sync(tx.transaction_hash); };