From 6947f4f76339b414f44cf0cf87068ca5e8b80b97 Mon Sep 17 00:00:00 2001 From: Tyr Chen Date: Mon, 28 Apr 2025 21:21:48 -0700 Subject: [PATCH 1/2] feature: support BankConfig --- .gitignore | 1 + src/bank.rs | 8 ++-- src/bin/codebank.rs | 6 ++- src/lib.rs | 111 +++++++++++++++++++++++++------------------- src/mcp.rs | 8 ++-- 5 files changed, 78 insertions(+), 56 deletions(-) diff --git a/.gitignore b/.gitignore index 96ef6c0..108b93f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target Cargo.lock +.codebank diff --git a/src/bank.rs b/src/bank.rs index 38b4478..292a87d 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -1,5 +1,5 @@ use crate::{ - Bank, BankStrategy, Error, Result, + Bank, BankConfig, Error, Result, parser::{ CppParser, FileUnit, GoParser, LanguageParser, LanguageType, PythonParser, RustParser, TypeScriptParser, formatter::Formatter, @@ -118,7 +118,9 @@ impl CodeBank { } impl Bank for CodeBank { - fn generate(&self, root_dir: &Path, strategy: BankStrategy) -> Result { + fn generate(&self, config: &BankConfig) -> Result { + let root_dir = &config.root_dir; + // Make sure the root directory exists if !root_dir.exists() { return Err(Error::DirectoryNotFound(root_dir.to_path_buf())); @@ -191,7 +193,7 @@ impl Bank for CodeBank { // Format the file unit using the Formatter trait let formatted_content = file_unit.format( - &strategy, + &config.strategy, code_bank .detect_language(&file_unit.path) .unwrap_or(LanguageType::Unknown), diff --git a/src/bin/codebank.rs b/src/bin/codebank.rs index d345b97..cab6f81 100644 --- a/src/bin/codebank.rs +++ b/src/bin/codebank.rs @@ -1,6 +1,6 @@ use anyhow::Result; use clap::{Parser, ValueEnum}; -use codebank::{Bank, BankStrategy, CodeBank}; +use codebank::{Bank, BankConfig, BankStrategy, CodeBank}; use std::fs; use std::path::PathBuf; @@ -45,8 +45,10 @@ fn main() -> Result<()> { OutputStrategy::Summary => BankStrategy::Summary, }; + let config = BankConfig::new(cli.input, strategy, vec![]); + // Generate the code bank - let content = code_bank.generate(&cli.input, strategy)?; + let content = code_bank.generate(&config)?; // Output to file or stdout if let Some(output_file) = cli.output { diff --git a/src/lib.rs b/src/lib.rs index 544053a..44ba615 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,7 +17,7 @@ //! ## Quick Start //! //! ```rust -//! use codebank::{Bank, BankStrategy, CodeBank, Result}; +//! use codebank::{Bank, BankConfig, BankStrategy, CodeBank, Result}; //! use std::path::Path; //! //! fn main() -> Result<()> { @@ -25,10 +25,8 @@ //! let code_bank = CodeBank::try_new()?; //! //! // Generate documentation for your source directory -//! let content = code_bank.generate( -//! Path::new("src"), -//! BankStrategy::Default -//! )?; +//! let config = BankConfig::new(Path::new("src"), BankStrategy::Default, vec![]); +//! let content = code_bank.generate(&config)?; //! //! println!("Generated documentation:\n{}", content); //! Ok(()) @@ -42,12 +40,13 @@ //! The default strategy includes all code elements with their complete implementations: //! //! ```rust -//! use codebank::{Bank, BankStrategy, CodeBank, Result}; +//! use codebank::{Bank, BankConfig, BankStrategy, CodeBank, Result}; //! use std::path::Path; //! //! # fn main() -> Result<()> { //! let code_bank = CodeBank::try_new()?; -//! let content = code_bank.generate(Path::new("src"), BankStrategy::Default)?; +//! let config = BankConfig::new(Path::new("src"), BankStrategy::Default, vec![]); +//! let content = code_bank.generate(&config)?; //! # Ok(()) //! # } //! ``` @@ -57,12 +56,13 @@ //! Exclude test-related code for cleaner documentation: //! //! ```rust -//! use codebank::{Bank, BankStrategy, CodeBank, Result}; +//! use codebank::{Bank, BankConfig, BankStrategy, CodeBank, Result}; //! use std::path::Path; //! //! # fn main() -> Result<()> { //! let code_bank = CodeBank::try_new()?; -//! let content = code_bank.generate(Path::new("src"), BankStrategy::NoTests)?; +//! let config = BankConfig::new(Path::new("src"), BankStrategy::NoTests, vec![]); +//! let content = code_bank.generate(&config)?; //! # Ok(()) //! # } //! ``` @@ -72,12 +72,13 @@ //! Generate documentation for public interfaces only: //! //! ```rust -//! use codebank::{Bank, BankStrategy, CodeBank, Result}; +//! use codebank::{Bank, BankConfig, BankStrategy, CodeBank, Result}; //! use std::path::Path; //! //! # fn main() -> Result<()> { //! let code_bank = CodeBank::try_new()?; -//! let content = code_bank.generate(Path::new("src"), BankStrategy::Summary)?; +//! let config = BankConfig::new(Path::new("src"), BankStrategy::Summary, vec![]); +//! let content = code_bank.generate(&config)?; //! # Ok(()) //! # } //! ``` @@ -87,13 +88,13 @@ //! You can implement the `Bank` trait for your own code bank generator: //! //! ```rust -//! use codebank::{Bank, BankStrategy, Result}; +//! use codebank::{Bank, BankConfig, BankStrategy, Result}; //! use std::path::Path; //! //! struct MyCodeBank; //! //! impl Bank for MyCodeBank { -//! fn generate(&self, root_dir: &Path, strategy: BankStrategy) -> Result { +//! fn generate(&self, config: &BankConfig) -> Result { //! // Your implementation here //! Ok("# Code Bank\n\nCustom implementation".to_string()) //! } @@ -105,13 +106,12 @@ //! The crate uses a custom `Result` type that wraps common error cases: //! //! ```rust -//! use codebank::{Bank, BankStrategy, CodeBank, Result, Error}; +//! use codebank::{Bank, BankConfig, BankStrategy, CodeBank, Result, Error}; //! //! # fn main() -> Result<()> { -//! let result = CodeBank::try_new()?.generate( -//! std::path::Path::new("nonexistent"), -//! BankStrategy::Default -//! ); +//! let code_bank = CodeBank::try_new()?; +//! let config = BankConfig::new(std::path::Path::new("nonexistent"), BankStrategy::Default, vec![]); +//! let result = code_bank.generate(&config); //! //! if let Err(err) = result { //! eprintln!("Failed to generate documentation: {}", err); @@ -127,7 +127,7 @@ mod parser; #[cfg(feature = "mcp")] mod mcp; -use std::path::Path; +use std::path::PathBuf; pub use bank::CodeBank; pub use error::{Error, Result}; @@ -136,6 +136,16 @@ pub use parser::*; #[cfg(feature = "mcp")] pub use mcp::CodeBankMcp; +/// Configuration for generating code bank documentation. +pub struct BankConfig { + /// Root directory to generate code bank for. + pub root_dir: PathBuf, + /// Strategy for generating code bank documentation. + pub strategy: BankStrategy, + /// Directories to ignore. + pub ignore_dirs: Vec, +} + /// Strategy for generating code bank documentation. /// /// This enum controls how the code bank generator processes and formats the code. @@ -162,17 +172,15 @@ pub enum BankStrategy { /// # Examples /// /// ``` - /// use codebank::{Bank, BankStrategy, CodeBank}; + /// use codebank::{Bank, BankConfig, BankStrategy, CodeBank}; /// use std::path::Path; /// /// # fn main() -> Result<(), Box> { /// let code_bank = CodeBank::try_new()?; /// /// // Generate complete documentation - /// let content = code_bank.generate( - /// Path::new("src"), // Use your source directory - /// BankStrategy::Default - /// )?; + /// let config = BankConfig::new(Path::new("src"), BankStrategy::Default, vec![]); + /// let content = code_bank.generate(&config)?; /// /// assert!(content.contains("# Code Bank")); /// # Ok(()) @@ -187,17 +195,15 @@ pub enum BankStrategy { /// # Examples /// /// ``` - /// use codebank::{Bank, BankStrategy, CodeBank, Result}; + /// use codebank::{Bank, BankConfig, BankStrategy, CodeBank, Result}; /// use std::path::Path; /// /// # fn main() -> Result<()> { /// let code_bank = CodeBank::try_new()?; /// /// // Generate documentation excluding tests - /// let content = code_bank.generate( - /// Path::new("src"), // Use your source directory - /// BankStrategy::NoTests - /// )?; + /// let config = BankConfig::new(Path::new("src"), BankStrategy::NoTests, vec![]); + /// let content = code_bank.generate(&config)?; /// /// // Content should not contain test-related code /// let lines = content.lines().collect::>(); @@ -215,17 +221,15 @@ pub enum BankStrategy { /// # Examples /// /// ``` - /// use codebank::{Bank, BankStrategy, CodeBank}; + /// use codebank::{Bank, BankConfig, BankStrategy, CodeBank}; /// use std::path::Path; /// /// # fn main() -> Result<(), Box> { /// let code_bank = CodeBank::try_new()?; /// /// // Generate public interface summary - /// let content = code_bank.generate( - /// Path::new("src"), // Use your source directory - /// BankStrategy::Summary - /// )?; + /// let config = BankConfig::new(Path::new("src"), BankStrategy::Summary, vec![]); + /// let content = code_bank.generate(&config)?; /// /// // Content should contain function signatures but not implementations /// assert!(content.contains("{ ... }")); @@ -244,7 +248,7 @@ pub enum BankStrategy { /// # Examples /// /// ``` -/// use codebank::{Bank, BankStrategy, CodeBank}; +/// use codebank::{Bank, BankConfig, BankStrategy, CodeBank}; /// use std::path::Path; /// /// # fn main() -> Result<(), Box> { @@ -252,10 +256,8 @@ pub enum BankStrategy { /// let code_bank = CodeBank::try_new()?; /// /// // Generate documentation using the Bank trait -/// let content = code_bank.generate( -/// Path::new("src"), // Use your source directory -/// BankStrategy::Default -/// )?; +/// let config = BankConfig::new(Path::new("src"), BankStrategy::Default, vec![]); +/// let content = code_bank.generate(&config)?; /// /// // The generated content should be markdown /// assert!(content.starts_with("# Code Bank")); @@ -268,13 +270,13 @@ pub enum BankStrategy { /// You can implement this trait for your own code bank generator: /// /// ``` -/// use codebank::{Bank, BankStrategy, Result}; +/// use codebank::{Bank, BankConfig, BankStrategy, Result}; /// use std::path::Path; /// /// struct MyCodeBank; /// /// impl Bank for MyCodeBank { -/// fn generate(&self, root_dir: &Path, strategy: BankStrategy) -> Result { +/// fn generate(&self, config: &BankConfig) -> Result { /// // Your implementation here /// Ok("# Code Bank\n\nCustom implementation".to_string()) /// } @@ -282,7 +284,8 @@ pub enum BankStrategy { /// /// # fn main() -> Result<()> { /// let my_bank = MyCodeBank; -/// let content = my_bank.generate(Path::new("."), BankStrategy::Default)?; +/// let config = BankConfig::new(Path::new("."), BankStrategy::Default, vec![]); +/// let content = my_bank.generate(&config)?; /// assert!(content.starts_with("# Code Bank")); /// # Ok(()) /// # } @@ -311,21 +314,33 @@ pub trait Bank { /// # Examples /// /// ``` - /// use codebank::{Bank, BankStrategy, CodeBank}; + /// use codebank::{Bank, BankConfig, BankStrategy, CodeBank}; /// use std::path::Path; /// /// # fn main() -> Result<(), Box> { /// let code_bank = CodeBank::try_new()?; /// /// // Generate documentation for the src directory - /// let content = code_bank.generate( - /// Path::new("src"), - /// BankStrategy::Default - /// )?; + /// let config = BankConfig::new(Path::new("src"), BankStrategy::Default, vec![]); + /// let content = code_bank.generate(&config)?; /// /// println!("Generated documentation:\n{}", content); /// # Ok(()) /// # } /// ``` - fn generate(&self, root_dir: &Path, strategy: BankStrategy) -> Result; + fn generate(&self, config: &BankConfig) -> Result; +} + +impl BankConfig { + pub fn new( + root_dir: impl Into, + strategy: BankStrategy, + ignore_dirs: Vec, + ) -> Self { + Self { + root_dir: root_dir.into(), + strategy, + ignore_dirs, + } + } } diff --git a/src/mcp.rs b/src/mcp.rs index c6faa1f..6b19bc2 100644 --- a/src/mcp.rs +++ b/src/mcp.rs @@ -1,4 +1,4 @@ -use crate::{Bank, BankStrategy, CodeBank}; +use crate::{Bank, BankConfig, BankStrategy, CodeBank}; use anyhow::Result; use rmcp::{ Error as McpError, ServerHandler, @@ -98,7 +98,8 @@ impl CodeBankMcp { } }; - let content = match codebank.generate(&path, bank_strategy) { + let config = BankConfig::new(path, bank_strategy, vec![]); + let content = match codebank.generate(&config) { Ok(content) => content, Err(e) => { return Err(internal_error(format!( @@ -148,7 +149,8 @@ impl CodeBankMcp { } }; - let content = match codebank.generate(&path, bank_strategy) { + let config = BankConfig::new(path, bank_strategy, vec![]); + let content = match codebank.generate(&config) { Ok(content) => content, Err(e) => { return Err(internal_error(format!( From 26c4d802cb76067bd0d1d4013ed78187617648ef Mon Sep 17 00:00:00 2001 From: Tyr Chen Date: Mon, 28 Apr 2025 22:18:34 -0700 Subject: [PATCH 2/2] feature: use serde for BankConfig --- .gitignore | 1 + Cargo.toml | 8 ++++---- src/lib.rs | 4 +++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 108b93f..043d471 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target Cargo.lock .codebank +.vscode diff --git a/Cargo.toml b/Cargo.toml index b02ca4e..d724107 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "codebank" -version = "0.4.2" +version = "0.4.3" edition = "2024" description = """ A powerful code documentation generator that creates structured markdown documentation from your codebase. @@ -32,7 +32,7 @@ rmcp = { version = "0.1.5", features = [ "transport-io", ], optional = true } schemars = { version = "0.8", optional = true } -serde = { version = "1.0", features = ["derive"], optional = true } +serde = { version = "1.0", features = ["derive"] } thiserror = "2.0" tokio = { version = "1.0", features = [ "macros", @@ -52,12 +52,12 @@ tree-sitter-rust = "0.23" tree-sitter-typescript = "0.23" [dev-dependencies] -tempfile = "3.9" +tempfile = "3.19" [features] default = ["cli", "mcp"] cli = ["clap", "tracing-subscriber"] -mcp = ["rmcp", "schemars", "serde", "tokio", "tokio-util"] +mcp = ["rmcp", "schemars", "tokio", "tokio-util"] [[bin]] name = "cb" diff --git a/src/lib.rs b/src/lib.rs index 44ba615..8c1868e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -127,6 +127,7 @@ mod parser; #[cfg(feature = "mcp")] mod mcp; +use serde::{Deserialize, Serialize}; use std::path::PathBuf; pub use bank::CodeBank; @@ -137,6 +138,7 @@ pub use parser::*; pub use mcp::CodeBankMcp; /// Configuration for generating code bank documentation. +#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)] pub struct BankConfig { /// Root directory to generate code bank for. pub root_dir: PathBuf, @@ -164,7 +166,7 @@ pub struct BankConfig { /// // Use Summary strategy for public interface only /// let strategy = BankStrategy::Summary; /// ``` -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)] pub enum BankStrategy { /// Generate the full code bank for the given directory using default settings. /// This includes all code elements with their complete implementations.