@kevinrabun/judges 3.57.0 → 3.59.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.
Files changed (70) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +112 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/api-misuse.d.ts +5 -0
  6. package/dist/commands/api-misuse.d.ts.map +1 -0
  7. package/dist/commands/api-misuse.js +261 -0
  8. package/dist/commands/api-misuse.js.map +1 -0
  9. package/dist/commands/assertion-density.d.ts +5 -0
  10. package/dist/commands/assertion-density.d.ts.map +1 -0
  11. package/dist/commands/assertion-density.js +264 -0
  12. package/dist/commands/assertion-density.js.map +1 -0
  13. package/dist/commands/async-safety.d.ts +5 -0
  14. package/dist/commands/async-safety.d.ts.map +1 -0
  15. package/dist/commands/async-safety.js +267 -0
  16. package/dist/commands/async-safety.js.map +1 -0
  17. package/dist/commands/clone-detect.d.ts +5 -0
  18. package/dist/commands/clone-detect.d.ts.map +1 -0
  19. package/dist/commands/clone-detect.js +233 -0
  20. package/dist/commands/clone-detect.js.map +1 -0
  21. package/dist/commands/completion-audit.d.ts +5 -0
  22. package/dist/commands/completion-audit.d.ts.map +1 -0
  23. package/dist/commands/completion-audit.js +297 -0
  24. package/dist/commands/completion-audit.js.map +1 -0
  25. package/dist/commands/contract-verify.d.ts +5 -0
  26. package/dist/commands/contract-verify.d.ts.map +1 -0
  27. package/dist/commands/contract-verify.js +317 -0
  28. package/dist/commands/contract-verify.js.map +1 -0
  29. package/dist/commands/cross-file-consistency.d.ts +5 -0
  30. package/dist/commands/cross-file-consistency.d.ts.map +1 -0
  31. package/dist/commands/cross-file-consistency.js +255 -0
  32. package/dist/commands/cross-file-consistency.js.map +1 -0
  33. package/dist/commands/dead-code-detect.d.ts +5 -0
  34. package/dist/commands/dead-code-detect.d.ts.map +1 -0
  35. package/dist/commands/dead-code-detect.js +256 -0
  36. package/dist/commands/dead-code-detect.js.map +1 -0
  37. package/dist/commands/encoding-safety.d.ts +5 -0
  38. package/dist/commands/encoding-safety.d.ts.map +1 -0
  39. package/dist/commands/encoding-safety.js +276 -0
  40. package/dist/commands/encoding-safety.js.map +1 -0
  41. package/dist/commands/example-leak.d.ts +5 -0
  42. package/dist/commands/example-leak.d.ts.map +1 -0
  43. package/dist/commands/example-leak.js +233 -0
  44. package/dist/commands/example-leak.js.map +1 -0
  45. package/dist/commands/input-guard.d.ts +5 -0
  46. package/dist/commands/input-guard.d.ts.map +1 -0
  47. package/dist/commands/input-guard.js +256 -0
  48. package/dist/commands/input-guard.js.map +1 -0
  49. package/dist/commands/logic-lint.d.ts +5 -0
  50. package/dist/commands/logic-lint.d.ts.map +1 -0
  51. package/dist/commands/logic-lint.js +256 -0
  52. package/dist/commands/logic-lint.js.map +1 -0
  53. package/dist/commands/phantom-import.d.ts +5 -0
  54. package/dist/commands/phantom-import.d.ts.map +1 -0
  55. package/dist/commands/phantom-import.js +261 -0
  56. package/dist/commands/phantom-import.js.map +1 -0
  57. package/dist/commands/review-focus.d.ts +5 -0
  58. package/dist/commands/review-focus.d.ts.map +1 -0
  59. package/dist/commands/review-focus.js +197 -0
  60. package/dist/commands/review-focus.js.map +1 -0
  61. package/dist/commands/spec-conform.d.ts +5 -0
  62. package/dist/commands/spec-conform.d.ts.map +1 -0
  63. package/dist/commands/spec-conform.js +305 -0
  64. package/dist/commands/spec-conform.js.map +1 -0
  65. package/dist/commands/state-integrity.d.ts +5 -0
  66. package/dist/commands/state-integrity.d.ts.map +1 -0
  67. package/dist/commands/state-integrity.js +284 -0
  68. package/dist/commands/state-integrity.js.map +1 -0
  69. package/package.json +1 -1
  70. package/server.json +2 -2
