Skip to main content

fallow_engine/
source.rs

1//! Source parsing contracts owned by the engine boundary.
2
3use fallow_types::discover::DiscoveredFile;
4#[cfg(test)]
5pub use fallow_types::extract::{ExportName, MemberKind, VisibilityTag};
6pub use fallow_types::extract::{ModuleInfo, ParseResult, SourceReadFailure};
7
8type CacheStore = fallow_extract::cache::CacheStore;
9
10/// On-demand, transient function extraction for local similar-code inference.
11pub mod similar_code {
12    use std::path::Path;
13
14    pub use fallow_types::similar_code::{
15        ExtractedSimilarCodeFunction, SIMILAR_CODE_EXTRACTION_SEMANTICS_VERSION,
16        SimilarCodeExtraction, SimilarCodeExtractionLimits, SimilarCodeExtractionSkip,
17        SimilarCodeExtractionSkipReason, SimilarCodeFunctionKind, SimilarCodeFunctionLocation,
18        SimilarCodeSideEffectHint, SimilarCodeSourceDigest,
19    };
20
21    /// Extract bounded named functions without touching the normal parse cache.
22    #[must_use]
23    pub fn extract(
24        path: &Path,
25        source: &str,
26        limits: SimilarCodeExtractionLimits,
27    ) -> SimilarCodeExtraction {
28        fallow_extract::extract_similar_code_functions(path, source, limits)
29    }
30}
31
32/// Source inventory walking for coverage and upload surfaces.
33pub mod inventory {
34    use std::path::Path;
35
36    use rustc_hash::FxHashMap;
37
38    /// A single static-inventory entry for one function.
39    ///
40    /// This is the engine-owned inventory contract exposed to CLI upload
41    /// surfaces. The extractor owns AST traversal; the engine owns the public
42    /// shape that downstream crates construct and upload.
43    #[derive(Debug, Clone, PartialEq, Eq)]
44    pub struct InventoryEntry {
45        /// Beacon-compatible function name.
46        pub name: String,
47        /// 1-based source line of the function declaration.
48        pub line: u32,
49        /// 1-indexed UTF-16 column of the function node start.
50        pub start_column: u32,
51        /// 1-based source line where the function node ends.
52        pub end_line: u32,
53        /// 1-indexed UTF-16 column of the function node end.
54        pub end_column: u32,
55        /// Content digest of the function's full-span source slice.
56        pub source_hash: String,
57    }
58
59    impl From<fallow_extract::inventory::InventoryEntry> for InventoryEntry {
60        fn from(entry: fallow_extract::inventory::InventoryEntry) -> Self {
61            Self {
62                name: entry.name,
63                line: entry.line,
64                start_column: entry.start_column,
65                end_line: entry.end_line,
66                end_column: entry.end_column,
67                source_hash: entry.source_hash,
68            }
69        }
70    }
71
72    /// Per-function static complexity collected alongside the inventory walk.
73    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
74    pub struct InventoryComplexity {
75        /// `McCabe` cyclomatic complexity (1 + decision points).
76        pub cyclomatic: u16,
77        /// `SonarSource` cognitive complexity (structural + nesting penalty).
78        pub cognitive: u16,
79    }
80
81    impl From<fallow_extract::inventory::InventoryComplexity> for InventoryComplexity {
82        fn from(complexity: fallow_extract::inventory::InventoryComplexity) -> Self {
83            Self {
84                cyclomatic: complexity.cyclomatic,
85                cognitive: complexity.cognitive,
86            }
87        }
88    }
89
90    /// Walk source and emit engine-owned function inventory entries.
91    #[must_use]
92    pub fn walk_source(path: &Path, source: &str) -> Vec<InventoryEntry> {
93        fallow_extract::inventory::walk_source(path, source)
94            .into_iter()
95            .map(InventoryEntry::from)
96            .collect()
97    }
98
99    /// Walk source once and emit inventory entries plus static complexity by source hash.
100    #[must_use]
101    pub fn walk_source_with_complexity(
102        path: &Path,
103        source: &str,
104    ) -> (Vec<InventoryEntry>, FxHashMap<String, InventoryComplexity>) {
105        let (entries, complexity) =
106            fallow_extract::inventory::walk_source_with_complexity(path, source);
107        let entries = entries.into_iter().map(InventoryEntry::from).collect();
108        let complexity = complexity
109            .into_iter()
110            .map(|(hash, metrics)| (hash, InventoryComplexity::from(metrics)))
111            .collect();
112        (entries, complexity)
113    }
114}
115
116/// Parse discovered source files into typed module facts.
117///
118/// Keeping parsing behind the engine boundary lets sessions and future
119/// incremental runners choose cache policy without exposing the extract crate
120/// as the public orchestration layer.
121#[must_use]
122pub(crate) fn parse_all_files(
123    files: &[DiscoveredFile],
124    cache: Option<&CacheStore>,
125    need_complexity: bool,
126) -> ParseResult {
127    fallow_extract::parse_all_files(files, cache, need_complexity)
128}