diff --git a/extensions/scarb-doc/src/docs_generation/markdown/summary.rs b/extensions/scarb-doc/src/docs_generation/markdown/summary.rs index b1fa35a87..5cf7ed96c 100644 --- a/extensions/scarb-doc/src/docs_generation/markdown/summary.rs +++ b/extensions/scarb-doc/src/docs_generation/markdown/summary.rs @@ -4,6 +4,8 @@ use crate::docs_generation::markdown::traits::TopLevelMarkdownDocItem; use crate::docs_generation::markdown::BASE_HEADER_LEVEL; use crate::docs_generation::TopLevelItems; +use super::traits::mark_duplicated_item_with_relative_path; + pub fn generate_summary_file_content(top_level_items: &TopLevelItems) -> String { let header = str::repeat("#", BASE_HEADER_LEVEL); @@ -51,8 +53,14 @@ fn generate_markdown_list_summary_for_top_level_subitems String { - format!("[{}](./{})", self.name(), self.filename()) + fn md_ref(&self, relative_path: Option) -> String { + match relative_path { + Some(path) => format!("[{}](./{})", path, self.filename()), + None => format!("[{}](./{})", self.name(), self.filename()), + } } - fn generate_markdown_list_item(&self) -> String { - format!("- {}\n", self.md_ref()) + fn generate_markdown_list_item(&self, relative_path: Option) -> String { + format!("- {}\n", self.md_ref(relative_path)) } } @@ -153,6 +157,65 @@ impl MarkdownDocItem for Trait { } } +/// Takes items, and appends for each of them a path, that was trimmed based on the common prefix of all of the items, +/// cthat share the same name. +pub fn mark_duplicated_item_with_relative_path<'a, T: TopLevelMarkdownDocItem + 'a>( + items: &'a [&'a T], +) -> Vec<(&&'a T, Option)> { + let mut paths_for_item_name = HashMap::>::new(); + for item in items { + paths_for_item_name + .entry(item.name().to_string()) + .or_default() + .push(item.name().to_string()); + } + + let common_path_prefix_lengths_for_item: HashMap = paths_for_item_name + .iter() + .filter(|(_, paths)| paths.len() > 1) + .map(|(name, paths)| { + let splitted_paths: Vec> = paths + .iter() + .map(|path| path.split("::").map(|val| val.to_string()).collect()) + .collect(); + + let min_len = splitted_paths + .iter() + .map(|vec| vec.len()) + .min() + .unwrap_or(0); + + let mut prefix_len = min_len; + for i in 0..min_len { + let first = &splitted_paths[0][i]; + if !splitted_paths.iter().all(|vec| &vec[i] == first) { + prefix_len = i; + break; + } + } + + (name.clone(), prefix_len) + }) + .collect(); + + items + .iter() + .map(|item| { + let relative_path = + common_path_prefix_lengths_for_item + .get(item.name()) + .map(|common_prefix_length| { + item.full_path() + .split("::") + .skip(*common_prefix_length) + .collect::>() + .join("::") + }); + (item, relative_path) + }) + .collect::>() +} + pub fn generate_markdown_list_for_top_level_subitems( subitems: &[&T], header_level: usize, @@ -163,8 +226,14 @@ pub fn generate_markdown_list_for_top_level_subitems let header = str::repeat("#", header_level); writeln!(&mut markdown, "{header} {}\n", T::HEADER).unwrap(); - for item in subitems { - writeln!(&mut markdown, "{}", item.generate_markdown_list_item()).unwrap(); + let items_with_relative_path = mark_duplicated_item_with_relative_path(subitems); + for (item, relative_path) in items_with_relative_path { + writeln!( + &mut markdown, + "{}", + item.generate_markdown_list_item(relative_path) + ) + .unwrap(); } } diff --git a/extensions/scarb-doc/tests/data/duplicated_item_names/book.toml b/extensions/scarb-doc/tests/data/duplicated_item_names/book.toml new file mode 100644 index 000000000..cbcfa69da --- /dev/null +++ b/extensions/scarb-doc/tests/data/duplicated_item_names/book.toml @@ -0,0 +1,19 @@ +[book] +authors = [""] +language = "en" +multilingual = false +src = "src" +title = "hello_world - Cairo" + +[output.html] +no-section-label = true + +[output.html.playground] +runnable = false + +[output.html.fold] +enable = true +level = 0 + +[output.html.code.hidelines] +cairo = "#" diff --git a/extensions/scarb-doc/tests/data/duplicated_item_names/src/SUMMARY.md b/extensions/scarb-doc/tests/data/duplicated_item_names/src/SUMMARY.md new file mode 100644 index 000000000..58324cd30 --- /dev/null +++ b/extensions/scarb-doc/tests/data/duplicated_item_names/src/SUMMARY.md @@ -0,0 +1,30 @@ +# Summary + +- [Modules](./modules.md) + + - [hello_world](./hello_world.md) + + - [sub_module](./hello_world-sub_module.md) + +- [Free functions](./free_functions.md) + + - [main](./hello_world-main.md) + + - [unique_function_name](./hello_world-unique_function_name.md) + + - [duplicated_function_name](./hello_world-duplicated_function_name.md) + + - [sub_module::duplicated_function_name](./hello_world-sub_module-duplicated_function_name.md) + +- [Enums](./enums.md) + + - [DuplicatedEnumName](./hello_world-DuplicatedEnumName.md) + + - [sub_module::DuplicatedEnumName](./hello_world-sub_module-DuplicatedEnumName.md) + +- [Traits](./traits.md) + + - [DuplicatedTraitName](./hello_world-DuplicatedTraitName.md) + + - [sub_module::DuplicatedTraitName](./hello_world-sub_module-DuplicatedTraitName.md) + diff --git a/extensions/scarb-doc/tests/data/duplicated_item_names/src/enums.md b/extensions/scarb-doc/tests/data/duplicated_item_names/src/enums.md new file mode 100644 index 000000000..1abe128aa --- /dev/null +++ b/extensions/scarb-doc/tests/data/duplicated_item_names/src/enums.md @@ -0,0 +1,6 @@ +# Enums + +- [DuplicatedEnumName](./hello_world-DuplicatedEnumName.md) + +- [sub_module::DuplicatedEnumName](./hello_world-sub_module-DuplicatedEnumName.md) + diff --git a/extensions/scarb-doc/tests/data/duplicated_item_names/src/free_functions.md b/extensions/scarb-doc/tests/data/duplicated_item_names/src/free_functions.md new file mode 100644 index 000000000..065773f67 --- /dev/null +++ b/extensions/scarb-doc/tests/data/duplicated_item_names/src/free_functions.md @@ -0,0 +1,10 @@ +# Free functions + +- [main](./hello_world-main.md) + +- [unique_function_name](./hello_world-unique_function_name.md) + +- [duplicated_function_name](./hello_world-duplicated_function_name.md) + +- [sub_module::duplicated_function_name](./hello_world-sub_module-duplicated_function_name.md) + diff --git a/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-DuplicatedEnumName.md b/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-DuplicatedEnumName.md new file mode 100644 index 000000000..57795f90f --- /dev/null +++ b/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-DuplicatedEnumName.md @@ -0,0 +1,4 @@ +# DuplicatedEnumName + +Fully qualified path: `hello_world::DuplicatedEnumName` + diff --git a/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-DuplicatedTraitName.md b/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-DuplicatedTraitName.md new file mode 100644 index 000000000..aa8cdff00 --- /dev/null +++ b/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-DuplicatedTraitName.md @@ -0,0 +1,8 @@ +# DuplicatedTraitName + +Fully qualified path: `hello_world::DuplicatedTraitName` + +```rust +trait DuplicatedTraitName +``` + diff --git a/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-duplicated_function_name.md b/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-duplicated_function_name.md new file mode 100644 index 000000000..bee90bb0b --- /dev/null +++ b/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-duplicated_function_name.md @@ -0,0 +1,8 @@ +# duplicated_function_name + +Fully qualified path: `hello_world::duplicated_function_name` + +```rust +fn duplicated_function_name() +``` + diff --git a/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-main.md b/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-main.md new file mode 100644 index 000000000..a77dd4bf8 --- /dev/null +++ b/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-main.md @@ -0,0 +1,8 @@ +# main + +Fully qualified path: `hello_world::main` + +```rust +fn main() +``` + diff --git a/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-sub_module-DuplicatedEnumName.md b/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-sub_module-DuplicatedEnumName.md new file mode 100644 index 000000000..5e9b686d1 --- /dev/null +++ b/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-sub_module-DuplicatedEnumName.md @@ -0,0 +1,4 @@ +# DuplicatedEnumName + +Fully qualified path: `hello_world::sub_module::DuplicatedEnumName` + diff --git a/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-sub_module-DuplicatedTraitName.md b/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-sub_module-DuplicatedTraitName.md new file mode 100644 index 000000000..b9b6a4797 --- /dev/null +++ b/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-sub_module-DuplicatedTraitName.md @@ -0,0 +1,8 @@ +# DuplicatedTraitName + +Fully qualified path: `hello_world::sub_module::DuplicatedTraitName` + +```rust +trait DuplicatedTraitName +``` + diff --git a/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-sub_module-duplicated_function_name.md b/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-sub_module-duplicated_function_name.md new file mode 100644 index 000000000..ac28dc46d --- /dev/null +++ b/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-sub_module-duplicated_function_name.md @@ -0,0 +1,8 @@ +# duplicated_function_name + +Fully qualified path: `hello_world::sub_module::duplicated_function_name` + +```rust +fn duplicated_function_name() +``` + diff --git a/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-sub_module.md b/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-sub_module.md new file mode 100644 index 000000000..f1792d42f --- /dev/null +++ b/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-sub_module.md @@ -0,0 +1,16 @@ +# sub_module + +Fully qualified path: `hello_world::sub_module` + +## Free functions + +- [duplicated_function_name](./hello_world-sub_module-duplicated_function_name.md) + +## Enums + +- [DuplicatedEnumName](./hello_world-sub_module-DuplicatedEnumName.md) + +## Traits + +- [DuplicatedTraitName](./hello_world-sub_module-DuplicatedTraitName.md) + diff --git a/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-unique_function_name.md b/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-unique_function_name.md new file mode 100644 index 000000000..9f824e6bb --- /dev/null +++ b/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world-unique_function_name.md @@ -0,0 +1,8 @@ +# unique_function_name + +Fully qualified path: `hello_world::unique_function_name` + +```rust +fn unique_function_name() +``` + diff --git a/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world.md b/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world.md new file mode 100644 index 000000000..770ed9809 --- /dev/null +++ b/extensions/scarb-doc/tests/data/duplicated_item_names/src/hello_world.md @@ -0,0 +1,24 @@ +# hello_world + +Fully qualified path: `hello_world` + +## Modules + +- [sub_module](./hello_world-sub_module.md) + +## Free functions + +- [main](./hello_world-main.md) + +- [unique_function_name](./hello_world-unique_function_name.md) + +- [duplicated_function_name](./hello_world-duplicated_function_name.md) + +## Enums + +- [DuplicatedEnumName](./hello_world-DuplicatedEnumName.md) + +## Traits + +- [DuplicatedTraitName](./hello_world-DuplicatedTraitName.md) + diff --git a/extensions/scarb-doc/tests/data/duplicated_item_names/src/modules.md b/extensions/scarb-doc/tests/data/duplicated_item_names/src/modules.md new file mode 100644 index 000000000..c81c92a20 --- /dev/null +++ b/extensions/scarb-doc/tests/data/duplicated_item_names/src/modules.md @@ -0,0 +1,6 @@ +# Modules + +- [hello_world](./hello_world.md) + +- [sub_module](./hello_world-sub_module.md) + diff --git a/extensions/scarb-doc/tests/data/duplicated_item_names/src/traits.md b/extensions/scarb-doc/tests/data/duplicated_item_names/src/traits.md new file mode 100644 index 000000000..26dbfd490 --- /dev/null +++ b/extensions/scarb-doc/tests/data/duplicated_item_names/src/traits.md @@ -0,0 +1,6 @@ +# Traits + +- [DuplicatedTraitName](./hello_world-DuplicatedTraitName.md) + +- [sub_module::DuplicatedTraitName](./hello_world-sub_module-DuplicatedTraitName.md) + diff --git a/extensions/scarb-doc/tests/duplicated_names.rs b/extensions/scarb-doc/tests/duplicated_names.rs new file mode 100644 index 000000000..7b0eb6ab4 --- /dev/null +++ b/extensions/scarb-doc/tests/duplicated_names.rs @@ -0,0 +1,73 @@ +use assert_fs::TempDir; +use indoc::indoc; +use scarb_test_support::command::Scarb; +use scarb_test_support::project_builder::ProjectBuilder; + +pub mod markdown_target; +use markdown_target::MarkdownTargetChecker; + +#[test] +fn test_duplicated_items_names() { + let root_dir = TempDir::new().unwrap(); + + ProjectBuilder::start() + .name("hello_world") + .lib_cairo(indoc! {r#" + mod sub_module; + + fn main() { + println!("hellow") + } + + fn unique_function_name() { + // pass + } + + fn duplicated_function_name() { + // pass + } + + enum DuplicatedEnumName { + // pass + } + + trait DuplicatedTraitName { + // pass + } + "#}) + .src( + "src/sub_module.cairo", + indoc! {r#" + fn duplicated_function_name() { + // pass + } + + enum DuplicatedEnumName { + // pass + } + + trait DuplicatedTraitName { + // pass + } + "#}, + ) + .build(&root_dir); + + Scarb::quick_snapbox() + .arg("doc") + .args(["--document-private-items"]) + .current_dir(&root_dir) + .assert() + .success(); + + MarkdownTargetChecker::default() + .actual( + root_dir + .path() + .join("target/doc/hello_world") + .to_str() + .unwrap(), + ) + .expected("tests/data/duplicated_item_names") + .assert_all_files_match(); +}