@@ -0,0 +1,261 @@
1
+ /**
2
+ * API misuse — detect incorrect API usage patterns that AI commonly generates.
3
+ */
4
+ import { readFileSync, readdirSync, statSync } from "fs";
5
+ import { join, extname } from "path";
6
+ // ─── File Collection ────────────────────────────────────────────────────────
7
+ const CODE_EXTS = new Set([".ts", ".tsx", ".js", ".jsx", ".py", ".java", ".go"]);
8
+ function collectFiles(dir, max = 300) {
9
+ const files = [];
10
+ function walk(d) {
11
+ if (files.length >= max)
12
+ return;
13
+ let entries;
14
+ try {
15
+ entries = readdirSync(d);
16
+ }
17
+ catch {
18
+ return;
19
+ }
20
+ for (const e of entries) {
21
+ if (files.length >= max)
22
+ return;
23
+ if (e.startsWith(".") || e === "node_modules" || e === "dist" || e === "build")
24
+ continue;
25
+ const full = join(d, e);
26
+ try {
27
+ if (statSync(full).isDirectory())
28
+ walk(full);
29
+ else if (CODE_EXTS.has(extname(full)))
30
+ files.push(full);
31
+ }
32
+ catch {
33
+ /* skip */
34
+ }
35
+ }
36
+ }
37
+ walk(dir);
38
+ return files;
39
+ }
40
+ // ─── Analysis ───────────────────────────────────────────────────────────────
41
+ function analyzeFile(filepath) {
42
+ const issues = [];
43
+ let content;
44
+ try {
45
+ content = readFileSync(filepath, "utf-8");
46
+ }
47
+ catch {
48
+ return issues;
49
+ }
50
+ const lines = content.split("\n");
51
+ for (let i = 0; i < lines.length; i++) {
52
+ const line = lines[i];
53
+ const trimmed = line.trim();
54
+ // Array.forEach with async callback (doesn't await)
55
+ if (/\.forEach\s*\(\s*async\b/.test(trimmed)) {
56
+ issues.push({
57
+ file: filepath,
58
+ line: i + 1,
59
+ issue: "async forEach (doesn't await)",
60
+ severity: "high",
61
+ detail: "Array.forEach ignores returned promises — use `for...of` with `await` or `Promise.all` with `.map`",
62
+ });
63
+ }
64
+ // JSON.parse without try/catch
65
+ if (/JSON\.parse\s*\(/.test(trimmed)) {
66
+ const block = lines.slice(Math.max(0, i - 5), i + 1).join("\n");
67
+ if (!/try\s*\{|catch|\.catch|safeParse|tryCatch/i.test(block)) {
68
+ issues.push({
69
+ file: filepath,
70
+ line: i + 1,
71
+ issue: "JSON.parse without error handling",
72
+ severity: "medium",
73
+ detail: "JSON.parse throws on invalid input — wrap in try/catch or use a safe parser",
74
+ });
75
+ }
76
+ }
77
+ // fetch/axios without error status check
78
+ if (/(?:await\s+)?fetch\s*\(/.test(trimmed) &&
79
+ !/\.ok|\.status|response\.ok|res\.ok/.test(lines.slice(i, Math.min(i + 5, lines.length)).join("\n"))) {
80
+ const block = lines.slice(i, Math.min(i + 8, lines.length)).join("\n");
81
+ if (/\.json\(\)/.test(block) && !/\.ok|\.status|response\.ok|res\.ok|catch|reject/.test(block)) {
82
+ issues.push({
83
+ file: filepath,
84
+ line: i + 1,
85
+ issue: "fetch() without status check",
86
+ severity: "high",
87
+ detail: "fetch() doesn't reject on HTTP errors — check `response.ok` before calling `.json()`",
88
+ });
89
+ }
90
+ }
91
+ // Array methods on possibly undefined (no optional chaining)
92
+ if (/\.\w+\.(map|filter|reduce|find|forEach|some|every)\s*\(/.test(trimmed)) {
93
+ const dotChain = trimmed.match(/(\w+)\.(\w+)\.(map|filter|reduce|find|forEach|some|every)/);
94
+ if (dotChain && !trimmed.includes("?.") && !/\(/.test(dotChain[2])) {
95
+ // Check if the property could be undefined
96
+ const propName = `${dotChain[1]}.${dotChain[2]}`;
97
+ if (!/\bconst\b/.test(trimmed) && !/length|size/.test(dotChain[2])) {
98
+ issues.push({
99
+ file: filepath,
100
+ line: i + 1,
101
+ issue: "Array method on possibly undefined property",
102
+ severity: "medium",
103
+ detail: `\`${propName}\` might be undefined — use optional chaining or null check before \`.${dotChain[3]}()\``,
104
+ });
105
+ }
106
+ }
107
+ }
108
+ // setTimeout/setInterval with string argument
109
+ if (/(?:setTimeout|setInterval)\s*\(\s*['"]/.test(trimmed)) {
110
+ issues.push({
111
+ file: filepath,
112
+ line: i + 1,
113
+ issue: "setTimeout/setInterval with string (eval)",
114
+ severity: "high",
115
+ detail: "String argument to setTimeout/setInterval is evaluated with eval — use a function instead",
116
+ });
117
+ }
118
+ // RegExp constructor with unescaped user input
119
+ if (/new\s+RegExp\s*\(/.test(trimmed)) {
120
+ const arg = trimmed.match(/new\s+RegExp\s*\(\s*(\w+)/)?.[1];
121
+ if (arg && !/escape|sanitize|literal|fixed|constant|regex/i.test(trimmed)) {
122
+ issues.push({
123
+ file: filepath,
124
+ line: i + 1,
125
+ issue: "RegExp from variable (ReDoS risk)",
126
+ severity: "medium",
127
+ detail: `\`new RegExp(${arg})\` — if ${arg} is user input, this enables ReDoS attacks. Escape special characters first`,
128
+ });
129
+ }
130
+ }
131
+ // Promise constructor anti-pattern
132
+ if (/new\s+Promise\s*\(\s*async\b/.test(trimmed)) {
133
+ issues.push({
134
+ file: filepath,
135
+ line: i + 1,
136
+ issue: "async Promise constructor anti-pattern",
137
+ severity: "medium",
138
+ detail: "async function inside `new Promise()` can swallow rejections — just use async/await directly",
139
+ });
140
+ }
141
+ // .then().then() chain mixing with await
142
+ if (/\.then\s*\(.*\.then\s*\(/.test(trimmed) ||
143
+ (/\.then\s*\(/.test(trimmed) && /await/.test(lines.slice(Math.max(0, i - 3), i).join("\n")))) {
144
+ if (/await.*\.then\s*\(/.test(lines.slice(Math.max(0, i - 1), i + 1).join("\n"))) {
145
+ issues.push({
146
+ file: filepath,
147
+ line: i + 1,
148
+ issue: "Mixing await with .then() chains",
149
+ severity: "low",
150
+ detail: "Mixing async/await with .then() chains makes code harder to reason about — pick one style",
151
+ });
152
+ }
153
+ }
154
+ // Object.keys/values/entries on Map or Set
155
+ if (/Object\.(?:keys|values|entries)\s*\(\s*\w+\s*\)/.test(trimmed)) {
156
+ const varName = trimmed.match(/Object\.(?:keys|values|entries)\s*\(\s*(\w+)\s*\)/)?.[1];
157
+ if (varName) {
158
+ const typeHint = content.match(new RegExp(`(?:Map|Set)\\b[^;]*\\b${varName}\\b|\\b${varName}\\b[^;]*(?:Map|Set)\\b`));
159
+ if (typeHint) {
160
+ issues.push({
161
+ file: filepath,
162
+ line: i + 1,
163
+ issue: "Object.keys/values/entries on Map/Set",
164
+ severity: "high",
165
+ detail: `\`${varName}\` appears to be a Map or Set — use \`.keys()\`, \`.values()\`, or \`.entries()\` methods instead`,
166
+ });
167
+ }
168
+ }
169
+ }
170
+ // String.replace without /g flag (replaces only first match)
171
+ if (/\.replace\s*\(\s*['"]/.test(trimmed) && !trimmed.includes("replaceAll")) {
172
+ issues.push({
173
+ file: filepath,
174
+ line: i + 1,
175
+ issue: ".replace() with string (first match only)",
176
+ severity: "low",
177
+ detail: "String.replace with string pattern only replaces the FIRST match — use .replaceAll() or regex with /g flag",
178
+ });
179
+ }
180
+ // Event listener without passive option for scroll/touch
181
+ if (/addEventListener\s*\(\s*['"](?:scroll|touchstart|touchmove|wheel)['"]/.test(trimmed)) {
182
+ if (!trimmed.includes("passive")) {
183
+ issues.push({
184
+ file: filepath,
185
+ line: i + 1,
186
+ issue: "Scroll/touch listener without passive",
187
+ severity: "low",
188
+ detail: "Add `{ passive: true }` to scroll/touch listeners for better performance",
189
+ });
190
+ }
191
+ }
192
+ // Using == instead of === (loose equality)
193
+ if (/[^!=]==[^=]/.test(trimmed) && !/===/.test(trimmed) && !/==\s*null/.test(trimmed)) {
194
+ issues.push({
195
+ file: filepath,
196
+ line: i + 1,
197
+ issue: "Loose equality (==) instead of strict (===)",
198
+ severity: "low",
199
+ detail: "AI often generates `==` — use `===` to avoid type coercion surprises",
200
+ });
201
+ }
202
+ }
203
+ return issues;
204
+ }
205
+ // ─── CLI ────────────────────────────────────────────────────────────────────
206
+ export function runApiMisuse(argv) {
207
+ if (argv.includes("--help") || argv.includes("-h")) {
208
+ console.log(`
209
+ judges api-misuse — Detect incorrect API usage patterns from AI-generated code
210
+
211
+ Usage:
212
+ judges api-misuse [dir]
213
+ judges api-misuse src/ --format json
214
+
215
+ Options:
216
+ [dir] Directory to scan (default: .)
217
+ --format json JSON output
218
+ --help, -h Show this help
219
+
220
+ Checks: async forEach, unprotected JSON.parse, fetch without status check, setTimeout with string,
221
+ Promise constructor anti-pattern, Object.keys on Map/Set, .replace first-match-only,
222
+ loose equality, RegExp ReDoS, missing passive listeners.
223
+ `);
224
+ return;
225
+ }
226
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
227
+ const dir = argv.find((a) => !a.startsWith("-") && argv.indexOf(a) > 0) || ".";
228
+ const files = collectFiles(dir);
229
+ const allIssues = [];
230
+ for (const f of files)
231
+ allIssues.push(...analyzeFile(f));
232
+ const highCount = allIssues.filter((i) => i.severity === "high").length;
233
+ const medCount = allIssues.filter((i) => i.severity === "medium").length;
234
+ const score = Math.max(0, 100 - highCount * 10 - medCount * 4);
235
+ if (format === "json") {
236
+ console.log(JSON.stringify({
237
+ issues: allIssues,
238
+ score,
239
+ summary: { high: highCount, medium: medCount, total: allIssues.length },
240
+ timestamp: new Date().toISOString(),
241
+ }, null, 2));
242
+ }
243
+ else {
244
+ const badge = score >= 80 ? "✅ CORRECT" : score >= 50 ? "⚠️ MISUSED" : "❌ BROKEN";
245
+ console.log(`\n API Misuse: ${badge} (${score}/100)\n ─────────────────────────────`);
246
+ if (allIssues.length === 0) {
247
+ console.log(" No API misuse patterns detected.\n");
248
+ return;
249
+ }
250
+ for (const issue of allIssues.slice(0, 25)) {
251
+ const icon = issue.severity === "high" ? "🔴" : issue.severity === "medium" ? "🟡" : "🔵";
252
+ console.log(` ${icon} ${issue.issue}`);
253
+ console.log(` ${issue.file}:${issue.line}`);
254
+ console.log(` ${issue.detail}`);
255
+ }
256
+ if (allIssues.length > 25)
257
+ console.log(` ... and ${allIssues.length - 25} more`);
258
+ console.log(`\n Total: ${allIssues.length} | High: ${highCount} | Medium: ${medCount} | Score: ${score}/100\n`);
259
+ }
260
+ }
261
+ //# sourceMappingURL=api-misuse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-misuse.js","sourceRoot":"","sources":["../../src/commands/api-misuse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Assertion density — measure and enforce guard-clause and invariant density in critical code.
3
+ */
4
+ export declare function runAssertionDensity(argv: string[]): void;
5
+ //# sourceMappingURL=assertion-density.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assertion-density.d.ts","sourceRoot":"","sources":["../../src/commands/assertion-density.ts"],"names":[],"mappings":"AAAA;;GAEG;AA2OH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA+DxD"}
@@ -0,0 +1,264 @@
1
+ /**
2
+ * Assertion density — measure and enforce guard-clause and invariant density in critical code.
3
+ */
4
+ import { readFileSync, readdirSync, statSync } from "fs";
5
+ import { join, extname } from "path";
6
+ // ─── File Collection ────────────────────────────────────────────────────────
7
+ const CODE_EXTS = new Set([".ts", ".tsx", ".js", ".jsx", ".py", ".java", ".go"]);
8
+ function collectFiles(dir, max = 300) {
9
+ const files = [];
10
+ function walk(d) {
11
+ if (files.length >= max)
12
+ return;
13
+ let entries;
14
+ try {
15
+ entries = readdirSync(d);
16
+ }
17
+ catch {
18
+ return;
19
+ }
20
+ for (const e of entries) {
21
+ if (files.length >= max)
22
+ return;
23
+ if (e.startsWith(".") || e === "node_modules" || e === "dist" || e === "build")
24
+ continue;
25
+ const full = join(d, e);
26
+ try {
27
+ if (statSync(full).isDirectory())
28
+ walk(full);
29
+ else if (CODE_EXTS.has(extname(full)))
30
+ files.push(full);
31
+ }
32
+ catch {
33
+ /* skip */
34
+ }
35
+ }
36
+ }
37
+ walk(dir);
38
+ return files;
39
+ }
40
+ // ─── Analysis ───────────────────────────────────────────────────────────────
41
+ function analyzeFile(filepath) {
42
+ const issues = [];
43
+ let content;
44
+ try {
45
+ content = readFileSync(filepath, "utf-8");
46
+ }
47
+ catch {
48
+ return issues;
49
+ }
50
+ // Skip test files
51
+ if (/\.test\.|\.spec\.|__test__|fixture/i.test(filepath))
52
+ return issues;
53
+ const lines = content.split("\n");
54
+ for (let i = 0; i < lines.length; i++) {
55
+ const line = lines[i];
56
+ // Function definition — check for precondition guards
57
+ const funcMatch = line.match(/(?:function\s+(\w+)|(?:const|let)\s+(\w+)\s*=\s*(?:async\s*)?(?:\([^)]*\)|[^=]+=>\s*\{))/);
58
+ if (funcMatch) {
59
+ const funcName = funcMatch[1] || funcMatch[2];
60
+ if (funcName && funcName.length > 2 && !funcName.startsWith("_")) {
61
+ let depth = 0;
62
+ let funcEnd = i;
63
+ let started = false;
64
+ for (let j = i; j < Math.min(i + 60, lines.length); j++) {
65
+ for (const ch of lines[j]) {
66
+ if (ch === "{") {
67
+ depth++;
68
+ started = true;
69
+ }
70
+ if (ch === "}")
71
+ depth--;
72
+ }
73
+ if (started && depth <= 0) {
74
+ funcEnd = j;
75
+ break;
76
+ }
77
+ }
78
+ const funcBody = lines.slice(i + 1, Math.min(funcEnd, i + 30));
79
+ const bodyText = funcBody.join("\n");
80
+ const bodyLength = funcBody.filter((l) => l.trim().length > 0).length;
81
+ if (bodyLength > 8) {
82
+ // Check for guard clauses
83
+ const hasGuards = /if\s*\(!|if\s*\(\s*\w+\s*===?\s*(?:null|undefined|false|0|''|"")|\bthrow\b|\bassert\b|invariant\(|precondition/i.test(funcBody.slice(0, 5).join("\n"));
84
+ const hasParamValidation = /typeof\s+\w+|instanceof|isNaN|isFinite|Array\.isArray|!==?\s*(?:null|undefined)/i.test(funcBody.slice(0, 5).join("\n"));
85
+ if (!hasGuards && !hasParamValidation) {
86
+ // Check if function takes parameters that should be validated
87
+ const paramLine = lines[i];
88
+ const hasParams = /\(\s*\w+/.test(paramLine) && !/\(\s*\)\s*/.test(paramLine);
89
+ if (hasParams) {
90
+ issues.push({
91
+ file: filepath,
92
+ line: i + 1,
93
+ issue: "Function without precondition guards",
94
+ severity: "medium",
95
+ detail: `\`${funcName}\` takes parameters but has no guard clauses — add validation for unexpected inputs`,
96
+ });
97
+ }
98
+ }
99
+ // Check for division without zero-check
100
+ if (/\/\s*\w+/.test(bodyText) && !/\/\s*\d+[^.]|\/\/|\/\*|\*\//.test(bodyText)) {
101
+ if (!/=== 0|!== 0|> 0|< 0|isNaN|isFinite|zero/i.test(bodyText)) {
102
+ // Only flag if dividing by a variable
103
+ const divMatch = bodyText.match(/\/\s*([a-zA-Z]\w*)/);
104
+ if (divMatch && !/length|size|count|PI|max|min/i.test(divMatch[1])) {
105
+ issues.push({
106
+ file: filepath,
107
+ line: i + 1,
108
+ issue: "Division without zero-check",
109
+ severity: "medium",
110
+ detail: `Division by \`${divMatch[1]}\` without verifying non-zero — may cause Infinity/NaN`,
111
+ });
112
+ }
113
+ }
114
+ }
115
+ }
116
+ }
117
+ }
118
+ // Switch without default
119
+ if (/^\s*switch\s*\(/.test(line)) {
120
+ let depth = 0;
121
+ let switchEnd = i;
122
+ let started = false;
123
+ for (let j = i; j < Math.min(i + 50, lines.length); j++) {
124
+ for (const ch of lines[j]) {
125
+ if (ch === "{") {
126
+ depth++;
127
+ started = true;
128
+ }
129
+ if (ch === "}")
130
+ depth--;
131
+ }
132
+ if (started && depth <= 0) {
133
+ switchEnd = j;
134
+ break;
135
+ }
136
+ }
137
+ const switchBody = lines.slice(i, switchEnd + 1).join("\n");
138
+ if (!/\bdefault\s*:/i.test(switchBody)) {
139
+ issues.push({
140
+ file: filepath,
141
+ line: i + 1,
142
+ issue: "Switch without default case",
143
+ severity: "medium",
144
+ detail: "Switch statement has no default — unhandled values will silently fall through",
145
+ });
146
+ }
147
+ }
148
+ // Array access without bounds check
149
+ if (/\w+\[\s*\w+\s*\]/.test(line) && !/\[\s*['"]/.test(line)) {
150
+ const accessMatch = line.match(/(\w+)\[\s*(\w+)\s*\]/);
151
+ if (accessMatch) {
152
+ const arr = accessMatch[1];
153
+ const idx = accessMatch[2];
154
+ // Only flag if index is a variable (not string, not 0/1)
155
+ if (/^[a-zA-Z]/.test(idx) && !/length|size|map|filter|reduce|find|forEach|Object|Math|console/i.test(arr)) {
156
+ const block = lines.slice(Math.max(0, i - 3), Math.min(i + 2, lines.length)).join("\n");
157
+ if (!/\.length|bounds|range|<|>|>=|<=|if\s*\(|assert|check|valid/i.test(block)) {
158
+ issues.push({
159
+ file: filepath,
160
+ line: i + 1,
161
+ issue: "Array access without bounds check",
162
+ severity: "low",
163
+ detail: `\`${arr}[${idx}]\` accessed without verifying index is within bounds`,
164
+ });
165
+ }
166
+ }
167
+ }
168
+ }
169
+ // Optional chaining overuse (hiding real bugs)
170
+ const optionalChainCount = (line.match(/\?\./g) || []).length;
171
+ if (optionalChainCount > 3) {
172
+ issues.push({
173
+ file: filepath,
174
+ line: i + 1,
175
+ issue: "Excessive optional chaining",
176
+ severity: "low",
177
+ detail: `${optionalChainCount} optional chains in one expression — may indicate unclear data contract`,
178
+ });
179
+ }
180
+ // Parsing without isNaN check
181
+ if (/(?:parseInt|parseFloat|Number)\s*\(/.test(line)) {
182
+ const block = lines.slice(i, Math.min(i + 3, lines.length)).join("\n");
183
+ if (!/isNaN|isFinite|Number\.is|!==\s*NaN|\|\||[?][?]/i.test(block)) {
184
+ issues.push({
185
+ file: filepath,
186
+ line: i + 1,
187
+ issue: "Number parsing without NaN check",
188
+ severity: "low",
189
+ detail: "parseInt/parseFloat/Number can return NaN — check before using the result",
190
+ });
191
+ }
192
+ }
193
+ // Map/object key access without existence check
194
+ if (/\.get\s*\(\s*\w+\s*\)/.test(line) && !/Map|WeakMap|Headers|URLSearchParams/i.test(line)) {
195
+ const block = lines.slice(i, Math.min(i + 3, lines.length)).join("\n");
196
+ if (!/if\s*\(|has\s*\(|undefined|null|\?\./i.test(block)) {
197
+ issues.push({
198
+ file: filepath,
199
+ line: i + 1,
200
+ issue: "Map.get without existence check",
201
+ severity: "low",
202
+ detail: "Map.get() returns undefined for missing keys — check with .has() or handle undefined",
203
+ });
204
+ }
205
+ }
206
+ }
207
+ return issues;
208
+ }
209
+ // ─── CLI ────────────────────────────────────────────────────────────────────
210
+ export function runAssertionDensity(argv) {
211
+ if (argv.includes("--help") || argv.includes("-h")) {
212
+ console.log(`
213
+ judges assertion-density — Measure guard-clause and invariant density in critical code
214
+
215
+ Usage:
216
+ judges assertion-density [dir]
217
+ judges assertion-density src/ --format json
218
+
219
+ Options:
220
+ [dir] Directory to scan (default: .)
221
+ --format json JSON output
222
+ --help, -h Show this help
223
+
224
+ Checks: functions without preconditions, division without zero-check, switch without default,
225
+ array access without bounds check, number parsing without NaN check, excessive optional chaining.
226
+ `);
227
+ return;
228
+ }
229
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
230
+ const dir = argv.find((a) => !a.startsWith("-") && argv.indexOf(a) > 0) || ".";
231
+ const files = collectFiles(dir);
232
+ const allIssues = [];
233
+ for (const f of files)
234
+ allIssues.push(...analyzeFile(f));
235
+ const highCount = allIssues.filter((i) => i.severity === "high").length;
236
+ const medCount = allIssues.filter((i) => i.severity === "medium").length;
237
+ const score = Math.max(0, 100 - highCount * 8 - medCount * 3);
238
+ if (format === "json") {
239
+ console.log(JSON.stringify({
240
+ issues: allIssues,
241
+ score,
242
+ summary: { high: highCount, medium: medCount, total: allIssues.length },
243
+ timestamp: new Date().toISOString(),
244
+ }, null, 2));
245
+ }
246
+ else {
247
+ const badge = score >= 80 ? "✅ DEFENSIVE" : score >= 50 ? "⚠️ OPTIMISTIC" : "❌ FRAGILE";
248
+ console.log(`\n Assertion Density: ${badge} (${score}/100)\n ─────────────────────────────`);
249
+ if (allIssues.length === 0) {
250
+ console.log(" No assertion density issues detected.\n");
251
+ return;
252
+ }
253
+ for (const issue of allIssues.slice(0, 25)) {
254
+ const icon = issue.severity === "high" ? "🔴" : issue.severity === "medium" ? "🟡" : "🔵";
255
+ console.log(` ${icon} ${issue.issue}`);
256
+ console.log(` ${issue.file}:${issue.line}`);
257
+ console.log(` ${issue.detail}`);
258
+ }
259
+ if (allIssues.length > 25)
260
+ console.log(` ... and ${allIssues.length - 25} more`);
261
+ console.log(`\n Total: ${allIssues.length} | High: ${highCount} | Medium: ${medCount} | Score: ${score}/100\n`);
262
+ }
263
+ }
264
+ //# sourceMappingURL=assertion-density.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assertion-density.js","sourceRoot":"","sources":["../../src/commands/assertion-density.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Async safety — detect async/await anti-patterns, fire-and-forget promises, and swallowed rejections.
3
+ */
4
+ export declare function runAsyncSafety(argv: string[]): void;
5
+ //# sourceMappingURL=async-safety.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async-safety.d.ts","sourceRoot":"","sources":["../../src/commands/async-safety.ts"],"names":[],"mappings":"AAAA;;GAEG;AA0OH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA+DnD"}