1pub mod error;
36pub mod file;
37pub mod types;
38pub mod config;
39pub mod traits;
40pub mod utils;
41pub mod tokenization;
42
43#[cfg(feature = "scaling")]
45pub mod scaling;
46
47pub use error::{ScribeError, Result};
49
50pub use file::{
51 FileInfo, FileType, Language, RenderDecision, RenderDecisionCategory,
52 DocumentationFormat, ConfigurationFormat, GitStatus, GitFileStatus,
53 bytes_to_human, BINARY_EXTENSIONS, MARKDOWN_EXTENSIONS,
54};
55
56pub use types::{
57 Position, Range,
59
60 ScoreComponents, HeuristicWeights,
62
63 RepositoryInfo, SizeStatistics, LanguageStats, FileTypeStats,
65 GitStatistics, ChurnInfo,
66
67 CentralityScores, GraphStats,
69
70 AnalysisResult, AnalysisMetadata,
72};
73
74pub use config::{
75 Config, GeneralConfig, FilteringConfig, AnalysisConfig, ScoringConfig,
76 PerformanceConfig, GitConfig, FeatureFlags, OutputConfig,
77 CustomScoringRule, ScoreModifier, OutputFormat,
78};
79
80pub use traits::{
81 FileAnalyzer, HeuristicScorer, RepositoryAnalyzer, GitIntegration,
83 CentralityComputer, LanguageExtension,
84
85 PatternMatcher, OutputFormatter, CacheStorage, ProgressReporter,
87 PluginRegistry,
88
89 DependencyGraph, DependencyNodeMetadata, GitRepositoryInfo,
91 DocumentationBlock, DocumentationType, CacheStats,
92};
93
94pub use utils::{
96 path::{normalize_path, relative_path, is_under_directory, path_depth, is_hidden, find_repo_root},
97 string::{truncate, dedent, count_lines, is_likely_binary, extract_identifier},
98 time::{duration_to_human, current_timestamp},
99 math::{mean, median, std_deviation, normalize, clamp},
100 validation::{validate_readable_path, validate_directory, validate_file},
101 hash::{generate_hash, hash_file_content},
102};
103
104pub use tokenization::{
105 TokenCounter, TokenizerConfig, TokenBudget,
106 ContentType, TokenizationComparison,
107};
108
109pub const VERSION: &str = env!("CARGO_PKG_VERSION");
111
112pub mod meta {
114 pub const NAME: &str = env!("CARGO_PKG_NAME");
116
117 pub const VERSION: &str = env!("CARGO_PKG_VERSION");
119
120 pub const DESCRIPTION: &str = env!("CARGO_PKG_DESCRIPTION");
122
123 pub const AUTHORS: &str = env!("CARGO_PKG_AUTHORS");
125
126 pub const REPOSITORY: &str = env!("CARGO_PKG_REPOSITORY");
128
129 pub const LICENSE: &str = env!("CARGO_PKG_LICENSE");
131
132 pub const TARGET: Option<&str> = option_env!("TARGET");
134
135 pub const BUILD_TIMESTAMP: Option<&str> = option_env!("BUILD_TIMESTAMP");
137
138 pub const GIT_HASH: Option<&str> = option_env!("GIT_HASH");
140
141 pub fn info() -> String {
143 format!(
144 "{} v{} - {}",
145 NAME,
146 VERSION,
147 DESCRIPTION
148 )
149 }
150
151 pub fn build_info() -> String {
153 let mut info = format!("{} v{}", NAME, VERSION);
154
155 if let Some(target) = TARGET {
156 info.push_str(&format!(" ({})", target));
157 }
158
159 if let Some(git_hash) = GIT_HASH {
160 info.push_str(&format!(" [{}]", &git_hash[..8]));
161 }
162
163 if let Some(timestamp) = BUILD_TIMESTAMP {
164 info.push_str(&format!(" built on {}", timestamp));
165 }
166
167 info
168 }
169}
170
171pub mod prelude {
173 pub use crate::{
176 Result, ScribeError,
178 FileInfo, FileType, Language, RenderDecision,
179 ScoreComponents, HeuristicWeights,
180 Config, FeatureFlags,
181
182 FileAnalyzer, HeuristicScorer, RepositoryAnalyzer,
184 OutputFormatter, ProgressReporter,
185
186 normalize_path, duration_to_human, generate_hash,
188 };
189}
190
191#[cfg(test)]
192mod tests {
193 use super::*;
194
195 #[test]
196 fn test_version() {
197 assert!(!VERSION.is_empty());
198 assert!(VERSION.parse::<semver::Version>().is_ok());
199 }
200
201 #[test]
202 fn test_meta_info() {
203 let info = meta::info();
204 assert!(info.contains("scribe-core"));
205 assert!(info.contains(VERSION));
206 }
207
208 #[test]
209 fn test_build_info() {
210 let build_info = meta::build_info();
211 assert!(build_info.contains("scribe-core"));
212 assert!(build_info.contains(VERSION));
213 }
214
215 #[test]
216 fn test_prelude_imports() {
217 use crate::prelude::*;
219
220 let config = Config::default();
221 assert!(config.general.verbosity <= 4);
222
223 let decision = RenderDecision::include("test");
224 assert!(decision.should_include());
225
226 let hash = generate_hash(&"test");
227 assert!(!hash.is_empty());
228 }
229
230 #[test]
231 fn test_core_functionality() {
232 let err = ScribeError::config("test error");
234 assert!(err.to_string().contains("test error"));
235
236 let lang = Language::from_extension("rs");
238 assert_eq!(lang, Language::Rust);
239
240 let depth = path_depth("src/lib/mod.rs");
242 assert_eq!(depth, 3);
243
244 let truncated = truncate("hello world", 5);
246 assert_eq!(truncated, "he...");
247 }
248
249 #[test]
250 fn test_score_components() {
251 let mut scores = ScoreComponents::zero();
252 scores.doc_score = 0.8;
253 scores.import_score = 0.6;
254
255 let weights = HeuristicWeights::default();
256 scores.compute_final_score(&weights);
257
258 assert!(scores.final_score > 0.0);
259 assert!(scores.final_score <= 1.0);
260 }
261
262 #[test]
263 fn test_configuration() {
264 let config = Config::default();
265 assert!(config.validate().is_ok());
266
267 let hash1 = config.compute_hash();
268 let hash2 = config.compute_hash();
269 assert_eq!(hash1, hash2);
270 }
271}