fob_graph/framework_rules/mod.rs
1//! Framework-aware dead code analysis.
2//!
3//! This module provides a generic trait for marking exports as framework-used,
4//! allowing external tools to implement framework-specific detection logic.
5//!
6//! # Overview
7//!
8//! Framework rules solve the problem of false-positive "unused export" warnings
9//! for exports that frameworks consume through naming conventions rather than
10//! explicit imports. Joy provides the infrastructure (the `FrameworkRule` trait),
11//! while external tools (like Danny) provide the framework-specific knowledge.
12//!
13//! # Custom Rules
14//!
15//! ```rust,ignore
16//! use fob_graph::graph::{FrameworkRule, ModuleGraph};
17//! use async_trait::async_trait;
18//!
19//! struct MyRule;
20//!
21//! #[async_trait]
22//! impl FrameworkRule for MyRule {
23//! async fn apply(&self, graph: &ModuleGraph) -> Result<()> {
24//! let modules = graph.modules().await?;
25//!
26//! for module in modules {
27//! let mut updated = module.clone();
28//! let mut changed = false;
29//!
30//! for export in updated.exports.iter_mut() {
31//! if export.name.starts_with("server_") {
32//! export.mark_framework_used();
33//! changed = true;
34//! }
35//! }
36//!
37//! if changed {
38//! graph.add_module(updated).await?;
39//! }
40//! }
41//!
42//! Ok(())
43//! }
44//!
45//! fn name(&self) -> &'static str { "MyRule" }
46//! fn description(&self) -> &'static str { "Server actions" }
47//! fn clone_box(&self) -> Box<dyn FrameworkRule> { Box::new(MyRule) }
48//! }
49//!
50//! // Apply custom rules via AnalyzeOptions
51//! use fob_graph::analysis::{analyze_with_options, AnalyzeOptions};
52//!
53//! let options = AnalyzeOptions {
54//! framework_rules: vec![Box::new(MyRule)],
55//! };
56//! let result = analyze_with_options(["src/index.tsx"], options).await?;
57//! ```
58
59mod trait_def;
60
61pub use trait_def::FrameworkRule;