stopslop 0.1.2 → 1.0.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/COMPATIBILITY.md +26 -0
- package/README.md +247 -247
- package/context7.json +21 -0
- package/dist/cli.js +10 -19
- package/dist/src.js +0 -0
- package/docs/ci-and-automation.md +100 -0
- package/docs/configuration.md +252 -0
- package/docs/node-api.md +114 -0
- package/docs/score.md +133 -0
- package/docs/thresholds.md +105 -0
- package/llms.txt +25 -0
- package/package.json +56 -8
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Threshold calibration
|
|
2
|
+
|
|
3
|
+
Two lenses on the same corpus:
|
|
4
|
+
|
|
5
|
+
- **Count percentiles** — each entity counts once. "pXX = N" means XX% of
|
|
6
|
+
entities score ≤ N. This is what we use for defaults: a god finding should be
|
|
7
|
+
the worst ~1–5% of entities.
|
|
8
|
+
- **LOC-weighted percentiles** — the Alves/Ypma/Visser (ICSM 2010) methodology:
|
|
9
|
+
each entity weighted by LOC, so "pXX = N" means XX% of *code volume* sits in
|
|
10
|
+
entities ≤ N. Kept for reference; it skews high because large entities are
|
|
11
|
+
both more complex and hold more volume.
|
|
12
|
+
|
|
13
|
+
Corpus: 22 TypeScript repositories, 65,817 analyzed files (tests, fixtures,
|
|
14
|
+
generated and bundled code excluded). The per-repository counts are listed
|
|
15
|
+
below.
|
|
16
|
+
|
|
17
|
+
## Count percentiles (basis for defaults)
|
|
18
|
+
|
|
19
|
+
### Function
|
|
20
|
+
| metric | n | p50 | p75 | p90 | p95 | p99 |
|
|
21
|
+
|---|---|---|---|---|---|---|
|
|
22
|
+
| cognitive complexity | 108102 | 0 | 2 | 7 | 13 | 38 |
|
|
23
|
+
|
|
24
|
+
### Class (≥3 methods)
|
|
25
|
+
| metric | n | p50 | p75 | p90 | p95 | p99 |
|
|
26
|
+
|---|---|---|---|---|---|---|
|
|
27
|
+
| methods | 2940 | 6 | 12 | 23 | 32 | 64 |
|
|
28
|
+
| responsibility groups (≥2) | 2940 | 1 | 1 | 2 | 2 | 4 |
|
|
29
|
+
| Σ cognitive complexity | 2940 | 8 | 24 | 58 | 93 | 207 |
|
|
30
|
+
|
|
31
|
+
### Module (≥5 top-level fns)
|
|
32
|
+
| metric | n | p50 | p75 | p90 | p95 | p99 |
|
|
33
|
+
|---|---|---|---|---|---|---|
|
|
34
|
+
| top-level definitions | 2819 | 8 | 11 | 16 | 22 | 37 |
|
|
35
|
+
| responsibility groups (≥2) | 2819 | 1 | 1 | 2 | 2 | 3 |
|
|
36
|
+
| Σ cognitive complexity | 2819 | 21 | 54 | 109 | 167 | 354 |
|
|
37
|
+
|
|
38
|
+
## LOC-weighted percentiles (Alves, reference)
|
|
39
|
+
|
|
40
|
+
### Function
|
|
41
|
+
| metric | n | p50 | p75 | p90 | p95 | p99 |
|
|
42
|
+
|---|---|---|---|---|---|---|
|
|
43
|
+
| cognitive complexity | 108102 | 4 | 16 | 45 | 95 | 309 |
|
|
44
|
+
|
|
45
|
+
### Class (≥3 methods)
|
|
46
|
+
| metric | n | p50 | p75 | p90 | p95 | p99 |
|
|
47
|
+
|---|---|---|---|---|---|---|
|
|
48
|
+
| methods | 2940 | 15 | 30 | 57 | 74 | 111 |
|
|
49
|
+
| responsibility groups (≥2) | 2940 | 1 | 1 | 2 | 3 | 5 |
|
|
50
|
+
| Σ cognitive complexity | 2940 | 41 | 104 | 205 | 341 | 825 |
|
|
51
|
+
|
|
52
|
+
### Module (≥5 top-level fns)
|
|
53
|
+
| metric | n | p50 | p75 | p90 | p95 | p99 |
|
|
54
|
+
|---|---|---|---|---|---|---|
|
|
55
|
+
| top-level definitions | 2819 | 10 | 17 | 29 | 38 | 72 |
|
|
56
|
+
| responsibility groups (≥2) | 2819 | 1 | 1 | 2 | 2 | 4 |
|
|
57
|
+
| Σ cognitive complexity | 2819 | 51 | 128 | 280 | 455 | 1175 |
|
|
58
|
+
|
|
59
|
+
## Final defaults
|
|
60
|
+
|
|
61
|
+
A god finding is rare by construction, but the detector does not compare each
|
|
62
|
+
metric with an independent p95 cutoff. It has two alternative axes:
|
|
63
|
+
|
|
64
|
+
- **dispersion** requires members **and** responsibility groups **and** total
|
|
65
|
+
complexity together, so its member floor can stay sensitive;
|
|
66
|
+
- **size/WMC** requires both a high member count and high total complexity, even
|
|
67
|
+
when the unit is cohesive.
|
|
68
|
+
|
|
69
|
+
| gate | members | groups | Σ complexity | final setting |
|
|
70
|
+
|---|---:|---:|---:|---|
|
|
71
|
+
| cognitive complexity | — | — | 15 | `cognitiveComplexity: 15` |
|
|
72
|
+
| class dispersion | 12 | 3 | 90 | `godClass: 12 / 3 / 90` |
|
|
73
|
+
| class size/WMC | 30 | — | 200 | `godClass: 30 / 200` |
|
|
74
|
+
| module dispersion | 15 | 3 | 150 | `godModule: 15 / 3 / 150` |
|
|
75
|
+
| module size/WMC | 37 | — | 350 | `godModule: 37 / 350` |
|
|
76
|
+
|
|
77
|
+
The size thresholds sit near the count p95–p99 tail. On the dispersion axis,
|
|
78
|
+
three substantive groups are already rare (between class p95 and p99; module
|
|
79
|
+
p99), and the conjunction with complexity supplies the precision. Raising the
|
|
80
|
+
member floor itself to p95 would make the conjunction unnecessarily blind to
|
|
81
|
+
smaller units that clearly contain three unrelated responsibilities.
|
|
82
|
+
|
|
83
|
+
## Per-repo file counts
|
|
84
|
+
- angular: 1971 files
|
|
85
|
+
- angular-components: 1971 files
|
|
86
|
+
- chakra-ui: 2359 files
|
|
87
|
+
- create-react-app: 122 files
|
|
88
|
+
- gatsby: 3086 files
|
|
89
|
+
- ionic-framework: 508 files
|
|
90
|
+
- material-ui: 26447 files
|
|
91
|
+
- nest: 1306 files
|
|
92
|
+
- nextjs: 4498 files
|
|
93
|
+
- ng-bootstrap: 527 files
|
|
94
|
+
- ng-bootstrap-fresh: 527 files
|
|
95
|
+
- nx: 3330 files
|
|
96
|
+
- playwright: 788 files
|
|
97
|
+
- primeng: 2743 files
|
|
98
|
+
- react: 1711 files
|
|
99
|
+
- react-bootstrap: 440 files
|
|
100
|
+
- remix: 805 files
|
|
101
|
+
- shadcn-ui: 3473 files
|
|
102
|
+
- storybook: 2617 files
|
|
103
|
+
- svelte: 2299 files
|
|
104
|
+
- taiga-ui: 2770 files
|
|
105
|
+
- tanstack-table: 1519 files
|
package/llms.txt
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# StopSlop
|
|
2
|
+
|
|
3
|
+
> Static analysis and CI gating for structural AI code slop in JavaScript and TypeScript. StopSlop finds cognitive complexity, god classes and modules, duplicate code, dead code, orphan features, and responsibility boundaries. It reports code patterns, not authorship.
|
|
4
|
+
|
|
5
|
+
Run without installing: `npx stopslop .`. Exit codes are `0` for a clear gate, `1` for detected findings, and `2` for an analysis error. Requires Node.js 20.19+ or 22.12+.
|
|
6
|
+
|
|
7
|
+
## Start here
|
|
8
|
+
|
|
9
|
+
- [Overview, installation, CLI and badge](https://raw.githubusercontent.com/BaryshevRS/stopslop/main/README.md)
|
|
10
|
+
- [Configuration reference](https://raw.githubusercontent.com/BaryshevRS/stopslop/main/docs/configuration.md)
|
|
11
|
+
- [CI baselines, Git comparison, SARIF and agent reports](https://raw.githubusercontent.com/BaryshevRS/stopslop/main/docs/ci-and-automation.md)
|
|
12
|
+
- [Typed Node.js API](https://raw.githubusercontent.com/BaryshevRS/stopslop/main/docs/node-api.md)
|
|
13
|
+
|
|
14
|
+
## How it works
|
|
15
|
+
|
|
16
|
+
- [Score formula and interpretation](https://raw.githubusercontent.com/BaryshevRS/stopslop/main/docs/score.md)
|
|
17
|
+
- [Default thresholds and calibration](https://raw.githubusercontent.com/BaryshevRS/stopslop/main/docs/thresholds.md)
|
|
18
|
+
- [Architecture and methodology](https://raw.githubusercontent.com/BaryshevRS/stopslop/main/ARCH.md)
|
|
19
|
+
- [Compatibility policy](https://raw.githubusercontent.com/BaryshevRS/stopslop/main/COMPATIBILITY.md)
|
|
20
|
+
|
|
21
|
+
## Package
|
|
22
|
+
|
|
23
|
+
- [npm package](https://www.npmjs.com/package/stopslop)
|
|
24
|
+
- [JSON Schema](https://unpkg.com/stopslop/schema.json)
|
|
25
|
+
- [GitHub repository](https://github.com/BaryshevRS/stopslop)
|
package/package.json
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stopslop",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Static analysis for AI-generated JavaScript and TypeScript: find cognitive complexity, god classes/modules, duplicate code, dead code and orphan features.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
7
9
|
"repository": {
|
|
8
10
|
"type": "git",
|
|
9
11
|
"url": "git+https://github.com/BaryshevRS/stopslop.git"
|
|
@@ -18,12 +20,20 @@
|
|
|
18
20
|
"exports": {
|
|
19
21
|
".": {
|
|
20
22
|
"types": "./dist/index.d.ts",
|
|
21
|
-
"import": "./dist/index.js"
|
|
23
|
+
"import": "./dist/index.js",
|
|
24
|
+
"default": "./dist/index.js"
|
|
22
25
|
},
|
|
23
|
-
"./schema.json": "./schema.json"
|
|
26
|
+
"./schema.json": "./schema.json",
|
|
27
|
+
"./package.json": "./package.json"
|
|
24
28
|
},
|
|
25
29
|
"files": [
|
|
26
|
-
"dist",
|
|
30
|
+
"dist/**/*",
|
|
31
|
+
"docs/**/*.md",
|
|
32
|
+
"README.md",
|
|
33
|
+
"COMPATIBILITY.md",
|
|
34
|
+
"LICENSE",
|
|
35
|
+
"llms.txt",
|
|
36
|
+
"context7.json",
|
|
27
37
|
"schema.json"
|
|
28
38
|
],
|
|
29
39
|
"engines": {
|
|
@@ -40,14 +50,20 @@
|
|
|
40
50
|
"test": "vitest run",
|
|
41
51
|
"test:watch": "vitest",
|
|
42
52
|
"test:package": "node scripts/package-smoke.mjs",
|
|
53
|
+
"check:clones": "clone-alert --minimum-tokens 100 --files src --format text --fail-on-violation",
|
|
43
54
|
"audit:prod": "pnpm audit --prod",
|
|
44
|
-
"ci:check": "pnpm test && pnpm typecheck && pnpm build",
|
|
55
|
+
"ci:check": "pnpm test && pnpm typecheck && pnpm check:clones && pnpm build",
|
|
45
56
|
"release:check": "pnpm ci:check && pnpm audit:prod && pnpm test:package",
|
|
46
57
|
"prepublishOnly": "pnpm release:check",
|
|
47
58
|
"calibrate": "tsx scripts/calibrate.ts",
|
|
48
59
|
"typecheck": "tsc --noEmit",
|
|
49
60
|
"schema:generate": "tsx scripts/generate-config-schema.ts",
|
|
50
|
-
"schema:check": "tsx scripts/generate-config-schema.ts --check"
|
|
61
|
+
"schema:check": "tsx scripts/generate-config-schema.ts --check",
|
|
62
|
+
"commitlint": "commitlint",
|
|
63
|
+
"prepare": "simple-git-hooks 1>&2"
|
|
64
|
+
},
|
|
65
|
+
"simple-git-hooks": {
|
|
66
|
+
"commit-msg": "pnpm exec commitlint --edit \"$1\""
|
|
51
67
|
},
|
|
52
68
|
"dependencies": {
|
|
53
69
|
"clone-alert": "^1.1.3",
|
|
@@ -57,8 +73,11 @@
|
|
|
57
73
|
},
|
|
58
74
|
"devDependencies": {
|
|
59
75
|
"@arethetypeswrong/core": "^0.18.1",
|
|
76
|
+
"@commitlint/cli": "^21.1.0",
|
|
77
|
+
"@commitlint/config-conventional": "^21.1.0",
|
|
60
78
|
"@types/node": "^22.10.0",
|
|
61
79
|
"publint": "^0.3.8",
|
|
80
|
+
"simple-git-hooks": "^2.13.1",
|
|
62
81
|
"tsdown": "^0.21.10",
|
|
63
82
|
"tsx": "^4.19.0",
|
|
64
83
|
"typescript": "^5.7.0",
|
|
@@ -66,12 +85,41 @@
|
|
|
66
85
|
},
|
|
67
86
|
"keywords": [
|
|
68
87
|
"ai",
|
|
88
|
+
"ai-code",
|
|
89
|
+
"ai-generated-code",
|
|
90
|
+
"ai-code-quality",
|
|
91
|
+
"ai-slop",
|
|
69
92
|
"slop",
|
|
93
|
+
"slop-detector",
|
|
94
|
+
"vibe-coding",
|
|
95
|
+
"static-analysis",
|
|
96
|
+
"code-analysis",
|
|
97
|
+
"code-quality",
|
|
70
98
|
"code-smell",
|
|
99
|
+
"technical-debt",
|
|
100
|
+
"javascript",
|
|
101
|
+
"typescript",
|
|
102
|
+
"jsx",
|
|
103
|
+
"tsx",
|
|
104
|
+
"cli",
|
|
105
|
+
"lint",
|
|
106
|
+
"ci",
|
|
107
|
+
"quality-gate",
|
|
108
|
+
"code-scanning",
|
|
109
|
+
"github-actions",
|
|
110
|
+
"sarif",
|
|
111
|
+
"baseline",
|
|
71
112
|
"god-class",
|
|
72
113
|
"god-module",
|
|
73
114
|
"cognitive-complexity",
|
|
74
115
|
"lcom",
|
|
75
|
-
"
|
|
116
|
+
"cohesion",
|
|
117
|
+
"duplicate-code",
|
|
118
|
+
"copy-paste-detector",
|
|
119
|
+
"dead-code",
|
|
120
|
+
"unused-code",
|
|
121
|
+
"orphan-code",
|
|
122
|
+
"monorepo",
|
|
123
|
+
"code-review"
|
|
76
124
|
]
|
|
77
125
|
}
|