@wbern/obscene 1.3.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -33
- package/dist/cli.js +7 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -76,15 +76,19 @@ Produces **four independent ranking tables**, each scoring files by a different
|
|
|
76
76
|
| Defects × Churn | `defects × churn` | Dfcts, DfDns |
|
|
77
77
|
| Authors × Churn | `authors × churn` | Auth |
|
|
78
78
|
|
|
79
|
+
Plus a **Combined** ranking using [Reciprocal Rank Fusion](https://doi.org/10.1145/1571941.1572114) (RRF) across all dimensions — files appearing near the top of multiple rankings score highest.
|
|
80
|
+
|
|
79
81
|
Each table has its own tier assignment by cumulative score distribution:
|
|
80
82
|
|
|
81
83
|
| Tier | Range | Meaning |
|
|
82
84
|
|------|-------|---------|
|
|
83
|
-
| **
|
|
84
|
-
| **
|
|
85
|
-
| **
|
|
85
|
+
| 🔥 **hot** | top 50% of total score | Highest churn × metric load |
|
|
86
|
+
| ☀️ **warm** | next 30% (50–80%) | Moderate load |
|
|
87
|
+
| 🧊 **cool** | bottom 20% | Low load |
|
|
88
|
+
|
|
89
|
+
Tiers are relative to THIS codebase, not absolute quality grades. A "hot" file is under heavy load, not necessarily broken.
|
|
86
90
|
|
|
87
|
-
A file may rank high in one dimension (e.g. complexity) but low in another (e.g. authors).
|
|
91
|
+
A file may rank high in one dimension (e.g. complexity) but low in another (e.g. authors). Rankings with insufficient data are skipped with an explanation (e.g. defects ranking requires 5+ `fix:` commits across 3+ files). Bot authors (`[bot]` suffix) are filtered automatically.
|
|
88
92
|
|
|
89
93
|
### `obscene coupling`
|
|
90
94
|
|
|
@@ -110,7 +114,7 @@ Per-file complexity without churn. Useful for raw complexity distribution.
|
|
|
110
114
|
| `--months <n>` | `3` | Churn window in months |
|
|
111
115
|
| `--format <type>` | `json` | `json` or `table` |
|
|
112
116
|
| `--min-cochanges <n>` | `2` | Minimum shared commits (coupling only) |
|
|
113
|
-
| `--exclude <patterns...>` | — | Additional exclusion patterns |
|
|
117
|
+
| `--exclude <patterns...>` | — | Additional exclusion patterns (also reads `.obsignore` / `.obsceneignore`) |
|
|
114
118
|
|
|
115
119
|
## Metrics
|
|
116
120
|
|
|
@@ -146,7 +150,7 @@ Maximum indentation level (tab stops) in the file. Deep nesting correlates with
|
|
|
146
150
|
|
|
147
151
|
#### Unique authors (`Auth`)
|
|
148
152
|
|
|
149
|
-
Number of distinct git authors who committed to the file within the churn window. Files touched by many authors may lack clear ownership and accumulate inconsistent patterns. Kamei et al. (2013) found developer count to be a significant predictor of defect-introducing changes.
|
|
153
|
+
Number of distinct git authors who committed to the file within the churn window. Bot authors (names ending in `[bot]`, e.g. `dependabot[bot]`) are excluded automatically. Files touched by many authors may lack clear ownership and accumulate inconsistent patterns. Kamei et al. (2013) found developer count to be a significant predictor of defect-introducing changes.
|
|
150
154
|
|
|
151
155
|
### Coupling metrics
|
|
152
156
|
|
|
@@ -168,38 +172,55 @@ Cumulative score distribution bucket:
|
|
|
168
172
|
|
|
169
173
|
| Tier | Range | Meaning |
|
|
170
174
|
|------|-------|---------|
|
|
171
|
-
| **
|
|
172
|
-
| **
|
|
173
|
-
| **
|
|
175
|
+
| 🔥 **hot** | top 50% of total score | Highest coupling load |
|
|
176
|
+
| ☀️ **warm** | next 30% (50–80%) | Moderate coupling |
|
|
177
|
+
| 🧊 **cool** | bottom 20% | Low coupling |
|
|
174
178
|
|
|
175
179
|
## Example output
|
|
176
180
|
|
|
177
181
|
```
|
|
178
182
|
Hotspots — 3 months churn window
|
|
179
183
|
|
|
180
|
-
|
|
181
|
-
|
|
184
|
+
🧬 COMPLEXITY × 🔄 CHURN — Total score: 35,452
|
|
185
|
+
complexity × churn. Complex code that changes often poses maintenance risk.
|
|
186
|
+
Tiers: 3 HOT, 13 WARM, 194 COOL
|
|
182
187
|
Showing: 5 of 210
|
|
183
188
|
|
|
184
189
|
File Score % Churn Cmplx Dens Tier
|
|
185
190
|
──────────────────────────────────────────────────────────────────────────────────────────────────
|
|
186
|
-
src/utils/effect-generator.ts 8,296 23.4 68 122 0.12
|
|
187
|
-
src/services/game-engine.ts 4,284 12.1 51 84 0.09
|
|
188
|
-
src/components/board-renderer.tsx 2,940 8.3 42 70 0.11
|
|
189
|
-
src/hooks/use-game-state.ts 1,320 3.7 33 40 0.08
|
|
190
|
-
src/utils/move-validator.ts 945 2.7 27 35 0.06
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
191
|
+
src/utils/effect-generator.ts 8,296 23.4 68 122 0.12 🔥 HOT
|
|
192
|
+
src/services/game-engine.ts 4,284 12.1 51 84 0.09 🔥 HOT
|
|
193
|
+
src/components/board-renderer.tsx 2,940 8.3 42 70 0.11 🔥 HOT
|
|
194
|
+
src/hooks/use-game-state.ts 1,320 3.7 33 40 0.08 ☀️ WARM
|
|
195
|
+
src/utils/move-validator.ts 945 2.7 27 35 0.06 ☀️ WARM
|
|
196
|
+
|
|
197
|
+
· · ·
|
|
198
|
+
|
|
199
|
+
📏 NESTING × 🔄 CHURN — Total score: 1,284
|
|
200
|
+
maxNesting × churn. Deeply nested code that changes often is harder to reason about.
|
|
201
|
+
Tiers: 2 HOT, 5 WARM, 203 COOL
|
|
194
202
|
Showing: 5 of 210
|
|
195
203
|
|
|
196
204
|
File Score % Churn Nest Tier
|
|
197
205
|
────────────────────────────────────────────────────────────────────────────────────────
|
|
198
|
-
src/utils/effect-generator.ts 408 31.8 68 6
|
|
199
|
-
src/services/game-engine.ts 255 19.8 51 5
|
|
200
|
-
src/components/board-renderer.tsx 210 16.4 42 5
|
|
201
|
-
src/hooks/use-game-state.ts 99 7.7 33 3
|
|
202
|
-
src/utils/move-validator.ts 54 4.2 27 2
|
|
206
|
+
src/utils/effect-generator.ts 408 31.8 68 6 🔥 HOT
|
|
207
|
+
src/services/game-engine.ts 255 19.8 51 5 🔥 HOT
|
|
208
|
+
src/components/board-renderer.tsx 210 16.4 42 5 ☀️ WARM
|
|
209
|
+
src/hooks/use-game-state.ts 99 7.7 33 3 ☀️ WARM
|
|
210
|
+
src/utils/move-validator.ts 54 4.2 27 2 ☀️ WARM
|
|
211
|
+
|
|
212
|
+
════════════════════════════════════════════════════════════════════════════════════
|
|
213
|
+
★ COMBINED — Total score: 1.2345
|
|
214
|
+
Tiers: 3 HOT, 5 WARM, 202 COOL
|
|
215
|
+
Showing: 5 of 210
|
|
216
|
+
|
|
217
|
+
File Score % Churn Dims Tier
|
|
218
|
+
────────────────────────────────────────────────────────────────────────────────────────
|
|
219
|
+
src/utils/effect-generator.ts 0.2727 22.1 68 4 🔥 HOT
|
|
220
|
+
src/services/game-engine.ts 0.1667 13.5 51 3 🔥 HOT
|
|
221
|
+
src/components/board-renderer.tsx 0.127 10.3 42 3 🔥 HOT
|
|
222
|
+
src/hooks/use-game-state.ts 0.0769 6.2 33 2 ☀️ WARM
|
|
223
|
+
src/utils/move-validator.ts 0.0667 5.4 27 2 ☀️ WARM
|
|
203
224
|
|
|
204
225
|
Score=metric×churn | Tiers are relative to THIS codebase, not absolute quality grades.
|
|
205
226
|
High scores flag review candidates, not bad code — stable complex files (parsers, engines) score high naturally.
|
|
@@ -210,18 +231,20 @@ Docs: https://github.com/wbern/obscene#metrics
|
|
|
210
231
|
|
|
211
232
|
```
|
|
212
233
|
Coupling — 6 months churn window | Min shared: 3 | Total score: 91
|
|
213
|
-
Tiers: 10
|
|
234
|
+
Tiers: 10 HOT, 7 WARM, 7 COOL
|
|
214
235
|
Showing: 5 of 24
|
|
215
236
|
|
|
216
|
-
File 1 File 2 Shared Degree Cmplx
|
|
217
|
-
|
|
218
|
-
…ePlayer/hooks/useChessEffects.ts src/utils/effect-generator.ts 6 46.2% 261
|
|
219
|
-
…ePlayer/hooks/useChessEffects.ts src/utils/pgn-types.ts 6 50.0% 121
|
|
220
|
-
src/test/pgn-fixtures.ts src/utils/pgn-parser.server.ts 5 71.4% 3
|
|
221
|
-
src/test/pgn-fixtures.ts src/utils/effect-generator.ts 4 57.1% 145
|
|
222
|
-
src/test/pgn-fixtures.ts src/utils/pgn-types.ts 4 57.1% 5
|
|
237
|
+
File 1 File 2 Shared Degree Cmplx Tier
|
|
238
|
+
──────────────────────────────────────────────────────────────────────────────────────────────────────
|
|
239
|
+
…ePlayer/hooks/useChessEffects.ts src/utils/effect-generator.ts 6 46.2% 261 🔥 HOT
|
|
240
|
+
…ePlayer/hooks/useChessEffects.ts src/utils/pgn-types.ts 6 50.0% 121 🔥 HOT
|
|
241
|
+
src/test/pgn-fixtures.ts src/utils/pgn-parser.server.ts 5 71.4% 3 🔥 HOT
|
|
242
|
+
src/test/pgn-fixtures.ts src/utils/effect-generator.ts 4 57.1% 145 🔥 HOT
|
|
243
|
+
src/test/pgn-fixtures.ts src/utils/pgn-types.ts 4 57.1% 5 🔥 HOT
|
|
223
244
|
|
|
224
245
|
Shared=co-changed commits | Degree=shared/min(churn)×100 | Cmplx=sum of both files
|
|
246
|
+
Tiers are relative to THIS codebase, not absolute quality grades. High coupling may be intentional and fine.
|
|
247
|
+
Same-directory pairs excluded. Commits touching >20 files skipped. Only cross-directory dependencies shown.
|
|
225
248
|
Docs: https://github.com/wbern/obscene#metrics
|
|
226
249
|
```
|
|
227
250
|
|
|
@@ -231,7 +254,26 @@ Any language [scc supports](https://github.com/boyter/scc#features) — 200+ lan
|
|
|
231
254
|
|
|
232
255
|
## Default exclusions
|
|
233
256
|
|
|
234
|
-
Test
|
|
257
|
+
Test files, lock files, and package manifests are excluded automatically: `*.test.*`, `*.spec.*`, `__tests__/`, `__mocks__/`, `*.stories.*`, `*.d.ts`, `package.json`, `package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`, `bun.lock`, and similar patterns. scc also skips generated files by default (`--no-gen`).
|
|
258
|
+
|
|
259
|
+
## Ignore files
|
|
260
|
+
|
|
261
|
+
Create a `.obsignore` or `.obsceneignore` file in your project root to persist exclusion patterns:
|
|
262
|
+
|
|
263
|
+
```
|
|
264
|
+
# vendored code
|
|
265
|
+
vendor/**
|
|
266
|
+
|
|
267
|
+
# generated API clients
|
|
268
|
+
*.generated.*
|
|
269
|
+
src/api/generated/**
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
- One glob pattern per line (same syntax as `--exclude`)
|
|
273
|
+
- Lines starting with `#` are comments
|
|
274
|
+
- Empty lines are ignored
|
|
275
|
+
- `.obsignore` takes priority if both files exist (they are not merged)
|
|
276
|
+
- CLI `--exclude` patterns are additive on top of ignore file patterns
|
|
235
277
|
|
|
236
278
|
## Why churn x complexity?
|
|
237
279
|
|
package/dist/cli.js
CHANGED
|
@@ -31,7 +31,12 @@ var DEFAULT_EXCLUDES = [
|
|
|
31
31
|
/__tests__\//,
|
|
32
32
|
/__mocks__\//,
|
|
33
33
|
/\.stories\./,
|
|
34
|
-
/\.d\.ts
|
|
34
|
+
/\.d\.ts$/,
|
|
35
|
+
/(?:^|\/)package\.json$/,
|
|
36
|
+
/(?:^|\/)package-lock\.json$/,
|
|
37
|
+
/(?:^|\/)pnpm-lock\.yaml$/,
|
|
38
|
+
/(?:^|\/)yarn\.lock$/,
|
|
39
|
+
/(?:^|\/)bun\.lock$/
|
|
35
40
|
];
|
|
36
41
|
var HOT_CUMULATIVE = 0.5;
|
|
37
42
|
var WARM_CUMULATIVE = 0.8;
|
|
@@ -751,7 +756,7 @@ function formatCompositeTable(output) {
|
|
|
751
756
|
|
|
752
757
|
// src/cli.ts
|
|
753
758
|
var program = new Command();
|
|
754
|
-
program.name("obscene").description("Identify hotspot files \u2014 complex code that changes frequently").version("1.
|
|
759
|
+
program.name("obscene").description("Identify hotspot files \u2014 complex code that changes frequently").version("1.4.0");
|
|
755
760
|
var REPORT_GUIDE = {
|
|
756
761
|
complexity: "Cyclomatic complexity (branch/loop count). NOT a quality judgment \u2014 a 500-line parser will naturally score high. Compare density, not raw values.",
|
|
757
762
|
complexityDensity: "Complexity per line of code. Normalizes for file size. >0.25 suggests dense logic worth reviewing; <0.10 is typical for straightforward code.",
|