fob_graph/framework_rules/trait_def.rs
1//! Framework rule trait definition for marking framework-convention exports.
2
3use crate::ModuleGraph;
4use crate::Result;
5use async_trait::async_trait;
6
7/// Framework-specific rule for marking exports as used by framework conventions.
8///
9/// Framework rules identify exports that appear unused but are actually consumed
10/// by framework magic (React hooks, Next.js data fetching, Vue composables, etc.).
11///
12/// # Example
13///
14/// ```rust,ignore
15/// use fob_graph::graph::{ModuleGraph, FrameworkRule};
16/// use async_trait::async_trait;
17///
18/// struct MyFrameworkRule;
19///
20/// #[async_trait]
21/// impl FrameworkRule for MyFrameworkRule {
22/// async fn apply(&self, graph: &ModuleGraph) -> Result<()> {
23/// let modules = graph.modules().await?;
24///
25/// for module in modules {
26/// let mut updated = module.clone();
27/// let mut changed = false;
28///
29/// for export in updated.exports.iter_mut() {
30/// if export.name.starts_with("action_") {
31/// export.mark_framework_used();
32/// changed = true;
33/// }
34/// }
35///
36/// if changed {
37/// graph.add_module(updated).await?;
38/// }
39/// }
40///
41/// Ok(())
42/// }
43///
44/// fn name(&self) -> &'static str {
45/// "MyFrameworkRule"
46/// }
47///
48/// fn description(&self) -> &'static str {
49/// "Marks exports prefixed with 'action_' as framework-used"
50/// }
51/// }
52/// ```
53#[async_trait]
54pub trait FrameworkRule: Send + Sync {
55 /// Apply the rule to the module graph, marking exports as framework-used.
56 ///
57 /// This method receives immutable access to the graph and should:
58 /// 1. Load modules via `graph.modules().await?`
59 /// 2. Clone and modify modules that need changes
60 /// 3. Save modified modules back via `graph.add_module(module).await?`
61 ///
62 /// The async nature allows the database backend to handle concurrent updates safely.
63 async fn apply(&self, graph: &ModuleGraph) -> Result<()>;
64
65 /// Human-readable name for the rule (used in diagnostics).
66 fn name(&self) -> &'static str;
67
68 /// Description of what patterns this rule matches.
69 fn description(&self) -> &'static str;
70
71 /// Whether this rule should be enabled by default.
72 ///
73 /// Built-in rules return `true`, custom rules typically return `false`.
74 fn is_default(&self) -> bool {
75 false
76 }
77
78 /// Clone the rule into a boxed trait object.
79 ///
80 /// Required for storing rules in collections.
81 fn clone_box(&self) -> Box<dyn FrameworkRule>;
82}
83
84impl Clone for Box<dyn FrameworkRule> {
85 fn clone(&self) -> Self {
86 self.clone_box()
87 }
88}