@lbroth/rothunter 1.0.0-rc.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.
Files changed (269) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +141 -0
  3. package/dist/adapters/llm.d.ts +68 -0
  4. package/dist/adapters/llm.d.ts.map +1 -0
  5. package/dist/adapters/llm.js +189 -0
  6. package/dist/adapters/llm.js.map +1 -0
  7. package/dist/config.d.ts +37 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +81 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/detector-registry.d.ts +32 -0
  12. package/dist/detector-registry.d.ts.map +1 -0
  13. package/dist/detector-registry.js +74 -0
  14. package/dist/detector-registry.js.map +1 -0
  15. package/dist/detectors/api-race.d.ts +6 -0
  16. package/dist/detectors/api-race.d.ts.map +1 -0
  17. package/dist/detectors/api-race.js +222 -0
  18. package/dist/detectors/api-race.js.map +1 -0
  19. package/dist/detectors/bad-config.d.ts +6 -0
  20. package/dist/detectors/bad-config.d.ts.map +1 -0
  21. package/dist/detectors/bad-config.js +529 -0
  22. package/dist/detectors/bad-config.js.map +1 -0
  23. package/dist/detectors/console-log-prod.d.ts +6 -0
  24. package/dist/detectors/console-log-prod.d.ts.map +1 -0
  25. package/dist/detectors/console-log-prod.js +72 -0
  26. package/dist/detectors/console-log-prod.js.map +1 -0
  27. package/dist/detectors/dead-api.d.ts +10 -0
  28. package/dist/detectors/dead-api.d.ts.map +1 -0
  29. package/dist/detectors/dead-api.js +115 -0
  30. package/dist/detectors/dead-api.js.map +1 -0
  31. package/dist/detectors/dead-export.d.ts +12 -0
  32. package/dist/detectors/dead-export.d.ts.map +1 -0
  33. package/dist/detectors/dead-export.js +140 -0
  34. package/dist/detectors/dead-export.js.map +1 -0
  35. package/dist/detectors/dead-handler.d.ts +12 -0
  36. package/dist/detectors/dead-handler.d.ts.map +1 -0
  37. package/dist/detectors/dead-handler.js +40 -0
  38. package/dist/detectors/dead-handler.js.map +1 -0
  39. package/dist/detectors/dead-module.d.ts +14 -0
  40. package/dist/detectors/dead-module.d.ts.map +1 -0
  41. package/dist/detectors/dead-module.js +50 -0
  42. package/dist/detectors/dead-module.js.map +1 -0
  43. package/dist/detectors/deep-nesting.d.ts +12 -0
  44. package/dist/detectors/deep-nesting.d.ts.map +1 -0
  45. package/dist/detectors/deep-nesting.js +133 -0
  46. package/dist/detectors/deep-nesting.js.map +1 -0
  47. package/dist/detectors/duplicate-function.d.ts +9 -0
  48. package/dist/detectors/duplicate-function.d.ts.map +1 -0
  49. package/dist/detectors/duplicate-function.js +199 -0
  50. package/dist/detectors/duplicate-function.js.map +1 -0
  51. package/dist/detectors/duplicate-type.d.ts +9 -0
  52. package/dist/detectors/duplicate-type.d.ts.map +1 -0
  53. package/dist/detectors/duplicate-type.js +166 -0
  54. package/dist/detectors/duplicate-type.js.map +1 -0
  55. package/dist/detectors/hot-hub-file.d.ts +11 -0
  56. package/dist/detectors/hot-hub-file.d.ts.map +1 -0
  57. package/dist/detectors/hot-hub-file.js +42 -0
  58. package/dist/detectors/hot-hub-file.js.map +1 -0
  59. package/dist/detectors/long-file.d.ts +12 -0
  60. package/dist/detectors/long-file.d.ts.map +1 -0
  61. package/dist/detectors/long-file.js +82 -0
  62. package/dist/detectors/long-file.js.map +1 -0
  63. package/dist/detectors/long-function.d.ts +12 -0
  64. package/dist/detectors/long-function.d.ts.map +1 -0
  65. package/dist/detectors/long-function.js +45 -0
  66. package/dist/detectors/long-function.js.map +1 -0
  67. package/dist/detectors/magic-numbers.d.ts +10 -0
  68. package/dist/detectors/magic-numbers.d.ts.map +1 -0
  69. package/dist/detectors/magic-numbers.js +332 -0
  70. package/dist/detectors/magic-numbers.js.map +1 -0
  71. package/dist/detectors/mutable-globals.d.ts +6 -0
  72. package/dist/detectors/mutable-globals.d.ts.map +1 -0
  73. package/dist/detectors/mutable-globals.js +95 -0
  74. package/dist/detectors/mutable-globals.js.map +1 -0
  75. package/dist/detectors/mutation.d.ts +11 -0
  76. package/dist/detectors/mutation.d.ts.map +1 -0
  77. package/dist/detectors/mutation.js +397 -0
  78. package/dist/detectors/mutation.js.map +1 -0
  79. package/dist/detectors/public-any.d.ts +6 -0
  80. package/dist/detectors/public-any.d.ts.map +1 -0
  81. package/dist/detectors/public-any.js +52 -0
  82. package/dist/detectors/public-any.js.map +1 -0
  83. package/dist/detectors/race-condition.d.ts +6 -0
  84. package/dist/detectors/race-condition.d.ts.map +1 -0
  85. package/dist/detectors/race-condition.js +608 -0
  86. package/dist/detectors/race-condition.js.map +1 -0
  87. package/dist/detectors/shared-db-write.d.ts +6 -0
  88. package/dist/detectors/shared-db-write.d.ts.map +1 -0
  89. package/dist/detectors/shared-db-write.js +656 -0
  90. package/dist/detectors/shared-db-write.js.map +1 -0
  91. package/dist/detectors/silent-catch.d.ts +6 -0
  92. package/dist/detectors/silent-catch.d.ts.map +1 -0
  93. package/dist/detectors/silent-catch.js +167 -0
  94. package/dist/detectors/silent-catch.js.map +1 -0
  95. package/dist/detectors/similar-functions.d.ts +15 -0
  96. package/dist/detectors/similar-functions.d.ts.map +1 -0
  97. package/dist/detectors/similar-functions.js +334 -0
  98. package/dist/detectors/similar-functions.js.map +1 -0
  99. package/dist/detectors/skip-tests.d.ts +6 -0
  100. package/dist/detectors/skip-tests.d.ts.map +1 -0
  101. package/dist/detectors/skip-tests.js +69 -0
  102. package/dist/detectors/skip-tests.js.map +1 -0
  103. package/dist/detectors/todo-comments.d.ts +29 -0
  104. package/dist/detectors/todo-comments.d.ts.map +1 -0
  105. package/dist/detectors/todo-comments.js +154 -0
  106. package/dist/detectors/todo-comments.js.map +1 -0
  107. package/dist/detectors/unused-deps.d.ts +8 -0
  108. package/dist/detectors/unused-deps.d.ts.map +1 -0
  109. package/dist/detectors/unused-deps.js +115 -0
  110. package/dist/detectors/unused-deps.js.map +1 -0
  111. package/dist/extraction/api-race-confirmer.d.ts +31 -0
  112. package/dist/extraction/api-race-confirmer.d.ts.map +1 -0
  113. package/dist/extraction/api-race-confirmer.js +110 -0
  114. package/dist/extraction/api-race-confirmer.js.map +1 -0
  115. package/dist/extraction/llm-confirmer.d.ts +25 -0
  116. package/dist/extraction/llm-confirmer.d.ts.map +1 -0
  117. package/dist/extraction/llm-confirmer.js +118 -0
  118. package/dist/extraction/llm-confirmer.js.map +1 -0
  119. package/dist/extraction/mutation-confirmer.d.ts +30 -0
  120. package/dist/extraction/mutation-confirmer.d.ts.map +1 -0
  121. package/dist/extraction/mutation-confirmer.js +73 -0
  122. package/dist/extraction/mutation-confirmer.js.map +1 -0
  123. package/dist/extraction/prompt-chunking.d.ts +37 -0
  124. package/dist/extraction/prompt-chunking.d.ts.map +1 -0
  125. package/dist/extraction/prompt-chunking.js +61 -0
  126. package/dist/extraction/prompt-chunking.js.map +1 -0
  127. package/dist/extraction/race-confirmer.d.ts +28 -0
  128. package/dist/extraction/race-confirmer.d.ts.map +1 -0
  129. package/dist/extraction/race-confirmer.js +68 -0
  130. package/dist/extraction/race-confirmer.js.map +1 -0
  131. package/dist/extraction/shared-db-write-confirmer.d.ts +31 -0
  132. package/dist/extraction/shared-db-write-confirmer.d.ts.map +1 -0
  133. package/dist/extraction/shared-db-write-confirmer.js +141 -0
  134. package/dist/extraction/shared-db-write-confirmer.js.map +1 -0
  135. package/dist/extraction/triage-confirmer.d.ts +59 -0
  136. package/dist/extraction/triage-confirmer.d.ts.map +1 -0
  137. package/dist/extraction/triage-confirmer.js +104 -0
  138. package/dist/extraction/triage-confirmer.js.map +1 -0
  139. package/dist/graph/cfg.d.ts +45 -0
  140. package/dist/graph/cfg.d.ts.map +1 -0
  141. package/dist/graph/cfg.js +198 -0
  142. package/dist/graph/cfg.js.map +1 -0
  143. package/dist/graph/decorator-entries.d.ts +2 -0
  144. package/dist/graph/decorator-entries.d.ts.map +1 -0
  145. package/dist/graph/decorator-entries.js +89 -0
  146. package/dist/graph/decorator-entries.js.map +1 -0
  147. package/dist/graph/entry-points.d.ts +12 -0
  148. package/dist/graph/entry-points.d.ts.map +1 -0
  149. package/dist/graph/entry-points.js +282 -0
  150. package/dist/graph/entry-points.js.map +1 -0
  151. package/dist/graph/handler-conventions.d.ts +2 -0
  152. package/dist/graph/handler-conventions.d.ts.map +1 -0
  153. package/dist/graph/handler-conventions.js +26 -0
  154. package/dist/graph/handler-conventions.js.map +1 -0
  155. package/dist/graph/iac-entries.d.ts +2 -0
  156. package/dist/graph/iac-entries.d.ts.map +1 -0
  157. package/dist/graph/iac-entries.js +123 -0
  158. package/dist/graph/iac-entries.js.map +1 -0
  159. package/dist/graph/import-graph.d.ts +48 -0
  160. package/dist/graph/import-graph.d.ts.map +1 -0
  161. package/dist/graph/import-graph.js +86 -0
  162. package/dist/graph/import-graph.js.map +1 -0
  163. package/dist/graph/monorepo-detect.d.ts +3 -0
  164. package/dist/graph/monorepo-detect.d.ts.map +1 -0
  165. package/dist/graph/monorepo-detect.js +166 -0
  166. package/dist/graph/monorepo-detect.js.map +1 -0
  167. package/dist/graph/tsconfig-paths.d.ts +23 -0
  168. package/dist/graph/tsconfig-paths.d.ts.map +1 -0
  169. package/dist/graph/tsconfig-paths.js +217 -0
  170. package/dist/graph/tsconfig-paths.js.map +1 -0
  171. package/dist/multi-workspace-scanner.d.ts +13 -0
  172. package/dist/multi-workspace-scanner.d.ts.map +1 -0
  173. package/dist/multi-workspace-scanner.js +130 -0
  174. package/dist/multi-workspace-scanner.js.map +1 -0
  175. package/dist/normalizers/type-normalizer.d.ts +16 -0
  176. package/dist/normalizers/type-normalizer.d.ts.map +1 -0
  177. package/dist/normalizers/type-normalizer.js +189 -0
  178. package/dist/normalizers/type-normalizer.js.map +1 -0
  179. package/dist/parsers/typescript-parser.d.ts +57 -0
  180. package/dist/parsers/typescript-parser.d.ts.map +1 -0
  181. package/dist/parsers/typescript-parser.js +502 -0
  182. package/dist/parsers/typescript-parser.js.map +1 -0
  183. package/dist/reporter/json-reporter.d.ts +12 -0
  184. package/dist/reporter/json-reporter.d.ts.map +1 -0
  185. package/dist/reporter/json-reporter.js +28 -0
  186. package/dist/reporter/json-reporter.js.map +1 -0
  187. package/dist/reporter/markdown-reporter.d.ts +11 -0
  188. package/dist/reporter/markdown-reporter.d.ts.map +1 -0
  189. package/dist/reporter/markdown-reporter.js +77 -0
  190. package/dist/reporter/markdown-reporter.js.map +1 -0
  191. package/dist/rothunter.d.ts +125 -0
  192. package/dist/rothunter.d.ts.map +1 -0
  193. package/dist/rothunter.js +1038 -0
  194. package/dist/rothunter.js.map +1 -0
  195. package/dist/server/false-positives.d.ts +34 -0
  196. package/dist/server/false-positives.d.ts.map +1 -0
  197. package/dist/server/false-positives.js +85 -0
  198. package/dist/server/false-positives.js.map +1 -0
  199. package/dist/server/index.d.ts +2 -0
  200. package/dist/server/index.d.ts.map +1 -0
  201. package/dist/server/index.js +1529 -0
  202. package/dist/server/index.js.map +1 -0
  203. package/dist/server/marked-to-fix.d.ts +16 -0
  204. package/dist/server/marked-to-fix.d.ts.map +1 -0
  205. package/dist/server/marked-to-fix.js +36 -0
  206. package/dist/server/marked-to-fix.js.map +1 -0
  207. package/dist/server/scan-store.d.ts +147 -0
  208. package/dist/server/scan-store.d.ts.map +1 -0
  209. package/dist/server/scan-store.js +291 -0
  210. package/dist/server/scan-store.js.map +1 -0
  211. package/dist/server/settings-store.d.ts +28 -0
  212. package/dist/server/settings-store.d.ts.map +1 -0
  213. package/dist/server/settings-store.js +46 -0
  214. package/dist/server/settings-store.js.map +1 -0
  215. package/dist/server/workspace-store.d.ts +39 -0
  216. package/dist/server/workspace-store.d.ts.map +1 -0
  217. package/dist/server/workspace-store.js +108 -0
  218. package/dist/server/workspace-store.js.map +1 -0
  219. package/dist/types/detector-input.d.ts +37 -0
  220. package/dist/types/detector-input.d.ts.map +1 -0
  221. package/dist/types/detector-input.js +2 -0
  222. package/dist/types/detector-input.js.map +1 -0
  223. package/dist/types.d.ts +110 -0
  224. package/dist/types.d.ts.map +1 -0
  225. package/dist/types.js +2 -0
  226. package/dist/types.js.map +1 -0
  227. package/dist/utils/clustering.d.ts +14 -0
  228. package/dist/utils/clustering.d.ts.map +1 -0
  229. package/dist/utils/clustering.js +56 -0
  230. package/dist/utils/clustering.js.map +1 -0
  231. package/dist/utils/gitignore.d.ts +32 -0
  232. package/dist/utils/gitignore.d.ts.map +1 -0
  233. package/dist/utils/gitignore.js +122 -0
  234. package/dist/utils/gitignore.js.map +1 -0
  235. package/dist/utils/hash.d.ts +11 -0
  236. package/dist/utils/hash.d.ts.map +1 -0
  237. package/dist/utils/hash.js +14 -0
  238. package/dist/utils/hash.js.map +1 -0
  239. package/dist/utils/ignore-annotation.d.ts +28 -0
  240. package/dist/utils/ignore-annotation.d.ts.map +1 -0
  241. package/dist/utils/ignore-annotation.js +46 -0
  242. package/dist/utils/ignore-annotation.js.map +1 -0
  243. package/dist/utils/llm-json.d.ts +2 -0
  244. package/dist/utils/llm-json.d.ts.map +1 -0
  245. package/dist/utils/llm-json.js +53 -0
  246. package/dist/utils/llm-json.js.map +1 -0
  247. package/dist/utils/logger.d.ts +3 -0
  248. package/dist/utils/logger.d.ts.map +1 -0
  249. package/dist/utils/logger.js +4 -0
  250. package/dist/utils/logger.js.map +1 -0
  251. package/dist/utils/project-conventions.d.ts +2 -0
  252. package/dist/utils/project-conventions.d.ts.map +1 -0
  253. package/dist/utils/project-conventions.js +108 -0
  254. package/dist/utils/project-conventions.js.map +1 -0
  255. package/dist/utils/regex.d.ts +9 -0
  256. package/dist/utils/regex.d.ts.map +1 -0
  257. package/dist/utils/regex.js +11 -0
  258. package/dist/utils/regex.js.map +1 -0
  259. package/dist/utils/snippet.d.ts +20 -0
  260. package/dist/utils/snippet.d.ts.map +1 -0
  261. package/dist/utils/snippet.js +28 -0
  262. package/dist/utils/snippet.js.map +1 -0
  263. package/dist/utils/source-reader.d.ts +19 -0
  264. package/dist/utils/source-reader.d.ts.map +1 -0
  265. package/dist/utils/source-reader.js +32 -0
  266. package/dist/utils/source-reader.js.map +1 -0
  267. package/logo.png +0 -0
  268. package/package.json +92 -0
  269. package/scripts/start-llm.mjs +161 -0
