scribe_core/
lib.rs

1#![cfg_attr(not(tarpaulin), deny(warnings))]
2#![cfg_attr(tarpaulin, allow(warnings))]
3
4//! # Scribe Core
5//! 
6//! Core types, utilities, and foundational components for the Scribe code analysis library.
7//! This crate provides the fundamental data structures and traits used across all other
8//! Scribe crates.
9//!
10//! ## Features
11//! 
12//! - **Comprehensive Error Handling**: Rich error types with proper context and error chaining
13//! - **File Analysis**: File metadata, language detection, and classification
14//! - **Scoring System**: Heuristic scoring components and configurable weights
15//! - **Configuration**: Flexible configuration with validation and serialization
16//! - **Extensibility**: Traits for custom analyzers, scorers, and formatters
17//! - **Utilities**: Common functions for path manipulation, string processing, and more
18//!
19//! ## Basic Usage
20//!
21//! ```rust
22//! use scribe_core::{Config, FileInfo, ScoreComponents, Result};
23//! use std::path::Path;
24//!
25//! # fn main() -> Result<()> {
26//! // Load configuration
27//! let config = Config::default();
28//!
29//! // Analyze a file (this would typically be done by other crates)
30//! // let file_info = analyze_file(Path::new("src/lib.rs"), &config)?;
31//! # Ok(())
32//! # }
33//! ```
34
35// Core modules
36pub mod error;
37pub mod file;
38pub mod types;
39pub mod config;
40pub mod traits;
41pub mod utils;
42
43// Re-export commonly used types for convenience
44pub use error::{ScribeError, Result};
45
46pub use file::{
47    FileInfo, FileType, Language, RenderDecision, RenderDecisionCategory,
48    DocumentationFormat, ConfigurationFormat, GitStatus, GitFileStatus,
49    bytes_to_human, BINARY_EXTENSIONS, MARKDOWN_EXTENSIONS,
50};
51
52pub use types::{
53    // Core positioning and ranges
54    Position, Range,
55    
56    // Scoring system
57    ScoreComponents, HeuristicWeights,
58    
59    // Repository information
60    RepositoryInfo, SizeStatistics, LanguageStats, FileTypeStats,
61    GitStatistics, ChurnInfo,
62    
63    // Graph analysis
64    CentralityScores, GraphStats,
65    
66    // Analysis results
67    AnalysisResult, AnalysisMetadata,
68};
69
70pub use config::{
71    Config, GeneralConfig, FilteringConfig, AnalysisConfig, ScoringConfig,
72    PerformanceConfig, GitConfig, FeatureFlags, OutputConfig,
73    CustomScoringRule, ScoreModifier, OutputFormat,
74};
75
76pub use traits::{
77    // Core analysis traits
78    FileAnalyzer, HeuristicScorer, RepositoryAnalyzer, GitIntegration,
79    CentralityComputer, LanguageExtension,
80    
81    // Infrastructure traits
82    PatternMatcher, OutputFormatter, CacheStorage, ProgressReporter,
83    PluginRegistry,
84    
85    // Data structures
86    DependencyGraph, DependencyNodeMetadata, GitRepositoryInfo,
87    DocumentationBlock, DocumentationType, CacheStats,
88};
89
90// Utility re-exports for common functionality
91pub use utils::{
92    path::{normalize_path, relative_path, is_under_directory, path_depth, is_hidden, find_repo_root},
93    string::{truncate, dedent, count_lines, is_likely_binary, extract_identifier},
94    time::{duration_to_human, current_timestamp},
95    math::{mean, median, std_deviation, normalize, clamp},
96    validation::{validate_readable_path, validate_directory, validate_file},
97    hash::{generate_hash, hash_file_content},
98};
99
100/// Current version of the Scribe library
101pub const VERSION: &str = env!("CARGO_PKG_VERSION");
102
103/// Library metadata and build information
104pub mod meta {
105    /// Library name
106    pub const NAME: &str = env!("CARGO_PKG_NAME");
107    
108    /// Library version
109    pub const VERSION: &str = env!("CARGO_PKG_VERSION");
110    
111    /// Library description
112    pub const DESCRIPTION: &str = env!("CARGO_PKG_DESCRIPTION");
113    
114    /// Authors
115    pub const AUTHORS: &str = env!("CARGO_PKG_AUTHORS");
116    
117    /// Repository URL
118    pub const REPOSITORY: &str = env!("CARGO_PKG_REPOSITORY");
119    
120    /// License
121    pub const LICENSE: &str = env!("CARGO_PKG_LICENSE");
122    
123    /// Target triple (if available)
124    pub const TARGET: Option<&str> = option_env!("TARGET");
125    
126    /// Build timestamp (if available)
127    pub const BUILD_TIMESTAMP: Option<&str> = option_env!("BUILD_TIMESTAMP");
128    
129    /// Git commit hash (if available)
130    pub const GIT_HASH: Option<&str> = option_env!("GIT_HASH");
131    
132    /// Get library information as a formatted string
133    pub fn info() -> String {
134        format!(
135            "{} v{} - {}",
136            NAME,
137            VERSION, 
138            DESCRIPTION
139        )
140    }
141    
142    /// Get detailed build information
143    pub fn build_info() -> String {
144        let mut info = format!("{} v{}", NAME, VERSION);
145        
146        if let Some(target) = TARGET {
147            info.push_str(&format!(" ({})", target));
148        }
149        
150        if let Some(git_hash) = GIT_HASH {
151            info.push_str(&format!(" [{}]", &git_hash[..8]));
152        }
153        
154        if let Some(timestamp) = BUILD_TIMESTAMP {
155            info.push_str(&format!(" built on {}", timestamp));
156        }
157        
158        info
159    }
160}
161
162/// Prelude module for convenient imports
163pub mod prelude {
164    //! Commonly used imports for Scribe applications
165    
166    pub use crate::{
167        // Core types
168        Result, ScribeError,
169        FileInfo, FileType, Language, RenderDecision,
170        ScoreComponents, HeuristicWeights,
171        Config, FeatureFlags,
172        
173        // Essential traits
174        FileAnalyzer, HeuristicScorer, RepositoryAnalyzer,
175        OutputFormatter, ProgressReporter,
176        
177        // Common utilities
178        normalize_path, duration_to_human, generate_hash,
179    };
180}
181
182#[cfg(test)]
183mod tests {
184    use super::*;
185
186    #[test]
187    fn test_version() {
188        assert!(!VERSION.is_empty());
189        assert!(VERSION.parse::<semver::Version>().is_ok());
190    }
191
192    #[test]
193    fn test_meta_info() {
194        let info = meta::info();
195        assert!(info.contains("scribe-core"));
196        assert!(info.contains(VERSION));
197    }
198
199    #[test]
200    fn test_build_info() {
201        let build_info = meta::build_info();
202        assert!(build_info.contains("scribe-core"));
203        assert!(build_info.contains(VERSION));
204    }
205
206    #[test]
207    fn test_prelude_imports() {
208        // Test that prelude imports work
209        use crate::prelude::*;
210        
211        let config = Config::default();
212        assert!(config.general.verbosity <= 4);
213        
214        let decision = RenderDecision::include("test");
215        assert!(decision.should_include());
216        
217        let hash = generate_hash(&"test");
218        assert!(!hash.is_empty());
219    }
220
221    #[test]
222    fn test_core_functionality() {
223        // Test error creation
224        let err = ScribeError::config("test error");
225        assert!(err.to_string().contains("test error"));
226        
227        // Test language detection
228        let lang = Language::from_extension("rs");
229        assert_eq!(lang, Language::Rust);
230        
231        // Test path utilities
232        let depth = path_depth("src/lib/mod.rs");
233        assert_eq!(depth, 3);
234        
235        // Test string utilities
236        let truncated = truncate("hello world", 5);
237        assert_eq!(truncated, "he...");
238    }
239
240    #[test]
241    fn test_score_components() {
242        let mut scores = ScoreComponents::zero();
243        scores.doc_score = 0.8;
244        scores.import_score = 0.6;
245        
246        let weights = HeuristicWeights::default();
247        scores.compute_final_score(&weights);
248        
249        assert!(scores.final_score > 0.0);
250        assert!(scores.final_score <= 1.0);
251    }
252
253    #[test]
254    fn test_configuration() {
255        let config = Config::default();
256        assert!(config.validate().is_ok());
257        
258        let hash1 = config.compute_hash();
259        let hash2 = config.compute_hash();
260        assert_eq!(hash1, hash2);
261    }
262}