oxide_sloc/lib.rs
1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Copyright (C) 2026 Nima Shafie <nimzshafie@gmail.com>
3
4//! # oxide-sloc
5//!
6//! **Cross-platform source line analysis tool** implementing IEEE 1045-1992 SLOC
7//! metrics, unit-test detection, coverage reporting, and CI/CD enforcement — with
8//! a localhost web UI, rich HTML/PDF reports, and deep Git integration.
9//!
10//! ## Overview
11//!
12//! `oxide-sloc` is a binary crate — its primary interface is the `oxide-sloc`
13//! executable. All analytical logic lives in focused library crates published
14//! separately on crates.io for programmatic use:
15//!
16//! | Crate | Purpose |
17//! |---|---|
18//! | [`sloc-config`](https://docs.rs/sloc-config) | Configuration schema and TOML parsing |
19//! | [`sloc-languages`](https://docs.rs/sloc-languages) | Language detection and lexical line analyzers |
20//! | [`sloc-core`](https://docs.rs/sloc-core) | File discovery, decoding, and aggregation engine |
21//! | [`sloc-report`](https://docs.rs/sloc-report) | HTML rendering and PDF export |
22//! | [`sloc-git`](https://docs.rs/sloc-git) | Git CLI wrappers and webhook parsing |
23//! | [`sloc-web`](https://docs.rs/sloc-web) | Axum web server and form handlers |
24//!
25//! ## Installation
26//!
27//! ```text
28//! cargo install oxide-sloc
29//! ```
30//!
31//! Or clone the repository and run `bash scripts/run.sh` for a fully offline,
32//! no-Rust-required build (all Rust crates and the toolchain are vendored in the
33//! repository — no internet connection or pre-installed Rust required).
34//!
35//! ## Quick Start
36//!
37//! ```text
38//! # Start the localhost web UI → http://127.0.0.1:4317
39//! oxide-sloc
40//!
41//! # Scan a directory, print a summary
42//! oxide-sloc analyze ./my-repo --plain
43//!
44//! # Produce JSON + HTML + PDF reports in one pass
45//! oxide-sloc analyze ./my-repo \
46//! --json-out result.json \
47//! --html-out result.html \
48//! --pdf-out result.pdf
49//!
50//! # Re-render a saved JSON result without re-scanning
51//! oxide-sloc report result.json --html-out result.html --pdf-out result.pdf
52//!
53//! # Compare two saved scans and show the delta
54//! oxide-sloc diff baseline.json current.json
55//!
56//! # Generate a starter config file
57//! oxide-sloc init
58//! ```
59//!
60//! ## Subcommands
61//!
62//! | Subcommand | Description |
63//! |---|---|
64//! | *(none)* | Alias for `serve` — starts the web UI |
65//! | `analyze` | Scan one or more directories and produce metrics |
66//! | `report` | Re-render a saved JSON result as HTML / PDF / CSV / XLSX |
67//! | `diff` | Compare two JSON results and show the delta |
68//! | `serve` | Start the Axum web UI (port 4317 by default) |
69//! | `init` | Write a starter `.oxide-sloc.toml` config file |
70//! | `validate` | Validate config file paths and glob patterns |
71//! | `send` | Deliver a report via SMTP, webhook, Microsoft Teams, or Confluence |
72//! | `git-scan` | Clone a repo and scan it at a specific branch / tag / SHA |
73//! | `git-compare` | Scan two git refs and produce a diff report |
74//! | `watch` | Poll a branch and scan on every new commit |
75//! | `pr-comment` | Post an SLOC diff as a GitHub / GitLab PR comment |
76//! | `completions` | Print a shell completion script (bash / zsh / fish / …) |
77//!
78//! ## Output formats
79//!
80//! All formats are produced by the `analyze` subcommand via output flags.
81//! The `report` subcommand can re-render any of them from a saved JSON result.
82//!
83//! | Flag | Format | Notes |
84//! |---|---|---|
85//! | `--json-out` | JSON | Full `AnalysisRun` struct; machine-readable and round-trippable |
86//! | `--html-out` | HTML | Self-contained, inline CSS, light/dark theme, charts |
87//! | `--pdf-out` | PDF | Rendered via headless Chromium (Chrome/Edge/Brave/Vivaldi/Opera) |
88//! | `--csv-out` | CSV | Per-language summary; suitable for spreadsheets |
89//! | `--xlsx-out` | Excel | Full workbook with per-language and per-file sheets |
90//! | `--plain` | key=value | Machine-readable terminal output for shell scripting |
91//!
92//! ## CI/CD Integration
93//!
94//! ### GitHub Actions / Jenkins — basic scan
95//!
96//! ```text
97//! oxide-sloc analyze . \
98//! --json-out sloc.json \
99//! --html-out sloc.html \
100//! --fail-on-warnings \
101//! --fail-below 1000
102//! ```
103//!
104//! ### SLOC budget enforcement
105//!
106//! Define per-language ceilings in `.oxide-sloc.toml` and add `--fail-on-budget`
107//! to your CI step. Exit code 4 when any threshold is exceeded.
108//!
109//! ```toml
110//! [analysis.budget]
111//! total_max = 200000 # hard ceiling across all languages
112//! rust = 120000
113//! typescript = 60000
114//! ```
115//!
116//! ### Baseline tracking
117//!
118//! ```text
119//! # Save the current scan as a named snapshot
120//! oxide-sloc analyze . --json-out sloc.json --set-baseline main
121//!
122//! # On the next PR — fail if code grew more than 5 %
123//! oxide-sloc analyze . --json-out sloc.json \
124//! --fail-above-baseline main --max-delta-pct 5
125//! ```
126//!
127//! ### PR diff comment (GitHub / GitLab)
128//!
129//! Posts an Adaptive Card–style comment to the pull request with code-line deltas.
130//!
131//! ```text
132//! oxide-sloc pr-comment current.json \
133//! --baseline baseline.json \
134//! --provider github \
135//! --repo owner/repo \
136//! --pr-number 42 \
137//! --token "$GITHUB_TOKEN" \
138//! --report-url "https://ci.example.com/sloc.html"
139//! ```
140//!
141//! ### LCOV coverage overlay
142//!
143//! Attach per-file coverage data produced by `cargo-llvm-cov`, `gcov`, or any
144//! LCOV-compatible tool:
145//!
146//! ```text
147//! oxide-sloc analyze . --coverage-file lcov.info --html-out sloc.html
148//! ```
149//!
150//! ### Exit codes
151//!
152//! | Code | Meaning |
153//! |---|---|
154//! | 0 | Success |
155//! | 1 | Analysis or I/O error |
156//! | 2 | `--fail-on-warnings`: one or more warnings emitted |
157//! | 3 | `--fail-below N`: code lines fell below the threshold |
158//! | 4 | `--fail-on-budget`: a budget ceiling was exceeded |
159//! | 5 | `--fail-above-baseline`: code grew beyond the allowed delta |
160//!
161//! ## Configuration
162//!
163//! Generate a starter config with `oxide-sloc init`, then edit as needed.
164//! The config file is loaded automatically when `.oxide-sloc.toml` exists in the
165//! current directory; pass `--config <path>` to override.
166//!
167//! ```toml
168//! [discovery]
169//! root_paths = ["."]
170//! exclude_globs = ["**/node_modules/**", "**/target/**"]
171//! honor_ignore_files = true # respect .gitignore / .ignore
172//! follow_symlinks = false
173//! submodule_breakdown = false # per-submodule stats in output
174//!
175//! [analysis]
176//! enabled_languages = [] # empty = all 60 languages
177//! mixed_line_policy = "code-only"
178//! python_docstrings_as_comments = true
179//! generated_file_detection = true
180//! vendor_directory_detection = true
181//!
182//! # IEEE 1045-1992 counting parameters
183//! continuation_line_policy = "each-physical-line"
184//! blank_in_block_comment_policy = "count-as-comment"
185//! count_compiler_directives = true
186//!
187//! [reporting]
188//! report_title = "SLOC Report"
189//! theme = "auto" # auto | light | dark
190//! company_name = "Acme Corp" # optional branding
191//! accent_color = "#3b82f6" # optional hex colour
192//!
193//! [web]
194//! bind_address = "127.0.0.1:4317"
195//! server_mode = false # true = bind 0.0.0.0, LAN mode
196//! ```
197//!
198//! ### Named profiles
199//!
200//! Override any config section per invocation with `--profile <name>`:
201//!
202//! ```toml
203//! [profile.frontend]
204//! [profile.frontend.discovery]
205//! root_paths = ["frontend"]
206//! exclude_globs = ["**/node_modules/**", "**/dist/**"]
207//! [profile.frontend.analysis]
208//! enabled_languages = ["TypeScript", "JavaScript", "CSS"]
209//! ```
210//!
211//! ## Web UI
212//!
213//! Running `oxide-sloc` with no arguments (or `oxide-sloc serve`) starts the
214//! Axum web UI at `http://127.0.0.1:4317`.
215//!
216//! - **Step 1** — pick a directory with the native file picker, choose output
217//! formats, configure discovery and analysis options.
218//! - **Step 2** — review the live analysis results, download JSON/HTML/PDF/CSV/XLSX.
219//! - **View Reports** — browse all past runs with trend charts.
220//! - **Compare Scans** — side-by-side delta between any two saved runs.
221//! - **Git Tools** — webhook configuration and repository integration.
222//!
223//! For LAN / multi-user access:
224//!
225//! ```text
226//! oxide-sloc serve --server # binds 0.0.0.0:4317
227//! oxide-sloc serve --bind 0.0.0.0:8080
228//! ```
229//!
230//! ## Delivery (`send` subcommand)
231//!
232//! Ship a saved analysis result to one or more destinations in a single call:
233//!
234//! ```text
235//! oxide-sloc send result.json \
236//! --smtp-to team@example.com \
237//! --smtp-from ci@example.com \
238//! --smtp-host mail.example.com \
239//! --notify-teams "$TEAMS_WEBHOOK_URL" \
240//! --webhook-url "$DASHBOARD_URL"
241//! ```
242//!
243//! | Destination | Flag(s) |
244//! |---|---|
245//! | Email (SMTP/TLS) | `--smtp-to`, `--smtp-from`, `--smtp-host` |
246//! | HTTP webhook | `--webhook-url`, `--webhook-token` |
247//! | Microsoft Teams | `--notify-teams` |
248//! | Confluence | `--confluence-url`, `--confluence-space`, `--confluence-page-title` |
249//!
250//! ## Git operations
251//!
252//! Scan a remote repository at a specific ref without a manual clone:
253//!
254//! ```text
255//! # Scan the v2.0.0 tag of a remote repo
256//! oxide-sloc git-scan https://github.com/org/repo --git-ref v2.0.0 \
257//! --json-out v2.json --html-out v2.html
258//!
259//! # Compare two tags
260//! oxide-sloc git-compare https://github.com/org/repo v1.0.0 v2.0.0 \
261//! --json-out delta.json
262//!
263//! # Watch a branch and scan on every new commit (poll every 5 min)
264//! oxide-sloc watch https://github.com/org/repo \
265//! --branch main --interval 300 --output-dir scans/
266//! ```
267//!
268//! ## Environment variables
269//!
270//! | Variable | Purpose |
271//! |---|---|
272//! | `SLOC_BIND` | Override web bind address (lower priority than `--bind`) |
273//! | `SLOC_API_KEY` | Enable bearer-token auth on the web server |
274//! | `SLOC_ALLOWED_ROOTS` | Colon-separated list of directories the web UI may scan |
275//! | `SLOC_TLS_CERT` / `SLOC_TLS_KEY` | Enable native TLS on the web server |
276//! | `SLOC_BROWSER` | Override the browser binary used for PDF export |
277//! | `SLOC_BROWSER_NOSANDBOX` | Set to `1` to pass `--no-sandbox` (required in Docker) |
278//! | `SLOC_COVERAGE_FILE` | Path to an LCOV `.info` file (same as `--coverage-file`) |
279//! | `SLOC_SMTP_HOST` / `SLOC_SMTP_USER` / `SLOC_SMTP_PASS` | SMTP credentials |
280//! | `SLOC_WEBHOOK_TOKEN` | Bearer token for webhook delivery |
281//! | `SLOC_ALLOW_PRIVATE_WEBHOOK` | Set to `1` to allow HTTP and private-IP webhooks |
282//! | `SLOC_VCS_API_URL` / `SLOC_VCS_REPO` / `SLOC_VCS_TOKEN` | VCS API for `pr-comment` |
283//! | `SLOC_PR_NUMBER` | PR number for `pr-comment` |
284//! | `SLOC_CONFLUENCE_URL` / `SLOC_CONFLUENCE_USER` / `SLOC_CONFLUENCE_TOKEN` | Confluence credentials |
285//! | `SLOC_CONFLUENCE_SPACE` | Confluence space key |
286//! | `RUST_LOG` | Tracing log level (e.g. `RUST_LOG=debug`) |
287//!
288//! ## Supported languages
289//!
290//! 60 languages detected by file extension and shebang:
291//!
292//! Ada, Assembly, Awk, C, C++, C#, Clojure, `CMake`, Crystal, CSS, D, Dart,
293//! Dockerfile, Elixir, Elm, Erlang, F#, Fortran, GLSL/HLSL, Go, GraphQL, Groovy,
294//! Haskell, HCL/Terraform, HTML, Java, JavaScript, Julia, Kotlin, Lisp/Scheme,
295//! Lua, Makefile, Nim, Nix, Objective-C, OCaml, Pascal/Delphi, Perl, PHP,
296//! PowerShell, Protocol Buffers, Python, R, Ruby, Rust, Scala, SCSS/Sass,
297//! Shell (bash/sh/zsh/ksh), Solidity, SQL, Svelte, Swift, Tcl, TypeScript,
298//! Verilog/SystemVerilog, VHDL, Visual Basic, Vue, XML/SVG, and Zig.
299//!
300//! TOML, Markdown, and YAML are intentionally excluded — no meaningful SLOC
301//! metric applies to them.
302//!
303//! Extension-to-language mappings can be overridden per project:
304//!
305//! ```toml
306//! [analysis.extension_overrides]
307//! "h" = "cpp" # treat .h files as C++ instead of C
308//! ```
309//!
310//! ## IEEE 1045-1992 compliance
311//!
312//! The counting engine implements the IEEE 1045-1992 standard. Three parameters
313//! let you choose the counting convention that matches your organisation's policy:
314//!
315//! | Parameter | Values | Default |
316//! |---|---|---|
317//! | `continuation_line_policy` | `each-physical-line` / `collapse-to-logical` | `each-physical-line` |
318//! | `blank_in_block_comment_policy` | `count-as-comment` / `count-as-blank` | `count-as-comment` |
319//! | `count_compiler_directives` | `true` / `false` | `true` |
320//!
321//! CLI flags (`--continuation-line-policy`, `--blank-in-block-comment-policy`,
322//! `--no-count-compiler-directives`) override the config file for a single run.
323//!
324//! ## See also
325//!
326//! - [Repository & full documentation](https://github.com/oxide-sloc/oxide-sloc)
327//! - [Changelog](https://github.com/oxide-sloc/oxide-sloc/releases)
328//! - [`sloc-core`](https://docs.rs/sloc-core) — programmatic analysis API
329//! - [`sloc-config`](https://docs.rs/sloc-config) — configuration schema
330//! - [`sloc-languages`](https://docs.rs/sloc-languages) — per-language analyzers