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
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
import { spawnSync } from "node:child_process";
|
|
11
11
|
import * as fs from "node:fs";
|
|
12
|
+
import * as path from "node:path";
|
|
13
|
+
import { safeSpawn } from "../../safe-spawn.js";
|
|
12
14
|
import type {
|
|
13
15
|
Diagnostic,
|
|
14
16
|
DispatchContext,
|
|
@@ -16,6 +18,27 @@ import type {
|
|
|
16
18
|
RunnerResult,
|
|
17
19
|
} from "../types.js";
|
|
18
20
|
|
|
21
|
+
// Simple YAML fix: field extractor
|
|
22
|
+
function extractFixFromRule(ruleId: string, ruleDir: string): string | undefined {
|
|
23
|
+
try {
|
|
24
|
+
const rulePath = `${ruleDir}/${ruleId}.yml`;
|
|
25
|
+
if (!fs.existsSync(rulePath)) return undefined;
|
|
26
|
+
|
|
27
|
+
const content = fs.readFileSync(rulePath, "utf-8");
|
|
28
|
+
const fixMatch = content.match(/^fix:\s*\|?([\s\S]*?)(?=^\w|^rule:|\Z)/m);
|
|
29
|
+
if (fixMatch) {
|
|
30
|
+
return fixMatch[1]
|
|
31
|
+
.split("\n")
|
|
32
|
+
.map((line) => line.replace(/^\s*\|?\s*/, ""))
|
|
33
|
+
.filter((line) => line.length > 0)
|
|
34
|
+
.join("\n");
|
|
35
|
+
}
|
|
36
|
+
} catch {
|
|
37
|
+
// Ignore errors
|
|
38
|
+
}
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
|
|
19
42
|
const astGrepRunner: RunnerDefinition = {
|
|
20
43
|
id: "ast-grep",
|
|
21
44
|
appliesTo: ["jsts", "python", "go", "rust", "cxx"],
|
|
@@ -24,11 +47,9 @@ const astGrepRunner: RunnerDefinition = {
|
|
|
24
47
|
skipTestFiles: true, // Many rules are noisy in tests
|
|
25
48
|
|
|
26
49
|
async run(ctx: DispatchContext): Promise<RunnerResult> {
|
|
27
|
-
// Check if ast-grep is available
|
|
28
|
-
const check =
|
|
29
|
-
encoding: "utf-8",
|
|
50
|
+
// Check if ast-grep is available (use npx for local installs)
|
|
51
|
+
const check = safeSpawn("npx", ["sg", "--version"], {
|
|
30
52
|
timeout: 5000,
|
|
31
|
-
shell: true,
|
|
32
53
|
});
|
|
33
54
|
|
|
34
55
|
if (check.error || check.status !== 0) {
|
|
@@ -41,13 +62,11 @@ const astGrepRunner: RunnerDefinition = {
|
|
|
41
62
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
42
63
|
}
|
|
43
64
|
|
|
44
|
-
// Run ast-grep scan on the file
|
|
45
|
-
const args = ["scan", "--config", configPath, "--json", ctx.filePath];
|
|
65
|
+
// Run ast-grep scan on the file (use npx for local installs)
|
|
66
|
+
const args = ["sg", "scan", "--config", configPath, "--json", ctx.filePath];
|
|
46
67
|
|
|
47
|
-
const result =
|
|
48
|
-
encoding: "utf-8",
|
|
68
|
+
const result = safeSpawn("npx", args, {
|
|
49
69
|
timeout: 30000,
|
|
50
|
-
shell: true,
|
|
51
70
|
});
|
|
52
71
|
|
|
53
72
|
const raw = result.stdout + result.stderr;
|
|
@@ -57,7 +76,7 @@ const astGrepRunner: RunnerDefinition = {
|
|
|
57
76
|
}
|
|
58
77
|
|
|
59
78
|
// Parse results
|
|
60
|
-
const diagnostics = parseAstGrepOutput(raw, ctx.filePath);
|
|
79
|
+
const diagnostics = parseAstGrepOutput(raw, ctx.filePath, configPath);
|
|
61
80
|
|
|
62
81
|
if (diagnostics.length === 0) {
|
|
63
82
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
@@ -88,28 +107,61 @@ function findAstGrepConfig(cwd: string): string | undefined {
|
|
|
88
107
|
return undefined;
|
|
89
108
|
}
|
|
90
109
|
|
|
91
|
-
function parseAstGrepOutput(
|
|
110
|
+
function parseAstGrepOutput(
|
|
111
|
+
raw: string,
|
|
112
|
+
filePath: string,
|
|
113
|
+
_configPath?: string,
|
|
114
|
+
): Diagnostic[] {
|
|
92
115
|
const diagnostics: Diagnostic[] = [];
|
|
93
116
|
|
|
94
117
|
// Try to parse as JSON
|
|
118
|
+
// Determine rule directory for fix: extraction
|
|
119
|
+
const ruleDir = _configPath
|
|
120
|
+
? path.dirname(_configPath).replace("/.sgconfig.yml", "/rules")
|
|
121
|
+
: path.join(process.cwd(), "rules", "ast-grep-rules", "rules");
|
|
122
|
+
|
|
95
123
|
try {
|
|
96
124
|
const parsed = JSON.parse(raw);
|
|
97
125
|
if (Array.isArray(parsed)) {
|
|
98
126
|
for (const item of parsed) {
|
|
99
127
|
const line = item.range?.start?.line || 1;
|
|
128
|
+
const ruleId = item.rule || "unknown";
|
|
129
|
+
|
|
130
|
+
// Build message with inline fix suggestion
|
|
131
|
+
let message = item.message || item.lines || "";
|
|
132
|
+
let fixSuggestion: string | undefined;
|
|
133
|
+
|
|
134
|
+
if (item.replacement) {
|
|
135
|
+
// Show the actual code change inline in the message
|
|
136
|
+
const replacementPreview =
|
|
137
|
+
item.replacement.length > 40
|
|
138
|
+
? `${item.replacement.substring(0, 40)}...`
|
|
139
|
+
: item.replacement;
|
|
140
|
+
message += `\n💡 Suggested fix: → "${replacementPreview}"`;
|
|
141
|
+
fixSuggestion = `Replace with: ${item.replacement}`;
|
|
142
|
+
} else {
|
|
143
|
+
// Try to get fix: from rule YAML
|
|
144
|
+
const ruleFix = extractFixFromRule(ruleId, ruleDir);
|
|
145
|
+
if (ruleFix) {
|
|
146
|
+
const fixPreview = ruleFix.length > 60
|
|
147
|
+
? `${ruleFix.substring(0, 60)}...`
|
|
148
|
+
: ruleFix;
|
|
149
|
+
message += `\n💡 Suggested fix:\n${fixPreview}`;
|
|
150
|
+
fixSuggestion = ruleFix;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
100
154
|
diagnostics.push({
|
|
101
|
-
id: `ast-grep-${line}-${
|
|
102
|
-
message
|
|
155
|
+
id: `ast-grep-${line}-${ruleId}`,
|
|
156
|
+
message,
|
|
103
157
|
filePath,
|
|
104
158
|
line,
|
|
105
159
|
severity: item.severity === "error" ? "error" : "warning",
|
|
106
160
|
semantic: item.severity === "error" ? "blocking" : "warning",
|
|
107
161
|
tool: "ast-grep",
|
|
108
|
-
rule:
|
|
109
|
-
fixable: !!item.replacement,
|
|
110
|
-
fixSuggestion
|
|
111
|
-
? "Run `sg fix` to auto-fix"
|
|
112
|
-
: undefined,
|
|
162
|
+
rule: ruleId,
|
|
163
|
+
fixable: !!item.replacement || !!fixSuggestion,
|
|
164
|
+
fixSuggestion,
|
|
113
165
|
});
|
|
114
166
|
}
|
|
115
167
|
}
|
|
@@ -3,46 +3,49 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Requires: @biomejs/biome (npm install -D @biomejs/biome)
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
function isBiomeAvailable() {
|
|
10
|
-
if (biomeAvailable !== null)
|
|
11
|
-
return biomeAvailable;
|
|
12
|
-
// Check if biome CLI is available (do NOT auto-install via npx)
|
|
13
|
-
const check = spawnSync("biome", ["--version"], {
|
|
14
|
-
encoding: "utf-8",
|
|
15
|
-
timeout: 5000,
|
|
16
|
-
shell: true,
|
|
17
|
-
});
|
|
18
|
-
biomeAvailable = !check.error && check.status === 0;
|
|
19
|
-
return biomeAvailable;
|
|
20
|
-
}
|
|
6
|
+
import { safeSpawn } from "../../safe-spawn.js";
|
|
7
|
+
import { createBiomeParser } from "./utils/diagnostic-parsers.js";
|
|
8
|
+
import { biome } from "./utils/runner-helpers.js";
|
|
21
9
|
const biomeRunner = {
|
|
22
10
|
id: "biome-lint",
|
|
23
11
|
appliesTo: ["jsts", "json"],
|
|
24
12
|
priority: 10,
|
|
25
13
|
enabledByDefault: true,
|
|
26
14
|
async run(ctx) {
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
15
|
+
// Check if biome is available (via PATH, venv, or npx)
|
|
16
|
+
let cmd = biome.getCommand();
|
|
17
|
+
let useNpx = false;
|
|
18
|
+
if (!cmd || !biome.isAvailable(ctx.cwd)) {
|
|
19
|
+
// Try npx as fallback
|
|
20
|
+
const npxCheck = safeSpawn("npx", ["biome", "--version"], {
|
|
21
|
+
timeout: 5000,
|
|
22
|
+
});
|
|
23
|
+
if (!npxCheck.error && npxCheck.status === 0) {
|
|
24
|
+
cmd = "npx";
|
|
25
|
+
useNpx = true;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
29
|
+
}
|
|
30
30
|
}
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
// IMPORTANT: Never use --write in dispatch runner to prevent infinite loops.
|
|
32
|
+
// Writing to the file would trigger another tool_result event, which would
|
|
33
|
+
// call dispatchLint again, creating a feedback loop.
|
|
34
|
+
// Use /lens-format command for explicit formatting, or autofix flags on
|
|
35
|
+
// the write/edit tools directly.
|
|
36
|
+
const args = useNpx
|
|
37
|
+
? ["biome", "check", ctx.filePath]
|
|
34
38
|
: ["check", ctx.filePath];
|
|
35
|
-
const result =
|
|
36
|
-
encoding: "utf-8",
|
|
39
|
+
const result = safeSpawn(cmd, args, {
|
|
37
40
|
timeout: 30000,
|
|
38
|
-
shell: true,
|
|
39
41
|
});
|
|
40
42
|
const output = result.stdout + result.stderr;
|
|
41
43
|
if (result.status === 0) {
|
|
42
44
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
43
45
|
}
|
|
44
|
-
// Parse diagnostics
|
|
45
|
-
const
|
|
46
|
+
// Parse diagnostics (never autofix in dispatch to prevent loops)
|
|
47
|
+
const parseBiomeOutput = createBiomeParser(false);
|
|
48
|
+
const diagnostics = parseBiomeOutput(output, ctx.filePath);
|
|
46
49
|
return {
|
|
47
50
|
status: "failed",
|
|
48
51
|
diagnostics,
|
|
@@ -50,31 +53,4 @@ const biomeRunner = {
|
|
|
50
53
|
};
|
|
51
54
|
},
|
|
52
55
|
};
|
|
53
|
-
function parseBiomeOutput(raw, filePath, autofix) {
|
|
54
|
-
const clean = raw.replace(/\x1b\[[0-9;]*m/g, "");
|
|
55
|
-
const lines = clean.split("\n").filter((l) => l.trim());
|
|
56
|
-
const diagnostics = [];
|
|
57
|
-
for (const line of lines) {
|
|
58
|
-
// Parse biome output format: file:line:col message (category)
|
|
59
|
-
const match = line.match(/^(.+?):(\d+):(\d+)\s+(.+?)\s*\((.+?)\)/);
|
|
60
|
-
if (match) {
|
|
61
|
-
diagnostics.push({
|
|
62
|
-
id: `biome-${match[2]}-${match[5]}`,
|
|
63
|
-
message: `${match[5]}: ${match[4]}`,
|
|
64
|
-
filePath,
|
|
65
|
-
line: parseInt(match[2], 10),
|
|
66
|
-
column: parseInt(match[3], 10),
|
|
67
|
-
severity: line.includes("error") ? "error" : "warning",
|
|
68
|
-
semantic: "warning",
|
|
69
|
-
tool: "biome",
|
|
70
|
-
rule: match[5],
|
|
71
|
-
fixable: true,
|
|
72
|
-
fixSuggestion: autofix
|
|
73
|
-
? "Auto-fix applied"
|
|
74
|
-
: "Run with --autofix-biome to fix",
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return diagnostics;
|
|
79
|
-
}
|
|
80
56
|
export default biomeRunner;
|
|
@@ -4,29 +4,14 @@
|
|
|
4
4
|
* Requires: @biomejs/biome (npm install -D @biomejs/biome)
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { safeSpawn } from "../../safe-spawn.js";
|
|
8
8
|
import type {
|
|
9
|
-
Diagnostic,
|
|
10
9
|
DispatchContext,
|
|
11
10
|
RunnerDefinition,
|
|
12
11
|
RunnerResult,
|
|
13
12
|
} from "../types.js";
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
let biomeAvailable: boolean | null = null;
|
|
17
|
-
|
|
18
|
-
function isBiomeAvailable(): boolean {
|
|
19
|
-
if (biomeAvailable !== null) return biomeAvailable;
|
|
20
|
-
|
|
21
|
-
// Check if biome CLI is available (do NOT auto-install via npx)
|
|
22
|
-
const check = spawnSync("biome", ["--version"], {
|
|
23
|
-
encoding: "utf-8",
|
|
24
|
-
timeout: 5000,
|
|
25
|
-
shell: true,
|
|
26
|
-
});
|
|
27
|
-
biomeAvailable = !check.error && check.status === 0;
|
|
28
|
-
return biomeAvailable;
|
|
29
|
-
}
|
|
13
|
+
import { createBiomeParser } from "./utils/diagnostic-parsers.js";
|
|
14
|
+
import { biome } from "./utils/runner-helpers.js";
|
|
30
15
|
|
|
31
16
|
const biomeRunner: RunnerDefinition = {
|
|
32
17
|
id: "biome-lint",
|
|
@@ -35,20 +20,34 @@ const biomeRunner: RunnerDefinition = {
|
|
|
35
20
|
enabledByDefault: true,
|
|
36
21
|
|
|
37
22
|
async run(ctx: DispatchContext): Promise<RunnerResult> {
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
|
|
23
|
+
// Check if biome is available (via PATH, venv, or npx)
|
|
24
|
+
let cmd = biome.getCommand();
|
|
25
|
+
let useNpx = false;
|
|
26
|
+
|
|
27
|
+
if (!cmd || !biome.isAvailable(ctx.cwd)) {
|
|
28
|
+
// Try npx as fallback
|
|
29
|
+
const npxCheck = safeSpawn("npx", ["biome", "--version"], {
|
|
30
|
+
timeout: 5000,
|
|
31
|
+
});
|
|
32
|
+
if (!npxCheck.error && npxCheck.status === 0) {
|
|
33
|
+
cmd = "npx";
|
|
34
|
+
useNpx = true;
|
|
35
|
+
} else {
|
|
36
|
+
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
37
|
+
}
|
|
41
38
|
}
|
|
42
39
|
|
|
43
|
-
//
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
// IMPORTANT: Never use --write in dispatch runner to prevent infinite loops.
|
|
41
|
+
// Writing to the file would trigger another tool_result event, which would
|
|
42
|
+
// call dispatchLint again, creating a feedback loop.
|
|
43
|
+
// Use /lens-format command for explicit formatting, or autofix flags on
|
|
44
|
+
// the write/edit tools directly.
|
|
45
|
+
const args = useNpx
|
|
46
|
+
? ["biome", "check", ctx.filePath]
|
|
46
47
|
: ["check", ctx.filePath];
|
|
47
48
|
|
|
48
|
-
const result =
|
|
49
|
-
encoding: "utf-8",
|
|
49
|
+
const result = safeSpawn(cmd, args, {
|
|
50
50
|
timeout: 30000,
|
|
51
|
-
shell: true,
|
|
52
51
|
});
|
|
53
52
|
|
|
54
53
|
const output = result.stdout + result.stderr;
|
|
@@ -57,8 +56,9 @@ const biomeRunner: RunnerDefinition = {
|
|
|
57
56
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
58
57
|
}
|
|
59
58
|
|
|
60
|
-
// Parse diagnostics
|
|
61
|
-
const
|
|
59
|
+
// Parse diagnostics (never autofix in dispatch to prevent loops)
|
|
60
|
+
const parseBiomeOutput = createBiomeParser(false);
|
|
61
|
+
const diagnostics = parseBiomeOutput(output, ctx.filePath);
|
|
62
62
|
|
|
63
63
|
return {
|
|
64
64
|
status: "failed",
|
|
@@ -68,38 +68,4 @@ const biomeRunner: RunnerDefinition = {
|
|
|
68
68
|
},
|
|
69
69
|
};
|
|
70
70
|
|
|
71
|
-
function parseBiomeOutput(
|
|
72
|
-
raw: string,
|
|
73
|
-
filePath: string,
|
|
74
|
-
autofix: boolean,
|
|
75
|
-
): Diagnostic[] {
|
|
76
|
-
const clean = raw.replace(/\x1b\[[0-9;]*m/g, "");
|
|
77
|
-
const lines = clean.split("\n").filter((l) => l.trim());
|
|
78
|
-
const diagnostics: Diagnostic[] = [];
|
|
79
|
-
|
|
80
|
-
for (const line of lines) {
|
|
81
|
-
// Parse biome output format: file:line:col message (category)
|
|
82
|
-
const match = line.match(/^(.+?):(\d+):(\d+)\s+(.+?)\s*\((.+?)\)/);
|
|
83
|
-
if (match) {
|
|
84
|
-
diagnostics.push({
|
|
85
|
-
id: `biome-${match[2]}-${match[5]}`,
|
|
86
|
-
message: `${match[5]}: ${match[4]}`,
|
|
87
|
-
filePath,
|
|
88
|
-
line: parseInt(match[2], 10),
|
|
89
|
-
column: parseInt(match[3], 10),
|
|
90
|
-
severity: line.includes("error") ? "error" : "warning",
|
|
91
|
-
semantic: "warning",
|
|
92
|
-
tool: "biome",
|
|
93
|
-
rule: match[5],
|
|
94
|
-
fixable: true,
|
|
95
|
-
fixSuggestion: autofix
|
|
96
|
-
? "Auto-fix applied"
|
|
97
|
-
: "Run with --autofix-biome to fix",
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return diagnostics;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
71
|
export default biomeRunner;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config Validation Runner
|
|
3
|
+
*
|
|
4
|
+
* Validates config/environment variable access against actual config files.
|
|
5
|
+
* Detects undefined keys, typos, and missing env vars.
|
|
6
|
+
*
|
|
7
|
+
* Uses Tree-sitter to find config access patterns in code and validates
|
|
8
|
+
* against parsed config files (.env, config.ini, config.yaml, etc.)
|
|
9
|
+
*/
|
|
10
|
+
import { createConfigValidator } from "../../config-validator.js";
|
|
11
|
+
const configValidationRunner = {
|
|
12
|
+
id: "config-validation",
|
|
13
|
+
appliesTo: ["jsts", "python", "go", "rust"],
|
|
14
|
+
priority: 8, // Run early, before other linters
|
|
15
|
+
enabledByDefault: true,
|
|
16
|
+
async run(ctx) {
|
|
17
|
+
// Only check supported file extensions
|
|
18
|
+
const ext = ctx.filePath.match(/\.(py|js|ts|tsx|go|rs)$/);
|
|
19
|
+
if (!ext) {
|
|
20
|
+
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const validator = await createConfigValidator(ctx.cwd);
|
|
24
|
+
const result = await validator.validateFile(ctx.filePath);
|
|
25
|
+
const diagnostics = [];
|
|
26
|
+
// Report undefined keys as warnings
|
|
27
|
+
for (const access of result.undefined) {
|
|
28
|
+
diagnostics.push({
|
|
29
|
+
id: `config-undefined:${access.key}`,
|
|
30
|
+
message: `Undefined config key: "${access.key}"`,
|
|
31
|
+
filePath: ctx.filePath,
|
|
32
|
+
line: access.line,
|
|
33
|
+
column: access.column,
|
|
34
|
+
severity: "warning",
|
|
35
|
+
semantic: "warning",
|
|
36
|
+
tool: "config-validation",
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
// Report typos with suggestion
|
|
40
|
+
for (const { access, suggestion } of result.typos) {
|
|
41
|
+
diagnostics.push({
|
|
42
|
+
id: `config-typo:${access.key}`,
|
|
43
|
+
message: `Possible typo: "${access.key}" — did you mean "${suggestion}"?`,
|
|
44
|
+
filePath: ctx.filePath,
|
|
45
|
+
line: access.line,
|
|
46
|
+
column: access.column,
|
|
47
|
+
severity: "warning",
|
|
48
|
+
semantic: "warning",
|
|
49
|
+
tool: "config-validation",
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
if (diagnostics.length === 0) {
|
|
53
|
+
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
status: "failed",
|
|
57
|
+
diagnostics,
|
|
58
|
+
semantic: "warning",
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
catch (_err) {
|
|
62
|
+
// Silently fail if validator can't run (e.g., tree-sitter not available)
|
|
63
|
+
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
export default configValidationRunner;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config Validation Runner
|
|
3
|
+
*
|
|
4
|
+
* Validates config/environment variable access against actual config files.
|
|
5
|
+
* Detects undefined keys, typos, and missing env vars.
|
|
6
|
+
*
|
|
7
|
+
* Uses Tree-sitter to find config access patterns in code and validates
|
|
8
|
+
* against parsed config files (.env, config.ini, config.yaml, etc.)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { createConfigValidator } from "../../config-validator.js";
|
|
12
|
+
import type {
|
|
13
|
+
Diagnostic,
|
|
14
|
+
DispatchContext,
|
|
15
|
+
RunnerDefinition,
|
|
16
|
+
RunnerResult,
|
|
17
|
+
} from "../types.js";
|
|
18
|
+
|
|
19
|
+
const configValidationRunner: RunnerDefinition = {
|
|
20
|
+
id: "config-validation",
|
|
21
|
+
appliesTo: ["jsts", "python", "go", "rust"],
|
|
22
|
+
priority: 8, // Run early, before other linters
|
|
23
|
+
enabledByDefault: true,
|
|
24
|
+
|
|
25
|
+
async run(ctx: DispatchContext): Promise<RunnerResult> {
|
|
26
|
+
// Only check supported file extensions
|
|
27
|
+
const ext = ctx.filePath.match(/\.(py|js|ts|tsx|go|rs)$/);
|
|
28
|
+
if (!ext) {
|
|
29
|
+
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const validator = await createConfigValidator(ctx.cwd);
|
|
34
|
+
const result = await validator.validateFile(ctx.filePath);
|
|
35
|
+
|
|
36
|
+
const diagnostics: Diagnostic[] = [];
|
|
37
|
+
|
|
38
|
+
// Report undefined keys as warnings
|
|
39
|
+
for (const access of result.undefined) {
|
|
40
|
+
diagnostics.push({
|
|
41
|
+
id: `config-undefined:${access.key}`,
|
|
42
|
+
message: `Undefined config key: "${access.key}"`,
|
|
43
|
+
filePath: ctx.filePath,
|
|
44
|
+
line: access.line,
|
|
45
|
+
column: access.column,
|
|
46
|
+
severity: "warning",
|
|
47
|
+
semantic: "warning",
|
|
48
|
+
tool: "config-validation",
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Report typos with suggestion
|
|
53
|
+
for (const { access, suggestion } of result.typos) {
|
|
54
|
+
diagnostics.push({
|
|
55
|
+
id: `config-typo:${access.key}`,
|
|
56
|
+
message: `Possible typo: "${access.key}" — did you mean "${suggestion}"?`,
|
|
57
|
+
filePath: ctx.filePath,
|
|
58
|
+
line: access.line,
|
|
59
|
+
column: access.column,
|
|
60
|
+
severity: "warning",
|
|
61
|
+
semantic: "warning",
|
|
62
|
+
tool: "config-validation",
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (diagnostics.length === 0) {
|
|
67
|
+
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
status: "failed",
|
|
72
|
+
diagnostics,
|
|
73
|
+
semantic: "warning",
|
|
74
|
+
};
|
|
75
|
+
} catch (_err) {
|
|
76
|
+
// Silently fail if validator can't run (e.g., tree-sitter not available)
|
|
77
|
+
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export default configValidationRunner;
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Runs `go vet` for Go files to catch common mistakes.
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import { safeSpawn } from "../../safe-spawn.js";
|
|
7
7
|
import { stripAnsi } from "../../sanitize.js";
|
|
8
|
+
import { parseGoVetOutput } from "./utils/diagnostic-parsers.js";
|
|
8
9
|
const goVetRunner = {
|
|
9
10
|
id: "go-vet",
|
|
10
11
|
appliesTo: ["go"],
|
|
@@ -12,19 +13,15 @@ const goVetRunner = {
|
|
|
12
13
|
enabledByDefault: true,
|
|
13
14
|
async run(ctx) {
|
|
14
15
|
// Check if go is available
|
|
15
|
-
const check =
|
|
16
|
-
encoding: "utf-8",
|
|
16
|
+
const check = safeSpawn("go", ["version"], {
|
|
17
17
|
timeout: 5000,
|
|
18
|
-
shell: true,
|
|
19
18
|
});
|
|
20
19
|
if (check.error || check.status !== 0) {
|
|
21
20
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
22
21
|
}
|
|
23
22
|
// Run go vet on the file
|
|
24
|
-
const result =
|
|
25
|
-
encoding: "utf-8",
|
|
23
|
+
const result = safeSpawn("go", ["vet", ctx.filePath], {
|
|
26
24
|
timeout: 30000,
|
|
27
|
-
shell: true,
|
|
28
25
|
});
|
|
29
26
|
const raw = stripAnsi(result.stdout + result.stderr);
|
|
30
27
|
if (result.status === 0 && !raw.trim()) {
|
|
@@ -48,25 +45,4 @@ const goVetRunner = {
|
|
|
48
45
|
};
|
|
49
46
|
},
|
|
50
47
|
};
|
|
51
|
-
function parseGoVetOutput(raw, filePath) {
|
|
52
|
-
const diagnostics = [];
|
|
53
|
-
const lines = raw.split("\n");
|
|
54
|
-
for (const line of lines) {
|
|
55
|
-
// Parse go vet output: file:line:col: message
|
|
56
|
-
const match = line.match(/^(.+?):(\d+):(\d+):\s*(.+)/);
|
|
57
|
-
if (match) {
|
|
58
|
-
diagnostics.push({
|
|
59
|
-
id: `go-vet-${match[2]}`,
|
|
60
|
-
message: match[4],
|
|
61
|
-
filePath,
|
|
62
|
-
line: parseInt(match[2], 10),
|
|
63
|
-
column: parseInt(match[3], 10),
|
|
64
|
-
severity: "warning",
|
|
65
|
-
semantic: "warning",
|
|
66
|
-
tool: "go-vet",
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
return diagnostics;
|
|
71
|
-
}
|
|
72
48
|
export default goVetRunner;
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
* Runs `go vet` for Go files to catch common mistakes.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { safeSpawn } from "../../safe-spawn.js";
|
|
8
8
|
import { stripAnsi } from "../../sanitize.js";
|
|
9
|
+
import { parseGoVetOutput } from "./utils/diagnostic-parsers.js";
|
|
9
10
|
import type {
|
|
10
|
-
Diagnostic,
|
|
11
11
|
DispatchContext,
|
|
12
12
|
RunnerDefinition,
|
|
13
13
|
RunnerResult,
|
|
@@ -21,10 +21,8 @@ const goVetRunner: RunnerDefinition = {
|
|
|
21
21
|
|
|
22
22
|
async run(ctx: DispatchContext): Promise<RunnerResult> {
|
|
23
23
|
// Check if go is available
|
|
24
|
-
const check =
|
|
25
|
-
encoding: "utf-8",
|
|
24
|
+
const check = safeSpawn("go", ["version"], {
|
|
26
25
|
timeout: 5000,
|
|
27
|
-
shell: true,
|
|
28
26
|
});
|
|
29
27
|
|
|
30
28
|
if (check.error || check.status !== 0) {
|
|
@@ -32,10 +30,8 @@ const goVetRunner: RunnerDefinition = {
|
|
|
32
30
|
}
|
|
33
31
|
|
|
34
32
|
// Run go vet on the file
|
|
35
|
-
const result =
|
|
36
|
-
encoding: "utf-8",
|
|
33
|
+
const result = safeSpawn("go", ["vet", ctx.filePath], {
|
|
37
34
|
timeout: 30000,
|
|
38
|
-
shell: true,
|
|
39
35
|
});
|
|
40
36
|
|
|
41
37
|
const raw = stripAnsi(result.stdout + result.stderr);
|
|
@@ -65,28 +61,4 @@ const goVetRunner: RunnerDefinition = {
|
|
|
65
61
|
},
|
|
66
62
|
};
|
|
67
63
|
|
|
68
|
-
function parseGoVetOutput(raw: string, filePath: string): Diagnostic[] {
|
|
69
|
-
const diagnostics: Diagnostic[] = [];
|
|
70
|
-
const lines = raw.split("\n");
|
|
71
|
-
|
|
72
|
-
for (const line of lines) {
|
|
73
|
-
// Parse go vet output: file:line:col: message
|
|
74
|
-
const match = line.match(/^(.+?):(\d+):(\d+):\s*(.+)/);
|
|
75
|
-
if (match) {
|
|
76
|
-
diagnostics.push({
|
|
77
|
-
id: `go-vet-${match[2]}`,
|
|
78
|
-
message: match[4],
|
|
79
|
-
filePath,
|
|
80
|
-
line: parseInt(match[2], 10),
|
|
81
|
-
column: parseInt(match[3], 10),
|
|
82
|
-
severity: "warning",
|
|
83
|
-
semantic: "warning",
|
|
84
|
-
tool: "go-vet",
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return diagnostics;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
64
|
export default goVetRunner;
|