1use serde::Serialize;
2use std::fmt;
3use std::path::PathBuf;
4use std::time::SystemTime;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
8pub enum RiskLevel {
9 Safe,
11 Moderate,
13 Risky,
15}
16
17impl fmt::Display for RiskLevel {
18 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19 match self {
20 Self::Safe => write!(f, "safe"),
21 Self::Moderate => write!(f, "moderate"),
22 Self::Risky => write!(f, "risky"),
23 }
24 }
25}
26
27impl RiskLevel {
28 pub fn emoji(&self) -> &'static str {
29 match self {
30 Self::Safe => "🟢",
31 Self::Moderate => "🟡",
32 Self::Risky => "🔴",
33 }
34 }
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
39pub enum Category {
40 Xcode,
41 Node,
42 Homebrew,
43 Python,
44 Rust,
45 Docker,
46 Ollama,
47 HuggingFace,
48 Claude,
49 VSCode,
50 Gradle,
51 CocoaPods,
52 Generic,
53}
54
55impl fmt::Display for Category {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 match self {
58 Self::Xcode => write!(f, "Xcode"),
59 Self::Node => write!(f, "Node.js"),
60 Self::Homebrew => write!(f, "Homebrew"),
61 Self::Python => write!(f, "Python"),
62 Self::Rust => write!(f, "Rust"),
63 Self::Docker => write!(f, "Docker"),
64 Self::Ollama => write!(f, "Ollama"),
65 Self::HuggingFace => write!(f, "HuggingFace"),
66 Self::Claude => write!(f, "Claude"),
67 Self::VSCode => write!(f, "VS Code"),
68 Self::Gradle => write!(f, "Gradle"),
69 Self::CocoaPods => write!(f, "CocoaPods"),
70 Self::Generic => write!(f, "Generic"),
71 }
72 }
73}
74
75#[derive(Debug, Clone, Serialize)]
77pub struct Finding {
78 pub path: PathBuf,
80 pub category: Category,
82 pub risk: RiskLevel,
84 pub size_bytes: u64,
86 pub description: String,
88 #[serde(skip)]
90 pub last_modified: Option<SystemTime>,
91}
92
93impl Finding {
94 pub fn size_human(&self) -> String {
95 crate::size::format_bytes(self.size_bytes)
96 }
97}