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,144 +0,0 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
3
|
-
import { BiomeClient } from "./biome-client.js";
|
|
4
|
-
import { createTempFile, setupTestEnvironment } from "./test-utils.js";
|
|
5
|
-
describe("BiomeClient", () => {
|
|
6
|
-
let client;
|
|
7
|
-
let tmpDir;
|
|
8
|
-
let cleanup;
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
client = new BiomeClient();
|
|
11
|
-
({ tmpDir, cleanup } = setupTestEnvironment("pi-lens-biome-test-"));
|
|
12
|
-
});
|
|
13
|
-
afterEach(() => {
|
|
14
|
-
cleanup();
|
|
15
|
-
});
|
|
16
|
-
afterEach(() => {
|
|
17
|
-
cleanup();
|
|
18
|
-
});
|
|
19
|
-
describe("isSupportedFile", () => {
|
|
20
|
-
it("should support JS/TS files", () => {
|
|
21
|
-
expect(client.isSupportedFile("test.js")).toBe(true);
|
|
22
|
-
expect(client.isSupportedFile("test.jsx")).toBe(true);
|
|
23
|
-
expect(client.isSupportedFile("test.ts")).toBe(true);
|
|
24
|
-
expect(client.isSupportedFile("test.tsx")).toBe(true);
|
|
25
|
-
expect(client.isSupportedFile("test.mjs")).toBe(true);
|
|
26
|
-
expect(client.isSupportedFile("test.cjs")).toBe(true);
|
|
27
|
-
});
|
|
28
|
-
it("should support CSS and JSON", () => {
|
|
29
|
-
expect(client.isSupportedFile("style.css")).toBe(true);
|
|
30
|
-
expect(client.isSupportedFile("config.json")).toBe(true);
|
|
31
|
-
});
|
|
32
|
-
it("should not support unsupported files", () => {
|
|
33
|
-
expect(client.isSupportedFile("test.py")).toBe(false);
|
|
34
|
-
expect(client.isSupportedFile("test.md")).toBe(false);
|
|
35
|
-
expect(client.isSupportedFile("test.txt")).toBe(false);
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
describe("isAvailable", () => {
|
|
39
|
-
it("should check biome availability", () => {
|
|
40
|
-
const available = client.isAvailable();
|
|
41
|
-
// Just verify it doesn't throw - actual availability depends on environment
|
|
42
|
-
expect(typeof available).toBe("boolean");
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
describe("checkFile", () => {
|
|
46
|
-
it("should return empty array for non-existent files", () => {
|
|
47
|
-
if (!client.isAvailable())
|
|
48
|
-
return;
|
|
49
|
-
const result = client.checkFile("/nonexistent/file.ts");
|
|
50
|
-
expect(result).toEqual([]);
|
|
51
|
-
});
|
|
52
|
-
it("should return array of diagnostics for TS files", {
|
|
53
|
-
timeout: 15000,
|
|
54
|
-
}, () => {
|
|
55
|
-
if (!client.isAvailable())
|
|
56
|
-
return;
|
|
57
|
-
const content = `
|
|
58
|
-
const x: number = "string";
|
|
59
|
-
`;
|
|
60
|
-
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
61
|
-
const result = client.checkFile(filePath);
|
|
62
|
-
// Should return an array (may or may not have issues)
|
|
63
|
-
expect(Array.isArray(result)).toBe(true);
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
describe("formatDiagnostics", () => {
|
|
67
|
-
it("should format diagnostics for display", () => {
|
|
68
|
-
const diags = [
|
|
69
|
-
{
|
|
70
|
-
line: 1,
|
|
71
|
-
column: 0,
|
|
72
|
-
endLine: 1,
|
|
73
|
-
endColumn: 10,
|
|
74
|
-
severity: "error",
|
|
75
|
-
message: "Unexpected var",
|
|
76
|
-
rule: "noVar",
|
|
77
|
-
category: "lint",
|
|
78
|
-
fixable: true,
|
|
79
|
-
},
|
|
80
|
-
];
|
|
81
|
-
const formatted = client.formatDiagnostics(diags, "test.ts");
|
|
82
|
-
expect(formatted).toContain("Biome");
|
|
83
|
-
expect(formatted).toContain("1 issue");
|
|
84
|
-
expect(formatted).toContain("noVar");
|
|
85
|
-
});
|
|
86
|
-
it("should show fixable count", () => {
|
|
87
|
-
const diags = [
|
|
88
|
-
{
|
|
89
|
-
line: 1,
|
|
90
|
-
column: 0,
|
|
91
|
-
endLine: 1,
|
|
92
|
-
endColumn: 10,
|
|
93
|
-
severity: "error",
|
|
94
|
-
message: "Error 1",
|
|
95
|
-
rule: "rule1",
|
|
96
|
-
category: "lint",
|
|
97
|
-
fixable: true,
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
line: 2,
|
|
101
|
-
column: 0,
|
|
102
|
-
endLine: 2,
|
|
103
|
-
endColumn: 10,
|
|
104
|
-
severity: "warning",
|
|
105
|
-
message: "Warning 1",
|
|
106
|
-
rule: "rule2",
|
|
107
|
-
category: "lint",
|
|
108
|
-
fixable: false,
|
|
109
|
-
},
|
|
110
|
-
];
|
|
111
|
-
const formatted = client.formatDiagnostics(diags, "test.ts");
|
|
112
|
-
expect(formatted).toContain("1 fixable");
|
|
113
|
-
});
|
|
114
|
-
it("should truncate long diagnostic lists", () => {
|
|
115
|
-
const diags = Array.from({ length: 20 }, (_, i) => ({
|
|
116
|
-
line: i + 1,
|
|
117
|
-
column: 0,
|
|
118
|
-
endLine: i + 1,
|
|
119
|
-
endColumn: 10,
|
|
120
|
-
severity: "warning",
|
|
121
|
-
message: `Warning ${i}`,
|
|
122
|
-
rule: `rule${i}`,
|
|
123
|
-
category: "lint",
|
|
124
|
-
fixable: false,
|
|
125
|
-
}));
|
|
126
|
-
const formatted = client.formatDiagnostics(diags, "test.ts");
|
|
127
|
-
expect(formatted).toContain("...");
|
|
128
|
-
expect(formatted).toContain("5 more");
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
describe("formatFile", () => {
|
|
132
|
-
it("should format a file", () => {
|
|
133
|
-
if (!client.isAvailable())
|
|
134
|
-
return;
|
|
135
|
-
const content = `const x={a:1,b:2}`;
|
|
136
|
-
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
137
|
-
const result = client.formatFile(filePath);
|
|
138
|
-
expect(result.success).toBe(true);
|
|
139
|
-
// Check if file was formatted (should have spaces)
|
|
140
|
-
const formatted = fs.readFileSync(filePath, "utf-8");
|
|
141
|
-
expect(formatted).toContain(": "); // Should have spaces after colons
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
});
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
3
|
-
import { BiomeClient } from "./biome-client.js";
|
|
4
|
-
import { createTempFile, setupTestEnvironment } from "./test-utils.js";
|
|
5
|
-
|
|
6
|
-
describe("BiomeClient", () => {
|
|
7
|
-
let client: BiomeClient;
|
|
8
|
-
let tmpDir: string;
|
|
9
|
-
let cleanup: () => void;
|
|
10
|
-
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
client = new BiomeClient();
|
|
13
|
-
({ tmpDir, cleanup } = setupTestEnvironment("pi-lens-biome-test-"));
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
afterEach(() => {
|
|
17
|
-
cleanup();
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
afterEach(() => {
|
|
21
|
-
cleanup();
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
describe("isSupportedFile", () => {
|
|
25
|
-
it("should support JS/TS files", () => {
|
|
26
|
-
expect(client.isSupportedFile("test.js")).toBe(true);
|
|
27
|
-
expect(client.isSupportedFile("test.jsx")).toBe(true);
|
|
28
|
-
expect(client.isSupportedFile("test.ts")).toBe(true);
|
|
29
|
-
expect(client.isSupportedFile("test.tsx")).toBe(true);
|
|
30
|
-
expect(client.isSupportedFile("test.mjs")).toBe(true);
|
|
31
|
-
expect(client.isSupportedFile("test.cjs")).toBe(true);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it("should support CSS and JSON", () => {
|
|
35
|
-
expect(client.isSupportedFile("style.css")).toBe(true);
|
|
36
|
-
expect(client.isSupportedFile("config.json")).toBe(true);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it("should not support unsupported files", () => {
|
|
40
|
-
expect(client.isSupportedFile("test.py")).toBe(false);
|
|
41
|
-
expect(client.isSupportedFile("test.md")).toBe(false);
|
|
42
|
-
expect(client.isSupportedFile("test.txt")).toBe(false);
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
describe("isAvailable", () => {
|
|
47
|
-
it("should check biome availability", () => {
|
|
48
|
-
const available = client.isAvailable();
|
|
49
|
-
// Just verify it doesn't throw - actual availability depends on environment
|
|
50
|
-
expect(typeof available).toBe("boolean");
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
describe("checkFile", () => {
|
|
55
|
-
it("should return empty array for non-existent files", () => {
|
|
56
|
-
if (!client.isAvailable()) return;
|
|
57
|
-
const result = client.checkFile("/nonexistent/file.ts");
|
|
58
|
-
expect(result).toEqual([]);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it("should return array of diagnostics for TS files", {
|
|
62
|
-
timeout: 15000,
|
|
63
|
-
}, () => {
|
|
64
|
-
if (!client.isAvailable()) return;
|
|
65
|
-
|
|
66
|
-
const content = `
|
|
67
|
-
const x: number = "string";
|
|
68
|
-
`;
|
|
69
|
-
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
70
|
-
const result = client.checkFile(filePath);
|
|
71
|
-
|
|
72
|
-
// Should return an array (may or may not have issues)
|
|
73
|
-
expect(Array.isArray(result)).toBe(true);
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
describe("formatDiagnostics", () => {
|
|
78
|
-
it("should format diagnostics for display", () => {
|
|
79
|
-
const diags = [
|
|
80
|
-
{
|
|
81
|
-
line: 1,
|
|
82
|
-
column: 0,
|
|
83
|
-
endLine: 1,
|
|
84
|
-
endColumn: 10,
|
|
85
|
-
severity: "error" as const,
|
|
86
|
-
message: "Unexpected var",
|
|
87
|
-
rule: "noVar",
|
|
88
|
-
category: "lint" as const,
|
|
89
|
-
fixable: true,
|
|
90
|
-
},
|
|
91
|
-
];
|
|
92
|
-
|
|
93
|
-
const formatted = client.formatDiagnostics(diags, "test.ts");
|
|
94
|
-
expect(formatted).toContain("Biome");
|
|
95
|
-
expect(formatted).toContain("1 issue");
|
|
96
|
-
expect(formatted).toContain("noVar");
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it("should show fixable count", () => {
|
|
100
|
-
const diags = [
|
|
101
|
-
{
|
|
102
|
-
line: 1,
|
|
103
|
-
column: 0,
|
|
104
|
-
endLine: 1,
|
|
105
|
-
endColumn: 10,
|
|
106
|
-
severity: "error" as const,
|
|
107
|
-
message: "Error 1",
|
|
108
|
-
rule: "rule1",
|
|
109
|
-
category: "lint" as const,
|
|
110
|
-
fixable: true,
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
line: 2,
|
|
114
|
-
column: 0,
|
|
115
|
-
endLine: 2,
|
|
116
|
-
endColumn: 10,
|
|
117
|
-
severity: "warning" as const,
|
|
118
|
-
message: "Warning 1",
|
|
119
|
-
rule: "rule2",
|
|
120
|
-
category: "lint" as const,
|
|
121
|
-
fixable: false,
|
|
122
|
-
},
|
|
123
|
-
];
|
|
124
|
-
|
|
125
|
-
const formatted = client.formatDiagnostics(diags, "test.ts");
|
|
126
|
-
expect(formatted).toContain("1 fixable");
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it("should truncate long diagnostic lists", () => {
|
|
130
|
-
const diags = Array.from({ length: 20 }, (_, i) => ({
|
|
131
|
-
line: i + 1,
|
|
132
|
-
column: 0,
|
|
133
|
-
endLine: i + 1,
|
|
134
|
-
endColumn: 10,
|
|
135
|
-
severity: "warning" as const,
|
|
136
|
-
message: `Warning ${i}`,
|
|
137
|
-
rule: `rule${i}`,
|
|
138
|
-
category: "lint" as const,
|
|
139
|
-
fixable: false,
|
|
140
|
-
}));
|
|
141
|
-
|
|
142
|
-
const formatted = client.formatDiagnostics(diags, "test.ts");
|
|
143
|
-
expect(formatted).toContain("...");
|
|
144
|
-
expect(formatted).toContain("5 more");
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
describe("formatFile", () => {
|
|
149
|
-
it("should format a file", () => {
|
|
150
|
-
if (!client.isAvailable()) return;
|
|
151
|
-
|
|
152
|
-
const content = `const x={a:1,b:2}`;
|
|
153
|
-
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
154
|
-
|
|
155
|
-
const result = client.formatFile(filePath);
|
|
156
|
-
expect(result.success).toBe(true);
|
|
157
|
-
|
|
158
|
-
// Check if file was formatted (should have spaces)
|
|
159
|
-
const formatted = fs.readFileSync(filePath, "utf-8");
|
|
160
|
-
expect(formatted).toContain(": "); // Should have spaces after colons
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
});
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Rule Cache for pi-lens
|
|
3
|
-
*
|
|
4
|
-
* Provides disk-based caching for parsed tree-sitter rules with
|
|
5
|
-
* automatic invalidation based on rule file modification times.
|
|
6
|
-
*/
|
|
7
|
-
import * as crypto from "node:crypto";
|
|
8
|
-
import * as fs from "node:fs";
|
|
9
|
-
import * as path from "node:path";
|
|
10
|
-
const CACHE_DIR = path.join(process.cwd(), ".pi-lens", "cache");
|
|
11
|
-
const CACHE_VERSION = "v1";
|
|
12
|
-
export class RuleCache {
|
|
13
|
-
constructor(language) {
|
|
14
|
-
this.cacheFile = path.join(CACHE_DIR, `${language}-rules-${CACHE_VERSION}.json`);
|
|
15
|
-
}
|
|
16
|
-
ensureCacheDir() {
|
|
17
|
-
if (!fs.existsSync(CACHE_DIR)) {
|
|
18
|
-
fs.mkdirSync(CACHE_DIR, { recursive: true });
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
computeRuleHash(ruleFiles) {
|
|
22
|
-
const hash = crypto.createHash("sha256");
|
|
23
|
-
for (const file of ruleFiles.sort()) {
|
|
24
|
-
if (fs.existsSync(file)) {
|
|
25
|
-
const stat = fs.statSync(file);
|
|
26
|
-
hash.update(`${file}:${stat.mtimeMs}:${stat.size}`);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
return hash.digest("hex").slice(0, 16);
|
|
30
|
-
}
|
|
31
|
-
get(ruleFiles) {
|
|
32
|
-
try {
|
|
33
|
-
this.ensureCacheDir();
|
|
34
|
-
if (!fs.existsSync(this.cacheFile))
|
|
35
|
-
return null;
|
|
36
|
-
const cached = JSON.parse(fs.readFileSync(this.cacheFile, "utf-8"));
|
|
37
|
-
const currentHash = this.computeRuleHash(ruleFiles);
|
|
38
|
-
if (cached.version !== CACHE_VERSION || cached.ruleHash !== currentHash) {
|
|
39
|
-
return null; // Cache invalid
|
|
40
|
-
}
|
|
41
|
-
return cached;
|
|
42
|
-
}
|
|
43
|
-
catch {
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
set(ruleFiles, queries) {
|
|
48
|
-
try {
|
|
49
|
-
this.ensureCacheDir();
|
|
50
|
-
const entry = {
|
|
51
|
-
version: CACHE_VERSION,
|
|
52
|
-
timestamp: Date.now(),
|
|
53
|
-
ruleHash: this.computeRuleHash(ruleFiles),
|
|
54
|
-
queries,
|
|
55
|
-
};
|
|
56
|
-
fs.writeFileSync(this.cacheFile, JSON.stringify(entry, null, 2));
|
|
57
|
-
}
|
|
58
|
-
catch {
|
|
59
|
-
// Cache write failure is non-fatal
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
clear() {
|
|
63
|
-
try {
|
|
64
|
-
if (fs.existsSync(this.cacheFile)) {
|
|
65
|
-
fs.unlinkSync(this.cacheFile);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
catch {
|
|
69
|
-
// Ignore
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
package/clients/cache-manager.js
DELETED
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CacheManager for pi-lens.
|
|
3
|
-
*
|
|
4
|
-
* Manages persistent cache for scanner results and turn state.
|
|
5
|
-
* Provides read/write/freshness checks for:
|
|
6
|
-
* - Scanner cache: .pi-lens/cache/{scanner}.json
|
|
7
|
-
* - Turn state: .pi-lens/turn-state.json
|
|
8
|
-
*
|
|
9
|
-
* All paths are relative to project root (process.cwd()).
|
|
10
|
-
*/
|
|
11
|
-
import * as fs from "node:fs";
|
|
12
|
-
import * as path from "node:path";
|
|
13
|
-
// --- Defaults ---
|
|
14
|
-
const DEFAULT_MAX_AGE_MS = 30 * 60 * 1000; // 30 minutes
|
|
15
|
-
const DEFAULT_TURN_STATE = {
|
|
16
|
-
files: {},
|
|
17
|
-
turnCycles: 0,
|
|
18
|
-
maxCycles: 3,
|
|
19
|
-
lastUpdated: "",
|
|
20
|
-
};
|
|
21
|
-
// --- Helpers ---
|
|
22
|
-
function getLensDir(cwd) {
|
|
23
|
-
return path.join(cwd, ".pi-lens");
|
|
24
|
-
}
|
|
25
|
-
function getCacheDir(cwd) {
|
|
26
|
-
return path.join(getLensDir(cwd), "cache");
|
|
27
|
-
}
|
|
28
|
-
function getTurnStatePath(cwd) {
|
|
29
|
-
return path.join(getLensDir(cwd), "turn-state.json");
|
|
30
|
-
}
|
|
31
|
-
// --- Cache Manager ---
|
|
32
|
-
export class CacheManager {
|
|
33
|
-
constructor(verbose = false) {
|
|
34
|
-
this.log = verbose
|
|
35
|
-
? (msg) => console.error(`[cache] ${msg}`)
|
|
36
|
-
: () => { };
|
|
37
|
-
}
|
|
38
|
-
// ---- Scanner Cache ----
|
|
39
|
-
/**
|
|
40
|
-
* Read a scanner cache entry. Returns null if not found or stale.
|
|
41
|
-
*/
|
|
42
|
-
readCache(scanner, cwd, maxAgeMs = DEFAULT_MAX_AGE_MS) {
|
|
43
|
-
const cachePath = path.join(getCacheDir(cwd), `${scanner}.json`);
|
|
44
|
-
const metaPath = path.join(getCacheDir(cwd), `${scanner}.meta.json`);
|
|
45
|
-
if (!fs.existsSync(cachePath) || !fs.existsSync(metaPath)) {
|
|
46
|
-
this.log(`Cache miss: ${scanner} (files don't exist)`);
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
|
-
try {
|
|
50
|
-
const meta = JSON.parse(fs.readFileSync(metaPath, "utf-8"));
|
|
51
|
-
const age = Date.now() - new Date(meta.timestamp).getTime();
|
|
52
|
-
if (age > maxAgeMs) {
|
|
53
|
-
this.log(`Cache stale: ${scanner} (age: ${Math.round(age / 1000)}s, max: ${maxAgeMs / 1000}s)`);
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
const data = JSON.parse(fs.readFileSync(cachePath, "utf-8"));
|
|
57
|
-
this.log(`Cache hit: ${scanner} (age: ${Math.round(age / 1000)}s)`);
|
|
58
|
-
return { data, meta };
|
|
59
|
-
}
|
|
60
|
-
catch (err) {
|
|
61
|
-
this.log(`Cache read error: ${scanner} — ${err}`);
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Write a scanner cache entry.
|
|
67
|
-
*/
|
|
68
|
-
writeCache(scanner, data, cwd, extraMeta) {
|
|
69
|
-
const cacheDir = getCacheDir(cwd);
|
|
70
|
-
fs.mkdirSync(cacheDir, { recursive: true });
|
|
71
|
-
const cachePath = path.join(cacheDir, `${scanner}.json`);
|
|
72
|
-
const metaPath = path.join(cacheDir, `${scanner}.meta.json`);
|
|
73
|
-
const meta = {
|
|
74
|
-
timestamp: new Date().toISOString(),
|
|
75
|
-
...extraMeta,
|
|
76
|
-
};
|
|
77
|
-
fs.writeFileSync(cachePath, JSON.stringify(data, null, 2));
|
|
78
|
-
fs.writeFileSync(metaPath, JSON.stringify(meta, null, 2));
|
|
79
|
-
this.log(`Cache written: ${scanner}`);
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Check if a cache entry is fresh (exists and not expired).
|
|
83
|
-
*/
|
|
84
|
-
isCacheFresh(scanner, cwd, maxAgeMs = DEFAULT_MAX_AGE_MS) {
|
|
85
|
-
const metaPath = path.join(getCacheDir(cwd), `${scanner}.meta.json`);
|
|
86
|
-
if (!fs.existsSync(metaPath))
|
|
87
|
-
return false;
|
|
88
|
-
try {
|
|
89
|
-
const meta = JSON.parse(fs.readFileSync(metaPath, "utf-8"));
|
|
90
|
-
const age = Date.now() - new Date(meta.timestamp).getTime();
|
|
91
|
-
return age <= maxAgeMs;
|
|
92
|
-
}
|
|
93
|
-
catch {
|
|
94
|
-
return false;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Clear a specific cache entry.
|
|
99
|
-
*/
|
|
100
|
-
clearCache(scanner, cwd) {
|
|
101
|
-
const cachePath = path.join(getCacheDir(cwd), `${scanner}.json`);
|
|
102
|
-
const metaPath = path.join(getCacheDir(cwd), `${scanner}.meta.json`);
|
|
103
|
-
for (const p of [cachePath, metaPath]) {
|
|
104
|
-
try {
|
|
105
|
-
fs.unlinkSync(p);
|
|
106
|
-
}
|
|
107
|
-
catch (err) {
|
|
108
|
-
// ENOENT: file doesn't exist, other errors logged
|
|
109
|
-
if (err.code !== "ENOENT") {
|
|
110
|
-
this.log(`Failed to delete ${p}: ${err}`);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
// ---- Turn State ----
|
|
116
|
-
/**
|
|
117
|
-
* Read turn state. Returns default if not found.
|
|
118
|
-
*/
|
|
119
|
-
readTurnState(cwd) {
|
|
120
|
-
const statePath = getTurnStatePath(cwd);
|
|
121
|
-
if (!fs.existsSync(statePath)) {
|
|
122
|
-
return {
|
|
123
|
-
...DEFAULT_TURN_STATE,
|
|
124
|
-
files: {},
|
|
125
|
-
lastUpdated: new Date().toISOString(),
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
try {
|
|
129
|
-
return JSON.parse(fs.readFileSync(statePath, "utf-8"));
|
|
130
|
-
}
|
|
131
|
-
catch {
|
|
132
|
-
return {
|
|
133
|
-
...DEFAULT_TURN_STATE,
|
|
134
|
-
files: {},
|
|
135
|
-
lastUpdated: new Date().toISOString(),
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Write turn state.
|
|
141
|
-
*/
|
|
142
|
-
writeTurnState(state, cwd) {
|
|
143
|
-
const lensDir = getLensDir(cwd);
|
|
144
|
-
fs.mkdirSync(lensDir, { recursive: true });
|
|
145
|
-
const statePath = getTurnStatePath(cwd);
|
|
146
|
-
state.lastUpdated = new Date().toISOString();
|
|
147
|
-
fs.writeFileSync(statePath, JSON.stringify(state, null, 2));
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Add or update a file's modified ranges in turn state.
|
|
151
|
-
* Merges overlapping ranges.
|
|
152
|
-
*/
|
|
153
|
-
addModifiedRange(filePath, range, importsChanged, cwd) {
|
|
154
|
-
const state = this.readTurnState(cwd);
|
|
155
|
-
const normalizedPath = path.relative(cwd, filePath).replace(/\\/g, "/");
|
|
156
|
-
const existing = state.files[normalizedPath];
|
|
157
|
-
if (existing) {
|
|
158
|
-
// Merge ranges
|
|
159
|
-
existing.modifiedRanges = this.mergeRanges([
|
|
160
|
-
...existing.modifiedRanges,
|
|
161
|
-
range,
|
|
162
|
-
]);
|
|
163
|
-
existing.importsChanged = existing.importsChanged || importsChanged;
|
|
164
|
-
existing.lastEdit = new Date().toISOString();
|
|
165
|
-
}
|
|
166
|
-
else {
|
|
167
|
-
state.files[normalizedPath] = {
|
|
168
|
-
modifiedRanges: [range],
|
|
169
|
-
importsChanged,
|
|
170
|
-
lastEdit: new Date().toISOString(),
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
this.writeTurnState(state, cwd);
|
|
174
|
-
return state;
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Clear turn state (after turn_end processes it).
|
|
178
|
-
*/
|
|
179
|
-
clearTurnState(cwd) {
|
|
180
|
-
const state = {
|
|
181
|
-
...DEFAULT_TURN_STATE,
|
|
182
|
-
files: {}, // fresh object — DEFAULT_TURN_STATE.files can be polluted by addModifiedRange
|
|
183
|
-
lastUpdated: new Date().toISOString(),
|
|
184
|
-
};
|
|
185
|
-
this.writeTurnState(state, cwd);
|
|
186
|
-
}
|
|
187
|
-
/**
|
|
188
|
-
* Increment turn cycle counter.
|
|
189
|
-
*/
|
|
190
|
-
incrementTurnCycle(cwd) {
|
|
191
|
-
const state = this.readTurnState(cwd);
|
|
192
|
-
state.turnCycles++;
|
|
193
|
-
this.writeTurnState(state, cwd);
|
|
194
|
-
return state;
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* Check if max cycles exceeded.
|
|
198
|
-
*/
|
|
199
|
-
isMaxCyclesExceeded(cwd) {
|
|
200
|
-
const state = this.readTurnState(cwd);
|
|
201
|
-
return state.turnCycles >= state.maxCycles;
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* Get files that need jscpd re-scan (any edit).
|
|
205
|
-
*/
|
|
206
|
-
getFilesForJscpd(cwd) {
|
|
207
|
-
const state = this.readTurnState(cwd);
|
|
208
|
-
return Object.keys(state.files);
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* Get files that need madge re-scan (imports changed).
|
|
212
|
-
*/
|
|
213
|
-
getFilesForMadge(cwd) {
|
|
214
|
-
const state = this.readTurnState(cwd);
|
|
215
|
-
return Object.entries(state.files)
|
|
216
|
-
.filter(([, f]) => f.importsChanged)
|
|
217
|
-
.map(([p]) => p);
|
|
218
|
-
}
|
|
219
|
-
// ---- Utilities ----
|
|
220
|
-
/**
|
|
221
|
-
* Merge overlapping or adjacent ranges.
|
|
222
|
-
*/
|
|
223
|
-
mergeRanges(ranges) {
|
|
224
|
-
if (ranges.length === 0)
|
|
225
|
-
return [];
|
|
226
|
-
const sorted = [...ranges].sort((a, b) => a.start - b.start);
|
|
227
|
-
const merged = [sorted[0]];
|
|
228
|
-
for (const current of sorted.slice(1)) {
|
|
229
|
-
const last = merged[merged.length - 1];
|
|
230
|
-
if (current.start <= last.end + 1) {
|
|
231
|
-
last.end = Math.max(last.end, current.end);
|
|
232
|
-
}
|
|
233
|
-
else {
|
|
234
|
-
merged.push({ ...current });
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
return merged;
|
|
238
|
-
}
|
|
239
|
-
/**
|
|
240
|
-
* Check if a line falls within any modified range.
|
|
241
|
-
*/
|
|
242
|
-
isLineInModifiedRange(line, ranges) {
|
|
243
|
-
return ranges.some((r) => r.start <= line && line <= r.end);
|
|
244
|
-
}
|
|
245
|
-
}
|