rskim_core/lib.rs
1//! Skim Core - Smart code reading and transformation library
2//!
3//! # Overview
4//!
5//! `skim-core` is a pure library for transforming source code by stripping
6//! implementation details while preserving structure, signatures, and types.
7//! Optimized for AI/LLM context windows.
8//!
9//! # Architecture
10//!
11//! **IMPORTANT: This is a LIBRARY with NO I/O.**
12//! - Accepts `&str` (source code), not file paths
13//! - Returns `Result<String>`, not stdout writes
14//! - Pure transformations, no side effects
15//!
16//! CLI/SDK/MCP interfaces handle I/O separately.
17//!
18//! # Example
19//!
20//! ```no_run
21//! use rskim_core::{transform, Language, Mode};
22//!
23//! let source = "function add(a: number, b: number) { return a + b; }";
24//! let result = transform(source, Language::TypeScript, Mode::Structure)?;
25//!
26//! // Result: "function add(a: number, b: number) { /* ... */ }"
27//! # Ok::<(), rskim_core::SkimError>(())
28//! ```
29//!
30//! # Design Principles
31//!
32//! 1. **Zero-copy where possible** - Use `&str` slices, avoid allocations
33//! 2. **Result types everywhere** - NO panics (enforced by clippy)
34//! 3. **Dependency injection** - NO global state
35//! 4. **Type-first** - Complete type schema before implementation
36
37// Re-export core types for public API
38pub use types::{
39 Language,
40 Mode,
41 TransformConfig,
42 TransformResult,
43 SkimError,
44 Result,
45 Parser,
46};
47
48mod types;
49mod parser;
50mod transform;
51
52// NOTE: Caching is implemented at the CLI layer (rskim binary), not in the core library.
53// The core library remains pure and I/O-free.
54// See: crates/rskim/src/cache.rs for the caching implementation.
55
56// ============================================================================
57// Public API - Core Transformation Functions
58// ============================================================================
59
60/// Transform source code based on mode
61///
62/// This is the PRIMARY function for transformation.
63///
64/// # Arguments
65///
66/// * `source` - Source code as string slice (zero-copy)
67/// * `language` - Programming language for parsing
68/// * `mode` - Transformation mode (Structure, Signatures, Types, Full)
69///
70/// # Returns
71///
72/// Transformed source code as `String`, or error if parsing fails.
73///
74/// # Performance
75///
76/// Target: <50ms for 1000-line files
77/// - Parse: ~5-10ms (tree-sitter)
78/// - Transform: ~10-20ms (AST traversal)
79/// - String building: ~5-10ms
80///
81/// # Errors
82///
83/// - `SkimError::ParseError` - tree-sitter failed to parse
84/// - `SkimError::TreeSitterError` - Grammar loading failed
85///
86/// # Examples
87///
88/// ```no_run
89/// use rskim_core::{transform, Language, Mode};
90///
91/// let typescript = "function greet(name: string) { console.log(`Hello, ${name}`); }";
92/// let result = transform(typescript, Language::TypeScript, Mode::Structure)?;
93///
94/// assert!(result.contains("function greet(name: string)"));
95/// assert!(!result.contains("console.log"));
96/// # Ok::<(), rskim_core::SkimError>(())
97/// ```
98pub fn transform(
99 source: &str,
100 language: Language,
101 mode: Mode,
102) -> Result<String> {
103 // ARCHITECTURE: Use default config for simple API
104 transform_with_config(source, language, &TransformConfig::with_mode(mode))
105}
106
107/// Transform source code with custom configuration
108///
109/// Advanced API that accepts full configuration struct.
110///
111/// # Arguments
112///
113/// * `source` - Source code as string slice
114/// * `language` - Programming language
115/// * `config` - Full transformation configuration
116///
117/// # Examples
118///
119/// ```no_run
120/// use rskim_core::{transform_with_config, Language, Mode, TransformConfig};
121///
122/// let config = TransformConfig::with_mode(Mode::Signatures)
123/// .preserve_comments(false);
124///
125/// let result = transform_with_config("fn main() {}", Language::Rust, &config)?;
126/// # Ok::<(), rskim_core::SkimError>(())
127/// ```
128pub fn transform_with_config(
129 source: &str,
130 language: Language,
131 config: &TransformConfig,
132) -> Result<String> {
133 // 1. Create parser for language
134 let mut parser = Parser::new(language)?;
135
136 // 2. Parse source code
137 let tree = parser.parse(source)?;
138
139 // 3. Transform based on mode
140 transform::transform_tree(source, &tree, language, config)
141}
142
143/// Transform source code with automatic language detection from file path
144///
145/// Convenience function that detects language from file extension.
146///
147/// # Arguments
148///
149/// * `source` - Source code as string slice
150/// * `path` - File path for language detection (NOT read from disk)
151/// * `mode` - Transformation mode
152///
153/// # Errors
154///
155/// - `SkimError::UnsupportedLanguage` - Could not detect language from path
156/// - All errors from `transform()`
157///
158/// # Examples
159///
160/// ```no_run
161/// use rskim_core::{transform_auto, Mode};
162/// use std::path::Path;
163///
164/// let source = "def hello(): pass";
165/// let path = Path::new("script.py");
166/// let result = transform_auto(source, path, Mode::Structure)?;
167/// # Ok::<(), rskim_core::SkimError>(())
168/// ```
169pub fn transform_auto(
170 source: &str,
171 path: &std::path::Path,
172 mode: Mode,
173) -> Result<String> {
174 let language = Language::from_path(path)
175 .ok_or_else(|| SkimError::UnsupportedLanguage(path.to_path_buf()))?;
176
177 transform(source, language, mode)
178}
179
180/// Transform source code with full result metadata
181///
182/// Returns `TransformResult` with optional token counts and timing.
183/// Useful for benchmarking and analysis.
184///
185/// # Phase 3 Feature
186///
187/// Token counting requires `token-counting` feature flag.
188///
189/// # Examples
190///
191/// ```no_run
192/// use rskim_core::{transform_detailed, Language, Mode};
193///
194/// let result = transform_detailed("code", Language::Python, Mode::Structure)?;
195///
196/// println!("Transformed: {}", result.content);
197/// if let Some(reduction) = result.reduction_percentage() {
198/// println!("Token reduction: {:.1}%", reduction);
199/// }
200/// # Ok::<(), rskim_core::SkimError>(())
201/// ```
202pub fn transform_detailed(
203 source: &str,
204 language: Language,
205 mode: Mode,
206) -> Result<TransformResult> {
207 let start = std::time::Instant::now();
208
209 let content = transform(source, language, mode)?;
210
211 let duration_ms = start.elapsed().as_millis() as u64;
212
213 Ok(TransformResult {
214 content,
215 original_tokens: None, // TODO: Implement in Phase 3
216 transformed_tokens: None, // TODO: Implement in Phase 3
217 duration_ms: Some(duration_ms),
218 })
219}
220
221// ============================================================================
222// Language Detection Utilities
223// ============================================================================
224
225/// Detect language from file extension
226///
227/// # Examples
228///
229/// ```
230/// use rskim_core::{detect_language, Language};
231///
232/// assert_eq!(detect_language("ts"), Some(Language::TypeScript));
233/// assert_eq!(detect_language("py"), Some(Language::Python));
234/// assert_eq!(detect_language("unknown"), None);
235/// ```
236pub fn detect_language(extension: &str) -> Option<Language> {
237 Language::from_extension(extension)
238}
239
240/// Detect language from file path
241///
242/// # Examples
243///
244/// ```
245/// use rskim_core::{detect_language_from_path, Language};
246/// use std::path::Path;
247///
248/// let path = Path::new("src/main.rs");
249/// assert_eq!(detect_language_from_path(path), Some(Language::Rust));
250/// ```
251pub fn detect_language_from_path(path: &std::path::Path) -> Option<Language> {
252 Language::from_path(path)
253}
254
255// ============================================================================
256// Version Information
257// ============================================================================
258
259/// Get library version
260pub fn version() -> &'static str {
261 env!("CARGO_PKG_VERSION")
262}
263
264/// Get list of supported languages
265pub fn supported_languages() -> &'static [Language] {
266 &[
267 Language::TypeScript,
268 Language::JavaScript,
269 Language::Python,
270 Language::Rust,
271 Language::Go,
272 Language::Java,
273 Language::Markdown,
274 ]
275}
276
277// ============================================================================
278// Module Tests
279// ============================================================================
280
281#[cfg(test)]
282mod tests {
283 use super::*;
284
285 #[test]
286 fn test_version() {
287 assert!(!version().is_empty());
288 }
289
290 #[test]
291 fn test_supported_languages() {
292 assert_eq!(supported_languages().len(), 7);
293 assert!(supported_languages().contains(&Language::Markdown));
294 }
295
296 #[test]
297 fn test_detect_language() {
298 assert_eq!(detect_language("ts"), Some(Language::TypeScript));
299 assert_eq!(detect_language("unknown"), None);
300 }
301
302 // NOTE: Actual transformation tests require implementation
303 // These are placeholders for schema validation
304}