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: 1 addition & 1 deletion src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ pub trait FromCommand: Sized {
fn from_command(command: crate::cli::Commands) -> Result<Self, crate::error::FerrisWheelError>;
}

/// Macro to implement TryFrom<Commands> using FromCommand trait
/// Macro to implement `TryFrom<Commands>` using [`FromCommand`] trait
#[macro_export]
macro_rules! impl_try_from_command {
($config:ty) => {
Expand Down
2 changes: 1 addition & 1 deletion src/detector/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
//! ## Example
//!
//! ```
//! use cargo_ferris_wheel::ConfigBuilder;
//! use cargo_ferris_wheel::common::ConfigBuilder;
//! use cargo_ferris_wheel::detector::CycleDetector;
//! use cargo_ferris_wheel::graph::{DependencyEdge, DependencyType, WorkspaceNode};
//! use petgraph::graph::DiGraph;
Expand Down
2 changes: 1 addition & 1 deletion src/graph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
//! ## Example
//!
//! ```
//! use cargo_ferris_wheel::ConfigBuilder;
//! use cargo_ferris_wheel::common::ConfigBuilder;
//! use cargo_ferris_wheel::graph::{DependencyEdge, DependencyType, GraphRenderer, WorkspaceNode};
//! use petgraph::graph::DiGraph;
//!
Expand Down
228 changes: 181 additions & 47 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,66 +14,205 @@
//!
//! ## Usage
//!
//! The library can be used programmatically:
//! ### Real-World Example: Analyzing a Rust Monorepo
//!
//! ```
//! use std::collections::HashMap;
//! use std::sync::Arc;
//! ```no_run
//! use std::path::PathBuf;
//!
//! use cargo_ferris_wheel::ConfigBuilder;
//! use cargo_ferris_wheel::analyzer::WorkspaceAnalyzer;
//! use cargo_ferris_wheel::detector::CycleDetector;
//! use cargo_ferris_wheel::graph::{
//! DependencyEdge, DependencyGraphBuilder, DependencyType, WorkspaceNode,
//! };
//! use cargo_ferris_wheel::graph::DependencyGraphBuilder;
//! use cargo_ferris_wheel::reports::{HumanReportGenerator, JsonReportGenerator, ReportGenerator};
//! use miette::IntoDiagnostic;
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Create a simple test scenario
//! # fn main() -> miette::Result<()> {
//! // Step 1: Discover all workspaces in your monorepo
//! let mut analyzer = WorkspaceAnalyzer::new();
//! let repo_root = PathBuf::from("/path/to/your/monorepo");
//! analyzer.discover_workspaces(&[repo_root], None)?;
//!
//! println!("Found {} workspaces", analyzer.workspaces().len());
//!
//! // For testing, we'll manually add some workspace info
//! // In real usage, you'd use analyzer.discover_workspaces()
//! let mut graph = petgraph::graph::DiGraph::new();
//!
//! // Add some test nodes
//! let ws1 = graph.add_node(
//! WorkspaceNode::builder()
//! .with_name("workspace-a".to_string())
//! .with_crates(vec!["crate-a".to_string()])
//! .build()
//! .unwrap(),
//! // Step 2: Build the dependency graph
//! let mut graph_builder = DependencyGraphBuilder::new(
//! false, // include dev dependencies
//! false, // include build dependencies
//! false, // include target-specific dependencies
//! );
//! let ws2 = graph.add_node(
//! WorkspaceNode::builder()
//! .with_name("workspace-b".to_string())
//! .with_crates(vec!["crate-b".to_string()])
//! .build()
//! .unwrap(),
//!
//! graph_builder.build_cross_workspace_graph(
//! analyzer.workspaces(),
//! analyzer.crate_to_workspace(),
//! None, // no progress reporter
//! )?;
//!
//! // Step 3: Detect circular dependencies
//! let mut detector = CycleDetector::new();
//! detector.detect_cycles(graph_builder.graph())?;
//!
//! // Step 4: Generate reports
//! if detector.has_cycles() {
//! println!(
//! "⚠️ Found {} circular dependencies!",
//! detector.cycle_count()
//! );
//!
//! // Human-readable report for console output
//! let human_report = HumanReportGenerator::new(Some(5)); // show max 5 cycles
//! println!("{}", human_report.generate_report(&detector)?);
//!
//! // JSON report for programmatic processing
//! let json_report = JsonReportGenerator::new();
//! let json_output = json_report.generate_report(&detector)?;
//! std::fs::write("cycles.json", json_output).into_diagnostic()?;
//! } else {
//! println!("✅ No circular dependencies found!");
//! }
//! # Ok(())
//! # }
//! ```
//!
//! ### Example: Visualizing the Dependency Graph
//!
//! ```no_run
//! use std::io::Write;
//!
//! use cargo_ferris_wheel::graph::GraphRenderer;
//! use miette::IntoDiagnostic;
//! # use std::path::PathBuf;
//! # use cargo_ferris_wheel::{
//! # analyzer::WorkspaceAnalyzer,
//! # detector::CycleDetector,
//! # graph::DependencyGraphBuilder,
//! # };
//!
//! # fn main() -> miette::Result<()> {
//! # let mut analyzer = WorkspaceAnalyzer::new();
//! # analyzer.discover_workspaces(&[PathBuf::from(".")], None)?;
//! # let mut graph_builder = DependencyGraphBuilder::new(false, false, false);
//! # graph_builder.build_cross_workspace_graph(
//! # analyzer.workspaces(),
//! # analyzer.crate_to_workspace(),
//! # None,
//! # )?;
//! # let mut detector = CycleDetector::new();
//! # detector.detect_cycles(graph_builder.graph())?;
//! // Create a visual representation of your dependency graph
//! let renderer = GraphRenderer::new(
//! true, // highlight cycles
//! false, // don't show individual crate details
//! );
//!
//! // Add a dependency
//! graph.add_edge(
//! ws1,
//! ws2,
//! DependencyEdge::builder()
//! .with_from_crate("crate-a")
//! .with_to_crate("crate-b")
//! .with_dependency_type(DependencyType::Normal)
//! .build()
//! .unwrap(),
//! // Generate a Mermaid diagram (great for documentation)
//! let mut mermaid_output = Vec::new();
//! renderer.render_mermaid(
//! graph_builder.graph(),
//! detector.cycles(),
//! &mut mermaid_output,
//! )?;
//!
//! std::fs::write("dependencies.mmd", mermaid_output).into_diagnostic()?;
//!
//! // Or generate a DOT file for Graphviz
//! let mut dot_output = Vec::new();
//! renderer.render_dot(graph_builder.graph(), detector.cycles(), &mut dot_output)?;
//!
//! std::fs::write("dependencies.dot", dot_output).into_diagnostic()?;
//! # Ok(())
//! # }
//! ```
//!
//! ### Example: Filtering Dependencies
//!
//! ```no_run
//! # use std::path::PathBuf;
//! # use cargo_ferris_wheel::{
//! # analyzer::WorkspaceAnalyzer,
//! # detector::CycleDetector,
//! # graph::DependencyGraphBuilder,
//! # };
//! # fn main() -> miette::Result<()> {
//! # let mut analyzer = WorkspaceAnalyzer::new();
//! # analyzer.discover_workspaces(&[PathBuf::from(".")], None)?;
//! // Check only production dependencies (exclude dev and build deps)
//! let mut graph_builder = DependencyGraphBuilder::new(
//! true, // exclude dev dependencies
//! true, // exclude build dependencies
//! false, // include target-specific dependencies
//! );
//!
//! // Detect cycles
//! graph_builder.build_cross_workspace_graph(
//! analyzer.workspaces(),
//! analyzer.crate_to_workspace(),
//! None,
//! )?;
//!
//! let mut detector = CycleDetector::new();
//! detector.detect_cycles(&graph)?;
//! detector.detect_cycles(graph_builder.graph())?;
//!
//! assert!(!detector.has_cycles());
//! println!("Production dependency cycles: {}", detector.cycle_count());
//! # Ok(())
//! # }
//! ```
//!
//! ### Example: Analyzing Specific Workspaces
//!
//! ```no_run
//! # use std::path::PathBuf;
//! # use cargo_ferris_wheel::{
//! # analyzer::WorkspaceAnalyzer,
//! # detector::{CycleDetector, WorkspaceCycle},
//! # graph::DependencyGraphBuilder,
//! # };
//! # fn main() -> miette::Result<()> {
//! # let mut analyzer = WorkspaceAnalyzer::new();
//! # analyzer.discover_workspaces(&[PathBuf::from(".")], None)?;
//! # let mut graph_builder = DependencyGraphBuilder::new(false, false, false);
//! # graph_builder.build_cross_workspace_graph(
//! # analyzer.workspaces(),
//! # analyzer.crate_to_workspace(),
//! # None,
//! # )?;
//! # let mut detector = CycleDetector::new();
//! # detector.detect_cycles(graph_builder.graph())?;
//! // Find cycles involving a specific workspace
//! let target_workspace = "backend-core";
//!
//! let cycles_with_target: Vec<&WorkspaceCycle> = detector
//! .cycles()
//! .iter()
//! .filter(|cycle| {
//! cycle
//! .workspace_names()
//! .contains(&target_workspace.to_string())
//! })
//! .collect();
//!
//! println!(
//! "Found {} cycles involving {}",
//! cycles_with_target.len(),
//! target_workspace
//! );
//!
//! for (i, cycle) in cycles_with_target.iter().enumerate() {
//! println!("\nCycle #{}", i + 1);
//! println!("Workspaces: {}", cycle.workspace_names().join(" → "));
//!
//! // Show specific crate-level dependencies
//! for edge in cycle.edges() {
//! println!(
//! " {} → {} ({:?} dependency)",
//! edge.from_crate(),
//! edge.to_crate(),
//! edge.dependency_type()
//! );
//! }
//! }
//! # Ok(())
//! # }
//! ```

// Private modules
mod common;
mod constants;
mod dependency_filter;
mod progress;
Expand All @@ -85,6 +224,7 @@ mod workspace_discovery;
pub mod analyzer;
pub mod cli;
pub mod commands;
pub mod common;
pub mod config;
pub mod core;
pub mod detector;
Expand All @@ -93,12 +233,6 @@ pub mod executors;
pub mod graph;
pub mod reports;

// Re-export commonly used types
pub use crate::common::ConfigBuilder;
pub use crate::detector::{CycleEdge, WorkspaceCycle};
pub use crate::error::FerrisWheelError;
pub use crate::graph::{DependencyEdge, DependencyType, WorkspaceNode};

// Main entry point for the library
pub fn run() -> miette::Result<()> {
use clap::Parser;
Expand Down
2 changes: 1 addition & 1 deletion tests/graph_renderer_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use std::io::Cursor;

use cargo_ferris_wheel::ConfigBuilder;
use cargo_ferris_wheel::common::ConfigBuilder;
use cargo_ferris_wheel::detector::WorkspaceCycle;
use cargo_ferris_wheel::graph::{DependencyEdge, DependencyType, GraphRenderer, WorkspaceNode};
use petgraph::graph::DiGraph;
Expand Down
2 changes: 1 addition & 1 deletion tests/readme_example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use std::io::Cursor;

use cargo_ferris_wheel::ConfigBuilder;
use cargo_ferris_wheel::common::ConfigBuilder;
use cargo_ferris_wheel::detector::{CycleDetector, WorkspaceCycle};
use cargo_ferris_wheel::graph::{DependencyEdge, DependencyType, GraphRenderer, WorkspaceNode};
use petgraph::graph::DiGraph;
Expand Down