tldr_cli/commands/
smells.rs1use std::path::PathBuf;
7
8use anyhow::Result;
9use clap::Args;
10
11use tldr_core::{
12 analyze_smells_aggregated, detect_smells, SmellType, SmellsReport, ThresholdPreset,
13};
14
15use crate::commands::daemon_router::{params_with_path, try_daemon_route};
16use crate::output::{format_smells_text, OutputFormat, OutputWriter};
17
18#[derive(Debug, Args)]
20pub struct SmellsArgs {
21 #[arg(default_value = ".")]
23 pub path: PathBuf,
24
25 #[arg(long, short = 't', default_value = "default")]
27 pub threshold: ThresholdPresetArg,
28
29 #[arg(long, short = 's')]
31 pub smell_type: Option<SmellTypeArg>,
32
33 #[arg(long)]
35 pub suggest: bool,
36
37 #[arg(long)]
41 pub deep: bool,
42}
43
44#[derive(Debug, Clone, Copy, Default, clap::ValueEnum)]
46pub enum ThresholdPresetArg {
47 Strict,
49 #[default]
51 Default,
52 Relaxed,
54}
55
56impl From<ThresholdPresetArg> for ThresholdPreset {
57 fn from(arg: ThresholdPresetArg) -> Self {
58 match arg {
59 ThresholdPresetArg::Strict => ThresholdPreset::Strict,
60 ThresholdPresetArg::Default => ThresholdPreset::Default,
61 ThresholdPresetArg::Relaxed => ThresholdPreset::Relaxed,
62 }
63 }
64}
65
66#[derive(Debug, Clone, Copy, clap::ValueEnum)]
68pub enum SmellTypeArg {
69 GodClass,
71 LongMethod,
73 LongParameterList,
75 FeatureEnvy,
77 DataClumps,
79 LowCohesion,
81 TightCoupling,
83 DeadCode,
85 CodeClone,
87 HighCognitiveComplexity,
89 DeepNesting,
91 DataClass,
93 LazyElement,
95 MessageChain,
97 PrimitiveObsession,
99 MiddleMan,
101 RefusedBequest,
103 InappropriateIntimacy,
105}
106
107impl From<SmellTypeArg> for SmellType {
108 fn from(arg: SmellTypeArg) -> Self {
109 match arg {
110 SmellTypeArg::GodClass => SmellType::GodClass,
111 SmellTypeArg::LongMethod => SmellType::LongMethod,
112 SmellTypeArg::LongParameterList => SmellType::LongParameterList,
113 SmellTypeArg::FeatureEnvy => SmellType::FeatureEnvy,
114 SmellTypeArg::DataClumps => SmellType::DataClumps,
115 SmellTypeArg::LowCohesion => SmellType::LowCohesion,
116 SmellTypeArg::TightCoupling => SmellType::TightCoupling,
117 SmellTypeArg::DeadCode => SmellType::DeadCode,
118 SmellTypeArg::CodeClone => SmellType::CodeClone,
119 SmellTypeArg::HighCognitiveComplexity => SmellType::HighCognitiveComplexity,
120 SmellTypeArg::DeepNesting => SmellType::DeepNesting,
121 SmellTypeArg::DataClass => SmellType::DataClass,
122 SmellTypeArg::LazyElement => SmellType::LazyElement,
123 SmellTypeArg::MessageChain => SmellType::MessageChain,
124 SmellTypeArg::PrimitiveObsession => SmellType::PrimitiveObsession,
125 SmellTypeArg::MiddleMan => SmellType::MiddleMan,
126 SmellTypeArg::RefusedBequest => SmellType::RefusedBequest,
127 SmellTypeArg::InappropriateIntimacy => SmellType::InappropriateIntimacy,
128 }
129 }
130}
131
132impl SmellsArgs {
133 pub fn run(&self, format: OutputFormat, quiet: bool) -> Result<()> {
135 let writer = OutputWriter::new(format, quiet);
136
137 if let Some(report) = try_daemon_route::<SmellsReport>(
139 &self.path,
140 "smells",
141 params_with_path(Some(&self.path)),
142 ) {
143 if writer.is_text() {
145 let text = format_smells_text(&report);
146 writer.write_text(&text)?;
147 return Ok(());
148 } else {
149 writer.write(&report)?;
150 return Ok(());
151 }
152 }
153
154 writer.progress(&format!(
156 "Scanning for code smells in {}{}...",
157 self.path.display(),
158 if self.deep { " (deep analysis)" } else { "" }
159 ));
160
161 let report = if self.deep {
163 analyze_smells_aggregated(
164 &self.path,
165 self.threshold.into(),
166 self.smell_type.map(|s| s.into()),
167 self.suggest,
168 )?
169 } else {
170 detect_smells(
171 &self.path,
172 self.threshold.into(),
173 self.smell_type.map(|s| s.into()),
174 self.suggest,
175 )?
176 };
177
178 if writer.is_text() {
180 let text = format_smells_text(&report);
181 writer.write_text(&text)?;
182 } else {
183 writer.write(&report)?;
184 }
185
186 Ok(())
187 }
188}