driven/context/
provider.rs1use super::{ProjectContext, ProjectScanner};
4use crate::{Result, parser::UnifiedRule};
5use std::path::Path;
6
7#[derive(Debug, Default)]
9pub struct ContextProvider {
10 context: Option<ProjectContext>,
11}
12
13impl ContextProvider {
14 pub fn new() -> Self {
16 Self { context: None }
17 }
18
19 pub fn with_context(context: ProjectContext) -> Self {
21 Self {
22 context: Some(context),
23 }
24 }
25
26 pub fn set_context(&mut self, context: ProjectContext) {
28 self.context = Some(context);
29 }
30
31 pub fn get_context(&self) -> Option<&ProjectContext> {
33 self.context.as_ref()
34 }
35
36 pub fn generate(&self, project_root: &Path) -> Result<String> {
38 let scanner = ProjectScanner::new();
39 let result = scanner.scan(project_root)?;
40
41 let mut output = String::new();
42 output.push_str("# Project Context\n\n");
43
44 output.push_str("## Languages\n");
45 for lang in &result.languages {
46 output.push_str(&format!("- {}\n", lang));
47 }
48
49 output.push_str("\n## Frameworks\n");
50 for framework in &result.frameworks {
51 output.push_str(&format!("- {}\n", framework));
52 }
53
54 if !result.key_directories.is_empty() {
55 output.push_str("\n## Key Directories\n");
56 for dir in &result.key_directories {
57 output.push_str(&format!("- {}\n", dir));
58 }
59 }
60
61 Ok(output)
62 }
63
64 pub fn generate_rules(&self) -> Result<Vec<UnifiedRule>> {
66 let Some(context) = &self.context else {
67 return Ok(Vec::new());
68 };
69
70 let mut rules = Vec::new();
71
72 let mut focus = Vec::new();
74
75 if let Some(project_type) = &context.project_type {
76 focus.push(format!("This is a {} project", project_type));
77 }
78
79 if !context.languages.is_empty() {
80 focus.push(format!("Languages: {}", context.languages.join(", ")));
81 }
82
83 if !context.frameworks.is_empty() {
84 focus.push(format!("Frameworks: {}", context.frameworks.join(", ")));
85 }
86
87 if let Some(style) = &context.naming_conventions.functions {
89 focus.push(format!("Use {} for functions", style));
90 }
91
92 if let Some(style) = &context.naming_conventions.types {
93 focus.push(format!("Use {} for types", style));
94 }
95
96 focus.extend(context.patterns.clone());
98
99 if !focus.is_empty() {
100 rules.push(UnifiedRule::Context {
101 includes: context.directories.clone(),
102 excludes: Vec::new(),
103 focus,
104 });
105 }
106
107 Ok(rules)
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 fn test_provider_new() {
117 let provider = ContextProvider::new();
118 assert!(provider.get_context().is_none());
119 }
120
121 #[test]
122 fn test_provider_with_context() {
123 let context = ProjectContext {
124 project_type: Some("Rust Project".to_string()),
125 ..Default::default()
126 };
127
128 let provider = ContextProvider::with_context(context);
129 assert!(provider.get_context().is_some());
130 }
131
132 #[test]
133 fn test_generate_rules_empty() {
134 let provider = ContextProvider::new();
135 let rules = provider.generate_rules().unwrap();
136 assert!(rules.is_empty());
137 }
138
139 #[test]
140 fn test_generate_rules_with_context() {
141 let context = ProjectContext {
142 project_type: Some("Rust Project".to_string()),
143 languages: vec!["Rust".to_string()],
144 ..Default::default()
145 };
146
147 let provider = ContextProvider::with_context(context);
148 let rules = provider.generate_rules().unwrap();
149 assert!(!rules.is_empty());
150 }
151}