codeprism_analysis/semantic/
concepts.rs

1//! Code concept mapping and understanding
2//!
3//! Provides mapping from high-level concepts to code elements
4//! and understanding of architectural patterns.
5
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9/// A high-level code concept
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct CodeConcept {
12    /// Concept name
13    pub name: String,
14    /// Concept description
15    pub description: String,
16    /// Associated keywords
17    pub keywords: Vec<String>,
18    /// Concept category
19    pub category: ConceptCategory,
20}
21
22/// Categories of code concepts
23#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
24pub enum ConceptCategory {
25    /// Architectural patterns
26    Architecture,
27    /// Design patterns
28    DesignPattern,
29    /// Data handling
30    DataProcessing,
31    /// Security-related
32    Security,
33    /// User interface
34    UserInterface,
35    /// System integration
36    Integration,
37    /// Performance-related
38    Performance,
39}
40
41/// Relationship between concepts
42#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct ConceptRelationship {
44    /// Source concept
45    pub from: String,
46    /// Target concept
47    pub to: String,
48    /// Relationship type
49    pub relationship_type: RelationshipType,
50    /// Relationship strength (0.0 to 1.0)
51    pub strength: f64,
52}
53
54/// Types of concept relationships
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub enum RelationshipType {
57    /// One concept is part of another
58    PartOf,
59    /// Concepts are similar
60    Similar,
61    /// One concept depends on another
62    DependsOn,
63    /// Concepts are commonly used together
64    ComplementaryTo,
65    /// One concept is an implementation of another
66    ImplementationOf,
67}
68
69/// Maps text and code to high-level concepts
70pub struct ConceptMapper {
71    /// Known concepts
72    concepts: HashMap<String, CodeConcept>,
73    /// Concept relationships
74    relationships: Vec<ConceptRelationship>,
75}
76
77impl ConceptMapper {
78    /// Create a new concept mapper
79    pub fn new() -> Self {
80        let mut concepts = HashMap::new();
81
82        // Authentication concept
83        concepts.insert(
84            "authentication".to_string(),
85            CodeConcept {
86                name: "authentication".to_string(),
87                description: "User identity verification and access control".to_string(),
88                keywords: vec![
89                    "login".to_string(),
90                    "auth".to_string(),
91                    "authenticate".to_string(),
92                    "verify".to_string(),
93                    "credential".to_string(),
94                    "token".to_string(),
95                    "session".to_string(),
96                    "password".to_string(),
97                    "oauth".to_string(),
98                    "jwt".to_string(),
99                ],
100                category: ConceptCategory::Security,
101            },
102        );
103
104        // Database concept
105        concepts.insert(
106            "database".to_string(),
107            CodeConcept {
108                name: "database".to_string(),
109                description: "Data storage and retrieval operations".to_string(),
110                keywords: vec![
111                    "query".to_string(),
112                    "sql".to_string(),
113                    "database".to_string(),
114                    "db".to_string(),
115                    "connection".to_string(),
116                    "transaction".to_string(),
117                    "repository".to_string(),
118                    "model".to_string(),
119                    "entity".to_string(),
120                    "orm".to_string(),
121                ],
122                category: ConceptCategory::DataProcessing,
123            },
124        );
125
126        // API concept
127        concepts.insert(
128            "api".to_string(),
129            CodeConcept {
130                name: "api".to_string(),
131                description: "Application programming interface and web services".to_string(),
132                keywords: vec![
133                    "endpoint".to_string(),
134                    "route".to_string(),
135                    "controller".to_string(),
136                    "handler".to_string(),
137                    "request".to_string(),
138                    "response".to_string(),
139                    "middleware".to_string(),
140                    "validation".to_string(),
141                    "rest".to_string(),
142                    "graphql".to_string(),
143                ],
144                category: ConceptCategory::Integration,
145            },
146        );
147
148        // Message processing concept
149        concepts.insert(
150            "message_processing".to_string(),
151            CodeConcept {
152                name: "message_processing".to_string(),
153                description: "Event-driven messaging and queue processing".to_string(),
154                keywords: vec![
155                    "message".to_string(),
156                    "queue".to_string(),
157                    "event".to_string(),
158                    "handler".to_string(),
159                    "processor".to_string(),
160                    "publish".to_string(),
161                    "subscribe".to_string(),
162                    "broker".to_string(),
163                    "dispatch".to_string(),
164                    "stream".to_string(),
165                ],
166                category: ConceptCategory::Architecture,
167            },
168        );
169
170        // Error handling concept
171        concepts.insert(
172            "error_handling".to_string(),
173            CodeConcept {
174                name: "error_handling".to_string(),
175                description: "Exception management and error recovery".to_string(),
176                keywords: vec![
177                    "error".to_string(),
178                    "exception".to_string(),
179                    "try".to_string(),
180                    "catch".to_string(),
181                    "handle".to_string(),
182                    "raise".to_string(),
183                    "throw".to_string(),
184                    "fail".to_string(),
185                    "recover".to_string(),
186                    "retry".to_string(),
187                ],
188                category: ConceptCategory::Architecture,
189            },
190        );
191
192        let relationships = vec![
193            ConceptRelationship {
194                from: "authentication".to_string(),
195                to: "api".to_string(),
196                relationship_type: RelationshipType::ComplementaryTo,
197                strength: 0.8,
198            },
199            ConceptRelationship {
200                from: "database".to_string(),
201                to: "api".to_string(),
202                relationship_type: RelationshipType::ComplementaryTo,
203                strength: 0.7,
204            },
205            ConceptRelationship {
206                from: "error_handling".to_string(),
207                to: "api".to_string(),
208                relationship_type: RelationshipType::PartOf,
209                strength: 0.6,
210            },
211        ];
212
213        Self {
214            concepts,
215            relationships,
216        }
217    }
218
219    /// Map text to relevant concepts
220    pub fn map_text_to_concepts(&self, text: &str) -> Vec<String> {
221        let mut matched_concepts = Vec::new();
222        let text_lower = text.to_lowercase();
223
224        for (concept_name, concept) in &self.concepts {
225            let mut score = 0.0;
226
227            // Check direct name match
228            if text_lower.contains(concept_name) {
229                score += 1.0;
230            }
231
232            // Check keyword matches
233            for keyword in &concept.keywords {
234                if text_lower.contains(keyword) {
235                    score += 0.5;
236                }
237            }
238
239            // If we have a good match, include the concept
240            if score >= 0.5 {
241                matched_concepts.push(concept_name.clone());
242            }
243        }
244
245        matched_concepts
246    }
247
248    /// Get concept by name
249    pub fn get_concept(&self, name: &str) -> Option<&CodeConcept> {
250        self.concepts.get(name)
251    }
252
253    /// Get all concepts in a category
254    pub fn get_concepts_by_category(&self, category: &ConceptCategory) -> Vec<&CodeConcept> {
255        self.concepts
256            .values()
257            .filter(|concept| &concept.category == category)
258            .collect()
259    }
260
261    /// Find related concepts
262    pub fn find_related_concepts(&self, concept_name: &str) -> Vec<String> {
263        let mut related = Vec::new();
264
265        for relationship in &self.relationships {
266            if relationship.from == concept_name && relationship.strength > 0.5 {
267                related.push(relationship.to.clone());
268            } else if relationship.to == concept_name && relationship.strength > 0.5 {
269                related.push(relationship.from.clone());
270            }
271        }
272
273        related
274    }
275
276    /// Add a new concept
277    pub fn add_concept(&mut self, concept: CodeConcept) {
278        self.concepts.insert(concept.name.clone(), concept);
279    }
280
281    /// Add a concept relationship
282    pub fn add_relationship(&mut self, relationship: ConceptRelationship) {
283        self.relationships.push(relationship);
284    }
285
286    /// Get all concept names
287    pub fn get_all_concept_names(&self) -> Vec<String> {
288        self.concepts.keys().cloned().collect()
289    }
290
291    /// Calculate concept similarity
292    pub fn calculate_similarity(&self, concept1: &str, concept2: &str) -> f64 {
293        if concept1 == concept2 {
294            return 1.0;
295        }
296
297        // Check direct relationships
298        for relationship in &self.relationships {
299            if (relationship.from == concept1 && relationship.to == concept2)
300                || (relationship.from == concept2 && relationship.to == concept1)
301            {
302                return relationship.strength;
303            }
304        }
305
306        // Check keyword overlap
307        if let (Some(c1), Some(c2)) = (self.concepts.get(concept1), self.concepts.get(concept2)) {
308            let common_keywords: Vec<_> = c1
309                .keywords
310                .iter()
311                .filter(|k| c2.keywords.contains(k))
312                .collect();
313
314            let total_keywords = c1.keywords.len() + c2.keywords.len();
315            if total_keywords > 0 {
316                return (common_keywords.len() * 2) as f64 / total_keywords as f64;
317            }
318        }
319
320        0.0
321    }
322}
323
324impl Default for ConceptMapper {
325    fn default() -> Self {
326        Self::new()
327    }
328}
329
330#[cfg(test)]
331mod tests {
332    use super::*;
333
334    #[test]
335    fn test_concept_creation() {
336        let concept = CodeConcept {
337            name: "test".to_string(),
338            description: "Test concept".to_string(),
339            keywords: vec!["test".to_string(), "testing".to_string()],
340            category: ConceptCategory::DataProcessing,
341        };
342
343        assert_eq!(concept.name, "test");
344        assert_eq!(concept.keywords.len(), 2, "Should have 2 items");
345    }
346
347    #[test]
348    fn test_concept_mapper() {
349        let mapper = ConceptMapper::new();
350
351        // Test text mapping
352        let concepts = mapper.map_text_to_concepts("user authentication system");
353        assert!(concepts.contains(&"authentication".to_string()));
354
355        // Test concept retrieval
356        let auth_concept = mapper.get_concept("authentication");
357        assert!(auth_concept.is_some(), "Should have value");
358
359        // Test related concepts
360        let related = mapper.find_related_concepts("authentication");
361        assert!(!related.is_empty(), "Should not be empty");
362    }
363
364    #[test]
365    fn test_concept_similarity() {
366        let mapper = ConceptMapper::new();
367
368        // Same concept should have similarity 1.0
369        let sim = mapper.calculate_similarity("authentication", "authentication");
370        assert_eq!(sim, 1.0);
371
372        // Related concepts should have some similarity
373        let sim = mapper.calculate_similarity("authentication", "api");
374        assert!(sim > 0.0);
375    }
376
377    #[test]
378    fn test_category_filtering() {
379        let mapper = ConceptMapper::new();
380        let security_concepts = mapper.get_concepts_by_category(&ConceptCategory::Security);
381
382        assert!(!security_concepts.is_empty(), "Should not be empty");
383        assert!(security_concepts.iter().any(|c| c.name == "authentication"));
384    }
385}