debtmap/complexity/
nested_callables.rs1use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
11pub struct NestedCallableSummary {
12 pub count: u32,
13 pub cyclomatic: u32,
14 pub cognitive: u32,
15 pub max_nesting: u32,
16}
17
18impl NestedCallableSummary {
19 pub fn is_empty(&self) -> bool {
20 self.count == 0
21 }
22}
23
24pub fn nested_callable_patterns(summary: &NestedCallableSummary) -> Vec<String> {
26 if summary.is_empty() {
27 return Vec::new();
28 }
29
30 vec![
31 format!("nested-functions:count={}", summary.count),
32 format!("nested-functions:cyclomatic={}", summary.cyclomatic),
33 format!("nested-functions:cognitive={}", summary.cognitive),
34 format!("nested-functions:max-nesting={}", summary.max_nesting),
35 ]
36}
37
38pub fn parse_nested_callable_patterns(patterns: Option<&[String]>) -> NestedCallableSummary {
40 let Some(patterns) = patterns else {
41 return NestedCallableSummary::default();
42 };
43
44 let mut summary = NestedCallableSummary::default();
45 for pattern in patterns {
46 if let Some(value) = pattern.strip_prefix("nested-functions:count=") {
47 summary.count = value.parse().unwrap_or(0);
48 } else if let Some(value) = pattern.strip_prefix("nested-functions:cyclomatic=") {
49 summary.cyclomatic = value.parse().unwrap_or(0);
50 } else if let Some(value) = pattern.strip_prefix("nested-functions:cognitive=") {
51 summary.cognitive = value.parse().unwrap_or(0);
52 } else if let Some(value) = pattern.strip_prefix("nested-functions:max-nesting=") {
53 summary.max_nesting = value.parse().unwrap_or(0);
54 }
55 }
56 summary
57}
58
59pub fn scoring_complexity(
61 cyclomatic: u32,
62 cognitive: u32,
63 patterns: Option<&[String]>,
64) -> (u32, u32) {
65 let nested = parse_nested_callable_patterns(patterns);
66 (
67 cyclomatic.saturating_add(nested.cyclomatic),
68 cognitive.saturating_add(nested.cognitive),
69 )
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn round_trips_nested_patterns() {
78 let summary = NestedCallableSummary {
79 count: 2,
80 cyclomatic: 4,
81 cognitive: 2,
82 max_nesting: 1,
83 };
84 let patterns = nested_callable_patterns(&summary);
85 let parsed = parse_nested_callable_patterns(Some(&patterns));
86 assert_eq!(parsed, summary);
87 }
88
89 #[test]
90 fn scoring_complexity_includes_nested_totals() {
91 let patterns = nested_callable_patterns(&NestedCallableSummary {
92 count: 1,
93 cyclomatic: 3,
94 cognitive: 5,
95 max_nesting: 2,
96 });
97 let (cyc, cog) = scoring_complexity(2, 1, Some(&patterns));
98 assert_eq!(cyc, 5);
99 assert_eq!(cog, 6);
100 }
101}