@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.
- 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/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/assertion-density.d.ts +5 -0
- package/dist/commands/assertion-density.d.ts.map +1 -0
- package/dist/commands/assertion-density.js +264 -0
- package/dist/commands/assertion-density.js.map +1 -0
- package/dist/commands/async-safety.d.ts +5 -0
- package/dist/commands/async-safety.d.ts.map +1 -0
- package/dist/commands/async-safety.js +267 -0
- package/dist/commands/async-safety.js.map +1 -0
- package/dist/commands/clone-detect.d.ts +5 -0
- package/dist/commands/clone-detect.d.ts.map +1 -0
- package/dist/commands/clone-detect.js +233 -0
- package/dist/commands/clone-detect.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/contract-verify.d.ts +5 -0
- package/dist/commands/contract-verify.d.ts.map +1 -0
- package/dist/commands/contract-verify.js +317 -0
- package/dist/commands/contract-verify.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/dead-code-detect.d.ts +5 -0
- package/dist/commands/dead-code-detect.d.ts.map +1 -0
- package/dist/commands/dead-code-detect.js +256 -0
- package/dist/commands/dead-code-detect.js.map +1 -0
- package/dist/commands/encoding-safety.d.ts +5 -0
- package/dist/commands/encoding-safety.d.ts.map +1 -0
- package/dist/commands/encoding-safety.js +276 -0
- package/dist/commands/encoding-safety.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/input-guard.d.ts +5 -0
- package/dist/commands/input-guard.d.ts.map +1 -0
- package/dist/commands/input-guard.js +256 -0
- package/dist/commands/input-guard.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/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-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/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/state-integrity.d.ts +5 -0
- package/dist/commands/state-integrity.d.ts.map +1 -0
- package/dist/commands/state-integrity.js +284 -0
- package/dist/commands/state-integrity.js.map +1 -0
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Async safety — detect async/await anti-patterns, fire-and-forget promises, and swallowed rejections.
|
|
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"]);
|
|
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
|
+
// Skip test files for some checks
|
|
52
|
+
const isTest = /\.test\.|\.spec\.|__test__/i.test(filepath);
|
|
53
|
+
for (let i = 0; i < lines.length; i++) {
|
|
54
|
+
const line = lines[i];
|
|
55
|
+
// Fire-and-forget: calling async function without await
|
|
56
|
+
if (/(?:^|\s)\w+\([^)]*\)\s*;?\s*$/.test(line.trim()) && !line.includes("await") && !line.includes("return")) {
|
|
57
|
+
const _prevLines = lines.slice(Math.max(0, i - 5), i + 1).join("\n");
|
|
58
|
+
// Check if the called function is async
|
|
59
|
+
const callMatch = line.trim().match(/^(\w+)\s*\(/);
|
|
60
|
+
if (callMatch) {
|
|
61
|
+
const funcName = callMatch[1];
|
|
62
|
+
if (content.includes(`async function ${funcName}`) || content.includes(`async ${funcName}`)) {
|
|
63
|
+
if (!/void\s+\w+|\/\/.*fire.and.forget|\/\/.*intentional|event.*handler|\.on\(/i.test(line)) {
|
|
64
|
+
issues.push({
|
|
65
|
+
file: filepath,
|
|
66
|
+
line: i + 1,
|
|
67
|
+
issue: "Fire-and-forget async call",
|
|
68
|
+
severity: "high",
|
|
69
|
+
detail: `\`${funcName}()\` is async but called without \`await\` — errors will be silently swallowed`,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// .then() without .catch()
|
|
76
|
+
if (/\.then\s*\(/.test(line) && !line.includes(".catch")) {
|
|
77
|
+
const block = lines.slice(i, Math.min(i + 5, lines.length)).join("\n");
|
|
78
|
+
if (!block.includes(".catch")) {
|
|
79
|
+
issues.push({
|
|
80
|
+
file: filepath,
|
|
81
|
+
line: i + 1,
|
|
82
|
+
issue: ".then() without .catch()",
|
|
83
|
+
severity: "medium",
|
|
84
|
+
detail: "Promise chain has no error handler — rejection will be unhandled",
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// async function that never awaits
|
|
89
|
+
if (/async\s+(?:function\s+)?(\w+)/.test(line)) {
|
|
90
|
+
const funcName = line.match(/async\s+(?:function\s+)?(\w+)/)?.[1] || "anonymous";
|
|
91
|
+
// Find the function body
|
|
92
|
+
let depth = 0;
|
|
93
|
+
let funcEnd = i;
|
|
94
|
+
let started = false;
|
|
95
|
+
for (let j = i; j < Math.min(i + 50, lines.length); j++) {
|
|
96
|
+
for (const ch of lines[j]) {
|
|
97
|
+
if (ch === "{") {
|
|
98
|
+
depth++;
|
|
99
|
+
started = true;
|
|
100
|
+
}
|
|
101
|
+
if (ch === "}")
|
|
102
|
+
depth--;
|
|
103
|
+
}
|
|
104
|
+
if (started && depth <= 0) {
|
|
105
|
+
funcEnd = j;
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const funcBody = lines.slice(i + 1, funcEnd).join("\n");
|
|
110
|
+
if (funcBody.length > 10 && !/await\b|\.then\(|yield\b/i.test(funcBody)) {
|
|
111
|
+
issues.push({
|
|
112
|
+
file: filepath,
|
|
113
|
+
line: i + 1,
|
|
114
|
+
issue: "Async function without await",
|
|
115
|
+
severity: "medium",
|
|
116
|
+
detail: `\`${funcName}\` is declared async but never awaits — unnecessary wrapper adds overhead`,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// try/catch around async with empty catch
|
|
121
|
+
if (/try\s*\{/.test(line)) {
|
|
122
|
+
const block = lines.slice(i, Math.min(i + 15, lines.length)).join("\n");
|
|
123
|
+
if (/await\b/.test(block)) {
|
|
124
|
+
const catchMatch = block.match(/catch\s*\(\s*\w*\s*\)\s*\{\s*\}/);
|
|
125
|
+
if (catchMatch) {
|
|
126
|
+
issues.push({
|
|
127
|
+
file: filepath,
|
|
128
|
+
line: i + 1,
|
|
129
|
+
issue: "Async try/catch with empty handler",
|
|
130
|
+
severity: "high",
|
|
131
|
+
detail: "Awaited operation errors are silently swallowed — log or rethrow",
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// Promise constructor anti-pattern (async executor)
|
|
137
|
+
if (/new\s+Promise\s*\(\s*async/.test(line)) {
|
|
138
|
+
issues.push({
|
|
139
|
+
file: filepath,
|
|
140
|
+
line: i + 1,
|
|
141
|
+
issue: "Async Promise constructor",
|
|
142
|
+
severity: "high",
|
|
143
|
+
detail: "Async executor in Promise constructor — rejections inside async can't be caught by the Promise",
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
// await in loop (performance issue)
|
|
147
|
+
if (!isTest && /^\s*(?:for|while)\s*\(/.test(line)) {
|
|
148
|
+
const loopBlock = lines.slice(i, Math.min(i + 15, lines.length)).join("\n");
|
|
149
|
+
const awaitCount = (loopBlock.match(/await\b/g) || []).length;
|
|
150
|
+
if (awaitCount >= 1 && !/sequential|order.*matters|rate.*limit|throttle/i.test(loopBlock)) {
|
|
151
|
+
issues.push({
|
|
152
|
+
file: filepath,
|
|
153
|
+
line: i + 1,
|
|
154
|
+
issue: "Sequential await in loop",
|
|
155
|
+
severity: "low",
|
|
156
|
+
detail: "Awaiting inside loop runs iterations sequentially — use Promise.all for parallel execution if order doesn't matter",
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// Mixing callbacks and promises
|
|
161
|
+
if (/\.then\s*\(/.test(line) && /callback|cb\s*\(|next\s*\(/i.test(line)) {
|
|
162
|
+
issues.push({
|
|
163
|
+
file: filepath,
|
|
164
|
+
line: i + 1,
|
|
165
|
+
issue: "Mixed callback and promise patterns",
|
|
166
|
+
severity: "medium",
|
|
167
|
+
detail: "Mixing callbacks with .then() chains — pick one pattern to avoid missed error paths",
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
// Unhandled promise rejection risk (process-level)
|
|
171
|
+
if (/process\.on\s*\(\s*['"]unhandledRejection['"]/.test(line)) {
|
|
172
|
+
const block = lines.slice(i, Math.min(i + 5, lines.length)).join("\n");
|
|
173
|
+
if (/process\.exit/i.test(block)) {
|
|
174
|
+
issues.push({
|
|
175
|
+
file: filepath,
|
|
176
|
+
line: i + 1,
|
|
177
|
+
issue: "Unhandled rejection handler exits process",
|
|
178
|
+
severity: "low",
|
|
179
|
+
detail: "Consider graceful shutdown instead of immediate exit on unhandled rejections",
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// Promise.all without error isolation
|
|
184
|
+
if (/Promise\.all\s*\(/.test(line) && !isTest) {
|
|
185
|
+
const block = lines.slice(i, Math.min(i + 5, lines.length)).join("\n");
|
|
186
|
+
if (!/Promise\.allSettled|\.catch|try|catch/i.test(block)) {
|
|
187
|
+
issues.push({
|
|
188
|
+
file: filepath,
|
|
189
|
+
line: i + 1,
|
|
190
|
+
issue: "Promise.all without error isolation",
|
|
191
|
+
severity: "medium",
|
|
192
|
+
detail: "One promise rejection cancels all — use Promise.allSettled if partial results are acceptable",
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// setTimeout/setInterval with async callback but no error handling
|
|
197
|
+
if (/(?:setTimeout|setInterval)\s*\(\s*async/.test(line)) {
|
|
198
|
+
const block = lines.slice(i, Math.min(i + 10, lines.length)).join("\n");
|
|
199
|
+
if (!/try|catch|\.catch/i.test(block)) {
|
|
200
|
+
issues.push({
|
|
201
|
+
file: filepath,
|
|
202
|
+
line: i + 1,
|
|
203
|
+
issue: "Async timer callback without error handling",
|
|
204
|
+
severity: "high",
|
|
205
|
+
detail: "Async callback in setTimeout/setInterval — errors become unhandled rejections",
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return issues;
|
|
211
|
+
}
|
|
212
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
213
|
+
export function runAsyncSafety(argv) {
|
|
214
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
215
|
+
console.log(`
|
|
216
|
+
judges async-safety — Detect async/await anti-patterns and fire-and-forget promises
|
|
217
|
+
|
|
218
|
+
Usage:
|
|
219
|
+
judges async-safety [dir]
|
|
220
|
+
judges async-safety src/ --format json
|
|
221
|
+
|
|
222
|
+
Options:
|
|
223
|
+
[dir] Directory to scan (default: .)
|
|
224
|
+
--format json JSON output
|
|
225
|
+
--help, -h Show this help
|
|
226
|
+
|
|
227
|
+
Checks: fire-and-forget calls, .then() without .catch(), async without await,
|
|
228
|
+
async Promise constructors, await in loops, async timer callbacks, Promise.all without error isolation.
|
|
229
|
+
`);
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
233
|
+
const dir = argv.find((a) => !a.startsWith("-") && argv.indexOf(a) > 0) || ".";
|
|
234
|
+
const files = collectFiles(dir);
|
|
235
|
+
const allIssues = [];
|
|
236
|
+
for (const f of files)
|
|
237
|
+
allIssues.push(...analyzeFile(f));
|
|
238
|
+
const highCount = allIssues.filter((i) => i.severity === "high").length;
|
|
239
|
+
const medCount = allIssues.filter((i) => i.severity === "medium").length;
|
|
240
|
+
const score = Math.max(0, 100 - highCount * 10 - medCount * 4);
|
|
241
|
+
if (format === "json") {
|
|
242
|
+
console.log(JSON.stringify({
|
|
243
|
+
issues: allIssues,
|
|
244
|
+
score,
|
|
245
|
+
summary: { high: highCount, medium: medCount, total: allIssues.length },
|
|
246
|
+
timestamp: new Date().toISOString(),
|
|
247
|
+
}, null, 2));
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
const badge = score >= 80 ? "✅ SAFE" : score >= 50 ? "⚠️ RISKY" : "❌ HAZARDOUS";
|
|
251
|
+
console.log(`\n Async Safety: ${badge} (${score}/100)\n ─────────────────────────────`);
|
|
252
|
+
if (allIssues.length === 0) {
|
|
253
|
+
console.log(" No async safety issues detected.\n");
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
for (const issue of allIssues.slice(0, 25)) {
|
|
257
|
+
const icon = issue.severity === "high" ? "🔴" : issue.severity === "medium" ? "🟡" : "🔵";
|
|
258
|
+
console.log(` ${icon} ${issue.issue}`);
|
|
259
|
+
console.log(` ${issue.file}:${issue.line}`);
|
|
260
|
+
console.log(` ${issue.detail}`);
|
|
261
|
+
}
|
|
262
|
+
if (allIssues.length > 25)
|
|
263
|
+
console.log(` ... and ${allIssues.length - 25} more`);
|
|
264
|
+
console.log(`\n Total: ${allIssues.length} | High: ${highCount} | Medium: ${medCount} | Score: ${score}/100\n`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
//# sourceMappingURL=async-safety.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"async-safety.js","sourceRoot":"","sources":["../../src/commands/async-safety.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAYrC,+EAA+E;AAE/E,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;AAE1D,SAAS,YAAY,CAAC,GAAW,EAAE,GAAG,GAAG,GAAG;IAC1C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,SAAS,IAAI,CAAC,CAAS;QACrB,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG;YAAE,OAAO;QAChC,IAAI,OAAiB,CAAC;QACtB,IAAI,CAAC;YACH,OAAO,GAAG,WAAW,CAAC,CAAC,CAAwB,CAAC;QAClD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG;gBAAE,OAAO;YAChC,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,cAAc,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,OAAO;gBAAE,SAAS;YACzF,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACxB,IAAI,CAAC;gBACH,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE;oBAAE,IAAI,CAAC,IAAI,CAAC,CAAC;qBACxC,IAAI,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;oBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC1D,CAAC;YAAC,MAAM,CAAC;gBACP,UAAU;YACZ,CAAC;QACH,CAAC;IACH,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,KAAK,CAAC;AACf,CAAC;AAED,+EAA+E;AAE/E,SAAS,WAAW,CAAC,QAAgB;IACnC,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAElC,kCAAkC;IAClC,MAAM,MAAM,GAAG,6BAA6B,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAE5D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAEtB,wDAAwD;QACxD,IAAI,+BAA+B,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7G,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrE,wCAAwC;YACxC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;YACnD,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;gBAC9B,IAAI,OAAO,CAAC,QAAQ,CAAC,kBAAkB,QAAQ,EAAE,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS,QAAQ,EAAE,CAAC,EAAE,CAAC;oBAC5F,IAAI,CAAC,2EAA2E,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;wBAC5F,MAAM,CAAC,IAAI,CAAC;4BACV,IAAI,EAAE,QAAQ;4BACd,IAAI,EAAE,CAAC,GAAG,CAAC;4BACX,KAAK,EAAE,4BAA4B;4BACnC,QAAQ,EAAE,MAAM;4BAChB,MAAM,EAAE,KAAK,QAAQ,gFAAgF;yBACtG,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,2BAA2B;QAC3B,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACvE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC9B,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,CAAC,GAAG,CAAC;oBACX,KAAK,EAAE,0BAA0B;oBACjC,QAAQ,EAAE,QAAQ;oBAClB,MAAM,EAAE,kEAAkE;iBAC3E,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,mCAAmC;QACnC,IAAI,+BAA+B,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,+BAA+B,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,WAAW,CAAC;YACjF,yBAAyB;YACzB,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,IAAI,OAAO,GAAG,CAAC,CAAC;YAChB,IAAI,OAAO,GAAG,KAAK,CAAC;YACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBACxD,KAAK,MAAM,EAAE,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC1B,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;wBACf,KAAK,EAAE,CAAC;wBACR,OAAO,GAAG,IAAI,CAAC;oBACjB,CAAC;oBACD,IAAI,EAAE,KAAK,GAAG;wBAAE,KAAK,EAAE,CAAC;gBAC1B,CAAC;gBACD,IAAI,OAAO,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;oBAC1B,OAAO,GAAG,CAAC,CAAC;oBACZ,MAAM;gBACR,CAAC;YACH,CAAC;YACD,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxD,IAAI,QAAQ,CAAC,MAAM,GAAG,EAAE,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACxE,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,CAAC,GAAG,CAAC;oBACX,KAAK,EAAE,8BAA8B;oBACrC,QAAQ,EAAE,QAAQ;oBAClB,MAAM,EAAE,KAAK,QAAQ,2EAA2E;iBACjG,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,0CAA0C;QAC1C,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxE,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC1B,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;gBAClE,IAAI,UAAU,EAAE,CAAC;oBACf,MAAM,CAAC,IAAI,CAAC;wBACV,IAAI,EAAE,QAAQ;wBACd,IAAI,EAAE,CAAC,GAAG,CAAC;wBACX,KAAK,EAAE,oCAAoC;wBAC3C,QAAQ,EAAE,MAAM;wBAChB,MAAM,EAAE,kEAAkE;qBAC3E,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,oDAAoD;QACpD,IAAI,4BAA4B,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5C,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,CAAC,GAAG,CAAC;gBACX,KAAK,EAAE,2BAA2B;gBAClC,QAAQ,EAAE,MAAM;gBAChB,MAAM,EAAE,gGAAgG;aACzG,CAAC,CAAC;QACL,CAAC;QAED,oCAAoC;QACpC,IAAI,CAAC,MAAM,IAAI,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC5E,MAAM,UAAU,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;YAC9D,IAAI,UAAU,IAAI,CAAC,IAAI,CAAC,iDAAiD,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC1F,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,CAAC,GAAG,CAAC;oBACX,KAAK,EAAE,0BAA0B;oBACjC,QAAQ,EAAE,KAAK;oBACf,MAAM,EACJ,oHAAoH;iBACvH,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,gCAAgC;QAChC,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,6BAA6B,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACzE,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,CAAC,GAAG,CAAC;gBACX,KAAK,EAAE,qCAAqC;gBAC5C,QAAQ,EAAE,QAAQ;gBAClB,MAAM,EAAE,qFAAqF;aAC9F,CAAC,CAAC;QACL,CAAC;QAED,mDAAmD;QACnD,IAAI,+CAA+C,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/D,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACvE,IAAI,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBACjC,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,CAAC,GAAG,CAAC;oBACX,KAAK,EAAE,2CAA2C;oBAClD,QAAQ,EAAE,KAAK;oBACf,MAAM,EAAE,8EAA8E;iBACvF,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,sCAAsC;QACtC,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACvE,IAAI,CAAC,wCAAwC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC1D,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,CAAC,GAAG,CAAC;oBACX,KAAK,EAAE,qCAAqC;oBAC5C,QAAQ,EAAE,QAAQ;oBAClB,MAAM,EAAE,8FAA8F;iBACvG,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,mEAAmE;QACnE,IAAI,yCAAyC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACzD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxE,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBACtC,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,CAAC,GAAG,CAAC;oBACX,KAAK,EAAE,6CAA6C;oBACpD,QAAQ,EAAE,MAAM;oBAChB,MAAM,EAAE,+EAA+E;iBACxF,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,+EAA+E;AAE/E,MAAM,UAAU,cAAc,CAAC,IAAc;IAC3C,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;CAcf,CAAC,CAAC;QACC,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,UAAU,CAAC,IAAI,MAAM,CAAC;IAC1F,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC;IAE/E,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,SAAS,GAAiB,EAAE,CAAC;IACnC,KAAK,MAAM,CAAC,IAAI,KAAK;QAAE,SAAS,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAEzD,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;IACxE,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,MAAM,CAAC;IACzE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,SAAS,GAAG,EAAE,GAAG,QAAQ,GAAG,CAAC,CAAC,CAAC;IAE/D,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CACZ;YACE,MAAM,EAAE,SAAS;YACjB,KAAK;YACL,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE;YACvE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,EACD,IAAI,EACJ,CAAC,CACF,CACF,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,MAAM,KAAK,GAAG,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,aAAa,CAAC;QACjF,OAAO,CAAC,GAAG,CAAC,qBAAqB,KAAK,KAAK,KAAK,wCAAwC,CAAC,CAAC;QAE1F,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;YACtD,OAAO;QACT,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YAC3C,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;YAC1F,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;YAC1C,OAAO,CAAC,GAAG,CAAC,WAAW,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YACnD,OAAO,CAAC,GAAG,CAAC,WAAW,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QACzC,CAAC;QACD,IAAI,SAAS,CAAC,MAAM,GAAG,EAAE;YAAE,OAAO,CAAC,GAAG,CAAC,eAAe,SAAS,CAAC,MAAM,GAAG,EAAE,OAAO,CAAC,CAAC;QAEpF,OAAO,CAAC,GAAG,CAAC,gBAAgB,SAAS,CAAC,MAAM,YAAY,SAAS,cAAc,QAAQ,aAAa,KAAK,QAAQ,CAAC,CAAC;IACrH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clone-detect.d.ts","sourceRoot":"","sources":["../../src/commands/clone-detect.ts"],"names":[],"mappings":"AAAA;;GAEG;AA6MH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA6DnD"}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clone detect — find duplicated logic blocks that should be extracted into shared functions.
|
|
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
|
+
// ─── Normalization ──────────────────────────────────────────────────────────
|
|
41
|
+
function normalize(line) {
|
|
42
|
+
return line
|
|
43
|
+
.trim()
|
|
44
|
+
.replace(/\/\/.*/, "") // strip comments
|
|
45
|
+
.replace(/\/\*.*?\*\//g, "") // strip inline comments
|
|
46
|
+
.replace(/['"][^'"]*['"]/g, "S") // normalize strings
|
|
47
|
+
.replace(/\b\d+\b/g, "N") // normalize numbers
|
|
48
|
+
.replace(/\b[a-z]\w{0,2}\b/gi, "V") // normalize short variable names
|
|
49
|
+
.replace(/\s+/g, " ") // collapse whitespace
|
|
50
|
+
.trim();
|
|
51
|
+
}
|
|
52
|
+
function extractBlocks(filepath, content, blockSize) {
|
|
53
|
+
const lines = content.split("\n");
|
|
54
|
+
const blocks = [];
|
|
55
|
+
for (let i = 0; i <= lines.length - blockSize; i++) {
|
|
56
|
+
const raw = lines.slice(i, i + blockSize);
|
|
57
|
+
const normalized = raw
|
|
58
|
+
.map(normalize)
|
|
59
|
+
.filter((l) => l.length > 3)
|
|
60
|
+
.join("|");
|
|
61
|
+
if (normalized.length > 20) {
|
|
62
|
+
blocks.push({ file: filepath, startLine: i + 1, normalized, raw: raw.join("\n") });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return blocks;
|
|
66
|
+
}
|
|
67
|
+
function detectClones(files, blockSize = 5, minSimilarity = 0.85) {
|
|
68
|
+
const issues = [];
|
|
69
|
+
const allBlocks = [];
|
|
70
|
+
for (const f of files) {
|
|
71
|
+
let content;
|
|
72
|
+
try {
|
|
73
|
+
content = readFileSync(f, "utf-8");
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
allBlocks.push(...extractBlocks(f, content, blockSize));
|
|
79
|
+
}
|
|
80
|
+
// Group by normalized form
|
|
81
|
+
const groups = new Map();
|
|
82
|
+
for (const block of allBlocks) {
|
|
83
|
+
const existing = groups.get(block.normalized);
|
|
84
|
+
if (existing) {
|
|
85
|
+
existing.push(block);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
groups.set(block.normalized, [block]);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const reported = new Set();
|
|
92
|
+
for (const [_norm, blocks] of groups) {
|
|
93
|
+
if (blocks.length < 2)
|
|
94
|
+
continue;
|
|
95
|
+
// Deduplicate overlapping blocks in same file
|
|
96
|
+
const unique = [];
|
|
97
|
+
for (const b of blocks) {
|
|
98
|
+
const isDuplicate = unique.some((u) => u.file === b.file && Math.abs(u.startLine - b.startLine) < blockSize);
|
|
99
|
+
if (!isDuplicate)
|
|
100
|
+
unique.push(b);
|
|
101
|
+
}
|
|
102
|
+
if (unique.length < 2)
|
|
103
|
+
continue;
|
|
104
|
+
// Report clones
|
|
105
|
+
for (let j = 1; j < unique.length && j < 3; j++) {
|
|
106
|
+
const key = `${unique[0].file}:${unique[0].startLine}-${unique[j].file}:${unique[j].startLine}`;
|
|
107
|
+
if (reported.has(key))
|
|
108
|
+
continue;
|
|
109
|
+
reported.add(key);
|
|
110
|
+
const sameFile = unique[0].file === unique[j].file;
|
|
111
|
+
const severity = unique.length > 3 ? "high" : unique.length > 2 ? "medium" : "low";
|
|
112
|
+
issues.push({
|
|
113
|
+
file: unique[0].file,
|
|
114
|
+
line: unique[0].startLine,
|
|
115
|
+
issue: sameFile ? "Intra-file code clone" : "Cross-file code clone",
|
|
116
|
+
severity,
|
|
117
|
+
detail: `${blockSize}-line block duplicated${sameFile ? ` at line ${unique[j].startLine}` : ` in ${unique[j].file}:${unique[j].startLine}`} — extract to shared function (${unique.length} copies total)`,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Also check for near-identical functions using a simpler heuristic
|
|
122
|
+
for (const f of files) {
|
|
123
|
+
let content;
|
|
124
|
+
try {
|
|
125
|
+
content = readFileSync(f, "utf-8");
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
const lines = content.split("\n");
|
|
131
|
+
const functions = [];
|
|
132
|
+
for (let i = 0; i < lines.length; i++) {
|
|
133
|
+
const funcMatch = lines[i].match(/(?:function\s+(\w+)|(?:const|let)\s+(\w+)\s*=\s*(?:async\s*)?\()/);
|
|
134
|
+
if (funcMatch) {
|
|
135
|
+
const name = funcMatch[1] || funcMatch[2];
|
|
136
|
+
let depth = 0;
|
|
137
|
+
let end = i;
|
|
138
|
+
for (let j = i; j < Math.min(i + 50, lines.length); j++) {
|
|
139
|
+
for (const ch of lines[j]) {
|
|
140
|
+
if (ch === "{")
|
|
141
|
+
depth++;
|
|
142
|
+
if (ch === "}")
|
|
143
|
+
depth--;
|
|
144
|
+
}
|
|
145
|
+
if (depth <= 0 && j > i) {
|
|
146
|
+
end = j;
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const body = lines
|
|
151
|
+
.slice(i, end + 1)
|
|
152
|
+
.map(normalize)
|
|
153
|
+
.join("|");
|
|
154
|
+
if (body.length > 30)
|
|
155
|
+
functions.push({ name, line: i + 1, body });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// Compare functions within same file
|
|
159
|
+
for (let a = 0; a < functions.length; a++) {
|
|
160
|
+
for (let b = a + 1; b < functions.length; b++) {
|
|
161
|
+
if (functions[a].body === functions[b].body && functions[a].body.length > 50) {
|
|
162
|
+
const key = `func:${f}:${functions[a].line}-${functions[b].line}`;
|
|
163
|
+
if (!reported.has(key)) {
|
|
164
|
+
reported.add(key);
|
|
165
|
+
issues.push({
|
|
166
|
+
file: f,
|
|
167
|
+
line: functions[a].line,
|
|
168
|
+
issue: "Duplicate functions",
|
|
169
|
+
severity: "medium",
|
|
170
|
+
detail: `\`${functions[a].name}\` and \`${functions[b].name}\` (line ${functions[b].line}) have identical logic — extract shared implementation`,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// Limit results
|
|
178
|
+
void minSimilarity;
|
|
179
|
+
return issues.slice(0, 50);
|
|
180
|
+
}
|
|
181
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
182
|
+
export function runCloneDetect(argv) {
|
|
183
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
184
|
+
console.log(`
|
|
185
|
+
judges clone-detect — Find duplicated logic blocks that should be shared functions
|
|
186
|
+
|
|
187
|
+
Usage:
|
|
188
|
+
judges clone-detect [dir]
|
|
189
|
+
judges clone-detect src/ --format json
|
|
190
|
+
|
|
191
|
+
Options:
|
|
192
|
+
[dir] Directory to scan (default: .)
|
|
193
|
+
--format json JSON output
|
|
194
|
+
--help, -h Show this help
|
|
195
|
+
|
|
196
|
+
Checks: intra-file code clones, cross-file clones, duplicate functions with renamed variables.
|
|
197
|
+
`);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
201
|
+
const dir = argv.find((a) => !a.startsWith("-") && argv.indexOf(a) > 0) || ".";
|
|
202
|
+
const files = collectFiles(dir);
|
|
203
|
+
const allIssues = detectClones(files);
|
|
204
|
+
const highCount = allIssues.filter((i) => i.severity === "high").length;
|
|
205
|
+
const medCount = allIssues.filter((i) => i.severity === "medium").length;
|
|
206
|
+
const score = Math.max(0, 100 - highCount * 8 - medCount * 3);
|
|
207
|
+
if (format === "json") {
|
|
208
|
+
console.log(JSON.stringify({
|
|
209
|
+
issues: allIssues,
|
|
210
|
+
score,
|
|
211
|
+
summary: { high: highCount, medium: medCount, total: allIssues.length },
|
|
212
|
+
timestamp: new Date().toISOString(),
|
|
213
|
+
}, null, 2));
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
const badge = score >= 80 ? "✅ DRY" : score >= 50 ? "⚠️ REPETITIVE" : "❌ DUPLICATED";
|
|
217
|
+
console.log(`\n Code Clones: ${badge} (${score}/100)\n ─────────────────────────────`);
|
|
218
|
+
if (allIssues.length === 0) {
|
|
219
|
+
console.log(" No code clones detected.\n");
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
for (const issue of allIssues.slice(0, 25)) {
|
|
223
|
+
const icon = issue.severity === "high" ? "🔴" : issue.severity === "medium" ? "🟡" : "🔵";
|
|
224
|
+
console.log(` ${icon} ${issue.issue}`);
|
|
225
|
+
console.log(` ${issue.file}:${issue.line}`);
|
|
226
|
+
console.log(` ${issue.detail}`);
|
|
227
|
+
}
|
|
228
|
+
if (allIssues.length > 25)
|
|
229
|
+
console.log(` ... and ${allIssues.length - 25} more`);
|
|
230
|
+
console.log(`\n Total: ${allIssues.length} | High: ${highCount} | Medium: ${medCount} | Score: ${score}/100\n`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=clone-detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clone-detect.js","sourceRoot":"","sources":["../../src/commands/clone-detect.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"}
|