pi-lens 2.0.8 → 2.0.9
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/clients/ast-grep-client.ts +10 -6
- package/clients/biome-client.ts +2 -2
- package/clients/go-client.ts +3 -1
- package/clients/jscpd-client.ts +4 -2
- package/clients/knip-client.ts +1 -1
- package/clients/ruff-client.ts +3 -5
- package/clients/rust-client.ts +6 -2
- package/clients/subprocess-client.ts +1 -1
- package/clients/test-runner-client.ts +8 -6
- package/clients/type-coverage-client.test.ts +3 -1
- package/clients/typescript-client.ts +1 -1
- package/index.ts +20 -13
- package/package.json +1 -1
- package/rules/ast-grep-rules/rules/empty-catch.yml +12 -9
- package/rules/ast-grep-rules/rules/silent-failure.yml +0 -14
|
@@ -354,12 +354,14 @@ message: found
|
|
|
354
354
|
}
|
|
355
355
|
|
|
356
356
|
return result_groups;
|
|
357
|
-
} catch {
|
|
357
|
+
} catch (err) { void err;
|
|
358
358
|
return [];
|
|
359
359
|
} finally {
|
|
360
360
|
try {
|
|
361
361
|
require("node:fs").rmSync(ruleDir, { recursive: true, force: true });
|
|
362
|
-
} catch (err) {
|
|
362
|
+
} catch (err) {
|
|
363
|
+
void err;
|
|
364
|
+
}
|
|
363
365
|
}
|
|
364
366
|
}
|
|
365
367
|
|
|
@@ -435,7 +437,9 @@ message: found
|
|
|
435
437
|
} finally {
|
|
436
438
|
try {
|
|
437
439
|
require("node:fs").rmSync(ruleDir, { recursive: true, force: true });
|
|
438
|
-
} catch (err) {
|
|
440
|
+
} catch (err) {
|
|
441
|
+
void err;
|
|
442
|
+
}
|
|
439
443
|
}
|
|
440
444
|
|
|
441
445
|
return exports;
|
|
@@ -484,7 +488,7 @@ message: found
|
|
|
484
488
|
const parsed = JSON.parse(stdout);
|
|
485
489
|
const matches = Array.isArray(parsed) ? parsed : [parsed];
|
|
486
490
|
resolve({ matches });
|
|
487
|
-
} catch {
|
|
491
|
+
} catch (err) { void err;
|
|
488
492
|
resolve({ matches: [], error: "Failed to parse output" });
|
|
489
493
|
}
|
|
490
494
|
});
|
|
@@ -595,7 +599,7 @@ message: found
|
|
|
595
599
|
}
|
|
596
600
|
return diagnostics;
|
|
597
601
|
}
|
|
598
|
-
} catch {
|
|
602
|
+
} catch (err) { void err;
|
|
599
603
|
// Not a JSON array, try ndjson format (legacy)
|
|
600
604
|
}
|
|
601
605
|
|
|
@@ -607,7 +611,7 @@ message: found
|
|
|
607
611
|
const item: AstGrepJsonDiagnostic = JSON.parse(line);
|
|
608
612
|
const diag = this.parseDiagnostic(item, resolvedFilterFile);
|
|
609
613
|
if (diag) diagnostics.push(diag);
|
|
610
|
-
} catch {
|
|
614
|
+
} catch (err) { void err;
|
|
611
615
|
// Skip unparseable lines
|
|
612
616
|
}
|
|
613
617
|
}
|
package/clients/biome-client.ts
CHANGED
|
@@ -313,7 +313,7 @@ export class BiomeClient {
|
|
|
313
313
|
if (content === formatted) return "";
|
|
314
314
|
|
|
315
315
|
return this.computeDiff(content, formatted);
|
|
316
|
-
} catch {
|
|
316
|
+
} catch (err) { void err;
|
|
317
317
|
return "";
|
|
318
318
|
}
|
|
319
319
|
}
|
|
@@ -368,7 +368,7 @@ export class BiomeClient {
|
|
|
368
368
|
}
|
|
369
369
|
|
|
370
370
|
return diagnostics;
|
|
371
|
-
} catch {
|
|
371
|
+
} catch (err) { void err;
|
|
372
372
|
this.log("Failed to parse biome JSON output");
|
|
373
373
|
return [];
|
|
374
374
|
}
|
package/clients/go-client.ts
CHANGED
package/clients/jscpd-client.ts
CHANGED
|
@@ -120,7 +120,9 @@ export class JscpdClient {
|
|
|
120
120
|
} finally {
|
|
121
121
|
try {
|
|
122
122
|
fs.rmSync(outDir, { recursive: true, force: true });
|
|
123
|
-
} catch (err) {
|
|
123
|
+
} catch (err) {
|
|
124
|
+
void err;
|
|
125
|
+
}
|
|
124
126
|
}
|
|
125
127
|
}
|
|
126
128
|
|
|
@@ -168,7 +170,7 @@ export class JscpdClient {
|
|
|
168
170
|
}));
|
|
169
171
|
|
|
170
172
|
return { success: true, clones, duplicatedLines, totalLines, percentage };
|
|
171
|
-
} catch {
|
|
173
|
+
} catch (err) { void err;
|
|
172
174
|
return {
|
|
173
175
|
success: false,
|
|
174
176
|
clones: [],
|
package/clients/knip-client.ts
CHANGED
package/clients/ruff-client.ts
CHANGED
|
@@ -64,7 +64,7 @@ export class RuffClient {
|
|
|
64
64
|
if (this.ruffAvailable) {
|
|
65
65
|
this.log(`Ruff found: ${result.stdout.trim()}`);
|
|
66
66
|
}
|
|
67
|
-
} catch {
|
|
67
|
+
} catch (err) { void err;
|
|
68
68
|
this.ruffAvailable = false;
|
|
69
69
|
}
|
|
70
70
|
|
|
@@ -147,9 +147,7 @@ export class RuffClient {
|
|
|
147
147
|
.split("\n")
|
|
148
148
|
.filter((l) => l.startsWith("+") || l.startsWith("-")).length;
|
|
149
149
|
return `[Ruff Format] ${diffLines} line(s) would change — run 'ruff format ${path.basename(filePath)}' to fix`;
|
|
150
|
-
} catch {
|
|
151
|
-
return "";
|
|
152
|
-
}
|
|
150
|
+
} catch (err) { void err; return ""; } // Intentionally return empty string on diff failure
|
|
153
151
|
}
|
|
154
152
|
|
|
155
153
|
/**
|
|
@@ -318,7 +316,7 @@ export class RuffClient {
|
|
|
318
316
|
}
|
|
319
317
|
|
|
320
318
|
return diagnostics;
|
|
321
|
-
} catch {
|
|
319
|
+
} catch (err) { void err;
|
|
322
320
|
this.log("Failed to parse ruff JSON output");
|
|
323
321
|
return [];
|
|
324
322
|
}
|
package/clients/rust-client.ts
CHANGED
|
@@ -95,7 +95,9 @@ export class RustClient {
|
|
|
95
95
|
return p;
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
|
-
} catch (err) {
|
|
98
|
+
} catch (err) {
|
|
99
|
+
void err;
|
|
100
|
+
}
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
return null;
|
|
@@ -265,7 +267,9 @@ export class RustClient {
|
|
|
265
267
|
});
|
|
266
268
|
}
|
|
267
269
|
}
|
|
268
|
-
} catch (err) {
|
|
270
|
+
} catch (err) {
|
|
271
|
+
void err;
|
|
272
|
+
} // Skip non-JSON lines
|
|
269
273
|
}
|
|
270
274
|
|
|
271
275
|
return diags;
|
|
@@ -262,7 +262,7 @@ export class TestRunnerClient {
|
|
|
262
262
|
this.availableRunners.set(`${cwd}:pytest:config`, true);
|
|
263
263
|
return { runner: "pytest", config: RUNNERS.pytest };
|
|
264
264
|
}
|
|
265
|
-
} catch {
|
|
265
|
+
} catch (err) { void err;
|
|
266
266
|
// package.json parse error
|
|
267
267
|
}
|
|
268
268
|
}
|
|
@@ -291,7 +291,7 @@ export class TestRunnerClient {
|
|
|
291
291
|
return files.some((f) =>
|
|
292
292
|
new RegExp(cf.replace(/\*/g, ".*")).test(f),
|
|
293
293
|
);
|
|
294
|
-
} catch {
|
|
294
|
+
} catch (err) { void err;
|
|
295
295
|
return false;
|
|
296
296
|
}
|
|
297
297
|
}
|
|
@@ -315,7 +315,9 @@ export class TestRunnerClient {
|
|
|
315
315
|
this.log("Detected pytest globally");
|
|
316
316
|
return { runner: "pytest", config: RUNNERS.pytest };
|
|
317
317
|
}
|
|
318
|
-
} catch (err) {
|
|
318
|
+
} catch (err) {
|
|
319
|
+
void err;
|
|
320
|
+
}
|
|
319
321
|
|
|
320
322
|
return null;
|
|
321
323
|
}
|
|
@@ -364,7 +366,7 @@ export class TestRunnerClient {
|
|
|
364
366
|
this.log(`Found test file: ${testPath}`);
|
|
365
367
|
return { testFile: testPath, runner: detected.runner };
|
|
366
368
|
}
|
|
367
|
-
} catch {
|
|
369
|
+
} catch (err) { void err;
|
|
368
370
|
// Directory not readable
|
|
369
371
|
}
|
|
370
372
|
}
|
|
@@ -545,7 +547,7 @@ export class TestRunnerClient {
|
|
|
545
547
|
failures,
|
|
546
548
|
duration: 0, // Vitest JSON doesn't include duration in this format
|
|
547
549
|
};
|
|
548
|
-
} catch {
|
|
550
|
+
} catch (err) { void err;
|
|
549
551
|
// If JSON parsing fails, check for basic pass/fail indicators
|
|
550
552
|
const failed = stdout.includes("FAIL") || stderr.includes("FAIL");
|
|
551
553
|
return this.emptyResult(
|
|
@@ -617,7 +619,7 @@ export class TestRunnerClient {
|
|
|
617
619
|
failures,
|
|
618
620
|
duration: 0,
|
|
619
621
|
};
|
|
620
|
-
} catch {
|
|
622
|
+
} catch (err) { void err;
|
|
621
623
|
const failed = stdout.includes("FAIL") || stderr.includes("FAIL");
|
|
622
624
|
return this.emptyResult(
|
|
623
625
|
testFile,
|
|
@@ -9,7 +9,9 @@ describe("TypeCoverageClient", () => {
|
|
|
9
9
|
|
|
10
10
|
beforeEach(() => {
|
|
11
11
|
client = new TypeCoverageClient();
|
|
12
|
-
({ tmpDir: _tmpDir, cleanup } = setupTestEnvironment(
|
|
12
|
+
({ tmpDir: _tmpDir, cleanup } = setupTestEnvironment(
|
|
13
|
+
"pi-lens-typecoverage-test-",
|
|
14
|
+
));
|
|
13
15
|
});
|
|
14
16
|
|
|
15
17
|
afterEach(() => {
|
|
@@ -81,7 +81,7 @@ function loadCompilerOptions(tsconfigPath: string): ts.CompilerOptions {
|
|
|
81
81
|
if (parsed.errors.length) return DEFAULT_COMPILER_OPTIONS;
|
|
82
82
|
// Always set skipLibCheck to avoid noise from node_modules
|
|
83
83
|
return { ...parsed.options, skipLibCheck: true };
|
|
84
|
-
} catch {
|
|
84
|
+
} catch (err) { void err;
|
|
85
85
|
return DEFAULT_COMPILER_OPTIONS;
|
|
86
86
|
}
|
|
87
87
|
}
|
package/index.ts
CHANGED
|
@@ -281,14 +281,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
281
281
|
if (trimmed.startsWith("[")) {
|
|
282
282
|
try {
|
|
283
283
|
return JSON.parse(trimmed);
|
|
284
|
-
} catch {
|
|
284
|
+
} catch (err) { void err;
|
|
285
285
|
return [];
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
288
|
return raw.split("\n").flatMap((l: string) => {
|
|
289
289
|
try {
|
|
290
290
|
return [JSON.parse(l)];
|
|
291
|
-
} catch {
|
|
291
|
+
} catch (err) { void err;
|
|
292
292
|
return [];
|
|
293
293
|
}
|
|
294
294
|
});
|
|
@@ -661,10 +661,6 @@ export default function (pi: ExtensionAPI) {
|
|
|
661
661
|
type: "agent",
|
|
662
662
|
note: "Add this.log('Error: ' + err.message) to the catch block",
|
|
663
663
|
},
|
|
664
|
-
"silent-failure": {
|
|
665
|
-
type: "agent",
|
|
666
|
-
note: "Add this.log('Error: ' + err.message) or rethrow",
|
|
667
|
-
},
|
|
668
664
|
"no-console-log": {
|
|
669
665
|
type: "agent",
|
|
670
666
|
note: "Remove or replace with class logger method",
|
|
@@ -833,7 +829,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
833
829
|
: raw.split("\n").flatMap((l: string) => {
|
|
834
830
|
try {
|
|
835
831
|
return [JSON.parse(l)];
|
|
836
|
-
} catch {
|
|
832
|
+
} catch (err) { void err;
|
|
837
833
|
return [];
|
|
838
834
|
}
|
|
839
835
|
});
|
|
@@ -1241,8 +1237,18 @@ export default function (pi: ExtensionAPI) {
|
|
|
1241
1237
|
report += `|-------|-------|------------|\n`;
|
|
1242
1238
|
for (const [grade, count] of Object.entries(gradeCount)) {
|
|
1243
1239
|
const pct = ((count / results.length) * 100).toFixed(1);
|
|
1244
|
-
const gradeIcons: Record<string, string> = {
|
|
1245
|
-
|
|
1240
|
+
const gradeIcons: Record<string, string> = {
|
|
1241
|
+
A: "🟢",
|
|
1242
|
+
B: "🟡",
|
|
1243
|
+
C: "🟠",
|
|
1244
|
+
D: "🔴",
|
|
1245
|
+
};
|
|
1246
|
+
const gradeThresholds: Record<string, number> = {
|
|
1247
|
+
A: 80,
|
|
1248
|
+
B: 60,
|
|
1249
|
+
C: 40,
|
|
1250
|
+
D: 20,
|
|
1251
|
+
};
|
|
1246
1252
|
const icon = gradeIcons[grade] ?? "⚫";
|
|
1247
1253
|
const threshold = gradeThresholds[grade] ?? 0;
|
|
1248
1254
|
report += `| ${icon} ${grade} (MI ≥ ${threshold}) | ${count} | ${pct}% |\n`;
|
|
@@ -1683,9 +1689,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
1683
1689
|
const preWriteHints = new Map<string, string>();
|
|
1684
1690
|
|
|
1685
1691
|
pi.on("tool_call", async (event, _ctx) => {
|
|
1686
|
-
const filePath =
|
|
1687
|
-
|
|
1688
|
-
|
|
1692
|
+
const filePath =
|
|
1693
|
+
isToolCallEventType("write", event) || isToolCallEventType("edit", event)
|
|
1694
|
+
? (event.input as { path: string }).path
|
|
1695
|
+
: undefined;
|
|
1689
1696
|
|
|
1690
1697
|
if (!filePath) return;
|
|
1691
1698
|
|
|
@@ -2113,7 +2120,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
2113
2120
|
for (const [name, file] of newExports) {
|
|
2114
2121
|
cachedExports.set(name, file);
|
|
2115
2122
|
}
|
|
2116
|
-
} catch {
|
|
2123
|
+
} catch (err) { void err;
|
|
2117
2124
|
// ast-grep not available, skip
|
|
2118
2125
|
}
|
|
2119
2126
|
}
|
package/package.json
CHANGED
|
@@ -4,13 +4,16 @@ message: "Empty catch block — handle or log the error"
|
|
|
4
4
|
severity: warning
|
|
5
5
|
note: |
|
|
6
6
|
Silently swallowing errors makes debugging impossible.
|
|
7
|
-
|
|
7
|
+
Catches with return statements, assignments, or error propagation are acceptable.
|
|
8
8
|
rule:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
kind: catch_clause
|
|
10
|
+
has:
|
|
11
|
+
kind: statement_block
|
|
12
|
+
not:
|
|
13
|
+
has:
|
|
14
|
+
any:
|
|
15
|
+
- kind: expression_statement # this.log(...), void err, etc.
|
|
16
|
+
- kind: return_statement # return defaultValue
|
|
17
|
+
- kind: throw_statement # rethrow
|
|
18
|
+
- kind: variable_declaration # const x = ...
|
|
19
|
+
- kind: assignment_expression # x = ...
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
id: silent-failure
|
|
2
|
-
language: TypeScript
|
|
3
|
-
message: "Silent failure detected — log or rethrow the error"
|
|
4
|
-
severity: warning
|
|
5
|
-
note: |
|
|
6
|
-
Empty catch blocks swallow errors silently.
|
|
7
|
-
Always log the error or rethrow it to aid debugging.
|
|
8
|
-
rule:
|
|
9
|
-
kind: catch_clause
|
|
10
|
-
has:
|
|
11
|
-
kind: statement_block
|
|
12
|
-
not:
|
|
13
|
-
has:
|
|
14
|
-
kind: throw_statement
|