pi-lens 3.1.2 â 3.2.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 +55 -0
- package/README.md +16 -12
- package/clients/ast-grep-client.js +8 -1
- package/clients/ast-grep-client.ts +9 -1
- package/clients/biome-client.js +51 -38
- package/clients/biome-client.ts +60 -58
- package/clients/dependency-checker.js +30 -1
- package/clients/dependency-checker.ts +35 -1
- package/clients/dispatch/__tests__/runner-registration.test.ts +286 -282
- package/clients/dispatch/bus-dispatcher.js +15 -14
- package/clients/dispatch/bus-dispatcher.ts +32 -25
- package/clients/dispatch/dispatcher.js +18 -25
- package/clients/dispatch/dispatcher.test.ts +2 -1
- package/clients/dispatch/dispatcher.ts +17 -28
- package/clients/dispatch/plan.js +77 -32
- package/clients/dispatch/plan.ts +78 -32
- package/clients/dispatch/runners/ast-grep-napi.js +36 -376
- package/clients/dispatch/runners/ast-grep-napi.ts +60 -433
- package/clients/dispatch/runners/index.js +8 -4
- package/clients/dispatch/runners/index.ts +8 -4
- package/clients/dispatch/runners/lsp.js +65 -0
- package/clients/dispatch/runners/lsp.ts +125 -0
- package/clients/dispatch/runners/oxlint.js +2 -2
- package/clients/dispatch/runners/oxlint.ts +2 -2
- package/clients/dispatch/runners/pyright.js +24 -8
- package/clients/dispatch/runners/pyright.ts +28 -14
- package/clients/dispatch/runners/rust-clippy.js +2 -2
- package/clients/dispatch/runners/rust-clippy.ts +2 -4
- package/clients/dispatch/runners/tree-sitter.js +14 -2
- package/clients/dispatch/runners/tree-sitter.ts +15 -2
- package/clients/dispatch/runners/ts-lsp.js +3 -3
- package/clients/dispatch/runners/ts-lsp.ts +8 -5
- package/clients/dispatch/runners/yaml-rule-parser.js +292 -0
- package/clients/dispatch/runners/yaml-rule-parser.ts +338 -0
- package/clients/dispatch/types.js +3 -0
- package/clients/dispatch/types.ts +3 -0
- package/clients/formatters.js +67 -14
- package/clients/formatters.ts +68 -15
- package/clients/installer/index.js +78 -10
- package/clients/installer/index.ts +519 -426
- package/clients/jscpd-client.js +28 -0
- package/clients/jscpd-client.ts +41 -3
- package/clients/knip-client.js +30 -1
- package/clients/knip-client.ts +34 -2
- package/clients/lsp/__tests__/client.test.ts +64 -41
- package/clients/lsp/__tests__/config.test.ts +25 -17
- package/clients/lsp/__tests__/launch.test.ts +108 -43
- package/clients/lsp/__tests__/service.test.ts +76 -48
- package/clients/lsp/client.js +87 -2
- package/clients/lsp/client.ts +150 -6
- package/clients/lsp/config.js +8 -11
- package/clients/lsp/config.ts +24 -21
- package/clients/lsp/index.js +69 -0
- package/clients/lsp/index.ts +82 -0
- package/clients/lsp/interactive-install.js +19 -8
- package/clients/lsp/interactive-install.ts +52 -27
- package/clients/lsp/launch.js +182 -32
- package/clients/lsp/launch.ts +241 -38
- package/clients/lsp/path-utils.js +3 -46
- package/clients/lsp/path-utils.ts +11 -51
- package/clients/lsp/server.js +93 -71
- package/clients/lsp/server.ts +173 -131
- package/clients/path-utils.js +142 -0
- package/clients/path-utils.ts +153 -0
- package/clients/ruff-client.js +33 -4
- package/clients/ruff-client.ts +44 -13
- package/clients/safe-spawn.js +3 -1
- package/clients/safe-spawn.ts +3 -1
- package/clients/services/effect-integration.js +11 -7
- package/clients/services/effect-integration.ts +34 -26
- package/clients/sg-runner.js +51 -9
- package/clients/sg-runner.ts +58 -15
- package/clients/tree-sitter-client.js +12 -0
- package/clients/tree-sitter-client.ts +12 -0
- package/clients/typescript-client.js +6 -2
- package/clients/typescript-client.ts +9 -2
- package/commands/booboo.js +2 -4
- package/commands/booboo.ts +2 -4
- package/index.ts +377 -93
- package/package.json +2 -1
- package/rules/tree-sitter-queries/tsx/no-nested-links.yml +45 -0
- package/rules/tree-sitter-queries/typescript/constructor-super.yml +55 -0
- package/rules/tree-sitter-queries/typescript/debugger.yml +1 -1
- package/rules/tree-sitter-queries/typescript/no-dupe-class-members.yml +47 -0
- package/tsconfig.json +1 -1
- package/clients/__tests__/file-time.test.js +0 -216
- package/clients/__tests__/format-service.test.js +0 -245
- package/clients/__tests__/formatters.test.js +0 -271
- package/clients/agent-behavior-client.test.js +0 -94
- package/clients/ast-grep-client.test.js +0 -129
- package/clients/ast-grep-client.test.ts +0 -155
- package/clients/biome-client.test.js +0 -144
- package/clients/cache-manager.test.js +0 -197
- package/clients/complexity-client.test.js +0 -234
- package/clients/dependency-checker.test.js +0 -60
- package/clients/dispatch/__tests__/autofix-integration.test.js +0 -245
- package/clients/dispatch/__tests__/runner-registration.test.js +0 -236
- package/clients/dispatch/dispatcher.edge.test.js +0 -82
- package/clients/dispatch/dispatcher.format.test.js +0 -46
- package/clients/dispatch/dispatcher.inline.test.js +0 -74
- package/clients/dispatch/dispatcher.test.js +0 -115
- package/clients/dispatch/runners/architect.test.js +0 -138
- package/clients/dispatch/runners/ast-grep-napi.test.js +0 -106
- package/clients/dispatch/runners/oxlint.test.js +0 -230
- package/clients/dispatch/runners/pyright.test.js +0 -98
- package/clients/dispatch/runners/python-slop.test.js +0 -203
- package/clients/dispatch/runners/scan_codebase.test.js +0 -89
- package/clients/dispatch/runners/shellcheck.test.js +0 -98
- package/clients/dispatch/runners/spellcheck.test.js +0 -158
- package/clients/dispatch/runners/ts-slop.test.js +0 -180
- package/clients/dispatch/runners/ts-slop.test.ts +0 -230
- package/clients/dogfood.test.js +0 -201
- package/clients/file-kinds.test.js +0 -169
- package/clients/go-client.test.js +0 -127
- package/clients/jscpd-client.test.js +0 -127
- package/clients/knip-client.test.js +0 -112
- package/clients/lsp/__tests__/client.test.js +0 -325
- package/clients/lsp/__tests__/config.test.js +0 -166
- package/clients/lsp/__tests__/error-recovery.test.js +0 -213
- package/clients/lsp/__tests__/integration.test.js +0 -127
- package/clients/lsp/__tests__/launch.test.js +0 -260
- package/clients/lsp/__tests__/server.test.js +0 -259
- package/clients/lsp/__tests__/service.test.js +0 -417
- package/clients/metrics-client.test.js +0 -141
- package/clients/ruff-client.test.js +0 -132
- package/clients/rust-client.test.js +0 -108
- package/clients/sanitize.test.js +0 -177
- package/clients/secrets-scanner.test.js +0 -100
- package/clients/services/__tests__/effect-integration.test.js +0 -86
- package/clients/test-runner-client.test.js +0 -192
- package/clients/todo-scanner.test.js +0 -301
- package/clients/type-coverage-client.test.js +0 -105
- package/clients/typescript-client.codefix.test.js +0 -157
- package/clients/typescript-client.test.js +0 -105
- package/commands/clients/ast-grep-client.js +0 -250
- package/commands/clients/ast-grep-parser.js +0 -86
- package/commands/clients/ast-grep-rule-manager.js +0 -91
- package/commands/clients/ast-grep-types.js +0 -9
- package/commands/clients/biome-client.js +0 -380
- package/commands/clients/complexity-client.js +0 -667
- package/commands/clients/file-kinds.js +0 -177
- package/commands/clients/file-utils.js +0 -40
- package/commands/clients/jscpd-client.js +0 -169
- package/commands/clients/knip-client.js +0 -211
- package/commands/clients/ruff-client.js +0 -297
- package/commands/clients/safe-spawn.js +0 -88
- package/commands/clients/scan-utils.js +0 -83
- package/commands/clients/sg-runner.js +0 -190
- package/commands/clients/types.js +0 -11
- package/commands/clients/typescript-client.js +0 -505
- package/commands/rate.test.js +0 -119
- package/rules/ast-grep-rules/rules/no-dangerously-set-inner-html.yml +0 -13
- package/rules/ast-grep-rules/rules/no-debugger.yml +0 -12
- package/rules/ast-grep-rules/rules/no-eval.yml +0 -13
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Effect Integration Tests
|
|
3
|
-
*
|
|
4
|
-
* Tests for Effect-TS concurrent runner execution.
|
|
5
|
-
*/
|
|
6
|
-
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
7
|
-
import { clearRunnerRegistry, listRunners, registerRunner, } from "../../dispatch/dispatcher.js";
|
|
8
|
-
import { dispatchLintWithEffect, dispatchWithEffect, } from "../effect-integration.js";
|
|
9
|
-
describe("Effect Integration", () => {
|
|
10
|
-
beforeEach(async () => {
|
|
11
|
-
clearRunnerRegistry();
|
|
12
|
-
// Register a simple test runner
|
|
13
|
-
const testRunner = {
|
|
14
|
-
id: "test-runner",
|
|
15
|
-
appliesTo: ["jsts"],
|
|
16
|
-
priority: 10,
|
|
17
|
-
enabledByDefault: true,
|
|
18
|
-
async run(ctx) {
|
|
19
|
-
return {
|
|
20
|
-
status: "succeeded",
|
|
21
|
-
diagnostics: [{
|
|
22
|
-
id: "test:1",
|
|
23
|
-
message: "Test diagnostic",
|
|
24
|
-
filePath: ctx.filePath,
|
|
25
|
-
severity: "info",
|
|
26
|
-
semantic: "silent",
|
|
27
|
-
tool: "test-runner",
|
|
28
|
-
}],
|
|
29
|
-
semantic: "none",
|
|
30
|
-
};
|
|
31
|
-
},
|
|
32
|
-
};
|
|
33
|
-
registerRunner(testRunner);
|
|
34
|
-
});
|
|
35
|
-
it("should have runners registered", () => {
|
|
36
|
-
const runners = listRunners();
|
|
37
|
-
expect(runners.length).toBeGreaterThan(0);
|
|
38
|
-
expect(runners.some(r => r.id === "test-runner")).toBe(true);
|
|
39
|
-
});
|
|
40
|
-
it("should run effect integration with real runners", async () => {
|
|
41
|
-
const ctx = {
|
|
42
|
-
filePath: "test.ts",
|
|
43
|
-
cwd: "/test",
|
|
44
|
-
kind: "jsts",
|
|
45
|
-
pi: {
|
|
46
|
-
getFlag: vi.fn(() => false),
|
|
47
|
-
},
|
|
48
|
-
autofix: true,
|
|
49
|
-
deltaMode: false,
|
|
50
|
-
baselines: new Map(),
|
|
51
|
-
hasTool: vi.fn(() => Promise.resolve(false)),
|
|
52
|
-
log: vi.fn(),
|
|
53
|
-
};
|
|
54
|
-
// Get actual runners for jsts
|
|
55
|
-
const { getRunnersForKind } = await import("../../dispatch/dispatcher.js");
|
|
56
|
-
const runners = getRunnersForKind("jsts");
|
|
57
|
-
const group = {
|
|
58
|
-
runnerIds: runners.slice(0, 2).map(r => r.id), // Use first 2 runners
|
|
59
|
-
mode: "all",
|
|
60
|
-
};
|
|
61
|
-
const result = await dispatchWithEffect(ctx, [group]);
|
|
62
|
-
// Just verify it doesn't crash and returns valid result
|
|
63
|
-
expect(result).toBeDefined();
|
|
64
|
-
expect(typeof result.durationMs).toBe("number");
|
|
65
|
-
});
|
|
66
|
-
it("should handle --lens-effect flag path", async () => {
|
|
67
|
-
const mockPi = {
|
|
68
|
-
getFlag: vi.fn((flag) => flag === "lens-effect"),
|
|
69
|
-
readFile: vi.fn(),
|
|
70
|
-
writeFile: vi.fn(),
|
|
71
|
-
editFile: vi.fn(),
|
|
72
|
-
bash: vi.fn(),
|
|
73
|
-
ui: {
|
|
74
|
-
notify: vi.fn(),
|
|
75
|
-
progress: vi.fn(),
|
|
76
|
-
prompt: vi.fn(),
|
|
77
|
-
},
|
|
78
|
-
llm: {
|
|
79
|
-
stream: vi.fn(),
|
|
80
|
-
createMessage: vi.fn(),
|
|
81
|
-
},
|
|
82
|
-
};
|
|
83
|
-
const output = await dispatchLintWithEffect("test.ts", "/test", mockPi);
|
|
84
|
-
expect(typeof output).toBe("string");
|
|
85
|
-
});
|
|
86
|
-
});
|
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import * as path from "node:path";
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
3
|
-
import { TestRunnerClient } from "./test-runner-client.js";
|
|
4
|
-
import { createTempFile, setupTestEnvironment } from "./test-utils.js";
|
|
5
|
-
describe("TestRunnerClient", () => {
|
|
6
|
-
let client;
|
|
7
|
-
let tmpDir;
|
|
8
|
-
let cleanup;
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
client = new TestRunnerClient();
|
|
11
|
-
({ tmpDir, cleanup } = setupTestEnvironment("pi-lens-test-runner-"));
|
|
12
|
-
});
|
|
13
|
-
afterEach(() => {
|
|
14
|
-
cleanup();
|
|
15
|
-
});
|
|
16
|
-
afterEach(() => {
|
|
17
|
-
cleanup();
|
|
18
|
-
});
|
|
19
|
-
describe("detectRunner", () => {
|
|
20
|
-
it("should detect vitest from config file", () => {
|
|
21
|
-
createTempFile(tmpDir, "vitest.config.ts", "export default {}");
|
|
22
|
-
createTempFile(tmpDir, "src/app.ts", "export const app = {};");
|
|
23
|
-
const result = client.detectRunner(tmpDir);
|
|
24
|
-
expect(result).not.toBeNull();
|
|
25
|
-
expect(result?.runner).toBe("vitest");
|
|
26
|
-
});
|
|
27
|
-
it("should detect jest from config file", () => {
|
|
28
|
-
createTempFile(tmpDir, "jest.config.js", "module.exports = {}");
|
|
29
|
-
createTempFile(tmpDir, "src/app.ts", "export const app = {};");
|
|
30
|
-
const result = client.detectRunner(tmpDir);
|
|
31
|
-
expect(result).not.toBeNull();
|
|
32
|
-
expect(result?.runner).toBe("jest");
|
|
33
|
-
});
|
|
34
|
-
it("should detect pytest from config file", () => {
|
|
35
|
-
createTempFile(tmpDir, "pytest.ini", "[tool:pytest]");
|
|
36
|
-
createTempFile(tmpDir, "src/app.py", "x = 1");
|
|
37
|
-
const result = client.detectRunner(tmpDir);
|
|
38
|
-
expect(result).not.toBeNull();
|
|
39
|
-
expect(result?.runner).toBe("pytest");
|
|
40
|
-
});
|
|
41
|
-
it("should detect runner from node_modules", () => {
|
|
42
|
-
// Create a node_modules/vitest to simulate installed package
|
|
43
|
-
createTempFile(tmpDir, "node_modules/vitest/package.json", "{}");
|
|
44
|
-
createTempFile(tmpDir, "src/app.ts", "export const app = {};");
|
|
45
|
-
const result = client.detectRunner(tmpDir);
|
|
46
|
-
// Should detect vitest from node_modules
|
|
47
|
-
expect(result).not.toBeNull();
|
|
48
|
-
});
|
|
49
|
-
it("should prefer vitest over jest when both exist", () => {
|
|
50
|
-
createTempFile(tmpDir, "vitest.config.ts", "export default {}");
|
|
51
|
-
createTempFile(tmpDir, "jest.config.js", "module.exports = {}");
|
|
52
|
-
createTempFile(tmpDir, "src/app.ts", "export const app = {};");
|
|
53
|
-
const result = client.detectRunner(tmpDir);
|
|
54
|
-
expect(result?.runner).toBe("vitest");
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
describe("findTestFile", () => {
|
|
58
|
-
it("should find test file with .test.ts suffix", () => {
|
|
59
|
-
createTempFile(tmpDir, "vitest.config.ts", "export default {}");
|
|
60
|
-
createTempFile(tmpDir, "src/app.ts", "export const app = {};");
|
|
61
|
-
createTempFile(tmpDir, "src/app.test.ts", "describe('app', () => {});");
|
|
62
|
-
const result = client.findTestFile(path.join(tmpDir, "src/app.ts"), tmpDir);
|
|
63
|
-
expect(result).not.toBeNull();
|
|
64
|
-
expect(result?.testFile).toContain("app.test.ts");
|
|
65
|
-
expect(result?.runner).toBe("vitest");
|
|
66
|
-
});
|
|
67
|
-
it("should find test file with .spec.ts suffix", () => {
|
|
68
|
-
createTempFile(tmpDir, "vitest.config.ts", "export default {}");
|
|
69
|
-
createTempFile(tmpDir, "src/app.ts", "export const app = {};");
|
|
70
|
-
createTempFile(tmpDir, "src/app.spec.ts", "describe('app', () => {});");
|
|
71
|
-
const result = client.findTestFile(path.join(tmpDir, "src/app.ts"), tmpDir);
|
|
72
|
-
expect(result).not.toBeNull();
|
|
73
|
-
expect(result?.testFile).toContain("app.spec.ts");
|
|
74
|
-
});
|
|
75
|
-
it("should find test file in __tests__ directory", () => {
|
|
76
|
-
createTempFile(tmpDir, "vitest.config.ts", "export default {}");
|
|
77
|
-
createTempFile(tmpDir, "src/app.ts", "export const app = {};");
|
|
78
|
-
createTempFile(tmpDir, "src/__tests__/app.test.ts", "describe('app', () => {});");
|
|
79
|
-
const result = client.findTestFile(path.join(tmpDir, "src/app.ts"), tmpDir);
|
|
80
|
-
expect(result).not.toBeNull();
|
|
81
|
-
expect(result?.testFile).toContain("__tests__");
|
|
82
|
-
});
|
|
83
|
-
it("should find test file in top-level tests/ directory", () => {
|
|
84
|
-
createTempFile(tmpDir, "vitest.config.ts", "export default {}");
|
|
85
|
-
createTempFile(tmpDir, "src/app.ts", "export const app = {};");
|
|
86
|
-
createTempFile(tmpDir, "tests/app.test.ts", "describe('app', () => {});");
|
|
87
|
-
const result = client.findTestFile(path.join(tmpDir, "src/app.ts"), tmpDir);
|
|
88
|
-
expect(result).not.toBeNull();
|
|
89
|
-
expect(result?.testFile).toContain(path.join("tests", "app.test.ts"));
|
|
90
|
-
});
|
|
91
|
-
it("should find pytest test file with test_ prefix", () => {
|
|
92
|
-
createTempFile(tmpDir, "pytest.ini", "[tool:pytest]");
|
|
93
|
-
createTempFile(tmpDir, "src/app.py", "x = 1");
|
|
94
|
-
createTempFile(tmpDir, "tests/test_app.py", "def test_app(): pass");
|
|
95
|
-
const result = client.findTestFile(path.join(tmpDir, "src/app.py"), tmpDir);
|
|
96
|
-
expect(result).not.toBeNull();
|
|
97
|
-
expect(result?.testFile).toContain("test_app.py");
|
|
98
|
-
expect(result?.runner).toBe("pytest");
|
|
99
|
-
});
|
|
100
|
-
it("should return null when no test file found", () => {
|
|
101
|
-
createTempFile(tmpDir, "vitest.config.ts", "export default {}");
|
|
102
|
-
createTempFile(tmpDir, "src/app.ts", "export const app = {};");
|
|
103
|
-
const result = client.findTestFile(path.join(tmpDir, "src/app.ts"), tmpDir);
|
|
104
|
-
expect(result).toBeNull();
|
|
105
|
-
});
|
|
106
|
-
it("should find test file even without config (if runner installed)", () => {
|
|
107
|
-
// Simulate vitest installed in node_modules
|
|
108
|
-
createTempFile(tmpDir, "node_modules/vitest/package.json", "{}");
|
|
109
|
-
createTempFile(tmpDir, "src/app.ts", "export const app = {};");
|
|
110
|
-
createTempFile(tmpDir, "src/app.test.ts", "describe('app', () => {});");
|
|
111
|
-
const result = client.findTestFile(path.join(tmpDir, "src/app.ts"), tmpDir);
|
|
112
|
-
// Should find the test file since vitest is "installed"
|
|
113
|
-
expect(result).not.toBeNull();
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
describe("formatResult", () => {
|
|
117
|
-
it("should format passing tests", () => {
|
|
118
|
-
const result = {
|
|
119
|
-
file: "/test/app.test.ts",
|
|
120
|
-
sourceFile: "/test/app.ts",
|
|
121
|
-
runner: "vitest",
|
|
122
|
-
passed: 5,
|
|
123
|
-
failed: 0,
|
|
124
|
-
skipped: 0,
|
|
125
|
-
failures: [],
|
|
126
|
-
duration: 420,
|
|
127
|
-
};
|
|
128
|
-
const formatted = client.formatResult(result);
|
|
129
|
-
expect(formatted).toContain("â");
|
|
130
|
-
expect(formatted).toContain("5/5 passed");
|
|
131
|
-
expect(formatted).toContain("0.42s");
|
|
132
|
-
});
|
|
133
|
-
it("should format failing tests", () => {
|
|
134
|
-
const result = {
|
|
135
|
-
file: "/test/app.test.ts",
|
|
136
|
-
sourceFile: "/test/app.ts",
|
|
137
|
-
runner: "vitest",
|
|
138
|
-
passed: 3,
|
|
139
|
-
failed: 2,
|
|
140
|
-
skipped: 0,
|
|
141
|
-
failures: [
|
|
142
|
-
{
|
|
143
|
-
name: "should add",
|
|
144
|
-
message: "expected 4, got 3",
|
|
145
|
-
location: "app.test.ts:10",
|
|
146
|
-
},
|
|
147
|
-
{
|
|
148
|
-
name: "should subtract",
|
|
149
|
-
message: "expected 1, got 2",
|
|
150
|
-
location: "app.test.ts:20",
|
|
151
|
-
},
|
|
152
|
-
],
|
|
153
|
-
duration: 420,
|
|
154
|
-
};
|
|
155
|
-
const formatted = client.formatResult(result);
|
|
156
|
-
expect(formatted).toContain("â");
|
|
157
|
-
expect(formatted).toContain("2/5 failed");
|
|
158
|
-
expect(formatted).toContain("should add");
|
|
159
|
-
expect(formatted).toContain("should subtract");
|
|
160
|
-
});
|
|
161
|
-
it("should format runner errors", () => {
|
|
162
|
-
const result = {
|
|
163
|
-
file: "/test/app.test.ts",
|
|
164
|
-
sourceFile: "/test/app.ts",
|
|
165
|
-
runner: "vitest",
|
|
166
|
-
passed: 0,
|
|
167
|
-
failed: 0,
|
|
168
|
-
skipped: 0,
|
|
169
|
-
failures: [],
|
|
170
|
-
duration: 0,
|
|
171
|
-
error: "Test file not found",
|
|
172
|
-
};
|
|
173
|
-
const formatted = client.formatResult(result);
|
|
174
|
-
expect(formatted).toContain("â ");
|
|
175
|
-
expect(formatted).toContain("Could not run tests");
|
|
176
|
-
});
|
|
177
|
-
it("should return empty string for no tests", () => {
|
|
178
|
-
const result = {
|
|
179
|
-
file: "/test/app.test.ts",
|
|
180
|
-
sourceFile: "/test/app.ts",
|
|
181
|
-
runner: "vitest",
|
|
182
|
-
passed: 0,
|
|
183
|
-
failed: 0,
|
|
184
|
-
skipped: 0,
|
|
185
|
-
failures: [],
|
|
186
|
-
duration: 0,
|
|
187
|
-
};
|
|
188
|
-
const formatted = client.formatResult(result);
|
|
189
|
-
expect(formatted).toBe("");
|
|
190
|
-
});
|
|
191
|
-
});
|
|
192
|
-
});
|
|
@@ -1,301 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
2
|
-
import { createTempFile, setupTestEnvironment } from "./test-utils.js";
|
|
3
|
-
import { TodoScanner } from "./todo-scanner.js";
|
|
4
|
-
describe("TodoScanner", () => {
|
|
5
|
-
let client;
|
|
6
|
-
let tmpDir;
|
|
7
|
-
let cleanup;
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
client = new TodoScanner();
|
|
10
|
-
({ tmpDir, cleanup } = setupTestEnvironment("pi-lens-todo-test-"));
|
|
11
|
-
});
|
|
12
|
-
afterEach(() => {
|
|
13
|
-
cleanup();
|
|
14
|
-
});
|
|
15
|
-
describe("scanFile", () => {
|
|
16
|
-
it("should return empty array for non-existent files", () => {
|
|
17
|
-
const result = client.scanFile("/nonexistent/file.ts");
|
|
18
|
-
expect(result).toEqual([]);
|
|
19
|
-
});
|
|
20
|
-
it("should find TODO comments", () => {
|
|
21
|
-
const content = `
|
|
22
|
-
// TODO: implement this function
|
|
23
|
-
function foo() {}
|
|
24
|
-
`;
|
|
25
|
-
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
26
|
-
const result = client.scanFile(filePath);
|
|
27
|
-
expect(result.length).toBe(1);
|
|
28
|
-
expect(result[0].type).toBe("TODO");
|
|
29
|
-
expect(result[0].message).toContain("implement this function");
|
|
30
|
-
});
|
|
31
|
-
it("should find FIXME comments", () => {
|
|
32
|
-
const content = `
|
|
33
|
-
// FIXME: this is broken
|
|
34
|
-
function foo() {}
|
|
35
|
-
`;
|
|
36
|
-
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
37
|
-
const result = client.scanFile(filePath);
|
|
38
|
-
expect(result.length).toBe(1);
|
|
39
|
-
expect(result[0].type).toBe("FIXME");
|
|
40
|
-
});
|
|
41
|
-
it("should find HACK comments", () => {
|
|
42
|
-
const content = `
|
|
43
|
-
// HACK: temporary workaround
|
|
44
|
-
const x = 1;
|
|
45
|
-
`;
|
|
46
|
-
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
47
|
-
const result = client.scanFile(filePath);
|
|
48
|
-
expect(result.length).toBe(1);
|
|
49
|
-
expect(result[0].type).toBe("HACK");
|
|
50
|
-
});
|
|
51
|
-
it("should find BUG comments", () => {
|
|
52
|
-
const content = `
|
|
53
|
-
// BUG: this causes a crash
|
|
54
|
-
const x = 1;
|
|
55
|
-
`;
|
|
56
|
-
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
57
|
-
const result = client.scanFile(filePath);
|
|
58
|
-
expect(result.length).toBe(1);
|
|
59
|
-
expect(result[0].type).toBe("BUG");
|
|
60
|
-
});
|
|
61
|
-
it("should find NOTE comments", () => {
|
|
62
|
-
const content = `
|
|
63
|
-
// NOTE: important design decision
|
|
64
|
-
const x = 1;
|
|
65
|
-
`;
|
|
66
|
-
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
67
|
-
const result = client.scanFile(filePath);
|
|
68
|
-
expect(result.length).toBe(1);
|
|
69
|
-
expect(result[0].type).toBe("NOTE");
|
|
70
|
-
});
|
|
71
|
-
it("should find TODO in block comments", () => {
|
|
72
|
-
const content = `
|
|
73
|
-
/*
|
|
74
|
-
* TODO: refactor this later
|
|
75
|
-
*/
|
|
76
|
-
const x = 1;
|
|
77
|
-
`;
|
|
78
|
-
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
79
|
-
const result = client.scanFile(filePath);
|
|
80
|
-
expect(result.length).toBe(1);
|
|
81
|
-
expect(result[0].type).toBe("TODO");
|
|
82
|
-
});
|
|
83
|
-
it("should find TODO in JSDoc comments", () => {
|
|
84
|
-
const content = `
|
|
85
|
-
/**
|
|
86
|
-
* TODO: add proper documentation
|
|
87
|
-
*/
|
|
88
|
-
function foo() {}
|
|
89
|
-
`;
|
|
90
|
-
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
91
|
-
const result = client.scanFile(filePath);
|
|
92
|
-
expect(result.length).toBe(1);
|
|
93
|
-
expect(result[0].type).toBe("TODO");
|
|
94
|
-
});
|
|
95
|
-
it("should find TODO in Python comments", () => {
|
|
96
|
-
const content = `
|
|
97
|
-
# TODO: implement this
|
|
98
|
-
def foo():
|
|
99
|
-
pass
|
|
100
|
-
`;
|
|
101
|
-
const filePath = createTempFile(tmpDir, "test.py", content);
|
|
102
|
-
const result = client.scanFile(filePath);
|
|
103
|
-
expect(result.length).toBe(1);
|
|
104
|
-
expect(result[0].type).toBe("TODO");
|
|
105
|
-
});
|
|
106
|
-
it("should skip TODO in strings", () => {
|
|
107
|
-
const content = `
|
|
108
|
-
const message = "TODO: buy milk";
|
|
109
|
-
`;
|
|
110
|
-
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
111
|
-
const result = client.scanFile(filePath);
|
|
112
|
-
expect(result.length).toBe(0);
|
|
113
|
-
});
|
|
114
|
-
it("should report correct line numbers", () => {
|
|
115
|
-
const content = `
|
|
116
|
-
const x = 1;
|
|
117
|
-
const y = 2;
|
|
118
|
-
// TODO: fix this
|
|
119
|
-
const z = 3;
|
|
120
|
-
`;
|
|
121
|
-
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
122
|
-
const result = client.scanFile(filePath);
|
|
123
|
-
expect(result[0].line).toBe(4);
|
|
124
|
-
});
|
|
125
|
-
it("should find multiple annotations in one file", () => {
|
|
126
|
-
const content = `
|
|
127
|
-
// TODO: first
|
|
128
|
-
// FIXME: second
|
|
129
|
-
// HACK: third
|
|
130
|
-
`;
|
|
131
|
-
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
132
|
-
const result = client.scanFile(filePath);
|
|
133
|
-
expect(result.length).toBe(3);
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
describe("scanDirectory", () => {
|
|
137
|
-
it("should scan all files in directory", () => {
|
|
138
|
-
createTempFile(tmpDir, "file1.ts", "// TODO: task 1");
|
|
139
|
-
createTempFile(tmpDir, "file2.ts", "// FIXME: bug 1");
|
|
140
|
-
createTempFile(tmpDir, "file3.py", "# HACK: workaround");
|
|
141
|
-
const result = client.scanDirectory(tmpDir);
|
|
142
|
-
expect(result.items.length).toBe(3);
|
|
143
|
-
});
|
|
144
|
-
it("should skip node_modules", () => {
|
|
145
|
-
createTempFile(tmpDir, "src/file.ts", "// TODO: task 1");
|
|
146
|
-
createTempFile(tmpDir, "node_modules/lib/file.ts", "// TODO: should be skipped");
|
|
147
|
-
const result = client.scanDirectory(tmpDir);
|
|
148
|
-
expect(result.items.length).toBe(1);
|
|
149
|
-
expect(result.items[0].file).not.toContain("node_modules");
|
|
150
|
-
});
|
|
151
|
-
it("should group items by type", () => {
|
|
152
|
-
createTempFile(tmpDir, "file1.ts", "// TODO: task 1");
|
|
153
|
-
createTempFile(tmpDir, "file2.ts", "// TODO: task 2");
|
|
154
|
-
createTempFile(tmpDir, "file3.ts", "// FIXME: bug 1");
|
|
155
|
-
const result = client.scanDirectory(tmpDir);
|
|
156
|
-
expect(result.byType.get("TODO")?.length).toBe(2);
|
|
157
|
-
expect(result.byType.get("FIXME")?.length).toBe(1);
|
|
158
|
-
});
|
|
159
|
-
it("should group items by file", () => {
|
|
160
|
-
createTempFile(tmpDir, "file1.ts", "// TODO: task 1\n// FIXME: bug 1");
|
|
161
|
-
createTempFile(tmpDir, "file2.ts", "// TODO: task 2");
|
|
162
|
-
const result = client.scanDirectory(tmpDir);
|
|
163
|
-
const file1Items = [...result.byFile.entries()].find(([k]) => k.includes("file1.ts"));
|
|
164
|
-
expect(file1Items?.[1].length).toBe(2);
|
|
165
|
-
});
|
|
166
|
-
});
|
|
167
|
-
describe("formatResult", () => {
|
|
168
|
-
it("should return empty string for no results", () => {
|
|
169
|
-
const result = { items: [], byType: new Map(), byFile: new Map() };
|
|
170
|
-
expect(client.formatResult(result)).toBe("");
|
|
171
|
-
});
|
|
172
|
-
it("should format results with counts", () => {
|
|
173
|
-
const result = {
|
|
174
|
-
items: [
|
|
175
|
-
{
|
|
176
|
-
type: "TODO",
|
|
177
|
-
message: "task 1",
|
|
178
|
-
file: "test.ts",
|
|
179
|
-
line: 1,
|
|
180
|
-
column: 0,
|
|
181
|
-
},
|
|
182
|
-
{
|
|
183
|
-
type: "FIXME",
|
|
184
|
-
message: "bug 1",
|
|
185
|
-
file: "test.ts",
|
|
186
|
-
line: 2,
|
|
187
|
-
column: 0,
|
|
188
|
-
},
|
|
189
|
-
],
|
|
190
|
-
byType: new Map([
|
|
191
|
-
[
|
|
192
|
-
"TODO",
|
|
193
|
-
[
|
|
194
|
-
{
|
|
195
|
-
type: "TODO",
|
|
196
|
-
message: "task 1",
|
|
197
|
-
file: "test.ts",
|
|
198
|
-
line: 1,
|
|
199
|
-
column: 0,
|
|
200
|
-
},
|
|
201
|
-
],
|
|
202
|
-
],
|
|
203
|
-
]),
|
|
204
|
-
byFile: new Map([
|
|
205
|
-
[
|
|
206
|
-
"test.ts",
|
|
207
|
-
[
|
|
208
|
-
{
|
|
209
|
-
type: "TODO",
|
|
210
|
-
message: "task 1",
|
|
211
|
-
file: "test.ts",
|
|
212
|
-
line: 1,
|
|
213
|
-
column: 0,
|
|
214
|
-
},
|
|
215
|
-
],
|
|
216
|
-
],
|
|
217
|
-
]),
|
|
218
|
-
};
|
|
219
|
-
const formatted = client.formatResult(result);
|
|
220
|
-
expect(formatted).toContain("2 annotation(s)");
|
|
221
|
-
expect(formatted).toContain("TODO");
|
|
222
|
-
expect(formatted).toContain("FIXME");
|
|
223
|
-
});
|
|
224
|
-
it("should prioritize FIXME/HACK before TODO", () => {
|
|
225
|
-
const result = {
|
|
226
|
-
items: [
|
|
227
|
-
{
|
|
228
|
-
type: "FIXME",
|
|
229
|
-
message: "bug",
|
|
230
|
-
file: "test.ts",
|
|
231
|
-
line: 2,
|
|
232
|
-
column: 0,
|
|
233
|
-
},
|
|
234
|
-
{
|
|
235
|
-
type: "TODO",
|
|
236
|
-
message: "task",
|
|
237
|
-
file: "test.ts",
|
|
238
|
-
line: 1,
|
|
239
|
-
column: 0,
|
|
240
|
-
},
|
|
241
|
-
],
|
|
242
|
-
byType: new Map(),
|
|
243
|
-
byFile: new Map(),
|
|
244
|
-
};
|
|
245
|
-
const formatted = client.formatResult(result);
|
|
246
|
-
// Check that FIXME line comes before TODO line in the sorted output
|
|
247
|
-
const fixmeLineIndex = formatted.indexOf("đ´");
|
|
248
|
-
const todoLineIndex = formatted.indexOf("đ");
|
|
249
|
-
expect(fixmeLineIndex).toBeLessThan(todoLineIndex);
|
|
250
|
-
});
|
|
251
|
-
it("should show correct icons", () => {
|
|
252
|
-
const result = {
|
|
253
|
-
items: [
|
|
254
|
-
{
|
|
255
|
-
type: "FIXME",
|
|
256
|
-
message: "bug",
|
|
257
|
-
file: "test.ts",
|
|
258
|
-
line: 1,
|
|
259
|
-
column: 0,
|
|
260
|
-
},
|
|
261
|
-
{
|
|
262
|
-
type: "HACK",
|
|
263
|
-
message: "hack",
|
|
264
|
-
file: "test.ts",
|
|
265
|
-
line: 2,
|
|
266
|
-
column: 0,
|
|
267
|
-
},
|
|
268
|
-
{
|
|
269
|
-
type: "BUG",
|
|
270
|
-
message: "bug",
|
|
271
|
-
file: "test.ts",
|
|
272
|
-
line: 3,
|
|
273
|
-
column: 0,
|
|
274
|
-
},
|
|
275
|
-
{
|
|
276
|
-
type: "TODO",
|
|
277
|
-
message: "todo",
|
|
278
|
-
file: "test.ts",
|
|
279
|
-
line: 4,
|
|
280
|
-
column: 0,
|
|
281
|
-
},
|
|
282
|
-
{
|
|
283
|
-
type: "NOTE",
|
|
284
|
-
message: "note",
|
|
285
|
-
file: "test.ts",
|
|
286
|
-
line: 5,
|
|
287
|
-
column: 0,
|
|
288
|
-
},
|
|
289
|
-
],
|
|
290
|
-
byType: new Map(),
|
|
291
|
-
byFile: new Map(),
|
|
292
|
-
};
|
|
293
|
-
const formatted = client.formatResult(result);
|
|
294
|
-
expect(formatted).toContain("đ´"); // FIXME
|
|
295
|
-
expect(formatted).toContain("đ "); // HACK
|
|
296
|
-
expect(formatted).toContain("đ"); // BUG
|
|
297
|
-
expect(formatted).toContain("đ"); // TODO
|
|
298
|
-
expect(formatted).toContain("âšī¸"); // NOTE
|
|
299
|
-
});
|
|
300
|
-
});
|
|
301
|
-
});
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
2
|
-
import { setupTestEnvironment } from "./test-utils.js";
|
|
3
|
-
import { TypeCoverageClient } from "./type-coverage-client.js";
|
|
4
|
-
describe("TypeCoverageClient", () => {
|
|
5
|
-
let client;
|
|
6
|
-
let _tmpDir;
|
|
7
|
-
let cleanup;
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
client = new TypeCoverageClient();
|
|
10
|
-
({ tmpDir: _tmpDir, cleanup } = setupTestEnvironment("pi-lens-typecoverage-test-"));
|
|
11
|
-
});
|
|
12
|
-
afterEach(() => {
|
|
13
|
-
cleanup();
|
|
14
|
-
});
|
|
15
|
-
afterEach(() => {
|
|
16
|
-
cleanup();
|
|
17
|
-
});
|
|
18
|
-
describe("isAvailable", () => {
|
|
19
|
-
it("should check type-coverage availability", () => {
|
|
20
|
-
const available = client.isAvailable();
|
|
21
|
-
expect(typeof available).toBe("boolean");
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
describe("formatResult", () => {
|
|
25
|
-
it("should return empty string when not successful", () => {
|
|
26
|
-
const result = {
|
|
27
|
-
success: false,
|
|
28
|
-
percentage: 0,
|
|
29
|
-
typed: 0,
|
|
30
|
-
total: 0,
|
|
31
|
-
untypedLocations: [],
|
|
32
|
-
};
|
|
33
|
-
expect(client.formatResult(result)).toBe("");
|
|
34
|
-
});
|
|
35
|
-
it("should show coverage percentage", () => {
|
|
36
|
-
const result = {
|
|
37
|
-
success: true,
|
|
38
|
-
percentage: 95,
|
|
39
|
-
typed: 95,
|
|
40
|
-
total: 100,
|
|
41
|
-
untypedLocations: [],
|
|
42
|
-
};
|
|
43
|
-
const formatted = client.formatResult(result);
|
|
44
|
-
expect(formatted).toContain("95.0%");
|
|
45
|
-
expect(formatted).toContain("95/100");
|
|
46
|
-
});
|
|
47
|
-
it("should show warning for low coverage", () => {
|
|
48
|
-
const result = {
|
|
49
|
-
success: true,
|
|
50
|
-
percentage: 80,
|
|
51
|
-
typed: 80,
|
|
52
|
-
total: 100,
|
|
53
|
-
untypedLocations: [],
|
|
54
|
-
};
|
|
55
|
-
const formatted = client.formatResult(result);
|
|
56
|
-
expect(formatted).toContain("â ");
|
|
57
|
-
});
|
|
58
|
-
it("should show checkmark for high coverage", () => {
|
|
59
|
-
const result = {
|
|
60
|
-
success: true,
|
|
61
|
-
percentage: 100,
|
|
62
|
-
typed: 100,
|
|
63
|
-
total: 100,
|
|
64
|
-
untypedLocations: [],
|
|
65
|
-
};
|
|
66
|
-
const formatted = client.formatResult(result);
|
|
67
|
-
expect(formatted).toContain("â");
|
|
68
|
-
});
|
|
69
|
-
it("should show untyped locations", () => {
|
|
70
|
-
const result = {
|
|
71
|
-
success: true,
|
|
72
|
-
percentage: 90,
|
|
73
|
-
typed: 90,
|
|
74
|
-
total: 100,
|
|
75
|
-
untypedLocations: [
|
|
76
|
-
{ file: "test.ts", line: 10, column: 5, name: "x" },
|
|
77
|
-
{ file: "test.ts", line: 20, column: 8, name: "y" },
|
|
78
|
-
],
|
|
79
|
-
};
|
|
80
|
-
const formatted = client.formatResult(result);
|
|
81
|
-
expect(formatted).toContain("test.ts:10");
|
|
82
|
-
expect(formatted).toContain("test.ts:20");
|
|
83
|
-
expect(formatted).toContain("x");
|
|
84
|
-
expect(formatted).toContain("y");
|
|
85
|
-
});
|
|
86
|
-
it("should truncate long untyped location lists", () => {
|
|
87
|
-
const locations = Array.from({ length: 20 }, (_, i) => ({
|
|
88
|
-
file: `file${i}.ts`,
|
|
89
|
-
line: i + 1,
|
|
90
|
-
column: 0,
|
|
91
|
-
name: `var${i}`,
|
|
92
|
-
}));
|
|
93
|
-
const result = {
|
|
94
|
-
success: true,
|
|
95
|
-
percentage: 80,
|
|
96
|
-
typed: 80,
|
|
97
|
-
total: 100,
|
|
98
|
-
untypedLocations: locations,
|
|
99
|
-
};
|
|
100
|
-
const formatted = client.formatResult(result, 10);
|
|
101
|
-
expect(formatted).toContain("...");
|
|
102
|
-
expect(formatted).toContain("10 more");
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
});
|