1414//!
1515//! ## Usage
1616//!
17- //! The library can be used programmatically:
17+ //! ### Real-World Example: Analyzing a Rust Monorepo
1818//!
19- //! ```
20- //! use std::collections::HashMap;
21- //! use std::sync::Arc;
19+ //! ```no_run
20+ //! use std::path::PathBuf;
2221//!
23- //! use cargo_ferris_wheel::ConfigBuilder;
2422//! use cargo_ferris_wheel::analyzer::WorkspaceAnalyzer;
2523//! use cargo_ferris_wheel::detector::CycleDetector;
26- //! use cargo_ferris_wheel::graph::{
27- //! DependencyEdge, DependencyGraphBuilder, DependencyType, WorkspaceNode,
28- //! } ;
24+ //! use cargo_ferris_wheel::graph::DependencyGraphBuilder;
25+ //! use cargo_ferris_wheel::reports::{HumanReportGenerator, JsonReportGenerator, ReportGenerator};
26+ //! use miette::IntoDiagnostic ;
2927//!
30- //! # fn main() -> Result<(), Box<dyn std::error::Error> > {
31- //! // Create a simple test scenario
28+ //! # fn main() -> miette:: Result<()> {
29+ //! // Step 1: Discover all workspaces in your monorepo
3230//! let mut analyzer = WorkspaceAnalyzer::new();
31+ //! let repo_root = PathBuf::from("/path/to/your/monorepo");
32+ //! analyzer.discover_workspaces(&[repo_root], None)?;
33+ //!
34+ //! println!("Found {} workspaces", analyzer.workspaces().len());
3335//!
34- //! // For testing, we'll manually add some workspace info
35- //! // In real usage, you'd use analyzer.discover_workspaces()
36- //! let mut graph = petgraph::graph::DiGraph::new();
37- //!
38- //! // Add some test nodes
39- //! let ws1 = graph.add_node(
40- //! WorkspaceNode::builder()
41- //! .with_name("workspace-a".to_string())
42- //! .with_crates(vec!["crate-a".to_string()])
43- //! .build()
44- //! .unwrap(),
36+ //! // Step 2: Build the dependency graph
37+ //! let mut graph_builder = DependencyGraphBuilder::new(
38+ //! false, // include dev dependencies
39+ //! false, // include build dependencies
40+ //! false, // include target-specific dependencies
4541//! );
46- //! let ws2 = graph.add_node(
47- //! WorkspaceNode::builder()
48- //! .with_name("workspace-b".to_string())
49- //! .with_crates(vec!["crate-b".to_string()])
50- //! .build()
51- //! .unwrap(),
42+ //!
43+ //! graph_builder.build_cross_workspace_graph(
44+ //! analyzer.workspaces(),
45+ //! analyzer.crate_to_workspace(),
46+ //! None, // no progress reporter
47+ //! )?;
48+ //!
49+ //! // Step 3: Detect circular dependencies
50+ //! let mut detector = CycleDetector::new();
51+ //! detector.detect_cycles(graph_builder.graph())?;
52+ //!
53+ //! // Step 4: Generate reports
54+ //! if detector.has_cycles() {
55+ //! println!(
56+ //! "⚠️ Found {} circular dependencies!",
57+ //! detector.cycle_count()
58+ //! );
59+ //!
60+ //! // Human-readable report for console output
61+ //! let human_report = HumanReportGenerator::new(Some(5)); // show max 5 cycles
62+ //! println!("{}", human_report.generate_report(&detector)?);
63+ //!
64+ //! // JSON report for programmatic processing
65+ //! let json_report = JsonReportGenerator::new();
66+ //! let json_output = json_report.generate_report(&detector)?;
67+ //! std::fs::write("cycles.json", json_output).into_diagnostic()?;
68+ //! } else {
69+ //! println!("✅ No circular dependencies found!");
70+ //! }
71+ //! # Ok(())
72+ //! # }
73+ //! ```
74+ //!
75+ //! ### Example: Visualizing the Dependency Graph
76+ //!
77+ //! ```no_run
78+ //! use std::io::Write;
79+ //!
80+ //! use cargo_ferris_wheel::graph::GraphRenderer;
81+ //! use miette::IntoDiagnostic;
82+ //! # use std::path::PathBuf;
83+ //! # use cargo_ferris_wheel::{
84+ //! # analyzer::WorkspaceAnalyzer,
85+ //! # detector::CycleDetector,
86+ //! # graph::DependencyGraphBuilder,
87+ //! # };
88+ //!
89+ //! # fn main() -> miette::Result<()> {
90+ //! # let mut analyzer = WorkspaceAnalyzer::new();
91+ //! # analyzer.discover_workspaces(&[PathBuf::from(".")], None)?;
92+ //! # let mut graph_builder = DependencyGraphBuilder::new(false, false, false);
93+ //! # graph_builder.build_cross_workspace_graph(
94+ //! # analyzer.workspaces(),
95+ //! # analyzer.crate_to_workspace(),
96+ //! # None,
97+ //! # )?;
98+ //! # let mut detector = CycleDetector::new();
99+ //! # detector.detect_cycles(graph_builder.graph())?;
100+ //! // Create a visual representation of your dependency graph
101+ //! let renderer = GraphRenderer::new(
102+ //! true, // highlight cycles
103+ //! false, // don't show individual crate details
52104//! );
53105//!
54- //! // Add a dependency
55- //! graph.add_edge(
56- //! ws1,
57- //! ws2,
58- //! DependencyEdge::builder()
59- //! .with_from_crate("crate-a")
60- //! .with_to_crate("crate-b")
61- //! .with_dependency_type(DependencyType::Normal)
62- //! .build()
63- //! .unwrap(),
106+ //! // Generate a Mermaid diagram (great for documentation)
107+ //! let mut mermaid_output = Vec::new();
108+ //! renderer.render_mermaid(
109+ //! graph_builder.graph(),
110+ //! detector.cycles(),
111+ //! &mut mermaid_output,
112+ //! )?;
113+ //!
114+ //! std::fs::write("dependencies.mmd", mermaid_output).into_diagnostic()?;
115+ //!
116+ //! // Or generate a DOT file for Graphviz
117+ //! let mut dot_output = Vec::new();
118+ //! renderer.render_dot(graph_builder.graph(), detector.cycles(), &mut dot_output)?;
119+ //!
120+ //! std::fs::write("dependencies.dot", dot_output).into_diagnostic()?;
121+ //! # Ok(())
122+ //! # }
123+ //! ```
124+ //!
125+ //! ### Example: Filtering Dependencies
126+ //!
127+ //! ```no_run
128+ //! # use std::path::PathBuf;
129+ //! # use cargo_ferris_wheel::{
130+ //! # analyzer::WorkspaceAnalyzer,
131+ //! # detector::CycleDetector,
132+ //! # graph::DependencyGraphBuilder,
133+ //! # };
134+ //! # fn main() -> miette::Result<()> {
135+ //! # let mut analyzer = WorkspaceAnalyzer::new();
136+ //! # analyzer.discover_workspaces(&[PathBuf::from(".")], None)?;
137+ //! // Check only production dependencies (exclude dev and build deps)
138+ //! let mut graph_builder = DependencyGraphBuilder::new(
139+ //! true, // exclude dev dependencies
140+ //! true, // exclude build dependencies
141+ //! false, // include target-specific dependencies
64142//! );
65143//!
66- //! // Detect cycles
144+ //! graph_builder.build_cross_workspace_graph(
145+ //! analyzer.workspaces(),
146+ //! analyzer.crate_to_workspace(),
147+ //! None,
148+ //! )?;
149+ //!
67150//! let mut detector = CycleDetector::new();
68- //! detector.detect_cycles(& graph)?;
151+ //! detector.detect_cycles(graph_builder. graph() )?;
69152//!
70- //! assert!(!detector.has_cycles());
153+ //! println!("Production dependency cycles: {}", detector.cycle_count());
154+ //! # Ok(())
155+ //! # }
156+ //! ```
157+ //!
158+ //! ### Example: Analyzing Specific Workspaces
159+ //!
160+ //! ```no_run
161+ //! # use std::path::PathBuf;
162+ //! # use cargo_ferris_wheel::{
163+ //! # analyzer::WorkspaceAnalyzer,
164+ //! # detector::{CycleDetector, WorkspaceCycle},
165+ //! # graph::DependencyGraphBuilder,
166+ //! # };
167+ //! # fn main() -> miette::Result<()> {
168+ //! # let mut analyzer = WorkspaceAnalyzer::new();
169+ //! # analyzer.discover_workspaces(&[PathBuf::from(".")], None)?;
170+ //! # let mut graph_builder = DependencyGraphBuilder::new(false, false, false);
171+ //! # graph_builder.build_cross_workspace_graph(
172+ //! # analyzer.workspaces(),
173+ //! # analyzer.crate_to_workspace(),
174+ //! # None,
175+ //! # )?;
176+ //! # let mut detector = CycleDetector::new();
177+ //! # detector.detect_cycles(graph_builder.graph())?;
178+ //! // Find cycles involving a specific workspace
179+ //! let target_workspace = "backend-core";
180+ //!
181+ //! let cycles_with_target: Vec<&WorkspaceCycle> = detector
182+ //! .cycles()
183+ //! .iter()
184+ //! .filter(|cycle| {
185+ //! cycle
186+ //! .workspace_names()
187+ //! .contains(&target_workspace.to_string())
188+ //! })
189+ //! .collect();
190+ //!
191+ //! println!(
192+ //! "Found {} cycles involving {}",
193+ //! cycles_with_target.len(),
194+ //! target_workspace
195+ //! );
196+ //!
197+ //! for (i, cycle) in cycles_with_target.iter().enumerate() {
198+ //! println!("\nCycle #{}", i + 1);
199+ //! println!("Workspaces: {}", cycle.workspace_names().join(" → "));
200+ //!
201+ //! // Show specific crate-level dependencies
202+ //! for edge in cycle.edges() {
203+ //! println!(
204+ //! " {} → {} ({:?} dependency)",
205+ //! edge.from_crate(),
206+ //! edge.to_crate(),
207+ //! edge.dependency_type()
208+ //! );
209+ //! }
210+ //! }
71211//! # Ok(())
72212//! # }
73213//! ```
74214
75215// Private modules
76- mod common;
77216mod constants;
78217mod dependency_filter;
79218mod progress;
@@ -85,6 +224,7 @@ mod workspace_discovery;
85224pub mod analyzer;
86225pub mod cli;
87226pub mod commands;
227+ pub mod common;
88228pub mod config;
89229pub mod core;
90230pub mod detector;
@@ -93,12 +233,6 @@ pub mod executors;
93233pub mod graph;
94234pub mod reports;
95235
96- // Re-export commonly used types
97- pub use crate :: common:: ConfigBuilder ;
98- pub use crate :: detector:: { CycleEdge , WorkspaceCycle } ;
99- pub use crate :: error:: FerrisWheelError ;
100- pub use crate :: graph:: { DependencyEdge , DependencyType , WorkspaceNode } ;
101-
102236// Main entry point for the library
103237pub fn run ( ) -> miette:: Result < ( ) > {
104238 use clap:: Parser ;
0 commit comments