scribe_core/
lib.rs

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