An open API service indexing awesome lists of open source software.

https://github.com/doraemonkeys/sloc-guard

🛡️ High-performance Rust CLI that enforces SLOC limits and directory structure rules to prevent code bloat — unlike counters, sloc-guard enforces them
https://github.com/doraemonkeys/sloc-guard

ci-cd cli code-metrics code-quality developer-tools git linter rust sloc static-analysis

Last synced: about 2 months ago
JSON representation

🛡️ High-performance Rust CLI that enforces SLOC limits and directory structure rules to prevent code bloat — unlike counters, sloc-guard enforces them

Awesome Lists containing this project

README

          

# sloc-guard

**Guard your codebase against complexity.**

`sloc-guard` is a high-performance command-line tool that enforces limits on **Source Lines of Code (SLOC)** and **Directory Structure**. Unlike passive counters that just tell you how big your project is, `sloc-guard` actively prevents code bloat and architectural decay by failing your build when thresholds are exceeded.

[![Crates.io](https://img.shields.io/crates/v/sloc-guard.svg)](https://crates.io/crates/sloc-guard)
[![Downloads](https://img.shields.io/crates/d/sloc-guard.svg)](https://crates.io/crates/sloc-guard)
[![License](https://img.shields.io/crates/l/sloc-guard.svg)](LICENSE)
[![CI](https://github.com/doraemonkeys/sloc-guard/actions/workflows/ci.yml/badge.svg)](https://github.com/doraemonkeys/sloc-guard/actions/workflows/ci.yml)
[![Test Coverage](https://img.shields.io/badge/coverage-90%25%2B-brightgreen.svg)](.github/workflows/ci.yml)
[![Rust](https://img.shields.io/badge/rust-2024%20edition-orange.svg)](https://www.rust-lang.org/)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/doraemonkeys/sloc-guard/pulls)

---

## ❓ Why sloc-guard?

Large files and messy directory structures are silent killers of codebase maintainability. By the time you notice, the damage is done.

**sloc-guard** enforces limits *before* code is merged:
- 🎯 **SLOC Limits** — Prevent files from exceeding line count thresholds (comments and blanks excluded by default)
- 📁 **Structure Guards** — Enforce directory organization (max files/dirs, naming conventions, sibling rules)
- 🔄 **Git-Aware** — Check only changed files (`--diff`, `--staged`) for fast CI integration
- 📊 **Trend Tracking** — Monitor codebase growth over time with historical snapshots

### How is it different from other tools?

| Feature | sloc-guard | cloc | tokei | SCC |
|---------|------------|------|-------|-----|
| **Enforce limits** | ✅ | — | — | — |
| **Directory structure rules** | ✅ | — | — | — |
| **Path-based rule overrides** | ✅ | — | — | — |
| **Git diff mode** | ✅ | — | — | — |
| **Baseline grandfathering** | ✅ | — | — | — |
| **Trend tracking** | ✅ | — | — | — |
| **SARIF output** | ✅ | — | — | — |
| **Remote config inheritance** | ✅ | — | — | — |

> Other tools *count* lines. sloc-guard *enforces* them.

### 🤖 Perfect for AI-Assisted Development

In the age of AI coding assistants, telling AI "don't write spaghetti code" is futile — it has no memory of your preferences. But **hard constraints work**: when sloc-guard fails the build, AI automatically responds by refactoring and splitting code.

Instead of endlessly reminding AI to keep files small, just let it hit the wall and fix itself.

---

## Quick Start

### Installation

**From crates.io:**

```bash
cargo install sloc-guard
```

**From source**

```bash
cargo install --git https://github.com/doraemonkeys/sloc-guard
```

**Or download pre-built binary from [GitHub Releases](https://github.com/doraemonkeys/sloc-guard/releases) and add it to your PATH.**

### 30-Second Setup

```bash
# 1. Initialize config with project type detection
sloc-guard init --detect

# 2. Check your codebase
sloc-guard check

# 3. See project statistics
sloc-guard stats summary
```

That's it! sloc-guard will enforce a 600-line limit per file by default.

- HTML report

```bash
# (Optional) Generate a visual HTML report
sloc-guard check -f html -o output.html
# OR
sloc-guard stats report -f html -o report.html
```

### Configuration

Create `.sloc-guard.toml` in your project root:

```toml
version = "2"

# Optional: inherit from presets or remote configs
# extends = "preset:rust-strict"

[scanner]
gitignore = true # Respect .gitignore (default: true)
exclude = [".git/**", "vendor/**", "dist/**"] # Exclude from scanning entirely

[content]
extensions = ["rs", "go", "py", "js", "ts"] # Files to check
max_lines = 500 # Max lines per file
warn_threshold = 0.8 # Warn at 80% (400 lines)
warn_at = 450 # Absolute threshold (takes precedence over warn_threshold)
skip_comments = true # Don't count comments (default: true)
skip_blank = true # Don't count blank lines (default: true)
exclude = ["**/*_test.go"] # Skip SLOC check (still visible to structure rules)

[structure]
max_files = 30 # Max files per directory
max_dirs = 10 # Max subdirectories
max_depth = 8 # Max nesting depth
warn_threshold = 0.8 # Warn at 80% of limits
warn_files_at = 25 # Absolute threshold (takes precedence)
warn_dirs_at = 8 # Absolute threshold (takes precedence)
count_exclude = ["*.md", ".gitkeep"] # Don't count these toward limits
deny_extensions = [".exe", ".dll", ".bak"] # Forbidden file types
deny_files = [".DS_Store", "Thumbs.db"] # Forbidden files

[baseline]
ratchet = "warn" # warn|auto|strict - violations can only decrease

[trend]
max_entries = 100 # Keep last N snapshots
max_age_days = 90 # Delete older entries
min_interval_secs = 3600 # At most one entry per hour
min_code_delta = 10 # Ignore changes < N lines
auto_snapshot_on_check = false # Auto-record on successful check

[check]
warnings_as_errors = false # Treat warnings as errors
fail_fast = false # Stop on first failure
```

---

## Features

### Content Rules (SLOC Limits)

Override line limits for specific paths (last match wins):

```toml
[[content.rules]]
pattern = "src/generated/**"
max_lines = 2000
reason = "Auto-generated code"

[[content.rules]]
pattern = "**/*_test.rs"
max_lines = 800
skip_comments = false # Override: count comments for tests
reason = "Test files need more space"

# Temporary exemption with expiration
[[content.rules]]
pattern = "src/legacy/parser.rs"
max_lines = 1500
reason = "Refactoring in progress - JIRA-1234"
expires = "2025-06-01"
```

### Structure Rules (Directory Organization)

Override structure limits and enforce naming conventions:

```toml
[[structure.rules]]
scope = "src/components/**"
max_files = 50
file_naming_pattern = "^[A-Z][a-zA-Z0-9]*\\.(tsx|css)$"
allow_extensions = [".tsx", ".css"] # Only these extensions allowed
reason = "React components: PascalCase required"

[[structure.rules]]
scope = "src/features/**"
max_files = -1 # -1 = unlimited
max_depth = 3
relative_depth = true # Depth relative to scope, not project root
siblings = [
{ match = "*.tsx", require = "{stem}.test.tsx" }
]
reason = "Feature modules: max 3 levels deep, every component needs a test"

[[structure.rules]]
scope = "tests/**"
max_files = -1
max_dirs = -1
reason = "No limits for test directories"
```

### Git Integration

Check only what changed for fast CI:

```bash
# Check files changed since main branch
sloc-guard check --diff main

# Check only staged files (pre-commit hooks)
sloc-guard check --staged

# Check specific commit range
sloc-guard check --diff v1.0..v2.0
```

> **Note**: `--diff` compares committed trees only (e.g., `main..HEAD`). Unstaged working directory changes are **not** checked. To catch uncommitted violations, stage your changes and use `--staged`.

### Baseline & Grandfathering

Adopt sloc-guard in existing projects without fixing everything at once:

```bash
# Create baseline from current violations
sloc-guard check --update-baseline

# Violations in baseline are "grandfathered" (pass with note)
sloc-guard check --baseline

# Ratchet mode: violations can only decrease over time
sloc-guard check --baseline --ratchet strict
```

### Stats Subcommands

Analyze your codebase with focused subcommands:

```bash
# Project-level summary
sloc-guard stats summary

# Top files by code lines
sloc-guard stats files --top 10 --sort code

# Language or directory breakdown
sloc-guard stats breakdown # By language (default)
sloc-guard stats breakdown --by dir --depth 2

# Trend comparison with history
sloc-guard stats trend # vs. last entry
sloc-guard stats trend --since 7d # vs. 7 days ago

# View historical snapshots
sloc-guard stats history --limit 20

# Comprehensive report (combines all above)
sloc-guard stats report --format html -o report.html
```

Record a snapshot manually:
```bash
sloc-guard snapshot # Record current state to history
```

Output example (`stats trend --since 7d`):
```
Trend (vs 7 days ago):
Code: +127 lines (+0.4%) ↑
Comments: -12 lines (-0.3%) ↓
Files: +3 ↑

Previous: 2024-12-22 @ abc123f (main)
Current: 2024-12-29 @ def456a (main)
```

### Split Suggestions

When a file exceeds limits, get actionable suggestions:

```bash
sloc-guard check --suggest
```

Output:
```
✗ src/parser.rs: 723 lines (limit: 500)

Split suggestion:
├── parse_expression() (lines 45-180, 135 lines)
├── parse_statement() (lines 182-340, 158 lines)
└── parse_block() (lines 342-520, 178 lines)
```

### Multiple Output Formats

```bash
sloc-guard check --format text # Human-readable (default)
sloc-guard check --format json # Machine-readable
sloc-guard check --format sarif # IDE integration (VS Code, GitHub)
sloc-guard check --format markdown # Documentation
sloc-guard check --format html # Rich reports with charts
```

### Explain Command

Debug which rules apply to a path:

```bash
sloc-guard explain src/components/Button.tsx
```

Output:
```
Path: src/components/Button.tsx
Matched Rule: [[content.rules]] #2
Pattern: src/components/**
Reason: "React components"
Effective Limit: 400 lines
Warn At: 320 lines (80%)
```

### Config Inheritance

Share configuration across projects:

```toml
# Built-in presets: rust-strict, node-strict, python-strict, monorepo-base
extends = "preset:rust-strict"

# Or remote URL with optional integrity check
extends = "https://example.com/team-config.toml"
extends_sha256 = "abc123..."

# Local values override inherited ones
[content]
max_lines = 600

# Arrays are merged (parent + child). Use "$reset" to start fresh:
# exclude = ["$reset", "only-this/**"]
```

### Supported Languages

sloc-guard ships with built-in comment-aware parsing for the following languages:

| Language | Extensions |
|----------|------------|
| Rust | `rs` |
| Go | `go` |
| Python | `py`, `pyi` |
| JavaScript | `js`, `mjs`, `cjs` |
| TypeScript | `ts`, `mts`, `cts`, `tsx` |
| JSX | `jsx` |
| Vue | `vue` |
| C | `c`, `h` |
| C++ | `cpp`, `hpp`, `cc`, `cxx`, `hxx` |
| C# | `cs` |
| Java | `java` |
| Kotlin | `kt`, `kts` |
| Swift | `swift` |
| Dart | `dart` |
| PHP | `php` |
| Ruby | `rb`, `rake` |
| Scala | `scala`, `sc` |
| Lua | `lua` |
| SQL | `sql` |
| Shell | `sh`, `bash`, `zsh` |
| Move | `move` |

Nested block comments are correctly handled for Rust and Swift. Need a language not listed? Define it below.

### Custom Languages

Define comment syntax for unsupported languages:

```toml
[languages.hcl]
extensions = ["tf", "hcl"]
single_line_comments = ["#", "//"]
multi_line_comments = [["/*", "*/"]]
```

---

## CLI Reference

```bash
Usage: sloc-guard [OPTIONS]

Commands:
check Check files against line count thresholds
stats Display statistics without checking thresholds
snapshot Record a statistics snapshot to trend history
init Generate a default configuration file
config Configuration file utilities
explain Explain which rules apply to a path
help Print this message or the help of the given subcommand(s)

Options:
-v, --verbose...
Increase output verbosity (-v, -vv for more)
-q, --quiet
Suppress non-essential output
--color
Control color output [default: auto] [possible values: auto, always, never]
--no-config
Skip loading configuration file
--no-extends
Skip resolving extends in configuration (ignore remote/local inheritance)
--extends-policy
Remote config fetch policy for `extends` URLs. - normal: use cache if within 1h TTL, otherwise fetch (default) - offline: use cached only, error on cache miss - refresh: skip cache, always fetch fresh [default: normal] [possible values: normal, offline, refresh]
-h, --help
Print help (see more with '--help')
-V, --version
Print version
```

### Stats Subcommands

| Subcommand | Description | Key Flags |
|------------|-------------|-----------|
| `summary` | Project totals (files, code, comments, blanks) | `--format` |
| `files` | File list with sorting | `--top`, `--sort`, `--format` |
| `breakdown`| Group by language or directory | `--by`, `--depth`, `--format` |
| `trend` | Delta comparison with history | `--since`, `--format` |
| `history` | List historical snapshots | `--limit`, `--format` |
| `report` | Comprehensive report | `--format`, `-o`, `--exclude-section` |

## Pre-commit Hook

Add to `.pre-commit-config.yaml`:

```yaml
repos:
- repo: https://github.com/doraemonkeys/sloc-guard
rev: master
hooks:
- id: sloc-guard
```

The hook uses `--staged` mode for fast incremental checks.

---

## Advanced Usage

### CI Integration

See [GitHub Action README](.github/action/README.md) for GitHub Actions, GitLab CI, Jenkins, Azure Pipelines, CircleCI examples.

### Docker

```bash
docker run --rm -v $(pwd):/workspace -w /workspace ghcr.io/doraemonkeys/sloc-guard check
```

### Monorepo & More Examples

See [Recipes & Examples](docs/RECIPES.md) for configuration patterns including:
- Monorepo setup
- React/Next.js projects
- Rust/Go/Python projects
- Temporary exemptions
- Remote config inheritance

---

## Performance

sloc-guard is designed for speed:

- **Parallel processing** via Rayon — utilizes all CPU cores
- **Intelligent caching** — skips unchanged files (mtime + size + hash)
- **Git-aware scanning** — respects `.gitignore` by default
- **Incremental mode** — `--diff` and `--staged` check only changed files

## 🛡️ Project Quality

- **90%+ test coverage** enforced by CI
- **Strict Clippy lints** (pedantic + nursery)
- **Comprehensive integration tests**
- **Dependency injection** for testability
- **Well-documented** internal architecture

See [ENGINEERING_GUIDELINES.md](docs/ENGINEERING_GUIDELINES.md) for coding standards.

## Exit Codes

| Code | Meaning |
|------|---------|
| 0 | All checks passed |
| 1 | Threshold exceeded (or warnings in `--strict` mode) |
| 2 | Configuration error |

---

## License

Apache-2.0 — see [LICENSE](LICENSE) for details.