use serde::Deserialize;
pub const DEFAULT_MAX_SUPPRESSION_RATIO: f64 = 0.05;
pub const DEFAULT_COMPLEXITY_ENABLED: bool = true;
pub const DEFAULT_MAX_COGNITIVE: usize = 15;
pub const DEFAULT_MAX_CYCLOMATIC: usize = 10;
pub const DEFAULT_MAX_NESTING_DEPTH: usize = 4;
pub const DEFAULT_MAX_FUNCTION_LINES: usize = 60;
pub const DEFAULT_DETECT_MAGIC_NUMBERS: bool = true;
pub const DEFAULT_DETECT_UNSAFE: bool = true;
pub const DEFAULT_DETECT_ERROR_HANDLING: bool = true;
pub const DEFAULT_ALLOW_EXPECT: bool = false;
pub const DEFAULT_DUPLICATES_ENABLED: bool = true;
pub const DEFAULT_DETECT_WILDCARD_IMPORTS: bool = true;
pub const DEFAULT_DETECT_REPEATED_MATCHES: bool = true;
pub const DEFAULT_SIMILARITY_THRESHOLD: f64 = 0.85;
pub const DEFAULT_MIN_TOKENS: usize = 30;
pub const DEFAULT_MIN_LINES: usize = 5;
pub const DEFAULT_MIN_STATEMENTS: usize = 3;
pub const DEFAULT_DETECT_DEAD_CODE: bool = true;
pub const DEFAULT_BOILERPLATE_ENABLED: bool = true;
pub const DEFAULT_SRP_ENABLED: bool = true;
pub const DEFAULT_SRP_SMELL_THRESHOLD: f64 = 0.6;
pub const DEFAULT_SRP_MAX_FIELDS: usize = 12;
pub const DEFAULT_SRP_MAX_METHODS: usize = 20;
pub const DEFAULT_SRP_MAX_FAN_OUT: usize = 10;
pub const DEFAULT_SRP_LCOM4_THRESHOLD: usize = 2;
pub const DEFAULT_SRP_FILE_LENGTH_BASELINE: usize = 300;
pub const DEFAULT_SRP_FILE_LENGTH_CEILING: usize = 800;
pub const DEFAULT_SRP_MAX_INDEPENDENT_CLUSTERS: usize = 2;
pub const DEFAULT_SRP_MIN_CLUSTER_STATEMENTS: usize = 5;
pub const DEFAULT_SRP_MAX_PARAMETERS: usize = 5;
pub const DEFAULT_COUPLING_ENABLED: bool = true;
pub const DEFAULT_CHECK_SDP: bool = true;
pub const DEFAULT_MAX_INSTABILITY: f64 = 0.8;
pub const DEFAULT_MAX_FAN_IN: usize = 15;
pub const DEFAULT_MAX_FAN_OUT_COUPLING: usize = 12;
pub const DEFAULT_STRUCTURAL_ENABLED: bool = true;
pub const DEFAULT_TEST_ENABLED: bool = true;
pub const DEFAULT_QUALITY_WEIGHTS: [f64; 7] = [0.22, 0.18, 0.13, 0.18, 0.09, 0.10, 0.10];
pub const WEIGHT_SUM_TOLERANCE: f64 = 0.001;
#[derive(Debug, Deserialize, Clone)]
#[serde(default, deny_unknown_fields)]
pub struct ComplexityConfig {
pub enabled: bool,
pub max_cognitive: usize,
pub max_cyclomatic: usize,
pub max_nesting_depth: usize,
pub max_function_lines: usize,
pub include_nesting_penalty: bool,
pub detect_magic_numbers: bool,
pub detect_unsafe: bool,
pub detect_error_handling: bool,
pub allow_expect: bool,
pub allowed_magic_numbers: Vec<String>,
}
impl Default for ComplexityConfig {
fn default() -> Self {
Self {
enabled: DEFAULT_COMPLEXITY_ENABLED,
max_cognitive: DEFAULT_MAX_COGNITIVE,
max_cyclomatic: DEFAULT_MAX_CYCLOMATIC,
max_nesting_depth: DEFAULT_MAX_NESTING_DEPTH,
max_function_lines: DEFAULT_MAX_FUNCTION_LINES,
include_nesting_penalty: true,
detect_magic_numbers: DEFAULT_DETECT_MAGIC_NUMBERS,
detect_unsafe: DEFAULT_DETECT_UNSAFE,
detect_error_handling: DEFAULT_DETECT_ERROR_HANDLING,
allow_expect: DEFAULT_ALLOW_EXPECT,
allowed_magic_numbers: vec![
"0".into(),
"1".into(),
"-1".into(),
"2".into(),
"0.0".into(),
"1.0".into(),
],
}
}
}
#[derive(Debug, Deserialize, Clone)]
#[serde(default, deny_unknown_fields)]
pub struct DuplicatesConfig {
pub enabled: bool,
pub similarity_threshold: f64,
pub min_tokens: usize,
pub min_lines: usize,
pub min_statements: usize,
pub ignore_tests: bool,
pub ignore_trait_impls: bool,
pub detect_dead_code: bool,
pub detect_wildcard_imports: bool,
pub detect_repeated_matches: bool,
}
impl Default for DuplicatesConfig {
fn default() -> Self {
Self {
enabled: DEFAULT_DUPLICATES_ENABLED,
similarity_threshold: DEFAULT_SIMILARITY_THRESHOLD,
min_tokens: DEFAULT_MIN_TOKENS,
min_lines: DEFAULT_MIN_LINES,
min_statements: DEFAULT_MIN_STATEMENTS,
ignore_tests: true,
ignore_trait_impls: true,
detect_dead_code: DEFAULT_DETECT_DEAD_CODE,
detect_wildcard_imports: DEFAULT_DETECT_WILDCARD_IMPORTS,
detect_repeated_matches: DEFAULT_DETECT_REPEATED_MATCHES,
}
}
}
#[derive(Debug, Deserialize, Clone)]
#[serde(default, deny_unknown_fields)]
pub struct BoilerplateConfig {
pub enabled: bool,
pub patterns: Vec<String>,
pub suggest_crates: bool,
}
impl Default for BoilerplateConfig {
fn default() -> Self {
Self {
enabled: DEFAULT_BOILERPLATE_ENABLED,
patterns: vec![],
suggest_crates: true,
}
}
}
#[derive(Debug, Deserialize, Clone)]
#[serde(default, deny_unknown_fields)]
pub struct SrpConfig {
pub enabled: bool,
pub smell_threshold: f64,
pub max_fields: usize,
pub max_methods: usize,
pub max_fan_out: usize,
pub lcom4_threshold: usize,
pub weights: [f64; 4],
pub file_length_baseline: usize,
pub file_length_ceiling: usize,
pub max_independent_clusters: usize,
pub min_cluster_statements: usize,
pub max_parameters: usize,
}
impl Default for SrpConfig {
fn default() -> Self {
Self {
enabled: DEFAULT_SRP_ENABLED,
smell_threshold: DEFAULT_SRP_SMELL_THRESHOLD,
max_fields: DEFAULT_SRP_MAX_FIELDS,
max_methods: DEFAULT_SRP_MAX_METHODS,
max_fan_out: DEFAULT_SRP_MAX_FAN_OUT,
lcom4_threshold: DEFAULT_SRP_LCOM4_THRESHOLD,
weights: [0.4, 0.25, 0.15, 0.2],
file_length_baseline: DEFAULT_SRP_FILE_LENGTH_BASELINE,
file_length_ceiling: DEFAULT_SRP_FILE_LENGTH_CEILING,
max_independent_clusters: DEFAULT_SRP_MAX_INDEPENDENT_CLUSTERS,
min_cluster_statements: DEFAULT_SRP_MIN_CLUSTER_STATEMENTS,
max_parameters: DEFAULT_SRP_MAX_PARAMETERS,
}
}
}
#[derive(Debug, Deserialize, Clone)]
#[serde(default, deny_unknown_fields)]
pub struct CouplingConfig {
pub enabled: bool,
pub max_instability: f64,
pub max_fan_in: usize,
pub max_fan_out: usize,
pub check_sdp: bool,
}
impl Default for CouplingConfig {
fn default() -> Self {
Self {
enabled: DEFAULT_COUPLING_ENABLED,
max_instability: DEFAULT_MAX_INSTABILITY,
max_fan_in: DEFAULT_MAX_FAN_IN,
max_fan_out: DEFAULT_MAX_FAN_OUT_COUPLING,
check_sdp: DEFAULT_CHECK_SDP,
}
}
}
#[derive(Debug, Deserialize, Clone)]
#[serde(default, deny_unknown_fields)]
pub struct StructuralConfig {
pub enabled: bool,
pub check_btc: bool,
pub check_slm: bool,
pub check_nms: bool,
pub check_oi: bool,
pub check_sit: bool,
pub check_deh: bool,
pub check_iet: bool,
}
impl Default for StructuralConfig {
fn default() -> Self {
Self {
enabled: DEFAULT_STRUCTURAL_ENABLED,
check_btc: true,
check_slm: true,
check_nms: true,
check_oi: true,
check_sit: true,
check_deh: true,
check_iet: true,
}
}
}
#[derive(Debug, Deserialize, Clone)]
#[serde(default, deny_unknown_fields)]
pub struct TestConfig {
pub enabled: bool,
pub coverage_file: Option<String>,
pub extra_assertion_macros: Vec<String>,
}
impl Default for TestConfig {
fn default() -> Self {
Self {
enabled: DEFAULT_TEST_ENABLED,
coverage_file: None,
extra_assertion_macros: vec![],
}
}
}
#[derive(Debug, Deserialize, Clone)]
#[serde(default, deny_unknown_fields)]
pub struct ReportConfig {
pub aggregation: String,
}
impl Default for ReportConfig {
fn default() -> Self {
Self {
aggregation: "loc_weighted".to_string(),
}
}
}
#[derive(Debug, Deserialize, Clone)]
#[serde(default, deny_unknown_fields)]
pub struct WeightsConfig {
pub iosp: f64,
pub complexity: f64,
pub dry: f64,
pub srp: f64,
pub coupling: f64,
pub test_quality: f64,
pub architecture: f64,
}
impl WeightsConfig {
pub fn as_array(&self) -> [f64; 7] {
[
self.iosp,
self.complexity,
self.dry,
self.srp,
self.coupling,
self.test_quality,
self.architecture,
]
}
}
impl Default for WeightsConfig {
fn default() -> Self {
let [iosp, complexity, dry, srp, coupling, test_quality, architecture] =
DEFAULT_QUALITY_WEIGHTS;
Self {
iosp,
complexity,
dry,
srp,
coupling,
test_quality,
architecture,
}
}
}