stopslop 1.2.0 → 1.2.1
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 +5 -1
- package/README.md +38 -2
- package/dist/cli.js +2 -2
- package/dist/src.js +0 -0
- package/docs/configuration.md +2 -1
- package/docs/rules.md +2 -2
- package/llms.txt +0 -1
- package/package.json +13 -13
- package/schema.json +56 -0
package/COMPATIBILITY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Compatibility
|
|
2
2
|
|
|
3
|
-
Last updated: 1.1
|
|
3
|
+
Last updated: 1.2.1 (2026-11-02)
|
|
4
4
|
|
|
5
5
|
StopSlop follows Semantic Versioning. Stable surfaces change incompatibly only
|
|
6
6
|
in a major release. Experimental surfaces may change in a minor release; such
|
|
@@ -20,6 +20,10 @@ calibration, and Knip or Clone Alert updates can change what a release reports
|
|
|
20
20
|
for the same code; such changes are called out in the changelog. Pin the
|
|
21
21
|
StopSlop version in CI when a gate must not move without a commit.
|
|
22
22
|
|
|
23
|
+
Version 1.2.1 preserves all stable surfaces and adds no deprecations. Anonymous
|
|
24
|
+
function detection and analysis-engine updates can produce new findings or
|
|
25
|
+
different scores for existing code.
|
|
26
|
+
|
|
23
27
|
## Runtime support
|
|
24
28
|
|
|
25
29
|
- Node.js 20.19+, 22.12+, and 24.
|
package/README.md
CHANGED
|
@@ -42,6 +42,41 @@ uses [Clone Alert](https://www.npmjs.com/package/clone-alert); dead-code analysi
|
|
|
42
42
|
uses [Knip](https://knip.dev). StopSlop detects code patterns, not whether a human
|
|
43
43
|
or an AI wrote them.
|
|
44
44
|
|
|
45
|
+
## A passing test does not mean the feature is connected
|
|
46
|
+
|
|
47
|
+
An agent adds a discount function and a test:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
// src/discount.ts
|
|
51
|
+
export function applyDiscount(total: number): number {
|
|
52
|
+
return total * 0.9;
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
// test/discount.test.ts
|
|
58
|
+
import { strictEqual } from 'node:assert';
|
|
59
|
+
import { test } from 'node:test';
|
|
60
|
+
import { applyDiscount } from '../src/discount.js';
|
|
61
|
+
|
|
62
|
+
test('applies a 10% discount', () => {
|
|
63
|
+
strictEqual(applyDiscount(100), 90);
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The test passes, but checkout still calculates the total without calling
|
|
68
|
+
`applyDiscount`. StopSlop reports:
|
|
69
|
+
|
|
70
|
+
```text
|
|
71
|
+
1 orphan feature
|
|
72
|
+
|
|
73
|
+
orphan feature `applyDiscount` is only used by the test `test/discount.test.ts`; connect it to production code, or remove it and its test if unneeded
|
|
74
|
+
src/discount.ts:1
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
If the discount belongs in checkout, connect it and keep the test. If the feature
|
|
78
|
+
was abandoned, remove the unused function and its test.
|
|
79
|
+
|
|
45
80
|
## Start with one command
|
|
46
81
|
|
|
47
82
|
Run without installing:
|
|
@@ -344,8 +379,9 @@ is experimental and may change in a minor release; see
|
|
|
344
379
|
- A baseline accepts finding identities. If an accepted function becomes more
|
|
345
380
|
complex without changing identity, the score rises but the gate stays clear.
|
|
346
381
|
|
|
347
|
-
|
|
348
|
-
|
|
382
|
+
The score formula and its limits are in [docs/score.md](docs/score.md), how
|
|
383
|
+
the default thresholds were calibrated in [docs/thresholds.md](docs/thresholds.md),
|
|
384
|
+
and what each finding means in [docs/rules.md](docs/rules.md).
|
|
349
385
|
|
|
350
386
|
## FAQ
|
|
351
387
|
|
package/dist/cli.js
CHANGED
|
@@ -216,8 +216,8 @@ const RULES = {
|
|
|
216
216
|
},
|
|
217
217
|
"orphan-feature": {
|
|
218
218
|
summary: "Function or class is used only by its own test",
|
|
219
|
-
why: "No production code calls it; one test is the only thing that imports it.
|
|
220
|
-
fix: "
|
|
219
|
+
why: "No production code calls it; one test is the only thing that imports it. This can be a feature written together with its test and never wired in, and the green test makes it look finished.",
|
|
220
|
+
fix: "Check whether the feature is meant to exist. If so, wire it into the production code that needs it. Otherwise, remove the unused symbol and its test together: deleting only the source breaks the test, and deleting only the test leaves dead code.",
|
|
221
221
|
config: "deadCode.orphans"
|
|
222
222
|
}
|
|
223
223
|
};
|
package/dist/src.js
CHANGED
|
Binary file
|
package/docs/configuration.md
CHANGED
|
@@ -62,7 +62,8 @@ the corpus it sits between count p95 ≈ 13 and p99 ≈ 38). Lower = stricter.
|
|
|
62
62
|
### `godClass` / `godModule` — object | false
|
|
63
63
|
|
|
64
64
|
A class (or a module's top-level definitions) is flagged on **either** of two
|
|
65
|
-
axes
|
|
65
|
+
axes, described below; [thresholds.md](thresholds.md) has the calibration behind
|
|
66
|
+
the defaults.
|
|
66
67
|
|
|
67
68
|
| field | meaning | default (class / module) |
|
|
68
69
|
|---|---|---|
|
package/docs/rules.md
CHANGED
|
@@ -95,8 +95,8 @@ File is not reachable from any entry point.
|
|
|
95
95
|
|
|
96
96
|
Function or class is used only by its own test.
|
|
97
97
|
|
|
98
|
-
**Why it matters.** No production code calls it; one test is the only thing that imports it.
|
|
98
|
+
**Why it matters.** No production code calls it; one test is the only thing that imports it. This can be a feature written together with its test and never wired in, and the green test makes it look finished.
|
|
99
99
|
|
|
100
|
-
**How to fix.**
|
|
100
|
+
**How to fix.** Check whether the feature is meant to exist. If so, wire it into the production code that needs it. Otherwise, remove the unused symbol and its test together: deleting only the source breaks the test, and deleting only the test leaves dead code.
|
|
101
101
|
|
|
102
102
|
**Tune or disable:** `deadCode.orphans` in `stopslop.json`.
|
package/llms.txt
CHANGED
|
@@ -20,7 +20,6 @@ Coding agents: this repository is a plugin for Claude Code (`/plugin marketplace
|
|
|
20
20
|
|
|
21
21
|
- [Score formula and interpretation](https://raw.githubusercontent.com/BaryshevRS/stopslop/main/docs/score.md)
|
|
22
22
|
- [Default thresholds and calibration](https://raw.githubusercontent.com/BaryshevRS/stopslop/main/docs/thresholds.md)
|
|
23
|
-
- [Architecture and methodology](https://raw.githubusercontent.com/BaryshevRS/stopslop/main/ARCH.md)
|
|
24
23
|
- [Compatibility policy](https://raw.githubusercontent.com/BaryshevRS/stopslop/main/COMPATIBILITY.md)
|
|
25
24
|
|
|
26
25
|
## Package
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stopslop",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1",
|
|
4
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",
|
|
@@ -69,22 +69,22 @@
|
|
|
69
69
|
"commit-msg": "pnpm exec commitlint --edit \"$1\""
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
|
-
"clone-alert": "^1.1.
|
|
73
|
-
"knip": "6.
|
|
74
|
-
"oxc-parser": "^0.
|
|
72
|
+
"clone-alert": "^1.1.5",
|
|
73
|
+
"knip": "6.44.1",
|
|
74
|
+
"oxc-parser": "^0.156.0",
|
|
75
75
|
"picocolors": "^1.1.1"
|
|
76
76
|
},
|
|
77
77
|
"devDependencies": {
|
|
78
|
-
"@arethetypeswrong/core": "^0.18.
|
|
79
|
-
"@commitlint/cli": "^21.
|
|
80
|
-
"@commitlint/config-conventional": "^21.
|
|
81
|
-
"@types/node": "^22.
|
|
82
|
-
"publint": "^0.3.
|
|
83
|
-
"simple-git-hooks": "^2.
|
|
78
|
+
"@arethetypeswrong/core": "^0.18.5",
|
|
79
|
+
"@commitlint/cli": "^21.2.4",
|
|
80
|
+
"@commitlint/config-conventional": "^21.2.4",
|
|
81
|
+
"@types/node": "^22.20.5",
|
|
82
|
+
"publint": "^0.3.25",
|
|
83
|
+
"simple-git-hooks": "^2.14.0",
|
|
84
84
|
"tsdown": "^0.21.10",
|
|
85
|
-
"tsx": "^4.
|
|
86
|
-
"typescript": "^5.
|
|
87
|
-
"vitest": "^3.
|
|
85
|
+
"tsx": "^4.23.15",
|
|
86
|
+
"typescript": "^5.9.3",
|
|
87
|
+
"vitest": "^3.2.7"
|
|
88
88
|
},
|
|
89
89
|
"keywords": [
|
|
90
90
|
"ai",
|
package/schema.json
CHANGED
|
@@ -842,6 +842,10 @@
|
|
|
842
842
|
"title": "borp plugin configuration (https://knip.dev/reference/plugins/borp)",
|
|
843
843
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
844
844
|
},
|
|
845
|
+
"buf": {
|
|
846
|
+
"title": "buf plugin configuration (https://knip.dev/reference/plugins/buf)",
|
|
847
|
+
"$ref": "#/definitions/knip/definitions/plugin"
|
|
848
|
+
},
|
|
845
849
|
"bumpp": {
|
|
846
850
|
"title": "bumpp plugin configuration (https://knip.dev/reference/plugins/bumpp)",
|
|
847
851
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
@@ -922,6 +926,10 @@
|
|
|
922
926
|
"title": "Drizzle plugin configuration (https://knip.dev/reference/plugins/drizzle)",
|
|
923
927
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
924
928
|
},
|
|
929
|
+
"electron-forge": {
|
|
930
|
+
"title": "Electron Forge plugin configuration (https://knip.dev/reference/plugins/electron-forge)",
|
|
931
|
+
"$ref": "#/definitions/knip/definitions/plugin"
|
|
932
|
+
},
|
|
925
933
|
"electron-vite": {
|
|
926
934
|
"title": "electron-vite plugin configuration (https://knip.dev/reference/plugins/electron-vite)",
|
|
927
935
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
@@ -950,6 +958,10 @@
|
|
|
950
958
|
"title": "Expo plugin configuration (https://knip.dev/reference/plugins/expo)",
|
|
951
959
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
952
960
|
},
|
|
961
|
+
"expo-router": {
|
|
962
|
+
"title": "Expo Router plugin configuration (https://knip.dev/reference/plugins/expo-router)",
|
|
963
|
+
"$ref": "#/definitions/knip/definitions/plugin"
|
|
964
|
+
},
|
|
953
965
|
"expressive-code": {
|
|
954
966
|
"title": "expressive-code plugin configuration (https://knip.dev/reference/plugins/expressive-code)",
|
|
955
967
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
@@ -958,6 +970,14 @@
|
|
|
958
970
|
"title": "fast plugin configuration (https://knip.dev/reference/plugins/fast)",
|
|
959
971
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
960
972
|
},
|
|
973
|
+
"filesystem-routing": {
|
|
974
|
+
"title": "filesystem-routing plugin configuration (https://knip.dev/reference/plugins/filesystem-routing)",
|
|
975
|
+
"$ref": "#/definitions/knip/definitions/plugin"
|
|
976
|
+
},
|
|
977
|
+
"flue": {
|
|
978
|
+
"title": "flue plugin configuration (https://knip.dev/reference/plugins/flue)",
|
|
979
|
+
"$ref": "#/definitions/knip/definitions/plugin"
|
|
980
|
+
},
|
|
961
981
|
"fumadocs": {
|
|
962
982
|
"title": "fumadocs plugin configuration (https://knip.dev/reference/plugins/fumadocs)",
|
|
963
983
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
@@ -990,6 +1010,10 @@
|
|
|
990
1010
|
"title": "i18next-parser plugin configuration (https://knip.dev/reference/plugins/i18next-parser)",
|
|
991
1011
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
992
1012
|
},
|
|
1013
|
+
"jasmine": {
|
|
1014
|
+
"title": "jasmine plugin configuration (https://knip.dev/reference/plugins/jasmine)",
|
|
1015
|
+
"$ref": "#/definitions/knip/definitions/plugin"
|
|
1016
|
+
},
|
|
993
1017
|
"jest": {
|
|
994
1018
|
"title": "Jest plugin configuration (https://knip.dev/reference/plugins/jest)",
|
|
995
1019
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
@@ -1002,6 +1026,10 @@
|
|
|
1002
1026
|
"title": "knex plugin configuration (https://knip.dev/reference/plugins/knex)",
|
|
1003
1027
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
1004
1028
|
},
|
|
1029
|
+
"kysely-codegen": {
|
|
1030
|
+
"title": "kysely-codegen plugin configuration (https://knip.dev/reference/plugins/kysely-codegen)",
|
|
1031
|
+
"$ref": "#/definitions/knip/definitions/plugin"
|
|
1032
|
+
},
|
|
1005
1033
|
"ladle": {
|
|
1006
1034
|
"title": "ladle plugin configuration (https://knip.dev/reference/plugins/ladle)",
|
|
1007
1035
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
@@ -1014,6 +1042,10 @@
|
|
|
1014
1042
|
"title": "lefthook plugin configuration (https://knip.dev/reference/plugins/lefthook)",
|
|
1015
1043
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
1016
1044
|
},
|
|
1045
|
+
"lingui": {
|
|
1046
|
+
"title": "lingui plugin configuration (https://knip.dev/reference/plugins/lingui)",
|
|
1047
|
+
"$ref": "#/definitions/knip/definitions/plugin"
|
|
1048
|
+
},
|
|
1017
1049
|
"lint-staged": {
|
|
1018
1050
|
"title": "lint-staged plugin configuration (https://knip.dev/reference/plugins/lint-staged)",
|
|
1019
1051
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
@@ -1046,6 +1078,14 @@
|
|
|
1046
1078
|
"title": "marko plugin configuration (https://knip.dev/reference/plugins/marko)",
|
|
1047
1079
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
1048
1080
|
},
|
|
1081
|
+
"mastra": {
|
|
1082
|
+
"title": "mastra plugin configuration (https://knip.dev/reference/plugins/mastra)",
|
|
1083
|
+
"$ref": "#/definitions/knip/definitions/plugin"
|
|
1084
|
+
},
|
|
1085
|
+
"mcp": {
|
|
1086
|
+
"title": "mcp plugin configuration (https://knip.dev/reference/plugins/mcp)",
|
|
1087
|
+
"$ref": "#/definitions/knip/definitions/plugin"
|
|
1088
|
+
},
|
|
1049
1089
|
"mdx": {
|
|
1050
1090
|
"title": "mdx plugin configuration (https://knip.dev/reference/plugins/mdx)",
|
|
1051
1091
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
@@ -1158,6 +1198,10 @@
|
|
|
1158
1198
|
"title": "orval plugin configuration (https://knip.dev/reference/plugins/orval)",
|
|
1159
1199
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
1160
1200
|
},
|
|
1201
|
+
"osls": {
|
|
1202
|
+
"title": "osls plugin configuration (https://knip.dev/reference/plugins/osls)",
|
|
1203
|
+
"$ref": "#/definitions/knip/definitions/plugin"
|
|
1204
|
+
},
|
|
1161
1205
|
"oxfmt": {
|
|
1162
1206
|
"title": "oxfmt plugin configuration (https://knip.dev/reference/plugins/oxfmt)",
|
|
1163
1207
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
@@ -1218,6 +1262,10 @@
|
|
|
1218
1262
|
"title": "Prisma plugin configuration (https://knip.dev/reference/plugins/prisma)",
|
|
1219
1263
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
1220
1264
|
},
|
|
1265
|
+
"purgecss": {
|
|
1266
|
+
"title": "purgecss plugin configuration (https://knip.dev/reference/plugins/purgecss)",
|
|
1267
|
+
"$ref": "#/definitions/knip/definitions/plugin"
|
|
1268
|
+
},
|
|
1221
1269
|
"quasar": {
|
|
1222
1270
|
"title": "quasar plugin configuration (https://knip.dev/reference/plugins/quasar)",
|
|
1223
1271
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
@@ -1310,6 +1358,10 @@
|
|
|
1310
1358
|
"title": "size-limit plugin configuration (https://knip.dev/reference/plugins/size-limit)",
|
|
1311
1359
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
1312
1360
|
},
|
|
1361
|
+
"solidjs-vite-plugin": {
|
|
1362
|
+
"title": "solidjs-vite-plugin plugin configuration (https://knip.dev/reference/plugins/solidjs-vite-plugin)",
|
|
1363
|
+
"$ref": "#/definitions/knip/definitions/plugin"
|
|
1364
|
+
},
|
|
1313
1365
|
"sst": {
|
|
1314
1366
|
"title": "sst plugin configuration (https://knip.dev/reference/plugins/sst)",
|
|
1315
1367
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
@@ -1402,6 +1454,10 @@
|
|
|
1402
1454
|
"title": "tsdown plugin configuration (https://knip.dev/reference/plugins/tsdown)",
|
|
1403
1455
|
"$ref": "#/definitions/knip/definitions/plugin"
|
|
1404
1456
|
},
|
|
1457
|
+
"tsrs": {
|
|
1458
|
+
"title": "tsrs plugin configuration (https://knip.dev/reference/plugins/tsrs)",
|
|
1459
|
+
"$ref": "#/definitions/knip/definitions/plugin"
|
|
1460
|
+
},
|
|
1405
1461
|
"tsup": {
|
|
1406
1462
|
"title": "tsup plugin configuration (https://knip.dev/reference/plugins/tsup)",
|
|
1407
1463
|
"$ref": "#/definitions/knip/definitions/plugin"
|