pi-lens 3.6.2 → 3.6.4
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 +10 -2
- package/package.json +4 -4
- package/tsconfig.json +1 -1
- package/clients/__tests__/file-time.test.js +0 -216
- package/clients/__tests__/file-time.test.ts +0 -276
- package/clients/__tests__/format-service.test.js +0 -245
- package/clients/__tests__/format-service.test.ts +0 -339
- package/clients/__tests__/formatters.test.js +0 -271
- package/clients/__tests__/formatters.test.ts +0 -401
- package/clients/agent-behavior-client.js +0 -110
- package/clients/agent-behavior-client.test.js +0 -94
- package/clients/agent-behavior-client.test.ts +0 -116
- package/clients/amain-types.js +0 -164
- package/clients/architect-client.js +0 -291
- package/clients/ast-grep-client.js +0 -253
- package/clients/ast-grep-parser.js +0 -84
- package/clients/ast-grep-rule-manager.js +0 -89
- package/clients/ast-grep-types.js +0 -9
- package/clients/auto-loop.js +0 -131
- package/clients/biome-client.js +0 -420
- package/clients/biome-client.test.js +0 -144
- package/clients/biome-client.test.ts +0 -163
- package/clients/cache/rule-cache.js +0 -72
- package/clients/cache-manager.js +0 -245
- package/clients/cache-manager.test.js +0 -197
- package/clients/cache-manager.test.ts +0 -299
- package/clients/complexity-client.js +0 -675
- package/clients/complexity-client.test.js +0 -234
- package/clients/complexity-client.test.ts +0 -255
- package/clients/config-validator.js +0 -465
- package/clients/dependency-checker.js +0 -325
- package/clients/dependency-checker.test.js +0 -60
- package/clients/dependency-checker.test.ts +0 -71
- package/clients/dispatch/__tests__/autofix-integration.test.js +0 -245
- package/clients/dispatch/__tests__/autofix-integration.test.ts +0 -300
- package/clients/dispatch/__tests__/runner-registration.test.js +0 -234
- package/clients/dispatch/__tests__/runner-registration.test.ts +0 -286
- package/clients/dispatch/debug.log +0 -1
- package/clients/dispatch/dispatcher.edge.test.js +0 -82
- package/clients/dispatch/dispatcher.edge.test.ts +0 -100
- package/clients/dispatch/dispatcher.format.test.js +0 -46
- package/clients/dispatch/dispatcher.format.test.ts +0 -58
- package/clients/dispatch/dispatcher.inline.test.js +0 -74
- package/clients/dispatch/dispatcher.inline.test.ts +0 -93
- package/clients/dispatch/dispatcher.js +0 -381
- package/clients/dispatch/dispatcher.test.js +0 -116
- package/clients/dispatch/dispatcher.test.ts +0 -149
- package/clients/dispatch/integration.js +0 -108
- package/clients/dispatch/plan.js +0 -183
- package/clients/dispatch/runners/architect.js +0 -83
- package/clients/dispatch/runners/architect.test.js +0 -138
- package/clients/dispatch/runners/architect.test.ts +0 -162
- package/clients/dispatch/runners/ast-grep-napi.js +0 -405
- package/clients/dispatch/runners/ast-grep-napi.test.js +0 -107
- package/clients/dispatch/runners/ast-grep-napi.test.ts +0 -129
- package/clients/dispatch/runners/ast-grep.js +0 -157
- package/clients/dispatch/runners/biome.js +0 -55
- package/clients/dispatch/runners/config-validation.js +0 -67
- package/clients/dispatch/runners/go-vet.js +0 -48
- package/clients/dispatch/runners/index.js +0 -47
- package/clients/dispatch/runners/lsp.js +0 -102
- package/clients/dispatch/runners/oxlint.js +0 -67
- package/clients/dispatch/runners/oxlint.test.js +0 -230
- package/clients/dispatch/runners/oxlint.test.ts +0 -303
- package/clients/dispatch/runners/pyright.js +0 -100
- package/clients/dispatch/runners/pyright.test.js +0 -98
- package/clients/dispatch/runners/pyright.test.ts +0 -121
- package/clients/dispatch/runners/python-slop.js +0 -97
- package/clients/dispatch/runners/python-slop.test.js +0 -203
- package/clients/dispatch/runners/python-slop.test.ts +0 -298
- package/clients/dispatch/runners/ruff.js +0 -48
- package/clients/dispatch/runners/rust-clippy.js +0 -102
- package/clients/dispatch/runners/scan_codebase.test.js +0 -89
- package/clients/dispatch/runners/scan_codebase.test.ts +0 -105
- package/clients/dispatch/runners/shellcheck.js +0 -147
- package/clients/dispatch/runners/shellcheck.test.js +0 -98
- package/clients/dispatch/runners/shellcheck.test.ts +0 -129
- package/clients/dispatch/runners/similarity.js +0 -230
- package/clients/dispatch/runners/spellcheck.js +0 -106
- package/clients/dispatch/runners/spellcheck.test.js +0 -158
- package/clients/dispatch/runners/spellcheck.test.ts +0 -214
- package/clients/dispatch/runners/tree-sitter.js +0 -246
- package/clients/dispatch/runners/ts-lsp.js +0 -125
- package/clients/dispatch/runners/ts-slop.js +0 -113
- package/clients/dispatch/runners/type-safety.js +0 -142
- package/clients/dispatch/runners/utils/diagnostic-parsers.js +0 -134
- package/clients/dispatch/runners/utils/runner-helpers.js +0 -115
- package/clients/dispatch/runners/utils.js +0 -51
- package/clients/dispatch/runners/yaml-rule-parser.js +0 -360
- package/clients/dispatch/types.js +0 -16
- package/clients/dispatch/utils/format-utils.js +0 -44
- package/clients/dogfood.test.js +0 -201
- package/clients/dogfood.test.ts +0 -269
- package/clients/file-kinds.js +0 -177
- package/clients/file-kinds.test.js +0 -169
- package/clients/file-kinds.test.ts +0 -210
- package/clients/file-time.js +0 -152
- package/clients/file-utils.js +0 -40
- package/clients/fix-scanners.js +0 -204
- package/clients/format-service.js +0 -184
- package/clients/formatters.js +0 -488
- package/clients/go-client.js +0 -203
- package/clients/go-client.test.js +0 -127
- package/clients/go-client.test.ts +0 -143
- package/clients/installer/index.js +0 -403
- package/clients/interviewer-templates.js +0 -75
- package/clients/interviewer.js +0 -173
- package/clients/jscpd-client.js +0 -196
- package/clients/jscpd-client.test.js +0 -127
- package/clients/jscpd-client.test.ts +0 -145
- package/clients/knip-client.js +0 -239
- package/clients/knip-client.test.js +0 -112
- package/clients/knip-client.test.ts +0 -128
- package/clients/latency-logger.js +0 -40
- package/clients/lsp/__tests__/client.test.js +0 -310
- package/clients/lsp/__tests__/client.test.ts +0 -412
- package/clients/lsp/__tests__/config.test.js +0 -167
- package/clients/lsp/__tests__/config.test.ts +0 -217
- package/clients/lsp/__tests__/error-recovery.test.js +0 -213
- package/clients/lsp/__tests__/error-recovery.test.ts +0 -279
- package/clients/lsp/__tests__/integration.test.js +0 -127
- package/clients/lsp/__tests__/integration.test.ts +0 -160
- package/clients/lsp/__tests__/launch.test.js +0 -313
- package/clients/lsp/__tests__/launch.test.ts +0 -394
- package/clients/lsp/__tests__/server.test.js +0 -259
- package/clients/lsp/__tests__/server.test.ts +0 -332
- package/clients/lsp/__tests__/service.test.js +0 -438
- package/clients/lsp/__tests__/service.test.ts +0 -530
- package/clients/lsp/client.js +0 -350
- package/clients/lsp/config.js +0 -112
- package/clients/lsp/index.js +0 -318
- package/clients/lsp/installer/index.js +0 -391
- package/clients/lsp/interactive-install.js +0 -221
- package/clients/lsp/language.js +0 -170
- package/clients/lsp/launch.js +0 -329
- package/clients/lsp/lsp/launch.js +0 -116
- package/clients/lsp/lsp/server.js +0 -532
- package/clients/lsp/lsp-index.js +0 -10
- package/clients/lsp/path-utils.js +0 -5
- package/clients/lsp/server.js +0 -725
- package/clients/lsp/test-py-spawn/requirements.txt +0 -1
- package/clients/lsp/test-py-spawn/test.py +0 -3
- package/clients/lsp/test-py-svc/requirements.txt +0 -1
- package/clients/lsp/test-py-svc/test.py +0 -3
- package/clients/lsp/test-python-project/requirements.txt +0 -1
- package/clients/lsp/test-python-project/test.py +0 -5
- package/clients/metrics-client.js +0 -107
- package/clients/metrics-client.test.js +0 -128
- package/clients/metrics-client.test.ts +0 -163
- package/clients/metrics-history.js +0 -367
- package/clients/path-utils.js +0 -142
- package/clients/pipeline.js +0 -272
- package/clients/production-readiness.js +0 -522
- package/clients/project-index.js +0 -255
- package/clients/project-metadata.js +0 -531
- package/clients/ruff-client.js +0 -325
- package/clients/ruff-client.test.js +0 -132
- package/clients/ruff-client.test.ts +0 -153
- package/clients/rules-scanner.js +0 -97
- package/clients/runner-tracker.js +0 -152
- package/clients/rust-client.js +0 -205
- package/clients/rust-client.test.js +0 -108
- package/clients/rust-client.test.ts +0 -130
- package/clients/safe-spawn-async.js +0 -163
- package/clients/safe-spawn.js +0 -241
- package/clients/sanitize.js +0 -291
- package/clients/sanitize.test.js +0 -177
- package/clients/sanitize.test.ts +0 -223
- package/clients/scan-architectural-debt.js +0 -167
- package/clients/scan-utils.js +0 -83
- package/clients/secrets-scanner.js +0 -119
- package/clients/secrets-scanner.test.js +0 -100
- package/clients/secrets-scanner.test.ts +0 -113
- package/clients/sg-runner.js +0 -292
- package/clients/state-matrix.js +0 -160
- package/clients/subprocess-client.js +0 -65
- package/clients/symbol-types.js +0 -5
- package/clients/test-runner-client.js +0 -523
- package/clients/test-runner-client.test.js +0 -192
- package/clients/test-runner-client.test.ts +0 -253
- package/clients/test-utils.js +0 -27
- package/clients/test-utils.ts +0 -36
- package/clients/todo-scanner.js +0 -200
- package/clients/todo-scanner.test.js +0 -301
- package/clients/todo-scanner.test.ts +0 -352
- package/clients/tool-availability.js +0 -207
- package/clients/tree-sitter-client.js +0 -601
- package/clients/tree-sitter-query-loader.js +0 -355
- package/clients/tree-sitter-symbol-extractor.js +0 -289
- package/clients/ts-service.js +0 -129
- package/clients/type-coverage-client.js +0 -127
- package/clients/type-coverage-client.test.js +0 -105
- package/clients/type-coverage-client.test.ts +0 -125
- package/clients/type-safety-client.js +0 -138
- package/clients/types.js +0 -11
- package/clients/typescript-client.codefix.test.js +0 -157
- package/clients/typescript-client.codefix.test.ts +0 -186
- package/clients/typescript-client.js +0 -509
- package/clients/typescript-client.test.js +0 -105
- package/clients/typescript-client.test.ts +0 -126
- package/commands/booboo.js +0 -1007
- package/commands/fix-from-booboo.js +0 -398
- package/commands/fix-simplified.js +0 -618
- package/commands/rate.js +0 -281
- package/commands/rate.test.js +0 -119
- package/commands/rate.test.ts +0 -131
- package/commands/refactor.js +0 -130
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Runner tracker for /lens-booboo and related commands
|
|
3
|
-
*
|
|
4
|
-
* Tracks execution time and findings for each analysis runner,
|
|
5
|
-
* producing a summary of what each runner found.
|
|
6
|
-
*/
|
|
7
|
-
export class RunnerTracker {
|
|
8
|
-
constructor(options) {
|
|
9
|
-
this.runners = [];
|
|
10
|
-
this.onProgress = options?.onProgress;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Run a function with timing and tracking
|
|
14
|
-
*/
|
|
15
|
-
async run(name, runFn, options) {
|
|
16
|
-
const startMs = Date.now();
|
|
17
|
-
const index = this.runners.length;
|
|
18
|
-
const runner = {
|
|
19
|
-
name,
|
|
20
|
-
status: "running",
|
|
21
|
-
findings: 0,
|
|
22
|
-
elapsedMs: 0,
|
|
23
|
-
};
|
|
24
|
-
this.runners.push(runner);
|
|
25
|
-
// Notify start
|
|
26
|
-
this.onProgress?.(runner, index);
|
|
27
|
-
try {
|
|
28
|
-
const result = await runFn();
|
|
29
|
-
const elapsedMs = Date.now() - startMs;
|
|
30
|
-
// Extract findings if result has it
|
|
31
|
-
const findings = typeof result === "object" &&
|
|
32
|
-
result !== null &&
|
|
33
|
-
"findings" in result &&
|
|
34
|
-
typeof result.findings === "number"
|
|
35
|
-
? result.findings
|
|
36
|
-
: 0;
|
|
37
|
-
runner.status = "done";
|
|
38
|
-
runner.elapsedMs = elapsedMs;
|
|
39
|
-
runner.findings = findings;
|
|
40
|
-
return result;
|
|
41
|
-
}
|
|
42
|
-
catch (err) {
|
|
43
|
-
const elapsedMs = Date.now() - startMs;
|
|
44
|
-
runner.status = "error";
|
|
45
|
-
runner.elapsedMs = elapsedMs;
|
|
46
|
-
runner.message = String(err);
|
|
47
|
-
throw err;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Mark a runner as skipped (for when preconditions aren't met)
|
|
52
|
-
*/
|
|
53
|
-
skip(name, message) {
|
|
54
|
-
this.runners.push({
|
|
55
|
-
name,
|
|
56
|
-
status: "skipped",
|
|
57
|
-
findings: 0,
|
|
58
|
-
elapsedMs: 0,
|
|
59
|
-
message,
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Update findings for a runner (useful when findings are discovered asynchronously)
|
|
64
|
-
*/
|
|
65
|
-
updateFindings(runnerName, findings) {
|
|
66
|
-
const runner = this.runners.find((r) => r.name === runnerName);
|
|
67
|
-
if (runner) {
|
|
68
|
-
runner.findings = findings;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Get all tracked runners
|
|
73
|
-
*/
|
|
74
|
-
getRunners() {
|
|
75
|
-
return [...this.runners];
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Get summary statistics
|
|
79
|
-
*/
|
|
80
|
-
getStats() {
|
|
81
|
-
return {
|
|
82
|
-
total: this.runners.length,
|
|
83
|
-
done: this.runners.filter((r) => r.status === "done").length,
|
|
84
|
-
skipped: this.runners.filter((r) => r.status === "skipped").length,
|
|
85
|
-
errors: this.runners.filter((r) => r.status === "error").length,
|
|
86
|
-
totalFindings: this.runners.reduce((sum, r) => sum + r.findings, 0),
|
|
87
|
-
totalTimeMs: this.runners.reduce((sum, r) => sum + r.elapsedMs, 0),
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Format a single runner result for display
|
|
92
|
-
*/
|
|
93
|
-
formatRunner(runner, index) {
|
|
94
|
-
const prefix = index !== undefined ? `[${index + 1}] ` : "";
|
|
95
|
-
const statusIcon = runner.status === "done"
|
|
96
|
-
? "✓"
|
|
97
|
-
: runner.status === "skipped"
|
|
98
|
-
? "⊘"
|
|
99
|
-
: runner.status === "error"
|
|
100
|
-
? "✗"
|
|
101
|
-
: "○";
|
|
102
|
-
const findings = runner.findings > 0 ? ` (${runner.findings} findings)` : "";
|
|
103
|
-
const time = this.formatElapsed(runner.elapsedMs);
|
|
104
|
-
const message = runner.message ? ` — ${runner.message}` : "";
|
|
105
|
-
return `${prefix}${statusIcon} ${runner.name}${findings} — ${time}${message}`;
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Format all runners as a summary table
|
|
109
|
-
*/
|
|
110
|
-
formatSummary() {
|
|
111
|
-
const lines = ["📊 Runner Summary:", ""];
|
|
112
|
-
for (let i = 0; i < this.runners.length; i++) {
|
|
113
|
-
lines.push(` ${this.formatRunner(this.runners[i], i)}`);
|
|
114
|
-
}
|
|
115
|
-
const stats = this.getStats();
|
|
116
|
-
lines.push("");
|
|
117
|
-
lines.push(` Total: ${stats.totalFindings} findings in ${this.formatElapsed(stats.totalTimeMs)}`);
|
|
118
|
-
return lines.join("\n");
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Format elapsed time in human-readable form
|
|
122
|
-
*/
|
|
123
|
-
formatElapsed(ms) {
|
|
124
|
-
if (ms < 1000)
|
|
125
|
-
return `${ms}ms`;
|
|
126
|
-
if (ms < 60000)
|
|
127
|
-
return `${(ms / 1000).toFixed(1)}s`;
|
|
128
|
-
const mins = Math.floor(ms / 60000);
|
|
129
|
-
const secs = ((ms % 60000) / 1000).toFixed(0);
|
|
130
|
-
return `${mins}m${secs.padStart(2, "0")}s`;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Convenience function to create a tracker and run a sequence
|
|
135
|
-
*/
|
|
136
|
-
export async function runSequence(sequence, onProgress) {
|
|
137
|
-
const tracker = new RunnerTracker({ onProgress });
|
|
138
|
-
const results = [];
|
|
139
|
-
for (const item of sequence) {
|
|
140
|
-
const result = await tracker.run(item.name, item.run, {
|
|
141
|
-
index: results.length,
|
|
142
|
-
total: sequence.length,
|
|
143
|
-
});
|
|
144
|
-
results.push(result);
|
|
145
|
-
// Update findings if handler provided
|
|
146
|
-
if (item.onFindings) {
|
|
147
|
-
const findings = item.onFindings(result);
|
|
148
|
-
tracker.updateFindings(item.name, findings);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
return { results, tracker };
|
|
152
|
-
}
|
package/clients/rust-client.js
DELETED
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Rust Client for pi-lens
|
|
3
|
-
*
|
|
4
|
-
* Provides Rust type checking and linting via cargo check and clippy.
|
|
5
|
-
*
|
|
6
|
-
* Requires: cargo (rustup)
|
|
7
|
-
* Docs: https://doc.rust-lang.org/cargo/
|
|
8
|
-
*/
|
|
9
|
-
import * as fs from "node:fs";
|
|
10
|
-
import * as path from "node:path";
|
|
11
|
-
import { safeSpawn } from "./safe-spawn.js";
|
|
12
|
-
// --- Common install paths ---
|
|
13
|
-
const CARGO_WINDOWS_PATHS = [
|
|
14
|
-
path.join(process.env.USERPROFILE || "", ".cargo", "bin", "cargo.exe"),
|
|
15
|
-
"C:\\cargo\\bin\\cargo.exe",
|
|
16
|
-
"cargo.exe", // PATH
|
|
17
|
-
];
|
|
18
|
-
const CARGO_UNIX_PATHS = [
|
|
19
|
-
path.join(process.env.HOME || "", ".cargo", "bin", "cargo"),
|
|
20
|
-
"/usr/local/cargo/bin/cargo",
|
|
21
|
-
"/usr/bin/cargo",
|
|
22
|
-
"cargo", // PATH
|
|
23
|
-
];
|
|
24
|
-
// --- Client ---
|
|
25
|
-
export class RustClient {
|
|
26
|
-
constructor(verbose = false) {
|
|
27
|
-
this.cargoAvailable = null;
|
|
28
|
-
this.cargoPath = null;
|
|
29
|
-
this.log = verbose
|
|
30
|
-
? (msg) => console.error(`[rust] ${msg}`)
|
|
31
|
-
: () => { };
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Find cargo executable path
|
|
35
|
-
*/
|
|
36
|
-
findCargoPath() {
|
|
37
|
-
if (this.cargoPath)
|
|
38
|
-
return this.cargoPath;
|
|
39
|
-
const paths = process.platform === "win32" ? CARGO_WINDOWS_PATHS : CARGO_UNIX_PATHS;
|
|
40
|
-
for (const p of paths) {
|
|
41
|
-
try {
|
|
42
|
-
if (p.includes("\\") || p.includes("/")) {
|
|
43
|
-
if (fs.existsSync(p)) {
|
|
44
|
-
this.cargoPath = p;
|
|
45
|
-
return p;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
const result = safeSpawn(p, ["--version"], {
|
|
50
|
-
timeout: 3000,
|
|
51
|
-
});
|
|
52
|
-
if (!result.error && result.status === 0) {
|
|
53
|
-
this.cargoPath = p;
|
|
54
|
-
return p;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
catch (err) {
|
|
59
|
-
void err;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Check if cargo is installed
|
|
66
|
-
*/
|
|
67
|
-
isAvailable() {
|
|
68
|
-
if (this.cargoAvailable !== null)
|
|
69
|
-
return this.cargoAvailable;
|
|
70
|
-
this.cargoAvailable = this.findCargoPath() !== null;
|
|
71
|
-
if (this.cargoAvailable) {
|
|
72
|
-
this.log(`Cargo found: ${this.cargoPath}`);
|
|
73
|
-
}
|
|
74
|
-
return this.cargoAvailable;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Check if a file is a Rust file
|
|
78
|
-
*/
|
|
79
|
-
isRustFile(filePath) {
|
|
80
|
-
return path.extname(filePath).toLowerCase() === ".rs";
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Run cargo check on the project
|
|
84
|
-
*/
|
|
85
|
-
checkFile(filePath, cwd) {
|
|
86
|
-
const cargoExe = this.findCargoPath();
|
|
87
|
-
if (!cargoExe)
|
|
88
|
-
return [];
|
|
89
|
-
const absolutePath = path.resolve(filePath);
|
|
90
|
-
if (!fs.existsSync(absolutePath))
|
|
91
|
-
return [];
|
|
92
|
-
try {
|
|
93
|
-
const result = safeSpawn(cargoExe, ["check", "--message-format", "json"], {
|
|
94
|
-
timeout: 60000,
|
|
95
|
-
cwd,
|
|
96
|
-
});
|
|
97
|
-
const output = result.stdout || "";
|
|
98
|
-
return this.parseJsonOutput(output, absolutePath);
|
|
99
|
-
}
|
|
100
|
-
catch (err) {
|
|
101
|
-
this.log(`Check error: ${err.message}`);
|
|
102
|
-
return [];
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Run clippy for additional lints
|
|
107
|
-
*/
|
|
108
|
-
clippyCheck(cwd) {
|
|
109
|
-
if (!this.isAvailable())
|
|
110
|
-
return [];
|
|
111
|
-
try {
|
|
112
|
-
const result = safeSpawn("cargo", ["clippy", "--message-format", "json"], {
|
|
113
|
-
timeout: 60000,
|
|
114
|
-
cwd,
|
|
115
|
-
});
|
|
116
|
-
const output = result.stdout || "";
|
|
117
|
-
return this.parseJsonOutput(output, "");
|
|
118
|
-
}
|
|
119
|
-
catch (err) {
|
|
120
|
-
this.log(`Clippy error: ${err.message}`);
|
|
121
|
-
return [];
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Format diagnostics for LLM consumption
|
|
126
|
-
*/
|
|
127
|
-
formatDiagnostics(diags, maxItems = 10) {
|
|
128
|
-
if (diags.length === 0)
|
|
129
|
-
return "";
|
|
130
|
-
const errors = diags.filter((d) => d.severity === "error");
|
|
131
|
-
const warnings = diags.filter((d) => d.severity === "warning");
|
|
132
|
-
let output = `[Rust] ${diags.length} issue(s)`;
|
|
133
|
-
if (errors.length)
|
|
134
|
-
output += ` — ${errors.length} error(s)`;
|
|
135
|
-
if (warnings.length)
|
|
136
|
-
output += ` — ${warnings.length} warning(s)`;
|
|
137
|
-
output += ":\n";
|
|
138
|
-
for (const d of diags.slice(0, maxItems)) {
|
|
139
|
-
const loc = `L${d.line}:${d.column}`;
|
|
140
|
-
const code = d.code ? ` [${d.code}]` : "";
|
|
141
|
-
output += ` [${d.severity}] ${loc} ${d.message.slice(0, 200)}${code}\n`;
|
|
142
|
-
}
|
|
143
|
-
if (diags.length > maxItems) {
|
|
144
|
-
output += ` ... and ${diags.length - maxItems} more\n`;
|
|
145
|
-
}
|
|
146
|
-
return output;
|
|
147
|
-
}
|
|
148
|
-
// --- Internal ---
|
|
149
|
-
parseJsonOutput(output, filterFile) {
|
|
150
|
-
if (!output.trim())
|
|
151
|
-
return [];
|
|
152
|
-
const diags = [];
|
|
153
|
-
const lines = output.split("\n").filter((l) => l.trim());
|
|
154
|
-
for (const line of lines) {
|
|
155
|
-
try {
|
|
156
|
-
const msg = JSON.parse(line);
|
|
157
|
-
if (msg.reason === "compiler-message" && msg.message) {
|
|
158
|
-
const { level, message, spans, code } = msg.message;
|
|
159
|
-
// Only include errors and warnings
|
|
160
|
-
if (level !== "error" && level !== "warning" && level !== "note") {
|
|
161
|
-
continue;
|
|
162
|
-
}
|
|
163
|
-
// Get location from spans
|
|
164
|
-
if (spans && spans.length > 0) {
|
|
165
|
-
for (const span of spans) {
|
|
166
|
-
const file = span.file_name;
|
|
167
|
-
// Filter to specific file if provided
|
|
168
|
-
if (filterFile &&
|
|
169
|
-
path.resolve(file) !== path.resolve(filterFile)) {
|
|
170
|
-
continue;
|
|
171
|
-
}
|
|
172
|
-
diags.push({
|
|
173
|
-
line: span.line_start,
|
|
174
|
-
column: span.column_start - 1,
|
|
175
|
-
endLine: span.line_end,
|
|
176
|
-
endColumn: span.column_end - 1,
|
|
177
|
-
severity: level,
|
|
178
|
-
message: message.slice(0, 300),
|
|
179
|
-
code,
|
|
180
|
-
file: path.resolve(file),
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
else {
|
|
185
|
-
// No span info, add as general diagnostic
|
|
186
|
-
diags.push({
|
|
187
|
-
line: 1,
|
|
188
|
-
column: 0,
|
|
189
|
-
endLine: 1,
|
|
190
|
-
endColumn: 0,
|
|
191
|
-
severity: level,
|
|
192
|
-
message: message.slice(0, 300),
|
|
193
|
-
code,
|
|
194
|
-
file: filterFile || "",
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
catch (err) {
|
|
200
|
-
void err;
|
|
201
|
-
} // Skip non-JSON lines
|
|
202
|
-
}
|
|
203
|
-
return diags;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import * as path from "node:path";
|
|
3
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
4
|
-
import { RustClient } from "./rust-client.js";
|
|
5
|
-
import { setupTestEnvironment } from "./test-utils.js";
|
|
6
|
-
describe("RustClient", () => {
|
|
7
|
-
let client;
|
|
8
|
-
let tmpDir;
|
|
9
|
-
let cleanup;
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
client = new RustClient();
|
|
12
|
-
({ tmpDir, cleanup } = setupTestEnvironment("pi-lens-rust-test-"));
|
|
13
|
-
});
|
|
14
|
-
afterEach(() => {
|
|
15
|
-
cleanup();
|
|
16
|
-
});
|
|
17
|
-
afterEach(() => {
|
|
18
|
-
cleanup();
|
|
19
|
-
});
|
|
20
|
-
describe("isRustFile", () => {
|
|
21
|
-
it("should recognize Rust files", () => {
|
|
22
|
-
expect(client.isRustFile("main.rs")).toBe(true);
|
|
23
|
-
expect(client.isRustFile("lib.rs")).toBe(true);
|
|
24
|
-
});
|
|
25
|
-
it("should not recognize non-Rust files", () => {
|
|
26
|
-
expect(client.isRustFile("main.ts")).toBe(false);
|
|
27
|
-
expect(client.isRustFile("main.py")).toBe(false);
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
describe("isAvailable", () => {
|
|
31
|
-
it("should check cargo availability", () => {
|
|
32
|
-
const available = client.isAvailable();
|
|
33
|
-
expect(typeof available).toBe("boolean");
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
describe("checkFile", () => {
|
|
37
|
-
it("should return empty array for non-existent files", () => {
|
|
38
|
-
if (!client.isAvailable())
|
|
39
|
-
return;
|
|
40
|
-
const result = client.checkFile("/nonexistent/file.rs", tmpDir);
|
|
41
|
-
expect(result).toEqual([]);
|
|
42
|
-
});
|
|
43
|
-
it("should return array for valid Rust files", () => {
|
|
44
|
-
if (!client.isAvailable())
|
|
45
|
-
return;
|
|
46
|
-
// Need a Cargo.toml for cargo to work
|
|
47
|
-
fs.writeFileSync(path.join(tmpDir, "Cargo.toml"), `
|
|
48
|
-
[package]
|
|
49
|
-
name = "test"
|
|
50
|
-
version = "0.1.0"
|
|
51
|
-
edition = "2021"
|
|
52
|
-
`);
|
|
53
|
-
fs.mkdirSync(path.join(tmpDir, "src"), { recursive: true });
|
|
54
|
-
fs.writeFileSync(path.join(tmpDir, "src", "main.rs"), `
|
|
55
|
-
fn main() {
|
|
56
|
-
println!("Hello, world!");
|
|
57
|
-
}
|
|
58
|
-
`);
|
|
59
|
-
const result = client.checkFile(path.join(tmpDir, "src", "main.rs"), tmpDir);
|
|
60
|
-
expect(Array.isArray(result)).toBe(true);
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
describe("formatDiagnostics", () => {
|
|
64
|
-
it("should format diagnostics for display", () => {
|
|
65
|
-
const diags = [
|
|
66
|
-
{
|
|
67
|
-
line: 3,
|
|
68
|
-
column: 0,
|
|
69
|
-
endLine: 3,
|
|
70
|
-
endColumn: 10,
|
|
71
|
-
severity: "error",
|
|
72
|
-
message: "cannot find value `x` in this scope",
|
|
73
|
-
code: "E0425",
|
|
74
|
-
file: "main.rs",
|
|
75
|
-
},
|
|
76
|
-
];
|
|
77
|
-
const formatted = client.formatDiagnostics(diags);
|
|
78
|
-
expect(formatted).toContain("Rust");
|
|
79
|
-
expect(formatted).toContain("1 issue");
|
|
80
|
-
expect(formatted).toContain("E0425");
|
|
81
|
-
});
|
|
82
|
-
it("should show error and warning counts", () => {
|
|
83
|
-
const diags = [
|
|
84
|
-
{
|
|
85
|
-
line: 1,
|
|
86
|
-
column: 0,
|
|
87
|
-
endLine: 1,
|
|
88
|
-
endColumn: 10,
|
|
89
|
-
severity: "error",
|
|
90
|
-
message: "Error",
|
|
91
|
-
file: "test.rs",
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
line: 2,
|
|
95
|
-
column: 0,
|
|
96
|
-
endLine: 2,
|
|
97
|
-
endColumn: 10,
|
|
98
|
-
severity: "warning",
|
|
99
|
-
message: "Warning",
|
|
100
|
-
file: "test.rs",
|
|
101
|
-
},
|
|
102
|
-
];
|
|
103
|
-
const formatted = client.formatDiagnostics(diags);
|
|
104
|
-
expect(formatted).toContain("1 error(s)");
|
|
105
|
-
expect(formatted).toContain("1 warning(s)");
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
});
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import * as path from "node:path";
|
|
3
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
4
|
-
import { RustClient } from "./rust-client.js";
|
|
5
|
-
import { setupTestEnvironment } from "./test-utils.js";
|
|
6
|
-
|
|
7
|
-
describe("RustClient", () => {
|
|
8
|
-
let client: RustClient;
|
|
9
|
-
let tmpDir: string;
|
|
10
|
-
let cleanup: () => void;
|
|
11
|
-
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
client = new RustClient();
|
|
14
|
-
({ tmpDir, cleanup } = setupTestEnvironment("pi-lens-rust-test-"));
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
afterEach(() => {
|
|
18
|
-
cleanup();
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
afterEach(() => {
|
|
22
|
-
cleanup();
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
describe("isRustFile", () => {
|
|
26
|
-
it("should recognize Rust files", () => {
|
|
27
|
-
expect(client.isRustFile("main.rs")).toBe(true);
|
|
28
|
-
expect(client.isRustFile("lib.rs")).toBe(true);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it("should not recognize non-Rust files", () => {
|
|
32
|
-
expect(client.isRustFile("main.ts")).toBe(false);
|
|
33
|
-
expect(client.isRustFile("main.py")).toBe(false);
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
describe("isAvailable", () => {
|
|
38
|
-
it("should check cargo availability", () => {
|
|
39
|
-
const available = client.isAvailable();
|
|
40
|
-
expect(typeof available).toBe("boolean");
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
describe("checkFile", () => {
|
|
45
|
-
it("should return empty array for non-existent files", () => {
|
|
46
|
-
if (!client.isAvailable()) return;
|
|
47
|
-
const result = client.checkFile("/nonexistent/file.rs", tmpDir);
|
|
48
|
-
expect(result).toEqual([]);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it("should return array for valid Rust files", () => {
|
|
52
|
-
if (!client.isAvailable()) return;
|
|
53
|
-
|
|
54
|
-
// Need a Cargo.toml for cargo to work
|
|
55
|
-
fs.writeFileSync(
|
|
56
|
-
path.join(tmpDir, "Cargo.toml"),
|
|
57
|
-
`
|
|
58
|
-
[package]
|
|
59
|
-
name = "test"
|
|
60
|
-
version = "0.1.0"
|
|
61
|
-
edition = "2021"
|
|
62
|
-
`,
|
|
63
|
-
);
|
|
64
|
-
fs.mkdirSync(path.join(tmpDir, "src"), { recursive: true });
|
|
65
|
-
fs.writeFileSync(
|
|
66
|
-
path.join(tmpDir, "src", "main.rs"),
|
|
67
|
-
`
|
|
68
|
-
fn main() {
|
|
69
|
-
println!("Hello, world!");
|
|
70
|
-
}
|
|
71
|
-
`,
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
const result = client.checkFile(
|
|
75
|
-
path.join(tmpDir, "src", "main.rs"),
|
|
76
|
-
tmpDir,
|
|
77
|
-
);
|
|
78
|
-
expect(Array.isArray(result)).toBe(true);
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
describe("formatDiagnostics", () => {
|
|
83
|
-
it("should format diagnostics for display", () => {
|
|
84
|
-
const diags = [
|
|
85
|
-
{
|
|
86
|
-
line: 3,
|
|
87
|
-
column: 0,
|
|
88
|
-
endLine: 3,
|
|
89
|
-
endColumn: 10,
|
|
90
|
-
severity: "error" as const,
|
|
91
|
-
message: "cannot find value `x` in this scope",
|
|
92
|
-
code: "E0425",
|
|
93
|
-
file: "main.rs",
|
|
94
|
-
},
|
|
95
|
-
];
|
|
96
|
-
|
|
97
|
-
const formatted = client.formatDiagnostics(diags);
|
|
98
|
-
expect(formatted).toContain("Rust");
|
|
99
|
-
expect(formatted).toContain("1 issue");
|
|
100
|
-
expect(formatted).toContain("E0425");
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it("should show error and warning counts", () => {
|
|
104
|
-
const diags = [
|
|
105
|
-
{
|
|
106
|
-
line: 1,
|
|
107
|
-
column: 0,
|
|
108
|
-
endLine: 1,
|
|
109
|
-
endColumn: 10,
|
|
110
|
-
severity: "error" as const,
|
|
111
|
-
message: "Error",
|
|
112
|
-
file: "test.rs",
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
line: 2,
|
|
116
|
-
column: 0,
|
|
117
|
-
endLine: 2,
|
|
118
|
-
endColumn: 10,
|
|
119
|
-
severity: "warning" as const,
|
|
120
|
-
message: "Warning",
|
|
121
|
-
file: "test.rs",
|
|
122
|
-
},
|
|
123
|
-
];
|
|
124
|
-
|
|
125
|
-
const formatted = client.formatDiagnostics(diags);
|
|
126
|
-
expect(formatted).toContain("1 error(s)");
|
|
127
|
-
expect(formatted).toContain("1 warning(s)");
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
});
|