···11+# Cyclomatic Complexity
22+33+## What is Cyclomatic Complexity?
44+55+Cyclomatic Complexity (CC), introduced by Thomas McCabe in 1976, measures the number of independent paths through a program's source code. It provides a quantitative measure of code complexity.
66+77+## How It Works
88+99+Mccabre uses a simplified formula:
1010+1111+`CC = (number of decision points) + 1`
1212+1313+### Decision Points
1414+1515+A decision point is any control flow statement that creates a branch:
1616+1717+- `if`, `else if`
1818+- `while`, `for`, `loop`
1919+- `switch`, `match`, `case`
2020+- `catch`
2121+- Logical operators: `&&`, `||`
2222+- Ternary operator: `?`
2323+2424+### Example
2525+2626+```javascript
2727+function checkUser(user) { // CC starts at 1
2828+ if (!user) { // +1 = 2
2929+ return false;
3030+ }
3131+3232+ if (user.age > 18 && user.verified) { // +1 (if) +1 (&&) = 4
3333+ return true;
3434+ }
3535+3636+ return false;
3737+}
3838+// Total CC = 4
3939+```
4040+4141+## Interpretation
4242+4343+| CC Range | Risk Level | Recommendation |
4444+|----------|-----------|----------------|
4545+| 1-10 | Low | Simple, easy to test |
4646+| 11-20 | Moderate | Consider refactoring |
4747+| 21-50 | High | Should refactor |
4848+| 50+ | Very High | Urgent refactoring needed |
4949+5050+## Why It Matters
5151+5252+### Testing Complexity
5353+5454+Higher CC means:
5555+5656+- More test cases needed for full coverage
5757+- Higher chance of bugs
5858+- Harder to understand and maintain
5959+6060+A function with CC=10 requires at least 10 test cases to cover all paths.
6161+6262+### Maintenance Burden
6363+6464+Complex functions are:
6565+6666+- Harder to modify without introducing bugs
6767+- More difficult for new developers to understand
6868+- More prone to subtle edge cases
6969+7070+## Reducing Complexity
7171+7272+### Extract Methods
7373+7474+**Before (CC=8):**
7575+7676+```javascript
7777+function processOrder(order) {
7878+ if (!order.id) throw new Error("No ID");
7979+ if (order.status === "cancelled") return null;
8080+ if (order.items.length === 0) throw new Error("No items");
8181+8282+ let total = 0;
8383+ for (let item of order.items) {
8484+ if (item.price && item.quantity) {
8585+ total += item.price * item.quantity;
8686+ }
8787+ }
8888+8989+ return total;
9090+}
9191+```
9292+9393+**After (CC=3 + 3 = 6 total):**
9494+9595+```javascript
9696+function processOrder(order) { // CC=3
9797+ validateOrder(order);
9898+ return calculateTotal(order);
9999+}
100100+101101+function validateOrder(order) { // CC=3
102102+ if (!order.id) throw new Error("No ID");
103103+ if (order.status === "cancelled") return null;
104104+ if (order.items.length === 0) throw new Error("No items");
105105+}
106106+107107+function calculateTotal(order) { // CC=2
108108+ let total = 0;
109109+ for (let item of order.items) {
110110+ if (item.price && item.quantity) {
111111+ total += item.price * item.quantity;
112112+ }
113113+ }
114114+ return total;
115115+}
116116+```
117117+118118+### Use Early Returns
119119+120120+**Before:**
121121+122122+```rust
123123+fn check(x: i32) -> bool { // CC=3
124124+ let mut result = false;
125125+ if x > 0 {
126126+ if x < 100 {
127127+ result = true;
128128+ }
129129+ }
130130+ result
131131+}
132132+```
133133+134134+**After:**
135135+136136+```rust
137137+fn check(x: i32) -> bool { // CC=3 (same but cleaner)
138138+ if x <= 0 { return false; }
139139+ if x >= 100 { return false; }
140140+ true
141141+}
142142+```
143143+144144+### Replace Complex Conditions
145145+146146+**Before:**
147147+148148+```javascript
149149+if ((user.role === "admin" || user.role === "moderator") &&
150150+ user.active && !user.suspended) { // CC contribution: 4
151151+ // ...
152152+}
153153+```
154154+155155+**After:**
156156+157157+```javascript
158158+function canModerate(user) { // CC=3
159159+ const isModerator = user.role === "admin" || user.role === "moderator";
160160+ return isModerator && user.active && !user.suspended;
161161+}
162162+163163+if (canModerate(user)) { // CC=1
164164+ // ...
165165+}
166166+```
167167+168168+## Using with Mccabre
169169+170170+### Check Specific Files
171171+172172+```bash
173173+mccabre complexity src/complex.js
174174+```
175175+176176+### Set Custom Threshold
177177+178178+```bash
179179+mccabre complexity . --threshold 15
180180+```
181181+182182+### JSON Output for CI
183183+184184+```bash
185185+mccabre complexity . --json | jq '.files[] | select(.cyclomatic.file_complexity > 20)'
186186+```
187187+188188+## References
189189+190190+- [McCabe (1976): "A Complexity Measure"](https://www.literateprogramming.com/mccabe.pdf)
191191+- [NIST Special Publication 500-235](https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication500-235.pdf)
192192+193193+## See Also
194194+195195+- [Lines of Code](./lines-of-code.md)
196196+- [Clone Detection](./clone-detection.md)
197197+- [CLI Reference](./cli-reference.md)
+284
docs/src/examples.md
···11+# Example Usage
22+33+This page demonstrates common Mccabre workflows with real examples.
44+55+## Example Files
66+77+The `examples/` directory contains sample files demonstrating different issues:
88+99+- **complex.js** - High cyclomatic complexity
1010+- **long.py** - Many lines of code with comments
1111+- **not_dry.go** - Duplicated code (clones)
1212+1313+## Analyzing the Examples
1414+1515+### Full Analysis
1616+1717+```bash
1818+mccabre analyze examples/
1919+```
2020+2121+**Output:**
2222+2323+```text
2424+================================================================================
2525+MCCABRE CODE ANALYSIS REPORT
2626+================================================================================
2727+2828+SUMMARY
2929+--------------------------------------------------------------------------------
3030+Total files analyzed: 3
3131+Total physical LOC: 215
3232+Total logical LOC: 165
3333+Average complexity: 10.33
3434+Maximum complexity: 18
3535+High complexity files: 1
3636+Clone groups detected: 2
3737+3838+FILE METRICS
3939+--------------------------------------------------------------------------------
4040+FILE: examples/complex.js
4141+ Cyclomatic Complexity: 18 (moderate)
4242+ Physical LOC: 49
4343+ Logical LOC: 42
4444+ Comment lines: 2
4545+ Blank lines: 5
4646+4747+FILE: examples/long.py
4848+ Cyclomatic Complexity: 8 (low)
4949+ Physical LOC: 95
5050+ Logical LOC: 62
5151+ Comment lines: 18
5252+ Blank lines: 15
5353+5454+FILE: examples/not_dry.go
5555+ Cyclomatic Complexity: 6 (low)
5656+ Physical LOC: 71
5757+ Logical LOC: 61
5858+ Comment lines: 5
5959+ Blank lines: 5
6060+6161+DETECTED CLONES
6262+--------------------------------------------------------------------------------
6363+Clone Group #1 (length: 30 tokens, 3 occurrences)
6464+ - examples/not_dry.go:12-26
6565+ - examples/not_dry.go:30-44
6666+ - examples/not_dry.go:48-62
6767+```
6868+6969+### Complexity Only
7070+7171+```bash
7272+mccabre complexity examples/complex.js
7373+```
7474+7575+Shows that `complex.js` has high cyclomatic complexity due to many conditional branches.
7676+7777+### Clone Detection Only
7878+7979+```bash
8080+mccabre clones examples/not_dry.go
8181+```
8282+8383+Identifies the three nearly-identical functions in `not_dry.go`.
8484+8585+## Real-World Scenarios
8686+8787+### Scenario 1: Pre-Commit Check
8888+8989+Ensure code quality before committing:
9090+9191+```bash
9292+#!/bin/sh
9393+# .git/hooks/pre-commit
9494+9595+echo "Checking code complexity..."
9696+9797+# Get list of staged Rust files
9898+FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.rs$')
9999+100100+if [ -n "$FILES" ]; then
101101+ mccabre complexity $FILES --threshold 15
102102+ if [ $? -ne 0 ]; then
103103+ echo "❌ Complexity check failed!"
104104+ exit 1
105105+ fi
106106+fi
107107+108108+echo "✅ Complexity check passed!"
109109+```
110110+111111+### Scenario 2: Finding Refactoring Targets
112112+113113+Combine complexity and clone detection:
114114+115115+```bash
116116+# Find high-complexity files
117117+echo "=== High Complexity Files ==="
118118+mccabre complexity src/ --json | \
119119+ jq -r '.files[] | select(.cyclomatic.file_complexity > 15) | .path'
120120+121121+# Find duplicated code
122122+echo "\n=== Code Clones ==="
123123+mccabre clones src/ --min-tokens 25
124124+```
125125+126126+Then refactor the flagged files.
127127+128128+### Scenario 3: Tracking Technical Debt
129129+130130+Weekly complexity tracking:
131131+132132+```bash
133133+#!/bin/bash
134134+# weekly-report.sh
135135+136136+DATE=$(date +%Y-%m-%d)
137137+REPORT_DIR="reports"
138138+139139+mkdir -p "$REPORT_DIR"
140140+141141+# Generate report
142142+mccabre analyze src/ --json > "$REPORT_DIR/report-$DATE.json"
143143+144144+# Extract key metrics
145145+echo "Complexity Report - $DATE"
146146+jq '.summary' "$REPORT_DIR/report-$DATE.json"
147147+148148+# Compare with last week
149149+LAST_WEEK=$(ls -t $REPORT_DIR/report-*.json | sed -n 2p)
150150+if [ -n "$LAST_WEEK" ]; then
151151+ echo "\nChange from last week:"
152152+ jq -s '.[1].summary.avg_complexity - .[0].summary.avg_complexity' \
153153+ "$LAST_WEEK" "$REPORT_DIR/report-$DATE.json"
154154+fi
155155+```
156156+157157+### Scenario 5: Code Review Automation
158158+159159+Automatically comment on PRs with complexity issues:
160160+161161+```bash
162162+#!/bin/bash
163163+# pr-comment.sh
164164+165165+# Run analysis
166166+mccabre analyze src/ --json > complexity.json
167167+168168+# Extract high complexity files
169169+HIGH_COMPLEXITY=$(jq -r '.files[] | select(.cyclomatic.file_complexity > 15) |
170170+ "- `\(.path)`: Complexity \(.cyclomatic.file_complexity)"' complexity.json)
171171+172172+if [ -n "$HIGH_COMPLEXITY" ]; then
173173+ # Post comment to GitHub PR (requires gh CLI)
174174+ gh pr comment --body "## ⚠️ Complexity Warning
175175+176176+Files with high complexity:
177177+$HIGH_COMPLEXITY
178178+179179+Consider refactoring before merging."
180180+fi
181181+```
182182+183183+### Scenario 5: Compare Branches
184184+185185+Compare complexity between branches:
186186+187187+```bash
188188+#!/bin/bash
189189+# compare-branches.sh
190190+191191+MAIN_BRANCH="main"
192192+FEATURE_BRANCH=$(git branch --show-current)
193193+194194+# Analyze main
195195+git checkout "$MAIN_BRANCH"
196196+mccabre analyze src/ --json > /tmp/main-complexity.json
197197+198198+# Analyze feature
199199+git checkout "$FEATURE_BRANCH"
200200+mccabre analyze src/ --json > /tmp/feature-complexity.json
201201+202202+# Compare
203203+echo "=== Complexity Comparison ==="
204204+echo "Main branch avg: $(jq '.summary.avg_complexity' /tmp/main-complexity.json)"
205205+echo "Feature branch avg: $(jq '.summary.avg_complexity' /tmp/feature-complexity.json)"
206206+207207+# Check if complexity increased
208208+MAIN_AVG=$(jq '.summary.avg_complexity' /tmp/main-complexity.json)
209209+FEATURE_AVG=$(jq '.summary.avg_complexity' /tmp/feature-complexity.json)
210210+211211+if (( $(echo "$FEATURE_AVG > $MAIN_AVG * 1.1" | bc -l) )); then
212212+ echo "❌ Complexity increased by more than 10%!"
213213+ exit 1
214214+else
215215+ echo "✅ Complexity is acceptable"
216216+fi
217217+```
218218+219219+## Filtering and Processing
220220+221221+### Find Files Above Threshold
222222+223223+```bash
224224+# JSON output piped to jq
225225+mccabre complexity src/ --json | \
226226+ jq '.files[] | select(.cyclomatic.file_complexity > 10) | .path'
227227+```
228228+229229+### Count Clone Groups
230230+231231+```bash
232232+mccabre clones src/ --json | jq '.clones | length'
233233+```
234234+235235+### Generate HTML
236236+237237+```bash
238238+# Create HTML from JSON
239239+mccabre analyze src/ --json | \
240240+ jq -r '.files[] | "<tr><td>\(.path)</td><td>\(.cyclomatic.file_complexity)</td></tr>"' | \
241241+ (echo "<html><table>" && cat && echo "</table></html>") > report.html
242242+```
243243+244244+### Summary Statistics
245245+246246+```bash
247247+# Extract just the summary
248248+mccabre analyze src/ --json | jq '.summary'
249249+```
250250+251251+## Tips and Tricks
252252+253253+### Incremental Analysis
254254+255255+Analyze only changed files:
256256+257257+```bash
258258+# Files changed in last commit
259259+git diff --name-only HEAD~1 | grep '\.rs$' | xargs mccabre complexity
260260+```
261261+262262+### Watch Mode
263263+264264+Continuously monitor (requires `watch` or `entr`):
265265+266266+```bash
267267+# Using entr
268268+ls src/**/*.rs | entr mccabre complexity src/
269269+```
270270+271271+### Focus on New Code
272272+273273+Analyze only files in your feature branch:
274274+275275+```bash
276276+git diff --name-only main...HEAD | grep '\.rs$' | xargs mccabre analyze
277277+```
278278+279279+## Next Steps
280280+281281+- Read about [Cyclomatic Complexity](./cyclomatic-complexity.md)
282282+- Learn about [Clone Detection](./clone-detection.md)
283283+- Configure [thresholds](./configuration.md)
284284+- Check the [CLI Reference](./cli-reference.md)
+56
docs/src/installation.md
···11+# Installation
22+33+## From Source
44+55+### Prerequisites
66+77+- Rust 1.70 or later
88+- Cargo (comes with Rust)
99+1010+### Build and Install
1111+1212+```bash
1313+# Clone the repository
1414+git clone https://github.com/yourusername/mccabre.git
1515+cd mccabre
1616+1717+# Build and install
1818+cargo install --path crates/cli
1919+```
2020+2121+### Development Build
2222+2323+```bash
2424+# Build in debug mode
2525+cargo build
2626+2727+# Run directly
2828+cargo run --bin mccabre -- analyze examples/
2929+3030+# Run tests
3131+cargo test --quiet
3232+```
3333+3434+## Verifying Installation
3535+3636+After building, verify your installation:
3737+3838+```bash
3939+mccabre --version
4040+4141+mccabre --help
4242+4343+mccabre analyze examples/
4444+```
4545+4646+You should see colored output with complexity metrics and detected clones.
4747+4848+## Uninstall
4949+5050+```bash
5151+cargo uninstall mccabre
5252+```
5353+5454+## Configuration
5555+5656+See [Configuration](./configuration.md) for customizing thresholds and behavior.
+29
docs/src/introduction.md
···11+# Introduction
22+33+**Mccabre** language-agnostic code complexity and clone detection tool designed to help developers identify problematic & repeated code patterns.
44+55+## Features
66+77+- **Cyclomatic Complexity Analysis**: Measure control-flow complexity using McCabe's algorithm
88+- **Lines of Code Metrics**: Count physical, logical, comment, and blank lines
99+- **Clone Detection**: Find duplicated code using Rabin-Karp rolling hash
1010+- **Multi-Language Support**: Rust, JavaScript/TypeScript, Go, Java, and C++
1111+- **Gitignore Aware**: Automatically respects .gitignore files
1212+- **Multiple Output Formats**: Beautiful terminal output or JSON
1313+1414+## Design Philosophy
1515+1616+Mccabre prioritizes:
1717+1818+1. **Speed**: Linear or near-linear performance through tokenization instead of full parsing
1919+2. **Simplicity**: Easy to use with sensible defaults
2020+3. **Actionability**: Clear, color-coded output highlighting issues
2121+4. **Extensibility**: Modular design allowing future enhancements
2222+2323+## Limitations
2424+2525+- **Token-based**: Function detection is heuristic-based and may miss some functions
2626+- **Language Support**: Currently supports C-style languages; Python coming soon
2727+- **Clone Detection**: Finds exact token matches, not semantic equivalence (yet)
2828+2929+See the [Quick Start](./quickstart.md) guide to begin using Mccabre.
+193
docs/src/lines-of-code.md
···11+# Lines of Code (LOC)
22+33+## Overview
44+55+Lines of Code (LOC) is a fundamental software metric that measures the size of a codebase. Mccabre provides several LOC variants to give you a complete picture.
66+77+## Metrics Provided
88+99+### Physical LOC
1010+1111+Total number of lines in the file, including everything.
1212+1313+```rust
1414+fn hello() { // Line 1
1515+1616+1717+ println!("Hi"); // Line 4
1818+} // Line 5
1919+// Physical LOC = 5
2020+```
2121+2222+### Logical LOC
2323+2424+Non-blank, non-comment lines that contain actual code.
2525+2626+```rust
2727+fn hello() { // Logical
2828+ // This is a comment (not counted)
2929+3030+ println!("Hi"); // Logical
3131+} // Logical
3232+// Logical LOC = 3
3333+```
3434+3535+### Comment Lines
3636+3737+Lines that contain comments (single-line or multi-line).
3838+3939+```rust
4040+// This is counted // Comment line
4141+/* This too */ // Comment line
4242+let x = 5; // inline // Code line (code takes precedence)
4343+```
4444+4545+### Blank Lines
4646+4747+Lines that contain only whitespace.
4848+4949+## Why LOC Matters
5050+5151+### Productivity Tracking
5252+5353+- Monitor codebase growth over time
5454+- Estimate project size
5555+- Compare different implementations
5656+5757+### Maintenance Effort
5858+5959+Larger codebases generally require:
6060+6161+- More time to understand
6262+- More effort to maintain
6363+- More potential for bugs
6464+6565+### Code Density
6666+6767+Compare logical vs physical LOC:
6868+6969+- High ratio (logical/physical): Dense code, few comments
7070+- Low ratio: Well-commented, more likely to be readable code
7171+7272+## Using LOC with Mccabre
7373+7474+### Basic Usage
7575+7676+```bash
7777+# Analyze LOC for a directory
7878+mccabre analyze src/
7979+8080+# Complexity command also includes LOC
8181+mccabre complexity src/
8282+```
8383+8484+### Sample Output
8585+8686+```text
8787+FILE: src/main.rs
8888+ Cyclomatic Complexity: 5
8989+ Physical LOC: 120
9090+ Logical LOC: 85
9191+ Comment lines: 25
9292+ Blank lines: 10
9393+```
9494+9595+### JSON
9696+9797+```bash
9898+mccabre analyze src/ --json
9999+```
100100+101101+```json
102102+{
103103+ "files": [
104104+ {
105105+ "path": "src/main.rs",
106106+ "loc": {
107107+ "physical": 120,
108108+ "logical": 85,
109109+ "comments": 25,
110110+ "blank": 10
111111+ }
112112+ }
113113+ ]
114114+}
115115+```
116116+117117+## Interpreting Results
118118+119119+### Healthy Ratios
120120+121121+**Comment Ratio**: `comments / logical`
122122+123123+- 0.1-0.3 (10-30%): Generally good
124124+- <0.05: Likely under-commented
125125+- >0.5: Possibly over-commented or tutorial code
126126+127127+**Code Density**: `logical / physical`
128128+129129+- 0.6-0.8: Good balance
130130+- <0.5: Many blank lines/comments (verbose)
131131+- >0.9: Very dense (potentially hard to read)
132132+133133+## LOC Limitations
134134+135135+### Not a Quality Metric
136136+137137+More LOC doesn't mean:
138138+139139+- ✗ Better code
140140+- ✗ More features
141141+- ✗ More value
142142+143143+### Context Matters
144144+145145+Compare LOC only within similar contexts:
146146+147147+- Same language
148148+- Same problem domain
149149+- Same team/style
150150+151151+### Generated Code
152152+153153+LOC counts everything, including:
154154+155155+- Auto-generated code
156156+- Vendored dependencies
157157+- Build artifacts
158158+159159+Use `.gitignore` to exclude these (Mccabre respects gitignore).
160160+161161+## Tracking LOC Over Time
162162+163163+### Baseline
164164+165165+```bash
166166+# Create baseline
167167+mccabre analyze src/ --json > baseline.json
168168+```
169169+170170+### Compare
171171+172172+```bash
173173+# Later...
174174+mccabre analyze src/ --json > current.json
175175+176176+# Compare (using jq)
177177+jq '.summary.total_logical_loc' baseline.json
178178+jq '.summary.total_logical_loc' current.json
179179+```
180180+181181+### Visualize Growth
182182+183183+Integrate with your CI to track:
184184+185185+- LOC growth per sprint
186186+- LOC per feature
187187+- Comment ratio trends
188188+189189+## See Also
190190+191191+- [Cyclomatic Complexity](./cyclomatic-complexity.md)
192192+- [Clone Detection](./clone-detection.md)
193193+- [Configuration](./configuration.md)
+83
docs/src/quickstart.md
···11+# Quick Start
22+33+This guide will get you analyzing code in minutes.
44+55+## Basic Usage
66+77+### Analyze Everything
88+99+Run a full analysis on a directory:
1010+1111+```bash
1212+mccabre analyze ./src
1313+```
1414+1515+This will show:
1616+1717+- Cyclomatic complexity per file
1818+- Lines of code metrics
1919+- Detected code clones
2020+2121+### Complexity Only
2222+2323+To check only complexity metrics:
2424+2525+```bash
2626+mccabre complexity ./src
2727+```
2828+2929+### Clone Detection Only
3030+3131+To find duplicated code:
3232+3333+```bash
3434+mccabre clones ./src
3535+```
3636+3737+## Understanding the Output
3838+3939+### Terminal Output
4040+4141+Mccabre uses colors to highlight issues:
4242+4343+- **Green**: Low complexity (1-10)
4444+- **Yellow**: Moderate complexity (11-20)
4545+- **Red**: High complexity (21+)
4646+4747+Example output:
4848+4949+```text
5050+================================================================================
5151+MCCABRE CODE ANALYSIS REPORT
5252+================================================================================
5353+5454+SUMMARY
5555+--------------------------------------------------------------------------------
5656+Total files analyzed: 5
5757+Total physical LOC: 450
5858+Total logical LOC: 320
5959+Average complexity: 8.50
6060+Maximum complexity: 18
6161+High complexity files: 2
6262+Clone groups detected: 3
6363+6464+FILE METRICS
6565+--------------------------------------------------------------------------------
6666+FILE: src/utils.rs
6767+ Cyclomatic Complexity: 5 (low)
6868+ Physical LOC: 45
6969+ Logical LOC: 32
7070+```
7171+7272+### JSON
7373+7474+```bash
7575+mccabre analyze ./src --json > report.json
7676+```
7777+7878+## Next Steps
7979+8080+- Learn about [Cyclomatic Complexity](./cyclomatic-complexity.md)
8181+- Understand [Clone Detection](./clone-detection.md)
8282+- Configure [thresholds](./configuration.md)
8383+- See more [examples](./examples.md)
+48
examples/complex.js
···11+// Example of high cyclomatic complexity
22+function processUserData(user, options) {
33+ if (!user) {
44+ throw new Error("User required");
55+ }
66+77+ if (user.age < 18 && !options.allowMinors) {
88+ return { error: "User too young" };
99+ }
1010+1111+ if (user.country === "US" || user.country === "CA") {
1212+ if (user.state && user.state.length === 2) {
1313+ console.log("North American user");
1414+ }
1515+ } else if (user.country === "UK" || user.country === "IE") {
1616+ console.log("European user");
1717+ }
1818+1919+ const result = {};
2020+2121+ if (options.includeEmail && user.email) {
2222+ result.email = user.email.toLowerCase();
2323+ }
2424+2525+ if (options.includePhone && user.phone) {
2626+ result.phone = user.phone.replace(/\D/g, '');
2727+ }
2828+2929+ if (user.premium || (user.credits && user.credits > 100)) {
3030+ result.tier = "premium";
3131+ } else if (user.credits && user.credits > 10) {
3232+ result.tier = "standard";
3333+ } else {
3434+ result.tier = "basic";
3535+ }
3636+3737+ for (let i = 0; i < user.preferences.length; i++) {
3838+ const pref = user.preferences[i];
3939+ if (pref.enabled && pref.value !== null) {
4040+ result.preferences = result.preferences || [];
4141+ result.preferences.push(pref);
4242+ }
4343+ }
4444+4545+ return result;
4646+}
4747+4848+// Cyclomatic complexity: ~15-20
+97
examples/long.py
···11+#!/usr/bin/env python3
22+"""
33+Example Python file with many lines of code
44+Demonstrates LOC counting with comments and blank lines
55+"""
66+77+import sys
88+import os
99+from typing import List, Dict, Optional
1010+1111+1212+class DataProcessor:
1313+ """Process data with various transformations"""
1414+1515+ def __init__(self, config: Dict):
1616+ self.config = config
1717+ self.data = []
1818+ self.results = {}
1919+2020+ def load_data(self, filepath: str) -> bool:
2121+ """Load data from a file"""
2222+ try:
2323+ with open(filepath, 'r') as f:
2424+ self.data = [line.strip() for line in f]
2525+ return True
2626+ except FileNotFoundError:
2727+ print(f"File not found: {filepath}")
2828+ return False
2929+3030+ def process(self) -> List[str]:
3131+ """Process the loaded data"""
3232+ results = []
3333+3434+ for item in self.data:
3535+ # Skip empty lines
3636+ if not item:
3737+ continue
3838+3939+ # Transform the item
4040+ transformed = self._transform(item)
4141+4242+ # Validate
4343+ if self._validate(transformed):
4444+ results.append(transformed)
4545+4646+ return results
4747+4848+ def _transform(self, item: str) -> str:
4949+ """Transform a single item"""
5050+ # Convert to lowercase
5151+ item = item.lower()
5252+5353+ # Remove special characters
5454+ item = ''.join(c for c in item if c.isalnum() or c.isspace())
5555+5656+ # Trim whitespace
5757+ item = item.strip()
5858+5959+ return item
6060+6161+ def _validate(self, item: str) -> bool:
6262+ """Validate an item"""
6363+ if len(item) < 3:
6464+ return False
6565+6666+ if not any(c.isalpha() for c in item):
6767+ return False
6868+6969+ return True
7070+7171+ def save_results(self, output_path: str) -> None:
7272+ """Save processed results"""
7373+ with open(output_path, 'w') as f:
7474+ for item in self.results:
7575+ f.write(f"{item}\n")
7676+7777+7878+def main():
7979+ """Main entry point"""
8080+ if len(sys.argv) < 2:
8181+ print("Usage: python long.py <input_file>")
8282+ sys.exit(1)
8383+8484+ processor = DataProcessor({"strict": True})
8585+ processor.load_data(sys.argv[1])
8686+ results = processor.process()
8787+8888+ print(f"Processed {len(results)} items")
8989+9090+9191+if __name__ == "__main__":
9292+ main()
9393+9494+# Physical LOC: ~95
9595+# Logical LOC: ~60
9696+# Comment lines: ~15
9797+# Blank lines: ~20
+85
examples/not_dry.go
···11+package main
22+33+import (
44+ "fmt"
55+ "strings"
66+)
77+88+// Example demonstrating code duplication (clones)
99+// Multiple functions have similar logic
1010+1111+func processUserInput(input string) string {
1212+ // Trim and validate input
1313+ trimmed := strings.TrimSpace(input)
1414+ if len(trimmed) == 0 {
1515+ return ""
1616+ }
1717+1818+ // Convert to lowercase
1919+ lower := strings.ToLower(trimmed)
2020+2121+ // Remove special characters
2222+ cleaned := ""
2323+ for _, char := range lower {
2424+ if (char >= 'a' && char <= 'z') || (char >= '0' && char <= '9') || char == ' ' {
2525+ cleaned += string(char)
2626+ }
2727+ }
2828+2929+ return cleaned
3030+}
3131+3232+func processProductName(name string) string {
3333+ // Trim and validate input
3434+ trimmed := strings.TrimSpace(name)
3535+ if len(trimmed) == 0 {
3636+ return ""
3737+ }
3838+3939+ // Convert to lowercase
4040+ lower := strings.ToLower(trimmed)
4141+4242+ // Remove special characters
4343+ cleaned := ""
4444+ for _, char := range lower {
4545+ if (char >= 'a' && char <= 'z') || (char >= '0' && char <= '9') || char == ' ' {
4646+ cleaned += string(char)
4747+ }
4848+ }
4949+5050+ return cleaned
5151+}
5252+5353+func sanitizeFileName(filename string) string {
5454+ // Trim and validate input
5555+ trimmed := strings.TrimSpace(filename)
5656+ if len(trimmed) == 0 {
5757+ return ""
5858+ }
5959+6060+ // Convert to lowercase
6161+ lower := strings.ToLower(trimmed)
6262+6363+ // Remove special characters
6464+ cleaned := ""
6565+ for _, char := range lower {
6666+ if (char >= 'a' && char <= 'z') || (char >= '0' && char <= '9') || char == ' ' {
6767+ cleaned += string(char)
6868+ }
6969+ }
7070+7171+ return cleaned
7272+}
7373+7474+func main() {
7575+ user := processUserInput(" Hello World! ")
7676+ product := processProductName(" Test Product 123 ")
7777+ file := sanitizeFileName(" my_file.txt ")
7878+7979+ fmt.Println(user)
8080+ fmt.Println(product)
8181+ fmt.Println(file)
8282+}
8383+8484+// This file has obvious code duplication across the three functions
8585+// Clone detection should identify the repeated token sequences