pi-lens 2.2.9 → 3.0.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 +198 -0
- package/README.md +709 -519
- package/clients/__tests__/file-time.test.js +216 -0
- package/clients/__tests__/file-time.test.ts +276 -0
- package/clients/__tests__/format-service.test.js +245 -0
- package/clients/__tests__/format-service.test.ts +339 -0
- package/clients/__tests__/formatters.test.js +271 -0
- package/clients/__tests__/formatters.test.ts +401 -0
- package/clients/amain-types.js +164 -0
- package/clients/amain-types.ts +165 -0
- package/clients/architect-client.js +56 -12
- package/clients/architect-client.ts +81 -16
- package/clients/ast-grep-client.js +2 -2
- package/clients/ast-grep-client.ts +14 -39
- package/clients/ast-grep-parser.ts +1 -1
- package/clients/ast-grep-rule-manager.js +8 -0
- package/clients/ast-grep-rule-manager.ts +10 -1
- package/clients/ast-grep-types.js +9 -0
- package/clients/ast-grep-types.ts +106 -0
- package/clients/auto-loop.js +10 -0
- package/clients/auto-loop.ts +14 -1
- package/clients/biome-client.js +81 -19
- package/clients/biome-client.ts +103 -22
- package/clients/bus/bus.js +191 -0
- package/clients/bus/bus.ts +251 -0
- package/clients/bus/events.js +214 -0
- package/clients/bus/events.ts +279 -0
- package/clients/bus/index.js +8 -0
- package/clients/bus/index.ts +9 -0
- package/clients/bus/integration.js +158 -0
- package/clients/bus/integration.ts +214 -0
- package/clients/complexity-client.js +13 -7
- package/clients/complexity-client.ts +13 -7
- package/clients/config-validator.js +465 -0
- package/clients/config-validator.ts +558 -0
- package/clients/dependency-checker.js +4 -10
- package/clients/dependency-checker.ts +4 -10
- package/clients/dispatch/__tests__/autofix-integration.test.js +245 -0
- package/clients/dispatch/__tests__/autofix-integration.test.ts +300 -0
- package/clients/dispatch/__tests__/runner-registration.test.js +236 -0
- package/clients/dispatch/__tests__/runner-registration.test.ts +282 -0
- package/clients/dispatch/bus-dispatcher.js +177 -0
- package/clients/dispatch/bus-dispatcher.ts +251 -0
- package/clients/dispatch/dispatcher.edge.test.js +82 -0
- package/clients/dispatch/dispatcher.edge.test.ts +100 -0
- package/clients/dispatch/dispatcher.format.test.js +46 -0
- package/clients/dispatch/dispatcher.format.test.ts +58 -0
- package/clients/dispatch/dispatcher.inline.test.js +74 -0
- package/clients/dispatch/dispatcher.inline.test.ts +93 -0
- package/clients/dispatch/dispatcher.js +19 -53
- package/clients/dispatch/dispatcher.ts +20 -67
- package/clients/dispatch/plan.js +9 -4
- package/clients/dispatch/plan.ts +9 -4
- package/clients/dispatch/runners/architect.js +21 -7
- package/clients/dispatch/runners/architect.test.js +138 -0
- package/clients/dispatch/runners/architect.test.ts +162 -0
- package/clients/dispatch/runners/architect.ts +22 -7
- package/clients/dispatch/runners/ast-grep-napi.js +462 -0
- package/clients/dispatch/runners/ast-grep-napi.test.js +111 -0
- package/clients/dispatch/runners/ast-grep-napi.test.ts +133 -0
- package/clients/dispatch/runners/ast-grep-napi.ts +506 -0
- package/clients/dispatch/runners/ast-grep.js +62 -19
- package/clients/dispatch/runners/ast-grep.ts +70 -18
- package/clients/dispatch/runners/biome.js +29 -53
- package/clients/dispatch/runners/biome.ts +29 -63
- package/clients/dispatch/runners/config-validation.js +67 -0
- package/clients/dispatch/runners/config-validation.ts +82 -0
- package/clients/dispatch/runners/go-vet.js +4 -28
- package/clients/dispatch/runners/go-vet.ts +4 -32
- package/clients/dispatch/runners/index.js +30 -10
- package/clients/dispatch/runners/index.ts +30 -10
- package/clients/dispatch/runners/oxlint.js +141 -0
- package/clients/dispatch/runners/oxlint.test.js +230 -0
- package/clients/dispatch/runners/oxlint.test.ts +303 -0
- package/clients/dispatch/runners/oxlint.ts +175 -0
- package/clients/dispatch/runners/pyright.js +40 -70
- package/clients/dispatch/runners/pyright.test.js +16 -2
- package/clients/dispatch/runners/pyright.test.ts +14 -2
- package/clients/dispatch/runners/pyright.ts +48 -91
- package/clients/dispatch/runners/python-slop.js +97 -0
- package/clients/dispatch/runners/python-slop.test.js +203 -0
- package/clients/dispatch/runners/python-slop.test.ts +298 -0
- package/clients/dispatch/runners/python-slop.ts +124 -0
- package/clients/dispatch/runners/ruff.js +18 -71
- package/clients/dispatch/runners/ruff.ts +19 -79
- package/clients/dispatch/runners/rust-clippy.js +28 -32
- package/clients/dispatch/runners/rust-clippy.ts +29 -31
- package/clients/dispatch/runners/scan_codebase.test.js +89 -0
- package/clients/dispatch/runners/scan_codebase.test.ts +105 -0
- package/clients/dispatch/runners/shellcheck.js +147 -0
- package/clients/dispatch/runners/shellcheck.test.js +98 -0
- package/clients/dispatch/runners/shellcheck.test.ts +129 -0
- package/clients/dispatch/runners/shellcheck.ts +188 -0
- package/clients/dispatch/runners/similarity.js +230 -0
- package/clients/dispatch/runners/similarity.ts +339 -0
- package/clients/dispatch/runners/spellcheck.js +106 -0
- package/clients/dispatch/runners/spellcheck.test.js +158 -0
- package/clients/dispatch/runners/spellcheck.test.ts +214 -0
- package/clients/dispatch/runners/spellcheck.ts +136 -0
- package/clients/dispatch/runners/tree-sitter.js +107 -0
- package/clients/dispatch/runners/tree-sitter.ts +135 -0
- package/clients/dispatch/runners/ts-lsp.js +104 -33
- package/clients/dispatch/runners/ts-lsp.ts +120 -38
- package/clients/dispatch/runners/ts-slop.js +113 -0
- package/clients/dispatch/runners/ts-slop.test.js +180 -0
- package/clients/dispatch/runners/ts-slop.test.ts +230 -0
- package/clients/dispatch/runners/ts-slop.ts +142 -0
- package/clients/dispatch/runners/utils/diagnostic-parsers.js +134 -0
- package/clients/dispatch/runners/utils/diagnostic-parsers.ts +186 -0
- package/clients/dispatch/runners/utils/runner-helpers.js +115 -0
- package/clients/dispatch/runners/utils/runner-helpers.ts +167 -0
- package/clients/dispatch/runners/utils.js +2 -4
- package/clients/dispatch/runners/utils.ts +2 -4
- package/clients/dispatch/types.ts +1 -1
- package/clients/dispatch/utils/format-utils.js +49 -0
- package/clients/dispatch/utils/format-utils.ts +60 -0
- package/clients/dogfood.test.js +201 -0
- package/clients/dogfood.test.ts +269 -0
- package/clients/file-time.js +152 -0
- package/clients/file-time.ts +208 -0
- package/clients/file-utils.js +40 -0
- package/clients/file-utils.ts +44 -0
- package/clients/fix-scanners.js +10 -20
- package/clients/fix-scanners.ts +10 -22
- package/clients/format-service.js +172 -0
- package/clients/format-service.ts +254 -0
- package/clients/formatters.js +435 -0
- package/clients/formatters.ts +508 -0
- package/clients/go-client.js +5 -14
- package/clients/go-client.ts +5 -13
- package/clients/installer/index.js +356 -0
- package/clients/installer/index.ts +426 -0
- package/clients/jscpd-client.js +11 -9
- package/clients/jscpd-client.ts +12 -8
- package/clients/knip-client.js +3 -7
- package/clients/knip-client.ts +3 -6
- package/clients/lsp/__tests__/client.test.js +325 -0
- package/clients/lsp/__tests__/client.test.ts +434 -0
- package/clients/lsp/__tests__/config.test.js +166 -0
- package/clients/lsp/__tests__/config.test.ts +209 -0
- package/clients/lsp/__tests__/error-recovery.test.js +213 -0
- package/clients/lsp/__tests__/error-recovery.test.ts +279 -0
- package/clients/lsp/__tests__/integration.test.js +127 -0
- package/clients/lsp/__tests__/integration.test.ts +160 -0
- package/clients/lsp/__tests__/launch.test.js +260 -0
- package/clients/lsp/__tests__/launch.test.ts +329 -0
- package/clients/lsp/__tests__/server.test.js +259 -0
- package/clients/lsp/__tests__/server.test.ts +332 -0
- package/clients/lsp/__tests__/service.test.js +417 -0
- package/clients/lsp/__tests__/service.test.ts +499 -0
- package/clients/lsp/client.js +235 -0
- package/clients/lsp/client.ts +328 -0
- package/clients/lsp/config.js +115 -0
- package/clients/lsp/config.ts +149 -0
- package/clients/lsp/index.js +222 -0
- package/clients/lsp/index.ts +280 -0
- package/clients/lsp/installer/index.js +391 -0
- package/clients/lsp/interactive-install.js +210 -0
- package/clients/lsp/interactive-install.ts +251 -0
- package/clients/lsp/language.js +170 -0
- package/clients/lsp/language.ts +216 -0
- package/clients/lsp/launch.js +174 -0
- package/clients/lsp/launch.ts +240 -0
- package/clients/lsp/lsp/launch.js +116 -0
- package/clients/lsp/lsp/server.js +532 -0
- package/clients/lsp/lsp-index.js +10 -0
- package/clients/lsp/lsp-index.ts +11 -0
- package/clients/lsp/path-utils.js +48 -0
- package/clients/lsp/path-utils.ts +52 -0
- package/clients/lsp/server.js +615 -0
- package/clients/lsp/server.ts +800 -0
- package/clients/lsp/test-py-spawn/requirements.txt +1 -0
- package/clients/lsp/test-py-spawn/test.py +3 -0
- package/clients/lsp/test-py-svc/requirements.txt +1 -0
- package/clients/lsp/test-py-svc/test.py +3 -0
- package/clients/lsp/test-python-project/requirements.txt +1 -0
- package/clients/lsp/test-python-project/test.py +5 -0
- package/clients/metrics-history.js +2 -2
- package/clients/metrics-history.ts +2 -2
- package/clients/production-readiness.js +522 -0
- package/clients/production-readiness.ts +556 -0
- package/clients/project-index.js +255 -0
- package/clients/project-index.ts +383 -0
- package/clients/project-metadata.js +531 -0
- package/clients/project-metadata.ts +624 -0
- package/clients/ruff-client.js +56 -16
- package/clients/ruff-client.ts +72 -15
- package/clients/runner-tracker.js +152 -0
- package/clients/runner-tracker.ts +213 -0
- package/clients/rust-client.js +4 -11
- package/clients/rust-client.ts +5 -11
- package/clients/safe-spawn.js +96 -0
- package/clients/safe-spawn.ts +128 -0
- package/clients/scan-architectural-debt.js +3 -6
- package/clients/scan-architectural-debt.ts +3 -6
- package/clients/scan-utils.js +5 -20
- package/clients/scan-utils.ts +5 -29
- package/clients/secrets-scanner.js +3 -17
- package/clients/secrets-scanner.ts +4 -20
- package/clients/services/__tests__/effect-integration.test.js +86 -0
- package/clients/services/__tests__/effect-integration.test.ts +111 -0
- package/clients/services/effect-integration.js +194 -0
- package/clients/services/effect-integration.ts +268 -0
- package/clients/services/index.js +7 -0
- package/clients/services/index.ts +8 -0
- package/clients/services/runner-service.js +105 -0
- package/clients/services/runner-service.ts +179 -0
- package/clients/sg-runner.js +87 -13
- package/clients/sg-runner.ts +97 -13
- package/clients/state-matrix.js +160 -0
- package/clients/state-matrix.ts +202 -0
- package/clients/subprocess-client.js +10 -9
- package/clients/subprocess-client.ts +10 -8
- package/clients/test-runner-client.js +3 -7
- package/clients/test-runner-client.ts +3 -6
- package/clients/tool-availability.js +4 -10
- package/clients/tool-availability.ts +4 -9
- package/clients/tree-sitter-client.js +564 -0
- package/clients/tree-sitter-client.ts +797 -0
- package/clients/tree-sitter-query-loader.js +355 -0
- package/clients/tree-sitter-query-loader.ts +425 -0
- package/clients/type-coverage-client.js +3 -7
- package/clients/type-coverage-client.ts +3 -6
- package/clients/typescript-client.codefix.test.js +157 -0
- package/clients/typescript-client.codefix.test.ts +186 -0
- package/clients/typescript-client.js +43 -0
- package/clients/typescript-client.ts +98 -0
- package/commands/booboo.js +799 -219
- package/commands/booboo.ts +1004 -225
- package/commands/clients/ast-grep-client.js +250 -0
- package/commands/clients/ast-grep-parser.js +86 -0
- package/commands/clients/ast-grep-rule-manager.js +91 -0
- package/commands/clients/ast-grep-types.js +9 -0
- package/commands/clients/biome-client.js +380 -0
- package/commands/clients/complexity-client.js +667 -0
- package/commands/clients/file-kinds.js +177 -0
- package/commands/clients/file-utils.js +40 -0
- package/commands/clients/jscpd-client.js +169 -0
- package/commands/clients/knip-client.js +211 -0
- package/commands/clients/ruff-client.js +297 -0
- package/commands/clients/safe-spawn.js +88 -0
- package/commands/clients/scan-utils.js +83 -0
- package/commands/clients/sg-runner.js +190 -0
- package/commands/clients/types.js +11 -0
- package/commands/clients/typescript-client.js +505 -0
- package/commands/fix-from-booboo.js +398 -0
- package/commands/fix-from-booboo.ts +485 -0
- package/commands/fix-simplified.js +618 -0
- package/commands/fix-simplified.ts +768 -0
- package/commands/rate.js +10 -14
- package/commands/rate.ts +9 -16
- package/default-architect.yaml +59 -15
- package/index.ts +342 -429
- package/package.json +16 -3
- package/rules/ast-grep-rules/rules/empty-catch.yml +38 -13
- package/rules/ast-grep-rules/rules/no-array-constructor.yml +1 -0
- package/rules/ast-grep-rules/rules/no-debugger.yml +2 -0
- package/rules/python-slop-rules/.sgconfig.yml +4 -0
- package/rules/python-slop-rules/rules/slop-rules.yml +647 -0
- package/rules/tree-sitter-queries/python/bare-except.yml +54 -0
- package/rules/tree-sitter-queries/python/eval-exec.yml +50 -0
- package/rules/tree-sitter-queries/python/is-vs-equals.yml +60 -0
- package/rules/tree-sitter-queries/python/mutable-default-arg.yml +57 -0
- package/rules/tree-sitter-queries/python/unreachable-except.yml +60 -0
- package/rules/tree-sitter-queries/python/wildcard-import.yml +46 -0
- package/rules/tree-sitter-queries/tsx/dangerously-set-inner-html.yml +63 -0
- package/rules/tree-sitter-queries/typescript/await-in-loop.yml +56 -0
- package/rules/tree-sitter-queries/typescript/console-statement.yml +47 -0
- package/rules/tree-sitter-queries/typescript/debugger.yml +47 -0
- package/rules/tree-sitter-queries/typescript/deep-nesting.yml +117 -0
- package/rules/tree-sitter-queries/typescript/deep-promise-chain.yml +73 -0
- package/rules/tree-sitter-queries/typescript/empty-catch.yml +64 -0
- package/rules/tree-sitter-queries/typescript/eval.yml +48 -0
- package/rules/tree-sitter-queries/typescript/hardcoded-secrets.yml +78 -0
- package/rules/tree-sitter-queries/typescript/long-parameter-list.yml +62 -0
- package/rules/tree-sitter-queries/typescript/mixed-async-styles.yml +49 -0
- package/rules/tree-sitter-queries/typescript/nested-ternary.yml +45 -0
- package/rules/ts-slop-rules/.sgconfig.yml +4 -0
- package/rules/ts-slop-rules/rules/in-correct-optional-input-type.yml +10 -0
- package/rules/ts-slop-rules/rules/jwt-no-verify.yml +13 -0
- package/rules/ts-slop-rules/rules/no-architecture-violation.yml +10 -0
- package/rules/ts-slop-rules/rules/no-case-declarations.yml +10 -0
- package/rules/ts-slop-rules/rules/no-dangerously-set-inner-html.yml +10 -0
- package/rules/ts-slop-rules/rules/no-debugger.yml +10 -0
- package/rules/ts-slop-rules/rules/no-dupe-args.yml +10 -0
- package/rules/ts-slop-rules/rules/no-dupe-class-members.yml +10 -0
- package/rules/ts-slop-rules/rules/no-dupe-keys.yml +10 -0
- package/rules/ts-slop-rules/rules/no-eval.yml +13 -0
- package/rules/ts-slop-rules/rules/no-hardcoded-secrets.yml +12 -0
- package/rules/ts-slop-rules/rules/no-implied-eval.yml +12 -0
- package/rules/ts-slop-rules/rules/no-inner-html.yml +13 -0
- package/rules/ts-slop-rules/rules/no-javascript-url.yml +10 -0
- package/rules/ts-slop-rules/rules/no-mutable-default.yml +10 -0
- package/rules/ts-slop-rules/rules/no-nested-links.yml +12 -0
- package/rules/ts-slop-rules/rules/no-new-symbol.yml +10 -0
- package/rules/ts-slop-rules/rules/no-new-wrappers.yml +13 -0
- package/rules/ts-slop-rules/rules/no-open-redirect.yml +16 -0
- package/rules/ts-slop-rules/rules/slop-rules.yml +455 -0
- package/rules/ts-slop-rules/rules/weak-rsa-key.yml +12 -0
- package/skills/ast-grep/SKILL.md +182 -0
- package/clients/dispatch/runners/secrets.js +0 -109
- package/commands/fix.js +0 -244
- package/commands/fix.ts +0 -373
- package/rules/ast-grep-rules/rules/no-lonely-if.yml +0 -13
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
2
|
+
import { createTempFile, setupTestEnvironment } from "./test-utils.js";
|
|
3
|
+
import { TypeScriptClient } from "./typescript-client.js";
|
|
4
|
+
|
|
5
|
+
describe("TypeScriptClient - Code Fixes", () => {
|
|
6
|
+
let client: TypeScriptClient;
|
|
7
|
+
let tmpDir: string;
|
|
8
|
+
let cleanup: () => void;
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
client = new TypeScriptClient();
|
|
12
|
+
({ tmpDir, cleanup } = setupTestEnvironment("pi-lens-codefix-test-"));
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
cleanup();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe("getCodeFixes", () => {
|
|
20
|
+
it("should provide fix for missing property on object literal", () => {
|
|
21
|
+
// Real-world case: Missing required property in object literal
|
|
22
|
+
const content = `
|
|
23
|
+
interface Config {
|
|
24
|
+
name: string;
|
|
25
|
+
port: number;
|
|
26
|
+
debug: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const config: Config = {
|
|
30
|
+
name: "my-app",
|
|
31
|
+
port: 3000
|
|
32
|
+
// Missing 'debug' property - TS2345
|
|
33
|
+
};
|
|
34
|
+
`;
|
|
35
|
+
const filePath = createTempFile(tmpDir, "missing-property.ts", content);
|
|
36
|
+
client.addFile(filePath, content);
|
|
37
|
+
|
|
38
|
+
const diags = client.getDiagnostics(filePath);
|
|
39
|
+
const missingPropError = diags.find(
|
|
40
|
+
(d) => d.code === 2345 || d.message.includes("missing"),
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
if (missingPropError) {
|
|
44
|
+
const line = missingPropError.range.start.line;
|
|
45
|
+
const char = missingPropError.range.start.character;
|
|
46
|
+
const fixes = client.getCodeFixes(filePath, line, char, [
|
|
47
|
+
missingPropError.code as number,
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
// TypeScript should suggest adding the missing property
|
|
51
|
+
expect(fixes.length).toBeGreaterThan(0);
|
|
52
|
+
const hasAddPropertyFix = fixes.some(
|
|
53
|
+
(f) =>
|
|
54
|
+
f.description.toLowerCase().includes("add") ||
|
|
55
|
+
f.description.toLowerCase().includes("property") ||
|
|
56
|
+
f.description.toLowerCase().includes("declare"),
|
|
57
|
+
);
|
|
58
|
+
expect(hasAddPropertyFix).toBe(true);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("should provide fix for missing await in async function", () => {
|
|
63
|
+
// Real-world case: Forgetting await on a Promise-returning function
|
|
64
|
+
const content = `
|
|
65
|
+
async function fetchUser(id: string): Promise<{ name: string }> {
|
|
66
|
+
return { name: "John" };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function getUserName(id: string): Promise<string> {
|
|
70
|
+
const user = fetchUser(id); // Missing await
|
|
71
|
+
return user.name; // Type 'Promise<{ name: string; }>' has no property 'name'
|
|
72
|
+
}
|
|
73
|
+
`;
|
|
74
|
+
const filePath = createTempFile(tmpDir, "missing-await.ts", content);
|
|
75
|
+
client.addFile(filePath, content);
|
|
76
|
+
|
|
77
|
+
const diags = client.getDiagnostics(filePath);
|
|
78
|
+
// TS2739: Type 'Promise<{ name: string; }>' is missing 'name'
|
|
79
|
+
const propertyError = diags.find(
|
|
80
|
+
(d) => d.code === 2739 || d.message.includes("is missing"),
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
if (propertyError) {
|
|
84
|
+
const fixes = client.getAllCodeFixes(filePath);
|
|
85
|
+
// If there's an error, check if we have fixes for it
|
|
86
|
+
const lineFixes = fixes.get(propertyError.range.start.line);
|
|
87
|
+
if (lineFixes) {
|
|
88
|
+
expect(lineFixes.length).toBeGreaterThan(0);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Test passes if we get here - not all TS versions provide fixes for this
|
|
92
|
+
expect(true).toBe(true);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("should provide fix for incorrect type assignment", () => {
|
|
96
|
+
// Real-world case: String instead of number
|
|
97
|
+
const content = `
|
|
98
|
+
function calculateTotal(price: number, tax: number): number {
|
|
99
|
+
return price + tax;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const result = calculateTotal("100", 10); // TS2345: Argument of type 'string' is not assignable to parameter of type 'number'
|
|
103
|
+
`;
|
|
104
|
+
const filePath = createTempFile(tmpDir, "type-mismatch.ts", content);
|
|
105
|
+
client.addFile(filePath, content);
|
|
106
|
+
|
|
107
|
+
const diags = client.getDiagnostics(filePath);
|
|
108
|
+
const typeError = diags.find((d) => d.code === 2345);
|
|
109
|
+
|
|
110
|
+
if (typeError) {
|
|
111
|
+
const line = typeError.range.start.line;
|
|
112
|
+
const char = typeError.range.start.character;
|
|
113
|
+
const fixes = client.getCodeFixes(filePath, line, char, [2345]);
|
|
114
|
+
|
|
115
|
+
// TypeScript often suggests fixes for type mismatches
|
|
116
|
+
expect(fixes).toBeDefined();
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("should collect all fixes via getAllCodeFixes", () => {
|
|
121
|
+
// Multiple errors in one file
|
|
122
|
+
const content = `
|
|
123
|
+
interface Person {
|
|
124
|
+
name: string;
|
|
125
|
+
age: number;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const person: Person = {
|
|
129
|
+
name: "Alice"
|
|
130
|
+
// Missing age
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
function greet(p: Person): string {
|
|
134
|
+
return "Hello " + p.name;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
greet({ name: "Bob" }); // Missing age in argument
|
|
138
|
+
`;
|
|
139
|
+
const filePath = createTempFile(tmpDir, "multiple-errors.ts", content);
|
|
140
|
+
client.addFile(filePath, content);
|
|
141
|
+
|
|
142
|
+
const allFixes = client.getAllCodeFixes(filePath);
|
|
143
|
+
|
|
144
|
+
// Should have fixes mapped by line number
|
|
145
|
+
expect(allFixes).toBeInstanceOf(Map);
|
|
146
|
+
|
|
147
|
+
// Each fix entry should have a description and changes
|
|
148
|
+
for (const [line, fixes] of allFixes.entries()) {
|
|
149
|
+
expect(typeof line).toBe("number");
|
|
150
|
+
expect(fixes.length).toBeGreaterThan(0);
|
|
151
|
+
for (const fix of fixes) {
|
|
152
|
+
expect(fix.description).toBeTruthy();
|
|
153
|
+
expect(fix.changes).toBeDefined();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
describe("Integration with diagnostic messages", () => {
|
|
160
|
+
it("should include fix suggestions in getAllCodeFixes output", () => {
|
|
161
|
+
const content = `
|
|
162
|
+
class User {
|
|
163
|
+
constructor(public name: string) {}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const user = new User(); // TS2554: Expected 1 arguments, but got 0
|
|
167
|
+
`;
|
|
168
|
+
const filePath = createTempFile(tmpDir, "constructor-args.ts", content);
|
|
169
|
+
client.addFile(filePath, content);
|
|
170
|
+
|
|
171
|
+
const diags = client.getDiagnostics(filePath);
|
|
172
|
+
const argError = diags.find((d) => d.code === 2554);
|
|
173
|
+
|
|
174
|
+
if (argError) {
|
|
175
|
+
const fixes = client.getAllCodeFixes(filePath);
|
|
176
|
+
const lineFixes = fixes.get(argError.range.start.line);
|
|
177
|
+
|
|
178
|
+
if (lineFixes && lineFixes.length > 0) {
|
|
179
|
+
// The runner would append this to the message
|
|
180
|
+
const suggestion = lineFixes[0].description;
|
|
181
|
+
expect(suggestion).toBeTruthy();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
});
|
|
@@ -432,6 +432,49 @@ export class TypeScriptClient {
|
|
|
432
432
|
return null;
|
|
433
433
|
return { message: errorAtLine.message, code: errorAtLine.code };
|
|
434
434
|
}
|
|
435
|
+
/**
|
|
436
|
+
* Get quick fixes (code actions) for a diagnostic at a position.
|
|
437
|
+
* Returns array of fix descriptions with their edit changes.
|
|
438
|
+
*/
|
|
439
|
+
getCodeFixes(filePath, line, character, errorCodes) {
|
|
440
|
+
const resolved = this.resolvePosition(filePath, line, character);
|
|
441
|
+
if (!resolved)
|
|
442
|
+
return [];
|
|
443
|
+
const { normalized, position, ls } = resolved;
|
|
444
|
+
const formatOpts = {
|
|
445
|
+
indentSize: 2,
|
|
446
|
+
tabSize: 2,
|
|
447
|
+
newLineCharacter: "\n",
|
|
448
|
+
convertTabsToSpaces: true,
|
|
449
|
+
};
|
|
450
|
+
const fixes = ls.getCodeFixesAtPosition(normalized, position, position, errorCodes, formatOpts, {});
|
|
451
|
+
if (!fixes)
|
|
452
|
+
return [];
|
|
453
|
+
return fixes.map((fix) => ({
|
|
454
|
+
description: fix.description,
|
|
455
|
+
changes: fix.changes?.map((change) => ({
|
|
456
|
+
fileName: change.fileName,
|
|
457
|
+
textChanges: change.textChanges,
|
|
458
|
+
})) || [],
|
|
459
|
+
}));
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Get all quick fixes for all diagnostics in a file.
|
|
463
|
+
* Returns a map of diagnostic line → fixes.
|
|
464
|
+
*/
|
|
465
|
+
getAllCodeFixes(filePath) {
|
|
466
|
+
const fixesByLine = new Map();
|
|
467
|
+
const diagnostics = this.getDiagnostics(filePath);
|
|
468
|
+
for (const diag of diagnostics) {
|
|
469
|
+
if (diag.severity !== 1 || diag.code === undefined)
|
|
470
|
+
continue;
|
|
471
|
+
const fixes = this.getCodeFixes(filePath, diag.range.start.line, diag.range.start.character, [diag.code]);
|
|
472
|
+
if (fixes.length > 0) {
|
|
473
|
+
fixesByLine.set(diag.range.start.line, fixes);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return fixesByLine;
|
|
477
|
+
}
|
|
435
478
|
symbolKind(kind) {
|
|
436
479
|
const map = {
|
|
437
480
|
script: "file",
|
|
@@ -562,6 +562,104 @@ export class TypeScriptClient {
|
|
|
562
562
|
return { message: errorAtLine.message, code: errorAtLine.code as number };
|
|
563
563
|
}
|
|
564
564
|
|
|
565
|
+
/**
|
|
566
|
+
* Get quick fixes (code actions) for a diagnostic at a position.
|
|
567
|
+
* Returns array of fix descriptions with their edit changes.
|
|
568
|
+
*/
|
|
569
|
+
getCodeFixes(
|
|
570
|
+
filePath: string,
|
|
571
|
+
line: number,
|
|
572
|
+
character: number,
|
|
573
|
+
errorCodes: number[],
|
|
574
|
+
): Array<{
|
|
575
|
+
description: string;
|
|
576
|
+
changes: Array<{
|
|
577
|
+
fileName: string;
|
|
578
|
+
textChanges: ReadonlyArray<{
|
|
579
|
+
span: { start: number; length: number };
|
|
580
|
+
newText: string;
|
|
581
|
+
}>;
|
|
582
|
+
}>;
|
|
583
|
+
}> {
|
|
584
|
+
const resolved = this.resolvePosition(filePath, line, character);
|
|
585
|
+
if (!resolved) return [];
|
|
586
|
+
const { normalized, position, ls } = resolved;
|
|
587
|
+
|
|
588
|
+
const formatOpts: ts.FormatCodeSettings = {
|
|
589
|
+
indentSize: 2,
|
|
590
|
+
tabSize: 2,
|
|
591
|
+
newLineCharacter: "\n",
|
|
592
|
+
convertTabsToSpaces: true,
|
|
593
|
+
};
|
|
594
|
+
|
|
595
|
+
const fixes = ls.getCodeFixesAtPosition(
|
|
596
|
+
normalized,
|
|
597
|
+
position,
|
|
598
|
+
position,
|
|
599
|
+
errorCodes,
|
|
600
|
+
formatOpts,
|
|
601
|
+
{}, // preferences
|
|
602
|
+
);
|
|
603
|
+
|
|
604
|
+
if (!fixes) return [];
|
|
605
|
+
|
|
606
|
+
return fixes.map((fix) => ({
|
|
607
|
+
description: fix.description,
|
|
608
|
+
changes:
|
|
609
|
+
fix.changes?.map((change) => ({
|
|
610
|
+
fileName: change.fileName,
|
|
611
|
+
textChanges: change.textChanges,
|
|
612
|
+
})) || [],
|
|
613
|
+
}));
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* Get all quick fixes for all diagnostics in a file.
|
|
618
|
+
* Returns a map of diagnostic line → fixes.
|
|
619
|
+
*/
|
|
620
|
+
getAllCodeFixes(filePath: string): Map<
|
|
621
|
+
number,
|
|
622
|
+
Array<{
|
|
623
|
+
description: string;
|
|
624
|
+
changes: Array<{
|
|
625
|
+
fileName: string;
|
|
626
|
+
textChanges: ReadonlyArray<{
|
|
627
|
+
span: { start: number; length: number };
|
|
628
|
+
newText: string;
|
|
629
|
+
}>;
|
|
630
|
+
}>;
|
|
631
|
+
}>
|
|
632
|
+
> {
|
|
633
|
+
const fixesByLine = new Map<
|
|
634
|
+
number,
|
|
635
|
+
Array<{
|
|
636
|
+
description: string;
|
|
637
|
+
changes: Array<{
|
|
638
|
+
fileName: string;
|
|
639
|
+
textChanges: ReadonlyArray<{
|
|
640
|
+
span: { start: number; length: number };
|
|
641
|
+
newText: string;
|
|
642
|
+
}>;
|
|
643
|
+
}>;
|
|
644
|
+
}>
|
|
645
|
+
>();
|
|
646
|
+
|
|
647
|
+
const diagnostics = this.getDiagnostics(filePath);
|
|
648
|
+
for (const diag of diagnostics) {
|
|
649
|
+
if (diag.severity !== 1 || diag.code === undefined) continue;
|
|
650
|
+
const fixes = this.getCodeFixes(
|
|
651
|
+
filePath,
|
|
652
|
+
diag.range.start.line,
|
|
653
|
+
diag.range.start.character,
|
|
654
|
+
[diag.code as number],
|
|
655
|
+
);
|
|
656
|
+
if (fixes.length > 0) {
|
|
657
|
+
fixesByLine.set(diag.range.start.line, fixes);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
return fixesByLine;
|
|
661
|
+
}
|
|
662
|
+
|
|
565
663
|
private symbolKind(kind: string): string {
|
|
566
664
|
const map: Record<string, string> = {
|
|
567
665
|
script: "file",
|