@@ -0,0 +1,529 @@
1
+ import * as path from 'node:path';
2
+ import { existsSync, readFileSync } from 'node:fs';
3
+ import { readdirSync, statSync } from 'node:fs';
4
+ import { stableHash } from '../utils/hash.js';
5
+ import { escapeForRegex } from '../utils/regex.js';
6
+ // Flags anti-patterns in tsconfig*.json, eslint config, biome.json:
7
+ // disabled strict family, any-permitting rules off, legacy targets.
8
+ // Cites the exact JSON key path.
9
+ export function detectBadConfig(input) {
10
+ const findings = [];
11
+ const seen = new Set();
12
+ const candidates = discoverConfigFiles(input.workspaceRoot, input.files);
13
+ for (const rel of candidates) {
14
+ if (seen.has(rel))
15
+ continue;
16
+ seen.add(rel);
17
+ const abs = path.resolve(input.workspaceRoot, rel);
18
+ let raw;
19
+ try {
20
+ raw = readFileSync(abs, 'utf-8');
21
+ }
22
+ catch {
23
+ continue;
24
+ }
25
+ if (rel.endsWith('.json') || /\/tsconfig.*\.json$/.test(rel) || rel.endsWith('biome.json') || rel.endsWith('biome.jsonc')) {
26
+ const parsed = tryParseJsonc(raw);
27
+ if (!parsed)
28
+ continue;
29
+ if (isTsConfig(rel)) {
30
+ // Resolve `extends` chain so inherited strict-family flags
31
+ // count. Operators commonly put `strict: true` in
32
+ // `tsconfig.base.json` and leave the leaf tsconfigs minimal;
33
+ // flagging those leafs as "strict not set" is a false positive.
34
+ const merged = mergeTsConfigExtends(input.workspaceRoot, rel, parsed);
35
+ findings.push(...analyseTsConfig(rel, raw, merged));
36
+ }
37
+ else if (rel.endsWith('biome.json') || rel.endsWith('biome.jsonc'))
38
+ findings.push(...analyseBiome(rel, raw, parsed));
39
+ else if (isEslintJson(rel))
40
+ findings.push(...analyseEslint(rel, raw, parsed));
41
+ }
42
+ else if (isEslintScript(rel)) {
43
+ findings.push(...analyseEslintScript(rel, raw));
44
+ }
45
+ }
46
+ return findings;
47
+ }
48
+ /**
49
+ * Walk the tsconfig `extends` chain (relative + bare specifiers),
50
+ * merging parent `compilerOptions` under the child's. Bounded depth
51
+ * (8) + a visited set guard against cyclic / pathological inheritance.
52
+ * The merged object is what the rule checks read — so a leaf tsconfig
53
+ * that only sets `outDir` no longer trips "strict not set" when its
54
+ * base has `"strict": true`.
55
+ */
56
+ function mergeTsConfigExtends(workspaceRoot, relConfig, raw, visited = new Set(), depth = 0) {
57
+ if (depth >= 8)
58
+ return raw;
59
+ const root = asObj(raw);
60
+ if (!root)
61
+ return raw;
62
+ const extendsValue = typeof root.extends === 'string' ? root.extends : null;
63
+ if (!extendsValue)
64
+ return raw;
65
+ const configAbs = path.resolve(workspaceRoot, relConfig);
66
+ if (visited.has(configAbs))
67
+ return raw;
68
+ visited.add(configAbs);
69
+ const configDir = path.dirname(configAbs);
70
+ const parentAbs = resolveExtends(configDir, extendsValue);
71
+ if (!parentAbs)
72
+ return raw;
73
+ let parentRaw;
74
+ try {
75
+ parentRaw = tryParseJsonc(readFileSync(parentAbs, 'utf-8'));
76
+ }
77
+ catch {
78
+ return raw;
79
+ }
80
+ if (!parentRaw)
81
+ return raw;
82
+ const parentMerged = mergeTsConfigExtends(workspaceRoot, path.relative(workspaceRoot, parentAbs), parentRaw, visited, depth + 1);
83
+ const parentObj = asObj(parentMerged) ?? {};
84
+ const parentCompiler = asObj(parentObj.compilerOptions) ?? {};
85
+ const childCompiler = asObj(root.compilerOptions) ?? {};
86
+ return {
87
+ ...parentObj,
88
+ ...root,
89
+ compilerOptions: { ...parentCompiler, ...childCompiler },
90
+ };
91
+ }
92
+ function resolveExtends(configDir, extendsValue) {
93
+ const tryPaths = (base) => {
94
+ if (existsSync(base))
95
+ return base;
96
+ if (existsSync(`${base}.json`))
97
+ return `${base}.json`;
98
+ return null;
99
+ };
100
+ if (extendsValue.startsWith('.') || extendsValue.startsWith('/')) {
101
+ return tryPaths(path.resolve(configDir, extendsValue));
102
+ }
103
+ // Bare specifier — walk node_modules up.
104
+ let cur = configDir;
105
+ while (cur !== path.dirname(cur)) {
106
+ const candidate = path.join(cur, 'node_modules', extendsValue);
107
+ const hit = tryPaths(candidate);
108
+ if (hit)
109
+ return hit;
110
+ cur = path.dirname(cur);
111
+ }
112
+ return null;
113
+ }
114
+ function discoverConfigFiles(workspaceRoot, files) {
115
+ const fromParse = files.filter((f) => isConfigFile(f));
116
+ // The parsed file set covers .ts/.tsx — but tsconfig/eslint are JSON or
117
+ // pre-import JS, so they're invisible to the symbol parser. Do a light
118
+ // scan of the workspace root for the common config filenames.
119
+ const fromRoot = [];
120
+ for (const name of CONFIG_ROOT_FILES) {
121
+ const candidate = path.join(workspaceRoot, name);
122
+ if (existsSync(candidate))
123
+ fromRoot.push(name);
124
+ }
125
+ // Pick up tsconfig.something.json variants too.
126
+ try {
127
+ for (const entry of readdirSync(workspaceRoot)) {
128
+ if (/^tsconfig(\..+)?\.json$/.test(entry))
129
+ fromRoot.push(entry);
130
+ }
131
+ }
132
+ catch {
133
+ // workspace unreadable — fall through
134
+ }
135
+ // Also pick tsconfig.json from immediate sub-packages (monorepo roots).
136
+ try {
137
+ for (const entry of readdirSync(workspaceRoot)) {
138
+ const sub = path.join(workspaceRoot, entry);
139
+ let s;
140
+ try {
141
+ s = statSync(sub);
142
+ }
143
+ catch {
144
+ continue;
145
+ }
146
+ if (!s.isDirectory())
147
+ continue;
148
+ if (entry.startsWith('.') || entry === 'node_modules')
149
+ continue;
150
+ for (const name of CONFIG_ROOT_FILES) {
151
+ const candidate = path.join(sub, name);
152
+ if (existsSync(candidate))
153
+ fromRoot.push(path.join(entry, name));
154
+ }
155
+ }
156
+ }
157
+ catch {
158
+ // ignore
159
+ }
160
+ return [...new Set([...fromParse, ...fromRoot])];
161
+ }
162
+ const CONFIG_ROOT_FILES = [
163
+ 'tsconfig.json',
164
+ 'tsconfig.base.json',
165
+ 'tsconfig.build.json',
166
+ '.eslintrc',
167
+ '.eslintrc.json',
168
+ '.eslintrc.js',
169
+ '.eslintrc.cjs',
170
+ 'eslint.config.js',
171
+ 'eslint.config.mjs',
172
+ 'eslint.config.cjs',
173
+ 'eslint.config.ts',
174
+ 'biome.json',
175
+ 'biome.jsonc',
176
+ ];
177
+ function isConfigFile(file) {
178
+ return /(^|\/)(tsconfig.*\.json|\.eslintrc(\.\w+)?|eslint\.config\.\w+|biome\.jsonc?)$/.test(file.replace(/\\/g, '/'));
179
+ }
180
+ function isTsConfig(file) {
181
+ return /(^|\/)tsconfig.*\.json$/.test(file.replace(/\\/g, '/'));
182
+ }
183
+ function isEslintJson(file) {
184
+ return /(^|\/)\.eslintrc(\.json)?$/.test(file.replace(/\\/g, '/'));
185
+ }
186
+ function isEslintScript(file) {
187
+ return /(^|\/)\.?eslintrc?\.(js|cjs|mjs|ts)$/.test(file.replace(/\\/g, '/'))
188
+ || /(^|\/)eslint\.config\.(js|mjs|cjs|ts)$/.test(file.replace(/\\/g, '/'));
189
+ }
190
+ /**
191
+ * Lightweight JSONC parser: strips // line comments, /* block comments,
192
+ * and trailing commas before JSON.parse. tsconfig.json + biome.jsonc
193
+ * accept all three; the editor-quoted location lines aren't affected
194
+ * because we only use this for value lookup, not editing.
195
+ */
196
+ function tryParseJsonc(text) {
197
+ try {
198
+ const stripped = text
199
+ .replace(/\/\*[\s\S]*?\*\//g, '')
200
+ .replace(/(^|[^:"\\])\/\/.*$/gm, '$1')
201
+ .replace(/,(\s*[}\]])/g, '$1');
202
+ return JSON.parse(stripped);
203
+ }
204
+ catch {
205
+ return null;
206
+ }
207
+ }
208
+ function asObj(v) {
209
+ return v && typeof v === 'object' && !Array.isArray(v) ? v : null;
210
+ }
211
+ function analyseTsConfig(file, raw, parsed) {
212
+ const root = asObj(parsed);
213
+ if (!root)
214
+ return [];
215
+ const compilerOptions = asObj(root.compilerOptions) ?? {};
216
+ const out = [];
217
+ // strict family
218
+ if (compilerOptions.strict === false) {
219
+ out.push(makeFinding({
220
+ file, raw, key: 'strict',
221
+ detectorId: 'bad-config',
222
+ severity: 'high',
223
+ title: 'tsconfig: \`strict\` disabled',
224
+ blurb: '`"strict": false` opts out of the umbrella that enables `noImplicitAny`, `strictNullChecks`, and other safety nets in one go. Code compiled under this setting silently accepts `any` and undefined-prone access.',
225
+ suggestion: 'Set `"strict": true` and burn down the resulting type errors. Use file-level `// @ts-expect-error` to triage gradually.',
226
+ }));
227
+ }
228
+ else if (compilerOptions.strict === undefined && compilerOptions.noImplicitAny !== true && compilerOptions.strictNullChecks !== true) {
229
+ out.push(makeFinding({
230
+ file, raw, key: 'compilerOptions',
231
+ detectorId: 'bad-config',
232
+ severity: 'medium',
233
+ title: 'tsconfig: \`strict\` not set',
234
+ blurb: 'Without `"strict": true` (and no explicit sub-flags), `noImplicitAny` and `strictNullChecks` default to false. Most type-safety guarantees are off.',
235
+ suggestion: 'Add `"strict": true` to `compilerOptions`.',
236
+ }));
237
+ }
238
+ if (compilerOptions.noImplicitAny === false) {
239
+ out.push(makeFinding({
240
+ file, raw, key: 'noImplicitAny',
241
+ detectorId: 'bad-config',
242
+ severity: 'high',
243
+ title: 'tsconfig: \`noImplicitAny\` disabled',
244
+ blurb: 'Untyped parameters silently become `any`. Refactors lose type-safety guarantees and a whole class of bugs becomes invisible.',
245
+ suggestion: 'Remove the override or set `"noImplicitAny": true`. Type the remaining offenders explicitly.',
246
+ }));
247
+ }
248
+ if (compilerOptions.strictNullChecks === false) {
249
+ out.push(makeFinding({
250
+ file, raw, key: 'strictNullChecks',
251
+ detectorId: 'bad-config',
252
+ severity: 'high',
253
+ title: 'tsconfig: \`strictNullChecks\` disabled',
254
+ blurb: '`null` and `undefined` are silently allowed in every value, defeating the most common class of runtime errors TS is meant to catch.',
255
+ suggestion: 'Set `"strictNullChecks": true` (or `"strict": true`). Use `?` and explicit unions where null is a legal value.',
256
+ }));
257
+ }
258
+ if (compilerOptions.noImplicitReturns === false) {
259
+ out.push(makeFinding({
260
+ file, raw, key: 'noImplicitReturns',
261
+ detectorId: 'bad-config',
262
+ severity: 'low',
263
+ title: 'tsconfig: \`noImplicitReturns\` disabled',
264
+ blurb: 'Functions can fall off the end without returning a value, returning `undefined` implicitly even when the type annotation forbids it.',
265
+ suggestion: 'Set `"noImplicitReturns": true`.',
266
+ }));
267
+ }
268
+ if (compilerOptions.noFallthroughCasesInSwitch === false) {
269
+ out.push(makeFinding({
270
+ file, raw, key: 'noFallthroughCasesInSwitch',
271
+ detectorId: 'bad-config',
272
+ severity: 'low',
273
+ title: 'tsconfig: \`noFallthroughCasesInSwitch\` disabled',
274
+ blurb: 'Missing `break` / `return` in switch cases silently falls through — a famous source of off-by-one bugs.',
275
+ suggestion: 'Set `"noFallthroughCasesInSwitch": true`.',
276
+ }));
277
+ }
278
+ if (compilerOptions.noUnusedLocals === false || compilerOptions.noUnusedParameters === false) {
279
+ out.push(makeFinding({
280
+ file, raw, key: compilerOptions.noUnusedLocals === false ? 'noUnusedLocals' : 'noUnusedParameters',
281
+ detectorId: 'bad-config',
282
+ severity: 'low',
283
+ title: 'tsconfig: unused-symbol checks disabled',
284
+ blurb: 'Unused locals/parameters accumulate as dead code and mask refactor mistakes.',
285
+ suggestion: 'Enable `"noUnusedLocals": true` and `"noUnusedParameters": true`. Prefix intentionally unused params with `_`.',
286
+ }));
287
+ }
288
+ if (compilerOptions.noUncheckedIndexedAccess === false) {
289
+ out.push(makeFinding({
290
+ file, raw, key: 'noUncheckedIndexedAccess',
291
+ detectorId: 'bad-config',
292
+ severity: 'low',
293
+ title: 'tsconfig: \`noUncheckedIndexedAccess\` disabled',
294
+ blurb: '`array[i]` is typed `T` instead of `T | undefined`. Out-of-bounds access is invisible to the type-checker.',
295
+ suggestion: 'Set `"noUncheckedIndexedAccess": true` and handle the `undefined` case at each index.',
296
+ }));
297
+ }
298
+ if (compilerOptions.allowJs === true && compilerOptions.checkJs !== true) {
299
+ out.push(makeFinding({
300
+ file, raw, key: 'allowJs',
301
+ detectorId: 'bad-config',
302
+ severity: 'medium',
303
+ title: 'tsconfig: \`allowJs\` without \`checkJs\`',
304
+ blurb: 'JS files are bundled with the TS project but not type-checked, so they leak unchecked `any` types into every importer.',
305
+ suggestion: 'Either remove `"allowJs"` once the migration is done, or add `"checkJs": true` to type-check the JS too.',
306
+ }));
307
+ }
308
+ if (compilerOptions.skipLibCheck === false) {
309
+ // Not actually a bad practice in most cases; skip.
310
+ }
311
+ if (typeof compilerOptions.target === 'string' && /^(ES3|ES5)$/i.test(compilerOptions.target)) {
312
+ out.push(makeFinding({
313
+ file, raw, key: 'target',
314
+ detectorId: 'bad-config',
315
+ severity: 'low',
316
+ title: `tsconfig: \`target\` is ${compilerOptions.target}`,
317
+ blurb: 'Pre-ES2015 target ships heavy polyfills, breaks async/await without runtime, and signals an old toolchain.',
318
+ suggestion: 'Bump `"target"` to `ES2020` or newer (Node 16+ supports it natively).',
319
+ }));
320
+ }
321
+ if (typeof compilerOptions.module === 'string' && compilerOptions.module.toLowerCase() === 'commonjs' && !file.endsWith('tsconfig.base.json')) {
322
+ out.push(makeFinding({
323
+ file, raw, key: 'module',
324
+ detectorId: 'bad-config',
325
+ severity: 'low',
326
+ title: 'tsconfig: \`module\` is CommonJS',
327
+ blurb: 'CommonJS output blocks top-level `await`, ESM-only deps, and complicates bundler interop. ESM is the default in modern toolchains.',
328
+ suggestion: 'Move to `"module": "ESNext"` (or `"NodeNext"` on Node), and `"moduleResolution": "Bundler"` (or `"NodeNext"`).',
329
+ }));
330
+ }
331
+ if (compilerOptions.suppressImplicitAnyIndexErrors === true || compilerOptions.suppressExcessPropertyErrors === true) {
332
+ out.push(makeFinding({
333
+ file, raw, key: compilerOptions.suppressImplicitAnyIndexErrors === true ? 'suppressImplicitAnyIndexErrors' : 'suppressExcessPropertyErrors',
334
+ detectorId: 'bad-config',
335
+ severity: 'high',
336
+ title: 'tsconfig: error-suppression flag enabled',
337
+ blurb: '`suppressImplicitAnyIndexErrors` / `suppressExcessPropertyErrors` silence whole classes of errors. Both are documented escape hatches the TS team discourages.',
338
+ suggestion: 'Remove the suppression flag and fix the underlying errors (typed index signatures, exact object shapes).',
339
+ }));
340
+ }
341
+ return out;
342
+ }
343
+ function analyseEslint(file, raw, parsed) {
344
+ const root = asObj(parsed);
345
+ if (!root)
346
+ return [];
347
+ const rules = asObj(root.rules) ?? {};
348
+ return analyseEslintRules(file, raw, rules);
349
+ }
350
+ function analyseEslintRules(file, raw, rules) {
351
+ const out = [];
352
+ const BAD = {
353
+ '@typescript-eslint/no-explicit-any': {
354
+ sev: 'high',
355
+ title: 'eslint: \`no-explicit-any\` disabled',
356
+ blurb: '`any` defeats type-checking by design. Disabling this rule across the project is the lint-config equivalent of `strict:false`.',
357
+ suggestion: 'Re-enable the rule, fix offenders with `unknown` or generics, and use eslint-disable comments for the few legitimate cases.',
358
+ },
359
+ '@typescript-eslint/no-non-null-assertion': {
360
+ sev: 'medium',
361
+ title: 'eslint: \`no-non-null-assertion\` disabled',
362
+ blurb: '`foo!` overrides the type-checker. Disabling the rule globally normalises a pattern that silently crashes at runtime when the assumption fails.',
363
+ suggestion: 'Keep the rule on; opt out with a comment + reason at the rare site that actually needs it.',
364
+ },
365
+ '@typescript-eslint/no-unused-vars': {
366
+ sev: 'low',
367
+ title: 'eslint: \`no-unused-vars\` disabled',
368
+ blurb: 'Unused imports / vars accumulate, masking refactor mistakes and inflating bundle size.',
369
+ suggestion: 'Re-enable; prefix intentional throwaways with `_`.',
370
+ },
371
+ 'eqeqeq': {
372
+ sev: 'low',
373
+ title: 'eslint: \`eqeqeq\` disabled',
374
+ blurb: '`==` coercion bugs are still real. Disabling the rule allows accidental `null == 0` weirdness.',
375
+ suggestion: 'Re-enable with `"always"`.',
376
+ },
377
+ };
378
+ for (const [name, cfg] of Object.entries(BAD)) {
379
+ const val = rules[name];
380
+ if (val == null)
381
+ continue;
382
+ if (val === 'off' || val === 0 || (Array.isArray(val) && (val[0] === 'off' || val[0] === 0))) {
383
+ out.push(makeFinding({
384
+ file, raw, key: name,
385
+ detectorId: 'bad-config',
386
+ severity: cfg.sev,
387
+ title: cfg.title,
388
+ blurb: cfg.blurb,
389
+ suggestion: cfg.suggestion,
390
+ }));
391
+ }
392
+ }
393
+ return out;
394
+ }
395
+ function analyseEslintScript(file, raw) {
396
+ // Best-effort heuristic for `eslint.config.js` (Flat) and legacy
397
+ // `.eslintrc.js` — we can't execute the module safely, so we regex for
398
+ // rule lines like `'@typescript-eslint/no-explicit-any': 'off'`.
399
+ const out = [];
400
+ const PATTERNS = [
401
+ {
402
+ name: '@typescript-eslint/no-explicit-any',
403
+ re: /['"]@typescript-eslint\/no-explicit-any['"]\s*:\s*\[?\s*['"]?off['"]?|['"]@typescript-eslint\/no-explicit-any['"]\s*:\s*0\b/,
404
+ sev: 'high',
405
+ title: 'eslint: \`no-explicit-any\` disabled',
406
+ blurb: '`any` defeats type-checking by design. Disabling this rule across the project is the lint-config equivalent of `strict:false`.',
407
+ suggestion: 'Re-enable; fix offenders with `unknown` or generics.',
408
+ },
409
+ {
410
+ name: '@typescript-eslint/no-non-null-assertion',
411
+ re: /['"]@typescript-eslint\/no-non-null-assertion['"]\s*:\s*\[?\s*['"]?off['"]?/,
412
+ sev: 'medium',
413
+ title: 'eslint: \`no-non-null-assertion\` disabled',
414
+ blurb: '`foo!` overrides the type-checker; rule should stay on.',
415
+ suggestion: 'Keep the rule on; opt out at site with a comment.',
416
+ },
417
+ {
418
+ name: '@typescript-eslint/no-unused-vars',
419
+ re: /['"]@typescript-eslint\/no-unused-vars['"]\s*:\s*\[?\s*['"]?off['"]?/,
420
+ sev: 'low',
421
+ title: 'eslint: \`no-unused-vars\` disabled',
422
+ blurb: 'Unused imports / vars accumulate, masking refactors.',
423
+ suggestion: 'Re-enable; prefix intentional throwaways with `_`.',
424
+ },
425
+ {
426
+ name: 'eqeqeq',
427
+ re: /['"]eqeqeq['"]\s*:\s*\[?\s*['"]?off['"]?/,
428
+ sev: 'low',
429
+ title: 'eslint: \`eqeqeq\` disabled',
430
+ blurb: '`==` coercion bugs are still real.',
431
+ suggestion: 'Re-enable with `"always"`.',
432
+ },
433
+ ];
434
+ for (const p of PATTERNS) {
435
+ const m = p.re.exec(raw);
436
+ if (!m)
437
+ continue;
438
+ out.push(makeFinding({
439
+ file, raw, key: p.name, indexOverride: m.index,
440
+ detectorId: 'bad-config',
441
+ severity: p.sev,
442
+ title: p.title,
443
+ blurb: p.blurb,
444
+ suggestion: p.suggestion,
445
+ }));
446
+ }
447
+ return out;
448
+ }
449
+ function analyseBiome(file, raw, parsed) {
450
+ const root = asObj(parsed);
451
+ if (!root)
452
+ return [];
453
+ const linter = asObj(root.linter) ?? {};
454
+ const rulesGroup = asObj(linter.rules) ?? {};
455
+ const suspicious = asObj(rulesGroup.suspicious) ?? {};
456
+ const style = asObj(rulesGroup.style) ?? {};
457
+ const out = [];
458
+ if (suspicious.noExplicitAny === 'off') {
459
+ out.push(makeFinding({
460
+ file, raw, key: 'noExplicitAny',
461
+ detectorId: 'bad-config',
462
+ severity: 'high',
463
+ title: 'biome: \`noExplicitAny\` disabled',
464
+ blurb: '`any` defeats type-checking by design.',
465
+ suggestion: 'Re-enable; fix offenders with `unknown` or generics.',
466
+ }));
467
+ }
468
+ if (style.noNonNullAssertion === 'off') {
469
+ out.push(makeFinding({
470
+ file, raw, key: 'noNonNullAssertion',
471
+ detectorId: 'bad-config',
472
+ severity: 'medium',
473
+ title: 'biome: \`noNonNullAssertion\` disabled',
474
+ blurb: '`foo!` overrides the type-checker.',
475
+ suggestion: 'Keep on; opt out at site with a comment.',
476
+ }));
477
+ }
478
+ if (linter.enabled === false) {
479
+ out.push(makeFinding({
480
+ file, raw, key: 'linter.enabled',
481
+ detectorId: 'bad-config',
482
+ severity: 'medium',
483
+ title: 'biome: linter disabled',
484
+ blurb: 'The whole linter is off — lint findings will never reach the developer.',
485
+ suggestion: 'Set `"enabled": true` and tune individual rules instead.',
486
+ }));
487
+ }
488
+ return out;
489
+ }
490
+ function makeFinding(args) {
491
+ const { line, snippetLines } = locateInSource(args.raw, args.key, args.indexOverride);
492
+ return {
493
+ detectorId: args.detectorId,
494
+ severity: args.severity,
495
+ confidence: 0.95,
496
+ layer: 1,
497
+ title: `${args.title} \`${args.file}\``,
498
+ description: args.blurb,
499
+ evidence: [
500
+ {
501
+ file: args.file,
502
+ range: { startLine: line, endLine: line },
503
+ snippet: snippetLines.join('\n'),
504
+ },
505
+ ],
506
+ suggestion: args.suggestion,
507
+ fingerprint: `bad-config:${stableHash(`${args.file}:${args.key}`)}`,
508
+ };
509
+ }
510
+ function locateInSource(raw, key, indexOverride) {
511
+ const idx = indexOverride ?? findKeyIndex(raw, key);
512
+ const lines = raw.split('\n');
513
+ if (idx < 0) {
514
+ return { line: 1, snippetLines: lines.slice(0, Math.min(3, lines.length)) };
515
+ }
516
+ const preceding = raw.slice(0, idx);
517
+ const line = preceding.split('\n').length;
518
+ const start = Math.max(0, line - 2);
519
+ const end = Math.min(lines.length, line + 2);
520
+ return { line, snippetLines: lines.slice(start, end) };
521
+ }
522
+ function findKeyIndex(raw, key) {
523
+ // Look for `"key"` or `'key'` followed by `:` — handles both JSONC and
524
+ // JS-style config dumps.
525
+ const re = new RegExp(`["']${escapeForRegex(key)}["']\\s*:`);
526
+ const m = re.exec(raw);
527
+ return m ? m.index : -1;
528
+ }
529
+ //# sourceMappingURL=bad-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bad-config.js","sourceRoot":"","sources":["../../src/detectors/bad-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { Finding } from '../types.js';
2
+ import type { FileWalkingDetectorInput } from '../types/detector-input.js';
3
+ export interface ConsoleLogProdDetectorInput extends FileWalkingDetectorInput {
4
+ }
5
+ export declare function detectConsoleLogsInProd(input: ConsoleLogProdDetectorInput): Finding[];
6
+ //# sourceMappingURL=console-log-prod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"console-log-prod.d.ts","sourceRoot":"","sources":["../../src/detectors/console-log-prod.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAI3C,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAE3E,MAAM,WAAW,2BAA4B,SAAQ,wBAAwB;CAAG;AAGhF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,2BAA2B,GAAG,OAAO,EAAE,CAUrF"}
@@ -0,0 +1,72 @@
1
+ import { makeSourceReader } from '../utils/source-reader.js';
2
+ import { stableHash } from '../utils/hash.js';
3
+ import { hasIgnoreAnnotation } from '../utils/ignore-annotation.js';
4
+ // console.log/.debug/.info in non-test source. warn/error are intentional. LOW.
5
+ export function detectConsoleLogsInProd(input) {
6
+ const read = makeSourceReader(input.workspaceRoot, input.project);
7
+ const findings = [];
8
+ for (const rel of input.files) {
9
+ if (!isAnalysable(rel))
10
+ continue;
11
+ const raw = read(rel);
12
+ if (raw == null)
13
+ continue;
14
+ findings.push(...analyseFile(rel, raw));
15
+ }
16
+ return findings;
17
+ }
18
+ const LOG_RE = /\bconsole\.(log|debug|info)\s*\(/g;
19
+ function analyseFile(file, raw) {
20
+ const out = [];
21
+ for (const m of raw.matchAll(LOG_RE)) {
22
+ const line = lineOf(raw, m.index);
23
+ // Skip if the call is inside a line comment.
24
+ const lineText = lineAt(raw, line);
25
+ if (/^\s*\/\//.test(lineText))
26
+ continue;
27
+ if (hasIgnoreAnnotation(raw, line, 'console-log-prod'))
28
+ continue;
29
+ out.push({
30
+ detectorId: 'console-log-prod',
31
+ severity: 'low',
32
+ confidence: 0.9,
33
+ layer: 1,
34
+ title: `console.${m[1]} in ${file}:${line}`,
35
+ description: `\`console.${m[1]}\` leaks to stdout in production. Loggers configured for severity, redaction, or sampling do not see this output, and CI / serverless / browser consoles pollute with debug noise.`,
36
+ evidence: [
37
+ {
38
+ file,
39
+ range: { startLine: line, endLine: line },
40
+ snippet: snippetAround(raw, line),
41
+ },
42
+ ],
43
+ suggestion: 'Route through the project logger (pino / winston / debug / your custom one). For temporary debugging, gate behind `if (process.env.DEBUG)` or remove before merging.',
44
+ fingerprint: `console-log-prod:${stableHash(`${file}:${line}:${m[1]}`)}`,
45
+ });
46
+ }
47
+ return out;
48
+ }
49
+ function lineAt(raw, line) {
50
+ return raw.split('\n')[line - 1] ?? '';
51
+ }
52
+ function isAnalysable(file) {
53
+ const posix = file.replace(/\\/g, '/');
54
+ return /\.(?:ts|tsx|mts|cts|js|jsx|mjs|cjs)$/.test(posix)
55
+ && !/\.d\.ts$/.test(posix)
56
+ && !/(^|\/)node_modules\//.test(posix)
57
+ && !/(?:^|\/)__tests__\//.test(posix)
58
+ && !/(?:^|\/)tests?\//.test(posix)
59
+ && !/(?:^|\/)scripts?\//.test(posix)
60
+ && !/\.test\.(?:ts|tsx|js|jsx)$/.test(posix)
61
+ && !/\.spec\.(?:ts|tsx|js|jsx)$/.test(posix);
62
+ }
63
+ function lineOf(raw, idx) {
64
+ return raw.slice(0, idx).split('\n').length;
65
+ }
66
+ function snippetAround(raw, line) {
67
+ const lines = raw.split('\n');
68
+ const from = Math.max(0, line - 1);
69
+ const to = Math.min(lines.length, line + 1);
70
+ return lines.slice(from, to).join('\n');
71
+ }
72
+ //# sourceMappingURL=console-log-prod.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"console-log-prod.js","sourceRoot":"","sources":["../../src/detectors/console-log-prod.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { Finding, SymbolRecord } from '../types.js';
2
+ import type { ImportRecord } from '../graph/import-graph.js';
3
+ export interface DeadApiDetectorInput {
4
+ /** Symbols from every linked workspace. `exported` set, `workspace` set. */
5
+ symbols: ReadonlyArray<SymbolRecord>;
6
+ /** Imports from every linked workspace, with `sourceWorkspace` + optional `targetWorkspace`. */
7
+ imports: ReadonlyArray<ImportRecord>;
8
+ }
9
+ export declare function detectDeadApis(input: DeadApiDetectorInput): Finding[];
10
+ //# sourceMappingURL=dead-api.d.ts.map