Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Markdown generation #1463

Merged
merged 1 commit into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion extensions/scarb-doc/src/docs_generation.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#![allow(dead_code)]
use crate::types::{
Constant, Crate, Enum, ExternFunction, ExternType, FreeFunction, Impl, ImplAlias, ImplConstant,
ImplFunction, ImplType, Member, Module, Struct, Trait, TraitConstant, TraitFunction, TraitType,
Expand Down
97 changes: 97 additions & 0 deletions extensions/scarb-doc/src/docs_generation/markdown.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,99 @@
use anyhow::{Context, Result};
use camino::Utf8Path;
use itertools::chain;
use std::fs;

use crate::docs_generation::markdown::book_toml::generate_book_toml_content;
use crate::docs_generation::markdown::summary::generate_summary_file_content;
use crate::docs_generation::markdown::traits::TopLevelMarkdownDocItem;
use crate::docs_generation::{collect_all_top_level_items, TopLevelItems};
use crate::PackageInformation;

mod book_toml;
mod summary;
mod traits;

const BASE_HEADER_LEVEL: usize = 1;
const SOURCE_DIRECTORY: &str = "src";
const BOOK_TOML_FILENAME: &str = "book.toml";
const SUMMARY_FILENAME: &str = "SUMMARY.md";

pub struct MarkdownContent<'a> {
book_toml: String,
summary: String,
top_level_docs: Vec<(&'a dyn TopLevelMarkdownDocItem, String)>,
}

impl<'a> MarkdownContent<'a> {
pub fn from_crate(package_information: &'a PackageInformation) -> Self {
let top_level_items = collect_all_top_level_items(&package_information.crate_);

let TopLevelItems {
ref modules,
ref constants,
ref free_functions,
ref structs,
ref enums,
ref type_aliases,
ref impl_aliases,
ref traits,
ref impls,
ref extern_types,
ref extern_functions,
} = top_level_items;

let top_level_docs = chain!(
generate_top_level_docs_contents(modules),
generate_top_level_docs_contents(constants),
generate_top_level_docs_contents(free_functions),
generate_top_level_docs_contents(structs),
generate_top_level_docs_contents(enums),
generate_top_level_docs_contents(type_aliases),
generate_top_level_docs_contents(impl_aliases),
generate_top_level_docs_contents(traits),
generate_top_level_docs_contents(impls),
generate_top_level_docs_contents(extern_types),
generate_top_level_docs_contents(extern_functions),
)
.collect();

Self {
book_toml: generate_book_toml_content(&package_information.metadata),
summary: generate_summary_file_content(&top_level_items),
top_level_docs,
}
}

pub fn save(self, output_dir: &Utf8Path) -> Result<()> {
let source_directory_path = output_dir.join(SOURCE_DIRECTORY);
fs::create_dir_all(&source_directory_path)
.context("failed to create directory for docs")?;

fs::write(output_dir.join(BOOK_TOML_FILENAME), self.book_toml)
.context("failed to write book.toml content to a file")?;

fs::write(source_directory_path.join(SUMMARY_FILENAME), self.summary)
.context("failed to write summary content to a file")?;

for (item, file_content) in self.top_level_docs {
fs::write(source_directory_path.join(item.filename()), file_content)
.context("failed to write content to a file")?;
}

Ok(())
}
}

fn generate_top_level_docs_contents<'a>(
items: &[&'a impl TopLevelMarkdownDocItem],
) -> Vec<(&'a dyn TopLevelMarkdownDocItem, String)> {
items
.iter()
.map(|item| {
(
*item as &dyn TopLevelMarkdownDocItem,
item.generate_markdown(BASE_HEADER_LEVEL),
)
})
.collect()
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use indoc::formatdoc;

use crate::AdditionalMetadata;

#[allow(dead_code)]
pub fn generate_book_toml_content(package_metadata: &AdditionalMetadata) -> String {
formatdoc! {
r#"
Expand Down
60 changes: 60 additions & 0 deletions extensions/scarb-doc/src/docs_generation/markdown/summary.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use crate::docs_generation::markdown::traits::generate_markdown_list_for_top_level_subitems;
use crate::docs_generation::markdown::BASE_HEADER_LEVEL;
use crate::docs_generation::TopLevelItems;

pub fn generate_summary_file_content(top_level_items: &TopLevelItems) -> String {
let header = str::repeat("#", BASE_HEADER_LEVEL);

let mut markdown = format!("{header} Summary\n\n");

let TopLevelItems {
modules,
constants,
free_functions,
structs,
enums,
type_aliases,
impl_aliases,
traits,
impls,
extern_types,
extern_functions,
} = top_level_items;

markdown +=
&generate_markdown_list_for_top_level_subitems(modules, "Modules", BASE_HEADER_LEVEL);
markdown +=
&generate_markdown_list_for_top_level_subitems(constants, "Constants", BASE_HEADER_LEVEL);
markdown += &generate_markdown_list_for_top_level_subitems(
free_functions,
"Free functions",
BASE_HEADER_LEVEL,
);
markdown +=
&generate_markdown_list_for_top_level_subitems(structs, "Structs", BASE_HEADER_LEVEL);
markdown += &generate_markdown_list_for_top_level_subitems(enums, "Enums", BASE_HEADER_LEVEL);
markdown += &generate_markdown_list_for_top_level_subitems(
type_aliases,
"Type Aliases",
BASE_HEADER_LEVEL,
);
markdown += &generate_markdown_list_for_top_level_subitems(
impl_aliases,
"Impl Aliases",
BASE_HEADER_LEVEL,
);
markdown += &generate_markdown_list_for_top_level_subitems(traits, "Traits", BASE_HEADER_LEVEL);
markdown += &generate_markdown_list_for_top_level_subitems(impls, "Impls", BASE_HEADER_LEVEL);
markdown += &generate_markdown_list_for_top_level_subitems(
extern_types,
"Extern types",
BASE_HEADER_LEVEL,
);
markdown += &generate_markdown_list_for_top_level_subitems(
extern_functions,
"Extern functions",
BASE_HEADER_LEVEL,
);

markdown
}
16 changes: 15 additions & 1 deletion extensions/scarb-doc/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use anyhow::{Context, Result};
use clap::Parser;
use scarb_doc::docs_generation::markdown::MarkdownContent;
use scarb_doc::metadata::get_target_dir;

use scarb_metadata::MetadataCommand;
Expand Down Expand Up @@ -51,7 +52,20 @@ fn main_inner() -> Result<()> {
.save_to_file(&output_dir)
.context("failed to write output of scarb doc to a file")?;
}
OutputFormat::Markdown => todo!("#1424"),
OutputFormat::Markdown => {
for pkg_information in packages_information {
let pkg_output_dir = output_dir.join(&pkg_information.metadata.name);

MarkdownContent::from_crate(&pkg_information)
.save(&pkg_output_dir)
.with_context(|| {
format!(
"failed to save docs for package {}",
pkg_information.metadata.name
)
})?;
}
}
}

Ok(())
Expand Down
Loading