Skip to content

Commit dddcfa7

Browse files
committed
feat: classify comment and code line stats
1 parent 3897ecc commit dddcfa7

12 files changed

Lines changed: 551 additions & 87 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
- Parse `.gitignore`, `.ignore`, and `.git/info/exclude` during working-tree scans.
66
- Add `--exclude-tests` to skip well-known test-case paths from aggregate scan analysis.
77
- Replace the linear score deduction with a bounded issue-density curve so noisy large repositories do not collapse to zero.
8-
- Add aggregate commented-line statistics to scan and diff reports.
8+
- Add aggregate code/blank/comment-only/inline-comment line statistics to scan and diff reports, and use code lines for issue-density scoring when available.
99

1010
## 0.0.1 - 2026-06-30
1111

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,11 @@ Detection uses extensions, shebangs, and common manifests such as `go.mod`, `pac
9797

9898
## Aggregate line statistics
9999

100-
Scan JSON includes `comment_lines` and `comment_density_percent` beside existing line totals. The same aggregate fields are reported for `totals`, `by_language`, and `by_module`; diff JSON includes before/after/delta values under `totals_delta`.
100+
Scan JSON includes `lines_scanned`, `blank_lines`, `code_lines`, `comment_lines`, `comment_only_lines`, `inline_comment_lines`, and `comment_density_percent`. The same aggregate fields are reported for `totals`, `by_language`, and `by_module`; diff JSON includes before/after/delta values under `totals_delta`.
101101

102-
Comment detection is lexical and language-aware: it recognizes `//`, `#`, and `/* ... */` style comments where those markers are valid, ignores markers inside quoted strings/raw strings, and never emits per-file locations or source snippets.
102+
`lines_scanned` is physical scanned lines. `code_lines` excludes blank lines and comment-only lines, but keeps lines that contain code plus an inline comment. The score model uses `code_lines` when available and falls back to physical lines for older reports.
103+
104+
Comment detection is lexical and language-aware for supported languages: it recognizes `//`, `#`, `/* ... */`, Rust nested block comments, Ruby `=begin`/`=end`, and standalone Python triple-quoted doc/comment blocks where those forms are valid. It ignores common markers inside quoted strings/raw strings/template literals and JavaScript/TypeScript regex literals, and never emits per-file locations or source snippets.
103105

104106
## Ignore files, test exclusion, and skip policy
105107

@@ -143,7 +145,7 @@ Unknown config fields and trailing JSON values are rejected.
143145
The score is a bounded weighted issue-density signal, not a SonarQube debt rating:
144146

145147
```text
146-
weighted_density_per_kloc = round((errors*10 + warnings*4 + info*1) * 1000 / max(lines_scanned, 1000))
148+
weighted_density_per_kloc = round((errors*10 + warnings*4 + info*1) * 1000 / max(code_lines, 1000))
147149
score = round(100 * 100 / (100 + weighted_density_per_kloc))
148150
```
149151

internal/cli/cli.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -556,10 +556,11 @@ func printScan(stdout io.Writer, scanReport model.ScanReport) error {
556556
fmt.Fprintf(&builder, "Score: %d (%s)\n", scanReport.Score, scanReport.Band)
557557
fmt.Fprintf(&builder, "Issues: %d (errors: %d, warnings: %d, info: %d)\n",
558558
scanReport.Totals.Issues, scanReport.Totals.Errors, scanReport.Totals.Warnings, scanReport.Totals.Info)
559-
fmt.Fprintf(&builder, "Files scanned: %d | Lines scanned: %d | Files skipped: %d\n",
560-
scanReport.Totals.FilesScanned, scanReport.Totals.LinesScanned, scanReport.Totals.FilesSkipped)
561-
fmt.Fprintf(&builder, "Comment lines: %d (%.1f%%)\n",
562-
scanReport.Totals.CommentLines, scanReport.Totals.CommentDensityPercent)
559+
fmt.Fprintf(&builder, "Files scanned: %d | Lines scanned: %d | Code lines: %d | Files skipped: %d\n",
560+
scanReport.Totals.FilesScanned, scanReport.Totals.LinesScanned, scanReport.Totals.CodeLines, scanReport.Totals.FilesSkipped)
561+
fmt.Fprintf(&builder, "Comments: %d lines (%.1f%%) | Comment-only: %d | Inline: %d | Blank: %d\n",
562+
scanReport.Totals.CommentLines, scanReport.Totals.CommentDensityPercent,
563+
scanReport.Totals.CommentOnlyLines, scanReport.Totals.InlineCommentLines, scanReport.Totals.BlankLines)
563564
fmt.Fprintf(&builder, "Languages: %s | Modules: %d (%s)\n",
564565
joinOrNone(scanLanguages(scanReport)), scanModuleCount(scanReport), moduleProfileText(scanReport))
565566
printDuplicationSummary(&builder, scanReport.Duplication)

internal/delta/delta.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@ func compareTotals(base, head model.ScanTotals) model.TotalsDelta {
2828
FilesScanned: countDelta(base.FilesScanned, head.FilesScanned),
2929
FilesSkipped: countDelta(base.FilesSkipped, head.FilesSkipped),
3030
LinesScanned: countDelta(base.LinesScanned, head.LinesScanned),
31+
BlankLines: countDelta(base.BlankLines, head.BlankLines),
32+
CodeLines: countDelta(base.CodeLines, head.CodeLines),
3133
CommentLines: countDelta(base.CommentLines, head.CommentLines),
34+
CommentOnlyLines: countDelta(base.CommentOnlyLines, head.CommentOnlyLines),
35+
InlineCommentLines: countDelta(base.InlineCommentLines, head.InlineCommentLines),
3236
CommentDensityPercent: percentDelta(base.CommentDensityPercent, head.CommentDensityPercent),
3337
Issues: countDelta(base.Issues, head.Issues),
3438
Errors: countDelta(base.Errors, head.Errors),

0 commit comments

Comments
 (0)