arborist/types.rs
1// SPDX-License-Identifier: MIT OR Apache-2.0
2// Copyright (c) 2026 Strange Days Tech S.A.S. de C.V. <https://strangedays.tech>
3
4use serde::{Deserialize, Serialize};
5use std::fmt;
6use std::str::FromStr;
7
8/// Supported programming languages.
9///
10/// Each variant corresponds to a compile-time feature flag. Languages whose
11/// feature flag is not enabled can still be named, but attempting to analyze
12/// code in that language will return [`ArboristError::LanguageNotEnabled`].
13///
14/// The enum is `#[non_exhaustive]` — new languages may be added in minor
15/// releases without breaking existing match arms.
16///
17/// [`ArboristError::LanguageNotEnabled`]: crate::ArboristError::LanguageNotEnabled
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
19#[non_exhaustive]
20pub enum Language {
21 Rust,
22 Python,
23 JavaScript,
24 TypeScript,
25 Java,
26 CSharp,
27 Cpp,
28 C,
29 Go,
30 Php,
31 Kotlin,
32 Swift,
33}
34
35impl fmt::Display for Language {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 match self {
38 Language::Rust => write!(f, "Rust"),
39 Language::Python => write!(f, "Python"),
40 Language::JavaScript => write!(f, "JavaScript"),
41 Language::TypeScript => write!(f, "TypeScript"),
42 Language::Java => write!(f, "Java"),
43 Language::CSharp => write!(f, "C#"),
44 Language::Cpp => write!(f, "C++"),
45 Language::C => write!(f, "C"),
46 Language::Go => write!(f, "Go"),
47 Language::Php => write!(f, "PHP"),
48 Language::Kotlin => write!(f, "Kotlin"),
49 Language::Swift => write!(f, "Swift"),
50 }
51 }
52}
53
54impl FromStr for Language {
55 type Err = String;
56
57 fn from_str(s: &str) -> Result<Self, Self::Err> {
58 match s.to_lowercase().as_str() {
59 "rust" => Ok(Language::Rust),
60 "python" => Ok(Language::Python),
61 "javascript" | "js" => Ok(Language::JavaScript),
62 "typescript" | "ts" => Ok(Language::TypeScript),
63 "java" => Ok(Language::Java),
64 "csharp" | "c#" => Ok(Language::CSharp),
65 "cpp" | "c++" => Ok(Language::Cpp),
66 "c" => Ok(Language::C),
67 "go" => Ok(Language::Go),
68 "php" => Ok(Language::Php),
69 "kotlin" | "kt" => Ok(Language::Kotlin),
70 "swift" => Ok(Language::Swift),
71 _ => Err(format!("Unknown language: {s}")),
72 }
73 }
74}
75
76/// Metrics for a single function or method.
77///
78/// Each function or method discovered by the AST walker produces one
79/// `FunctionMetrics` value. Closures and lambdas do not produce their own
80/// entries; they contribute to the metrics of their containing function.
81///
82/// All three complexity dimensions are always populated. The optional
83/// `exceeds_threshold` field is only set when an [`AnalysisConfig`] with a
84/// `cognitive_threshold` is used.
85#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
86pub struct FunctionMetrics {
87 /// Function or method name (e.g., `"process"` or `"MyStruct::method"`).
88 pub name: String,
89 /// 1-based start line number.
90 pub start_line: usize,
91 /// 1-based end line number.
92 pub end_line: usize,
93 /// Cognitive complexity (SonarSource algorithm).
94 pub cognitive: u64,
95 /// Cyclomatic complexity (McCabe).
96 pub cyclomatic: u64,
97 /// Source lines of code within the function.
98 pub sloc: u64,
99 /// `Some(true)` if cognitive complexity exceeds configured threshold,
100 /// `Some(false)` if within threshold, `None` if no threshold configured.
101 pub exceeds_threshold: Option<bool>,
102}
103
104/// Analysis report for a complete source file.
105///
106/// Returned by [`analyze_file`](crate::analyze_file) and
107/// [`analyze_source`](crate::analyze_source). Contains per-function metrics
108/// and file-level aggregates. Implements `Serialize` and `Deserialize` for
109/// easy JSON output.
110#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
111pub struct FileReport {
112 /// File path (empty string for in-memory analysis).
113 pub path: String,
114 /// Detected or specified language.
115 pub language: Language,
116 /// Functions found, ordered by `start_line` ascending.
117 pub functions: Vec<FunctionMetrics>,
118 /// Sum of all functions' cognitive complexity.
119 pub file_cognitive: u64,
120 /// Sum of all functions' cyclomatic complexity.
121 pub file_cyclomatic: u64,
122 /// Total source lines in the entire file (includes top-level code).
123 pub file_sloc: u64,
124}
125
126/// User-configurable analysis parameters.
127///
128/// Pass to [`analyze_file_with_config`](crate::analyze_file_with_config) or
129/// [`analyze_source_with_config`](crate::analyze_source_with_config) to
130/// control threshold flagging and method inclusion. The [`Default`] impl
131/// sets no threshold and includes methods.
132#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
133pub struct AnalysisConfig {
134 /// When set, populates `exceeds_threshold` on each `FunctionMetrics`.
135 pub cognitive_threshold: Option<u64>,
136 /// Whether to include class/struct methods (default: `true`).
137 pub include_methods: bool,
138}
139
140impl Default for AnalysisConfig {
141 fn default() -> Self {
142 Self {
143 cognitive_threshold: None,
144 include_methods: true,
145 }
146 }
147}