Skip to content
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
/target
Cargo.lock
.codebank
.vscode
8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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",
Expand All @@ -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"
Expand Down
8 changes: 5 additions & 3 deletions src/bank.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -118,7 +118,9 @@ impl CodeBank {
}

impl Bank for CodeBank {
fn generate(&self, root_dir: &Path, strategy: BankStrategy) -> Result<String> {
fn generate(&self, config: &BankConfig) -> Result<String> {
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()));
Expand Down Expand Up @@ -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),
Expand Down
6 changes: 4 additions & 2 deletions src/bin/codebank.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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 {
Expand Down
115 changes: 66 additions & 49 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,16 @@
//! ## Quick Start
//!
//! ```rust
//! use codebank::{Bank, BankStrategy, CodeBank, Result};
//! use codebank::{Bank, BankConfig, BankStrategy, CodeBank, Result};
//! use std::path::Path;
//!
//! fn main() -> Result<()> {
//! // Create a new code bank generator
//! 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(())
Expand All @@ -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(())
//! # }
//! ```
Expand All @@ -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(())
//! # }
//! ```
Expand All @@ -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(())
//! # }
//! ```
Expand All @@ -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<String> {
//! fn generate(&self, config: &BankConfig) -> Result<String> {
//! // Your implementation here
//! Ok("# Code Bank\n\nCustom implementation".to_string())
//! }
Expand All @@ -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);
Expand All @@ -127,7 +127,8 @@ mod parser;
#[cfg(feature = "mcp")]
mod mcp;

use std::path::Path;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

pub use bank::CodeBank;
pub use error::{Error, Result};
Expand All @@ -136,6 +137,17 @@ pub use parser::*;
#[cfg(feature = "mcp")]
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,
/// Strategy for generating code bank documentation.
pub strategy: BankStrategy,
/// Directories to ignore.
pub ignore_dirs: Vec<String>,
}

/// Strategy for generating code bank documentation.
///
/// This enum controls how the code bank generator processes and formats the code.
Expand All @@ -154,25 +166,23 @@ pub use mcp::CodeBankMcp;
/// // 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.
///
/// # Examples
///
/// ```
/// use codebank::{Bank, BankStrategy, CodeBank};
/// use codebank::{Bank, BankConfig, BankStrategy, CodeBank};
/// use std::path::Path;
///
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// 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(())
Expand All @@ -187,17 +197,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::<Vec<_>>();
Expand All @@ -215,17 +223,15 @@ pub enum BankStrategy {
/// # Examples
///
/// ```
/// use codebank::{Bank, BankStrategy, CodeBank};
/// use codebank::{Bank, BankConfig, BankStrategy, CodeBank};
/// use std::path::Path;
///
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// 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("{ ... }"));
Expand All @@ -244,18 +250,16 @@ pub enum BankStrategy {
/// # Examples
///
/// ```
/// use codebank::{Bank, BankStrategy, CodeBank};
/// use codebank::{Bank, BankConfig, BankStrategy, CodeBank};
/// use std::path::Path;
///
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// // Create a new code bank generator
/// 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"));
Expand All @@ -268,21 +272,22 @@ 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<String> {
/// fn generate(&self, config: &BankConfig) -> Result<String> {
/// // Your implementation here
/// Ok("# Code Bank\n\nCustom implementation".to_string())
/// }
/// }
///
/// # 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(())
/// # }
Expand Down Expand Up @@ -311,21 +316,33 @@ pub trait Bank {
/// # Examples
///
/// ```
/// use codebank::{Bank, BankStrategy, CodeBank};
/// use codebank::{Bank, BankConfig, BankStrategy, CodeBank};
/// use std::path::Path;
///
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// 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<String>;
fn generate(&self, config: &BankConfig) -> Result<String>;
}

impl BankConfig {
pub fn new(
root_dir: impl Into<PathBuf>,
strategy: BankStrategy,
ignore_dirs: Vec<String>,
) -> Self {
Self {
root_dir: root_dir.into(),
strategy,
ignore_dirs,
}
}
}
Loading