1use std::fmt;
2use std::path::PathBuf;
3
4use clap::ValueEnum;
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, ValueEnum)]
9#[serde(rename_all = "kebab-case")]
10pub enum Category {
11 RustTarget,
13 NodeModules,
15 FrameworkCache,
17 BuildOutput,
19 TestCache,
21 GlobalCache,
23 ExpensiveGlobalCache,
25}
26
27impl Category {
28 #[must_use]
30 pub fn all() -> [Self; 7] {
31 [
32 Self::RustTarget,
33 Self::NodeModules,
34 Self::FrameworkCache,
35 Self::BuildOutput,
36 Self::TestCache,
37 Self::GlobalCache,
38 Self::ExpensiveGlobalCache,
39 ]
40 }
41
42 #[must_use]
44 pub fn safe_defaults() -> [Self; 3] {
45 [Self::RustTarget, Self::NodeModules, Self::FrameworkCache]
46 }
47}
48
49impl fmt::Display for Category {
50 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
51 let value = match self {
52 Self::RustTarget => "rust-target",
53 Self::NodeModules => "node-modules",
54 Self::FrameworkCache => "framework-cache",
55 Self::BuildOutput => "build-output",
56 Self::TestCache => "test-cache",
57 Self::GlobalCache => "global-cache",
58 Self::ExpensiveGlobalCache => "expensive-global-cache",
59 };
60 formatter.write_str(value)
61 }
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct Candidate {
67 pub category: Category,
69 pub path: PathBuf,
71 pub bytes: u64,
73 pub reason: String,
75 pub modified_at_unix: Option<u64>,
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize)]
81pub struct ScanReport {
82 pub roots: Vec<PathBuf>,
84 pub candidates: Vec<Candidate>,
86 pub warnings: Vec<String>,
88 pub total_bytes: u64,
90 #[serde(default = "default_true")]
92 pub protect_git_tracked: bool,
93}
94
95const fn default_true() -> bool {
96 true
97}
98
99#[derive(Debug, Clone, Copy, ValueEnum)]
101pub enum OutputFormat {
102 Table,
104 Json,
106 Jsonl,
108 Html,
110}
111
112#[derive(Debug, Clone, Copy, Default)]
114pub struct RenderOptions {
115 pub redact_paths: bool,
117}