diff --git a/extensions/scarb-doc/src/types.rs b/extensions/scarb-doc/src/types.rs index a3a2b3530..c5faacfac 100644 --- a/extensions/scarb-doc/src/types.rs +++ b/extensions/scarb-doc/src/types.rs @@ -149,15 +149,72 @@ impl Crate { pointer.insert_extern_function(item); } for item in all_pub_ues.use_submodules.into_iter() { - let ancestors = get_ancestors_vector(&mut Vec::new(), item.module_id, db); - self.ensure_module_structure(db, ancestors); - // todo! replace pointer with a new merged module because it cannot be determined at this point if - // pointer was a virtual module. If so, not all module items might be documented as expected. + let mut ancestors = get_ancestors_vector(&mut Vec::new(), item.module_id, db); + if let Some(last_path) = ancestors.pop() { + let pointer = self.ensure_module_structure(db, ancestors); + if let Some(index) = pointer + .submodules + .iter() + .position(|module| module.module_id == last_path) + { + merge_modules(&mut pointer.submodules[index], item); + } + } } self.to_owned() } } +/// Merges subitems of virtual_module into documented_module so it contains all unique data from both modules. +/// Note that documented_module might have been created by [`Module::new_virtual`]. +fn merge_modules(documented_module: &mut Module, virtual_module: Module) -> &mut Module { + for constant in virtual_module.constants { + documented_module.insert_constant(constant); + } + for free_function in virtual_module.free_functions { + documented_module.insert_free_function(free_function); + } + for struct_ in virtual_module.structs { + documented_module.insert_struct(struct_); + } + for enum_ in virtual_module.enums { + documented_module.insert_enum(enum_); + } + for type_alias in virtual_module.type_aliases { + documented_module.insert_type_alias(type_alias); + } + for impl_alias in virtual_module.impl_aliases { + documented_module.insert_impl_alias(impl_alias); + } + for trait_ in virtual_module.traits { + documented_module.insert_trait(trait_); + } + for impl_ in virtual_module.impls { + documented_module.insert_impl(impl_); + } + for extern_type in virtual_module.extern_types { + documented_module.insert_extern_type(extern_type); + } + for extern_function in virtual_module.extern_functions { + documented_module.insert_extern_function(extern_function); + } + for submodule2 in virtual_module.submodules { + if let Some(submodule_index) = documented_module + .submodules + .iter() + .position(|submodule1| submodule1.module_id == submodule2.module_id) + { + merge_modules( + &mut documented_module.submodules[submodule_index], + submodule2, + ); + } else { + documented_module.submodules.push(submodule2); + } + } + documented_module +} + fn get_ancestors_vector( ancestors: &mut Vec, module_id: ModuleId, diff --git a/extensions/scarb-doc/tests/data/json_reexports_merged_module.json b/extensions/scarb-doc/tests/data/json_reexports_merged_module.json new file mode 100644 index 000000000..cf6465b89 --- /dev/null +++ b/extensions/scarb-doc/tests/data/json_reexports_merged_module.json @@ -0,0 +1,261 @@ +{ + "format_version": 1, + "packages_information": [ + { + "crate_": { + "root_module": { + "item_data": { + "name": "hello_world", + "doc": null, + "signature": null, + "full_path": "hello_world" + }, + "submodules": [ + { + "item_data": { + "name": "Alejandro", + "doc": null, + "signature": null, + "full_path": "hello_world::Alejandro" + }, + "submodules": [], + "constants": [], + "free_functions": [], + "structs": [], + "enums": [], + "type_aliases": [], + "impl_aliases": [], + "traits": [], + "impls": [], + "extern_types": [], + "extern_functions": [], + "pub_uses": { + "use_constants": [], + "use_free_functions": [], + "use_structs": [], + "use_enums": [], + "use_module_type_aliases": [], + "use_impl_aliases": [], + "use_traits": [], + "use_impl_defs": [], + "use_extern_types": [], + "use_extern_functions": [], + "use_submodules": [ + { + "item_data": { + "name": "Rodrigo", + "doc": null, + "signature": null, + "full_path": "hello_world::Rodrigo" + }, + "submodules": [ + { + "item_data": { + "name": "Valentina", + "doc": null, + "signature": null, + "full_path": "hello_world::Rodrigo::Valentina" + }, + "submodules": [], + "constants": [], + "free_functions": [], + "structs": [], + "enums": [], + "type_aliases": [], + "impl_aliases": [], + "traits": [], + "impls": [], + "extern_types": [], + "extern_functions": [], + "pub_uses": { + "use_constants": [], + "use_free_functions": [], + "use_structs": [], + "use_enums": [], + "use_module_type_aliases": [], + "use_impl_aliases": [], + "use_traits": [], + "use_impl_defs": [], + "use_extern_types": [], + "use_extern_functions": [], + "use_submodules": [] + } + } + ], + "constants": [], + "free_functions": [], + "structs": [], + "enums": [], + "type_aliases": [], + "impl_aliases": [], + "traits": [], + "impls": [], + "extern_types": [], + "extern_functions": [], + "pub_uses": { + "use_constants": [], + "use_free_functions": [], + "use_structs": [], + "use_enums": [], + "use_module_type_aliases": [], + "use_impl_aliases": [], + "use_traits": [], + "use_impl_defs": [], + "use_extern_types": [], + "use_extern_functions": [], + "use_submodules": [] + } + } + ] + } + }, + { + "item_data": { + "name": "Isabella", + "doc": null, + "signature": null, + "full_path": "hello_world::Isabella" + }, + "submodules": [], + "constants": [], + "free_functions": [], + "structs": [], + "enums": [], + "type_aliases": [], + "impl_aliases": [], + "traits": [], + "impls": [], + "extern_types": [], + "extern_functions": [], + "pub_uses": { + "use_constants": [], + "use_free_functions": [], + "use_structs": [ + { + "members": [], + "item_data": { + "name": "Mariana", + "doc": null, + "signature": "struct Mariana {}", + "full_path": "hello_world::Rodrigo::Mariana" + } + } + ], + "use_enums": [], + "use_module_type_aliases": [], + "use_impl_aliases": [], + "use_traits": [], + "use_impl_defs": [], + "use_extern_types": [], + "use_extern_functions": [], + "use_submodules": [] + } + }, + { + "item_data": { + "name": "Rodrigo", + "doc": null, + "signature": null, + "full_path": "hello_world::Rodrigo" + }, + "submodules": [ + { + "item_data": { + "name": "Valentina", + "doc": null, + "signature": null, + "full_path": "hello_world::Rodrigo::Valentina" + }, + "submodules": [], + "constants": [], + "free_functions": [], + "structs": [], + "enums": [], + "type_aliases": [], + "impl_aliases": [], + "traits": [], + "impls": [], + "extern_types": [], + "extern_functions": [], + "pub_uses": { + "use_constants": [], + "use_free_functions": [], + "use_structs": [], + "use_enums": [], + "use_module_type_aliases": [], + "use_impl_aliases": [], + "use_traits": [], + "use_impl_defs": [], + "use_extern_types": [], + "use_extern_functions": [], + "use_submodules": [] + } + } + ], + "constants": [], + "free_functions": [], + "structs": [ + { + "members": [], + "item_data": { + "name": "Mariana", + "doc": null, + "signature": "struct Mariana {}", + "full_path": "hello_world::Rodrigo::Mariana" + } + } + ], + "enums": [], + "type_aliases": [], + "impl_aliases": [], + "traits": [], + "impls": [], + "extern_types": [], + "extern_functions": [], + "pub_uses": { + "use_constants": [], + "use_free_functions": [], + "use_structs": [], + "use_enums": [], + "use_module_type_aliases": [], + "use_impl_aliases": [], + "use_traits": [], + "use_impl_defs": [], + "use_extern_types": [], + "use_extern_functions": [], + "use_submodules": [] + } + } + ], + "constants": [], + "free_functions": [], + "structs": [], + "enums": [], + "type_aliases": [], + "impl_aliases": [], + "traits": [], + "impls": [], + "extern_types": [], + "extern_functions": [], + "pub_uses": { + "use_constants": [], + "use_free_functions": [], + "use_structs": [], + "use_enums": [], + "use_module_type_aliases": [], + "use_impl_aliases": [], + "use_traits": [], + "use_impl_defs": [], + "use_extern_types": [], + "use_extern_functions": [], + "use_submodules": [] + } + } + }, + "metadata": { + "name": "hello_world", + "authors": null + } + } + ] +} diff --git a/extensions/scarb-doc/tests/reexports.rs b/extensions/scarb-doc/tests/reexports.rs index 7d27cc1ee..efa8483fd 100644 --- a/extensions/scarb-doc/tests/reexports.rs +++ b/extensions/scarb-doc/tests/reexports.rs @@ -127,3 +127,39 @@ fn test_reexports() { .expected("./data/json_reexports.json") .assert_files_match(); } + +#[test] +fn test_reexports_merged_modules() { + let root_dir = TempDir::new().unwrap(); + + ProjectBuilder::start() + .name("hello_world") + .lib_cairo(indoc! {r#" + pub mod Alejandro { + pub use crate::Rodrigo; + } + + pub mod Isabella { + pub use crate::Rodrigo::Mariana; + } + + mod Rodrigo { + struct Mariana {} + struct Vicente {} + pub mod Valentina {} + } + "#}) + .build(&root_dir); + + Scarb::quick_snapbox() + .arg("doc") + .args(["--output-format", "json"]) + .current_dir(&root_dir) + .assert() + .success(); + + JsonTargetChecker::default() + .actual(&root_dir.path().join("target/doc/output.json")) + .expected("./data/json_reexports_merged_module.json") + .assert_files_match(); +}