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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Compatibility
2
2
 
3
- Last updated: 1.1.0
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
- Architecture, research references, and the boundary between published methods
348
- and StopSlop heuristics are documented in [ARCH.md](ARCH.md).
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. That is a feature written together with its test and never wired in, and the green test makes it look finished.",
220
- fix: "Delete the symbol and its test together: deleting only the source breaks the test, and deleting only the test leaves dead code. If the feature is meant to exist, wire it into the production code that needs it.",
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
@@ -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 — see [ARCH.md](../ARCH.md) for the reasoning.
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. That is a feature written together with its test and never wired in, and the green test makes it look finished.
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.** Delete the symbol and its test together: deleting only the source breaks the test, and deleting only the test leaves dead code. If the feature is meant to exist, wire it into the production code that needs it.
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.0",
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.3",
73
- "knip": "6.39.0",
74
- "oxc-parser": "^0.139.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.1",
79
- "@commitlint/cli": "^21.1.0",
80
- "@commitlint/config-conventional": "^21.1.0",
81
- "@types/node": "^22.10.0",
82
- "publint": "^0.3.8",
83
- "simple-git-hooks": "^2.13.1",
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.19.0",
86
- "typescript": "^5.7.0",
87
- "vitest": "^3.0.0"
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"