@kevinrabun/judges 3.58.0 → 3.60.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +112 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/adoption-track.d.ts +5 -0
- package/dist/commands/adoption-track.d.ts.map +1 -0
- package/dist/commands/adoption-track.js +247 -0
- package/dist/commands/adoption-track.js.map +1 -0
- package/dist/commands/api-misuse.d.ts +5 -0
- package/dist/commands/api-misuse.d.ts.map +1 -0
- package/dist/commands/api-misuse.js +261 -0
- package/dist/commands/api-misuse.js.map +1 -0
- package/dist/commands/completion-audit.d.ts +5 -0
- package/dist/commands/completion-audit.d.ts.map +1 -0
- package/dist/commands/completion-audit.js +297 -0
- package/dist/commands/completion-audit.js.map +1 -0
- package/dist/commands/context-blind.d.ts +5 -0
- package/dist/commands/context-blind.d.ts.map +1 -0
- package/dist/commands/context-blind.js +273 -0
- package/dist/commands/context-blind.js.map +1 -0
- package/dist/commands/cross-file-consistency.d.ts +5 -0
- package/dist/commands/cross-file-consistency.d.ts.map +1 -0
- package/dist/commands/cross-file-consistency.js +255 -0
- package/dist/commands/cross-file-consistency.js.map +1 -0
- package/dist/commands/example-leak.d.ts +5 -0
- package/dist/commands/example-leak.d.ts.map +1 -0
- package/dist/commands/example-leak.js +233 -0
- package/dist/commands/example-leak.js.map +1 -0
- package/dist/commands/finding-budget.d.ts +5 -0
- package/dist/commands/finding-budget.d.ts.map +1 -0
- package/dist/commands/finding-budget.js +233 -0
- package/dist/commands/finding-budget.js.map +1 -0
- package/dist/commands/hallucination-detect.d.ts +5 -0
- package/dist/commands/hallucination-detect.d.ts.map +1 -0
- package/dist/commands/hallucination-detect.js +351 -0
- package/dist/commands/hallucination-detect.js.map +1 -0
- package/dist/commands/logic-lint.d.ts +5 -0
- package/dist/commands/logic-lint.d.ts.map +1 -0
- package/dist/commands/logic-lint.js +256 -0
- package/dist/commands/logic-lint.js.map +1 -0
- package/dist/commands/over-abstraction.d.ts +5 -0
- package/dist/commands/over-abstraction.d.ts.map +1 -0
- package/dist/commands/over-abstraction.js +308 -0
- package/dist/commands/over-abstraction.js.map +1 -0
- package/dist/commands/phantom-import.d.ts +5 -0
- package/dist/commands/phantom-import.d.ts.map +1 -0
- package/dist/commands/phantom-import.js +261 -0
- package/dist/commands/phantom-import.js.map +1 -0
- package/dist/commands/review-digest.d.ts +5 -0
- package/dist/commands/review-digest.d.ts.map +1 -0
- package/dist/commands/review-digest.js +266 -0
- package/dist/commands/review-digest.js.map +1 -0
- package/dist/commands/review-focus.d.ts +5 -0
- package/dist/commands/review-focus.d.ts.map +1 -0
- package/dist/commands/review-focus.js +197 -0
- package/dist/commands/review-focus.js.map +1 -0
- package/dist/commands/security-theater.d.ts +5 -0
- package/dist/commands/security-theater.d.ts.map +1 -0
- package/dist/commands/security-theater.js +279 -0
- package/dist/commands/security-theater.js.map +1 -0
- package/dist/commands/spec-conform.d.ts +5 -0
- package/dist/commands/spec-conform.d.ts.map +1 -0
- package/dist/commands/spec-conform.js +305 -0
- package/dist/commands/spec-conform.js.map +1 -0
- package/dist/commands/stale-pattern.d.ts +5 -0
- package/dist/commands/stale-pattern.d.ts.map +1 -0
- package/dist/commands/stale-pattern.js +294 -0
- package/dist/commands/stale-pattern.js.map +1 -0
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adoption-track — measure team-level Judges adoption metrics from local data.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, readdirSync, statSync, existsSync } from "fs";
|
|
5
|
+
import { join, extname, relative } from "path";
|
|
6
|
+
// ─── File Collection ────────────────────────────────────────────────────────
|
|
7
|
+
const CODE_EXTS = new Set([".ts", ".tsx", ".js", ".jsx", ".py", ".java", ".go", ".cs"]);
|
|
8
|
+
function collectFiles(dir, max = 500) {
|
|
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
|
+
function analyzeConfig(dir) {
|
|
41
|
+
const configPaths = [
|
|
42
|
+
join(dir, ".judgesrc"),
|
|
43
|
+
join(dir, ".judgesrc.json"),
|
|
44
|
+
join(dir, "judgesrc.json"),
|
|
45
|
+
join(dir, ".judges.json"),
|
|
46
|
+
];
|
|
47
|
+
for (const p of configPaths) {
|
|
48
|
+
if (existsSync(p)) {
|
|
49
|
+
try {
|
|
50
|
+
const raw = readFileSync(p, "utf-8");
|
|
51
|
+
const config = JSON.parse(raw);
|
|
52
|
+
let completeness = 20; // Base for having a config at all
|
|
53
|
+
if (config.preset)
|
|
54
|
+
completeness += 15;
|
|
55
|
+
if (config.minSeverity)
|
|
56
|
+
completeness += 10;
|
|
57
|
+
if (config.judges && Object.keys(config.judges).length > 0)
|
|
58
|
+
completeness += 20;
|
|
59
|
+
if (config.disabledRules && config.disabledRules.length > 0)
|
|
60
|
+
completeness += 10;
|
|
61
|
+
if (config.ruleOverrides && Object.keys(config.ruleOverrides).length > 0)
|
|
62
|
+
completeness += 15;
|
|
63
|
+
if (config.disabledJudges && config.disabledJudges.length > 0)
|
|
64
|
+
completeness += 10;
|
|
65
|
+
return { config, completeness: Math.min(100, completeness) };
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
/* malformed config */
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Check package.json for judges config
|
|
73
|
+
const pkgPath = join(dir, "package.json");
|
|
74
|
+
if (existsSync(pkgPath)) {
|
|
75
|
+
try {
|
|
76
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
77
|
+
if (pkg.judges || pkg.judgesConfig) {
|
|
78
|
+
return { config: (pkg.judges || pkg.judgesConfig), completeness: 30 };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
/* skip */
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return { config: null, completeness: 0 };
|
|
86
|
+
}
|
|
87
|
+
// ─── Suppression tracking ───────────────────────────────────────────────────
|
|
88
|
+
function countSuppressions(files) {
|
|
89
|
+
let total = 0;
|
|
90
|
+
const categories = new Map();
|
|
91
|
+
for (const f of files) {
|
|
92
|
+
let content;
|
|
93
|
+
try {
|
|
94
|
+
content = readFileSync(f, "utf-8");
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const suppressions = content.match(/judges-disable|judges-ignore|judges-suppress|noinspection|@suppress/gi) || [];
|
|
100
|
+
total += suppressions.length;
|
|
101
|
+
// Categorize by nearby judge name
|
|
102
|
+
const lines = content.split("\n");
|
|
103
|
+
for (let i = 0; i < lines.length; i++) {
|
|
104
|
+
if (/judges-disable|judges-ignore|judges-suppress/i.test(lines[i])) {
|
|
105
|
+
const ruleMatch = lines[i].match(/(?:judges-(?:disable|ignore|suppress))\s+(\S+)/i);
|
|
106
|
+
const cat = ruleMatch ? ruleMatch[1] : "unspecified";
|
|
107
|
+
categories.set(cat, (categories.get(cat) || 0) + 1);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return { total, categories };
|
|
112
|
+
}
|
|
113
|
+
// ─── Cold spots (directories with no judges integration) ────────────────────
|
|
114
|
+
function findColdSpots(dir, files) {
|
|
115
|
+
const dirCounts = new Map();
|
|
116
|
+
const dirFiles = new Map();
|
|
117
|
+
for (const f of files) {
|
|
118
|
+
const rel = relative(dir, f);
|
|
119
|
+
const parts = rel.split(/[/\\]/);
|
|
120
|
+
if (parts.length > 1) {
|
|
121
|
+
const topDir = parts[0];
|
|
122
|
+
dirFiles.set(topDir, (dirFiles.get(topDir) || 0) + 1);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Directories with code but no suppression comments → likely not being reviewed
|
|
126
|
+
for (const f of files) {
|
|
127
|
+
let content;
|
|
128
|
+
try {
|
|
129
|
+
content = readFileSync(f, "utf-8");
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
const rel = relative(dir, f);
|
|
135
|
+
const parts = rel.split(/[/\\]/);
|
|
136
|
+
if (parts.length > 1) {
|
|
137
|
+
const topDir = parts[0];
|
|
138
|
+
if (/judges-|@judges|judges\.config/i.test(content)) {
|
|
139
|
+
dirCounts.set(topDir, (dirCounts.get(topDir) || 0) + 1);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// Directories with files but zero judges references
|
|
144
|
+
const coldSpots = [];
|
|
145
|
+
for (const [d, count] of dirFiles) {
|
|
146
|
+
if (count >= 3 && !dirCounts.has(d)) {
|
|
147
|
+
coldSpots.push(d);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return coldSpots;
|
|
151
|
+
}
|
|
152
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
153
|
+
export function runAdoptionTrack(argv) {
|
|
154
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
155
|
+
console.log(`
|
|
156
|
+
judges adoption-track — Measure team-level Judges adoption metrics
|
|
157
|
+
|
|
158
|
+
Usage:
|
|
159
|
+
judges adoption-track [dir]
|
|
160
|
+
judges adoption-track --format json
|
|
161
|
+
|
|
162
|
+
Options:
|
|
163
|
+
[dir] Directory to scan (default: .)
|
|
164
|
+
--format json JSON output
|
|
165
|
+
--help, -h Show this help
|
|
166
|
+
|
|
167
|
+
Measures: config completeness, suppression rate, rule override count,
|
|
168
|
+
cold spots (directories with code but no review engagement),
|
|
169
|
+
adoption health score.
|
|
170
|
+
|
|
171
|
+
Note: All metrics are computed from local files only — no data is sent
|
|
172
|
+
or stored externally.
|
|
173
|
+
`);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
177
|
+
const dir = argv.find((a) => !a.startsWith("-") && argv.indexOf(a) > 0) || ".";
|
|
178
|
+
const files = collectFiles(dir);
|
|
179
|
+
const { config, completeness } = analyzeConfig(dir);
|
|
180
|
+
const { total: suppressionTotal, categories: suppressionCats } = countSuppressions(files);
|
|
181
|
+
const coldSpots = findColdSpots(dir, files);
|
|
182
|
+
const suppressionRate = files.length > 0 ? Math.round((suppressionTotal / files.length) * 100) : 0;
|
|
183
|
+
const ruleOverrideCount = config?.ruleOverrides ? Object.keys(config.ruleOverrides).length : 0;
|
|
184
|
+
const disabledCount = config?.disabledJudges?.length || 0;
|
|
185
|
+
// Estimate active vs total judges (heuristic)
|
|
186
|
+
const totalJudgeCount = 60; // Approximate total available judges
|
|
187
|
+
const activeJudgeCount = totalJudgeCount - disabledCount;
|
|
188
|
+
const coverageEstimate = files.length > 0 ? Math.round((activeJudgeCount / totalJudgeCount) * 100) : 0;
|
|
189
|
+
// Health score
|
|
190
|
+
let healthScore = 0;
|
|
191
|
+
healthScore += completeness * 0.3; // Config completeness weight
|
|
192
|
+
healthScore += coverageEstimate * 0.3; // Coverage weight
|
|
193
|
+
healthScore += Math.max(0, 100 - suppressionRate * 2) * 0.2; // Low suppression is good
|
|
194
|
+
healthScore += Math.max(0, 100 - coldSpots.length * 15) * 0.2; // Few cold spots is good
|
|
195
|
+
healthScore = Math.round(Math.min(100, Math.max(0, healthScore)));
|
|
196
|
+
const metrics = {
|
|
197
|
+
configCompleteness: completeness,
|
|
198
|
+
coverageEstimate,
|
|
199
|
+
suppressionRate,
|
|
200
|
+
ruleOverrideCount,
|
|
201
|
+
activeJudgeCount,
|
|
202
|
+
totalJudgeCount,
|
|
203
|
+
coldSpots,
|
|
204
|
+
healthScore,
|
|
205
|
+
};
|
|
206
|
+
if (format === "json") {
|
|
207
|
+
console.log(JSON.stringify({
|
|
208
|
+
metrics,
|
|
209
|
+
suppressionCategories: Object.fromEntries(suppressionCats),
|
|
210
|
+
filesScanned: files.length,
|
|
211
|
+
timestamp: new Date().toISOString(),
|
|
212
|
+
}, null, 2));
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
const badge = healthScore >= 80 ? "✅ HIGH ADOPTION" : healthScore >= 50 ? "⚠️ PARTIAL ADOPTION" : "❌ LOW ADOPTION";
|
|
216
|
+
console.log(`\n Adoption Track: ${badge} (${healthScore}/100)\n ─────────────────────────────`);
|
|
217
|
+
console.log(` Files scanned: ${files.length}`);
|
|
218
|
+
console.log(` Config completeness: ${completeness}%${config ? "" : " (no config found)"}`);
|
|
219
|
+
console.log(` Judge coverage: ${coverageEstimate}% (${activeJudgeCount}/${totalJudgeCount} judges active)`);
|
|
220
|
+
console.log(` Suppression rate: ${suppressionRate}% (${suppressionTotal} suppressions)`);
|
|
221
|
+
console.log(` Rule overrides: ${ruleOverrideCount}`);
|
|
222
|
+
if (suppressionCats.size > 0) {
|
|
223
|
+
console.log(`\n Suppressed categories:`);
|
|
224
|
+
for (const [cat, count] of [...suppressionCats.entries()].sort((a, b) => b[1] - a[1]).slice(0, 10)) {
|
|
225
|
+
console.log(` ${cat}: ${count}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (coldSpots.length > 0) {
|
|
229
|
+
console.log(`\n Cold spots (low/no engagement):`);
|
|
230
|
+
for (const spot of coldSpots.slice(0, 10))
|
|
231
|
+
console.log(` 📁 ${spot}/`);
|
|
232
|
+
}
|
|
233
|
+
console.log(`\n Recommendations:`);
|
|
234
|
+
if (completeness < 50)
|
|
235
|
+
console.log(` → Create or improve .judgesrc configuration`);
|
|
236
|
+
if (disabledCount > 10)
|
|
237
|
+
console.log(` → Review disabled judges — ${disabledCount} disabled may be excessive`);
|
|
238
|
+
if (suppressionRate > 20)
|
|
239
|
+
console.log(` → High suppression rate (${suppressionRate}%) — review if suppressions are justified`);
|
|
240
|
+
if (coldSpots.length > 0)
|
|
241
|
+
console.log(` → Engage cold-spot directories: ${coldSpots.slice(0, 3).join(", ")}`);
|
|
242
|
+
if (healthScore >= 80)
|
|
243
|
+
console.log(` → Adoption is healthy — maintain current practices`);
|
|
244
|
+
console.log();
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=adoption-track.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adoption-track.js","sourceRoot":"","sources":["../../src/commands/adoption-track.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-misuse.d.ts","sourceRoot":"","sources":["../../src/commands/api-misuse.ts"],"names":[],"mappings":"AAAA;;GAEG;AA2OH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA6DjD"}
|
|
@@ -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 @@
|
|
|
1
|
+
{"version":3,"file":"completion-audit.d.ts","sourceRoot":"","sources":["../../src/commands/completion-audit.ts"],"names":[],"mappings":"AAAA;;GAEG;AAqQH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA4DvD"}
|