pi-lens 1.3.8 → 1.3.10
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/complexity-client.ts +38 -15
- package/index.ts +15 -0
- package/package.json +1 -1
|
@@ -212,7 +212,7 @@ export class ComplexityClient {
|
|
|
212
212
|
maintainabilityIndex: Math.round(maintainabilityIndex * 10) / 10,
|
|
213
213
|
linesOfCode: codeLines,
|
|
214
214
|
commentLines,
|
|
215
|
-
codeEntropy: Math.round(codeEntropy *
|
|
215
|
+
codeEntropy: Math.round(codeEntropy * 100) / 100,
|
|
216
216
|
};
|
|
217
217
|
} catch (err: any) {
|
|
218
218
|
this.log(`Analysis error for ${filePath}: ${err.message}`);
|
|
@@ -247,11 +247,9 @@ export class ComplexityClient {
|
|
|
247
247
|
parts.push(` Max nesting: ${metrics.maxNestingDepth} levels (consider extracting)`);
|
|
248
248
|
}
|
|
249
249
|
|
|
250
|
-
// Code entropy (
|
|
251
|
-
if (metrics.codeEntropy >
|
|
252
|
-
parts.push(` Entropy: ${metrics.codeEntropy} (
|
|
253
|
-
} else if (metrics.codeEntropy < 0.3) {
|
|
254
|
-
parts.push(` Entropy: ${metrics.codeEntropy} (low — repetitive patterns detected)`);
|
|
250
|
+
// Code entropy (in bits, >3.5 = risky AI-induced complexity)
|
|
251
|
+
if (metrics.codeEntropy > 3.5) {
|
|
252
|
+
parts.push(` Entropy: ${metrics.codeEntropy.toFixed(1)} bits (>3.5 — risky AI-induced complexity)`);
|
|
255
253
|
}
|
|
256
254
|
|
|
257
255
|
// Function length
|
|
@@ -267,6 +265,35 @@ export class ComplexityClient {
|
|
|
267
265
|
return parts.length > 0 ? `[Complexity] ${metrics.filePath}\n${parts.join("\n")}` : "";
|
|
268
266
|
}
|
|
269
267
|
|
|
268
|
+
/**
|
|
269
|
+
* Check thresholds and return actionable warnings
|
|
270
|
+
*/
|
|
271
|
+
checkThresholds(metrics: FileComplexity): string[] {
|
|
272
|
+
const warnings: string[] = [];
|
|
273
|
+
|
|
274
|
+
if (metrics.maintainabilityIndex < 60) {
|
|
275
|
+
warnings.push(`Maintainability dropped to ${metrics.maintainabilityIndex} — extract logic into helper functions`);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (metrics.cyclomaticComplexity > 10) {
|
|
279
|
+
warnings.push(`High complexity (${metrics.cyclomaticComplexity}) — use early returns or switch expressions`);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (metrics.cognitiveComplexity > 15) {
|
|
283
|
+
warnings.push(`Cognitive complexity (${metrics.cognitiveComplexity}) — simplify logic flow`);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (metrics.maxNestingDepth > 4) {
|
|
287
|
+
warnings.push(`Deep nesting (${metrics.maxNestingDepth} levels) — extract nested logic into separate functions`);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (metrics.codeEntropy > 3.5) {
|
|
291
|
+
warnings.push(`High entropy (${metrics.codeEntropy.toFixed(1)} bits) — follow project conventions`);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return warnings;
|
|
295
|
+
}
|
|
296
|
+
|
|
270
297
|
/**
|
|
271
298
|
* Format delta for session summary
|
|
272
299
|
*/
|
|
@@ -504,9 +531,9 @@ export class ComplexityClient {
|
|
|
504
531
|
}
|
|
505
532
|
|
|
506
533
|
/**
|
|
507
|
-
* Calculate Shannon entropy of code tokens
|
|
508
|
-
*
|
|
509
|
-
*
|
|
534
|
+
* Calculate Shannon entropy of code tokens (in bits)
|
|
535
|
+
* Uses log2 for entropy measured in bits
|
|
536
|
+
* Threshold: >3.5 bits indicates risky AI-induced complexity
|
|
510
537
|
*/
|
|
511
538
|
private calculateCodeEntropy(sourceText: string): number {
|
|
512
539
|
// Tokenize by splitting on whitespace and common delimiters
|
|
@@ -526,7 +553,7 @@ export class ComplexityClient {
|
|
|
526
553
|
freq.set(token, (freq.get(token) || 0) + 1);
|
|
527
554
|
}
|
|
528
555
|
|
|
529
|
-
// Calculate Shannon entropy: H = -sum(p * log2(p))
|
|
556
|
+
// Calculate Shannon entropy in bits: H = -sum(p * log2(p))
|
|
530
557
|
let entropy = 0;
|
|
531
558
|
for (const count of freq.values()) {
|
|
532
559
|
const p = count / tokens.length;
|
|
@@ -535,11 +562,7 @@ export class ComplexityClient {
|
|
|
535
562
|
}
|
|
536
563
|
}
|
|
537
564
|
|
|
538
|
-
//
|
|
539
|
-
const maxEntropy = Math.log2(freq.size);
|
|
540
|
-
if (maxEntropy === 0) return 0;
|
|
541
|
-
|
|
542
|
-
return Math.min(1, entropy / maxEntropy);
|
|
565
|
+
return entropy; // Return in bits, not normalized
|
|
543
566
|
}
|
|
544
567
|
|
|
545
568
|
private isKeyword(text: string): boolean {
|
package/index.ts
CHANGED
|
@@ -829,6 +829,21 @@ export default function (pi: ExtensionAPI) {
|
|
|
829
829
|
}
|
|
830
830
|
}
|
|
831
831
|
|
|
832
|
+
// Complexity threshold warnings (actionable)
|
|
833
|
+
if (complexityClient.isSupportedFile(filePath)) {
|
|
834
|
+
const metrics = complexityClient.analyzeFile(filePath);
|
|
835
|
+
if (metrics) {
|
|
836
|
+
const warnings = complexityClient.checkThresholds(metrics);
|
|
837
|
+
if (warnings.length > 0) {
|
|
838
|
+
let warningReport = `[Complexity Warnings]\n`;
|
|
839
|
+
for (const w of warnings) {
|
|
840
|
+
warningReport += ` ⚠ ${w}\n`;
|
|
841
|
+
}
|
|
842
|
+
lspOutput += `\n\n${warningReport}`;
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
|
|
832
847
|
// Test runner — run tests for the edited file
|
|
833
848
|
if (!pi.getFlag("no-tests")) {
|
|
834
849
|
const cwd = process.cwd();
|
package/package.json
CHANGED