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
|
@@ -3,22 +3,42 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { registerRunner } from "../dispatcher.js";
|
|
5
5
|
import architectRunner from "./architect.js";
|
|
6
|
-
// Import all runners
|
|
7
6
|
import astGrepRunner from "./ast-grep.js";
|
|
7
|
+
// Import all runners
|
|
8
|
+
import astGrepNapiRunner from "./ast-grep-napi.js";
|
|
8
9
|
import biomeRunner from "./biome.js";
|
|
10
|
+
import configValidationRunner from "./config-validation.js";
|
|
9
11
|
import goVetRunner from "./go-vet.js";
|
|
12
|
+
import oxlintRunner from "./oxlint.js";
|
|
10
13
|
import pyrightRunner from "./pyright.js";
|
|
14
|
+
import pythonSlopRunner from "./python-slop.js";
|
|
11
15
|
import ruffRunner from "./ruff.js";
|
|
12
16
|
import rustClippyRunner from "./rust-clippy.js";
|
|
17
|
+
import shellcheckRunner from "./shellcheck.js";
|
|
18
|
+
// Import similarity runner
|
|
19
|
+
import similarityRunner from "./similarity.js";
|
|
20
|
+
import spellcheckRunner from "./spellcheck.js";
|
|
21
|
+
// Import tree-sitter runner
|
|
22
|
+
import treeSitterRunner from "./tree-sitter.js";
|
|
13
23
|
import tsLspRunner from "./ts-lsp.js";
|
|
24
|
+
import tsSlopRunner from "./ts-slop.js";
|
|
14
25
|
import typeSafetyRunner from "./type-safety.js";
|
|
15
26
|
// Register all runners (ordered by priority)
|
|
16
|
-
registerRunner(tsLspRunner); // TypeScript type-checking
|
|
17
|
-
registerRunner(pyrightRunner); // Python type-checking
|
|
18
|
-
registerRunner(
|
|
19
|
-
registerRunner(
|
|
20
|
-
registerRunner(
|
|
21
|
-
registerRunner(
|
|
22
|
-
registerRunner(
|
|
23
|
-
registerRunner(
|
|
24
|
-
registerRunner(
|
|
27
|
+
registerRunner(tsLspRunner); // TypeScript type-checking (priority 5)
|
|
28
|
+
registerRunner(pyrightRunner); // Python type-checking (priority 5)
|
|
29
|
+
registerRunner(configValidationRunner); // Config/env validation (priority 8)
|
|
30
|
+
registerRunner(astGrepNapiRunner); // TS/JS structural analysis via NAPI (priority 15)
|
|
31
|
+
registerRunner(biomeRunner); // Biome formatting/linting (priority 10)
|
|
32
|
+
registerRunner(oxlintRunner); // Oxlint fast JS/TS linter (priority 12)
|
|
33
|
+
registerRunner(treeSitterRunner); // Tree-sitter structural analysis (priority 14)
|
|
34
|
+
registerRunner(ruffRunner); // Python linting (priority 10)
|
|
35
|
+
registerRunner(tsSlopRunner); // DISABLED - TypeScript slop via CLI (disabled, use NAPI)
|
|
36
|
+
registerRunner(pythonSlopRunner); // Python slop via CLI (priority 25)
|
|
37
|
+
registerRunner(typeSafetyRunner); // Type safety checks (priority 20)
|
|
38
|
+
registerRunner(shellcheckRunner); // Shell script linting (priority 20)
|
|
39
|
+
registerRunner(astGrepRunner); // Other languages via CLI (priority 30)
|
|
40
|
+
registerRunner(similarityRunner); // Semantic reuse detection (priority 35)
|
|
41
|
+
registerRunner(architectRunner); // Architectural rules (priority 40)
|
|
42
|
+
registerRunner(spellcheckRunner); // Spellcheck for markdown/docs (priority 30)
|
|
43
|
+
registerRunner(goVetRunner); // Go analysis (priority 50)
|
|
44
|
+
registerRunner(rustClippyRunner); // Rust analysis (priority 50)
|
|
@@ -4,23 +4,43 @@
|
|
|
4
4
|
|
|
5
5
|
import { registerRunner } from "../dispatcher.js";
|
|
6
6
|
import architectRunner from "./architect.js";
|
|
7
|
-
// Import all runners
|
|
8
7
|
import astGrepRunner from "./ast-grep.js";
|
|
8
|
+
// Import all runners
|
|
9
|
+
import astGrepNapiRunner from "./ast-grep-napi.js";
|
|
9
10
|
import biomeRunner from "./biome.js";
|
|
11
|
+
import configValidationRunner from "./config-validation.js";
|
|
10
12
|
import goVetRunner from "./go-vet.js";
|
|
13
|
+
import oxlintRunner from "./oxlint.js";
|
|
11
14
|
import pyrightRunner from "./pyright.js";
|
|
15
|
+
import pythonSlopRunner from "./python-slop.js";
|
|
12
16
|
import ruffRunner from "./ruff.js";
|
|
13
17
|
import rustClippyRunner from "./rust-clippy.js";
|
|
18
|
+
import shellcheckRunner from "./shellcheck.js";
|
|
19
|
+
// Import similarity runner
|
|
20
|
+
import similarityRunner from "./similarity.js";
|
|
21
|
+
import spellcheckRunner from "./spellcheck.js";
|
|
22
|
+
// Import tree-sitter runner
|
|
23
|
+
import treeSitterRunner from "./tree-sitter.js";
|
|
14
24
|
import tsLspRunner from "./ts-lsp.js";
|
|
25
|
+
import tsSlopRunner from "./ts-slop.js";
|
|
15
26
|
import typeSafetyRunner from "./type-safety.js";
|
|
16
27
|
|
|
17
28
|
// Register all runners (ordered by priority)
|
|
18
|
-
registerRunner(tsLspRunner); // TypeScript type-checking
|
|
19
|
-
registerRunner(pyrightRunner); // Python type-checking
|
|
20
|
-
registerRunner(
|
|
21
|
-
registerRunner(
|
|
22
|
-
registerRunner(
|
|
23
|
-
registerRunner(
|
|
24
|
-
registerRunner(
|
|
25
|
-
registerRunner(
|
|
26
|
-
registerRunner(
|
|
29
|
+
registerRunner(tsLspRunner); // TypeScript type-checking (priority 5)
|
|
30
|
+
registerRunner(pyrightRunner); // Python type-checking (priority 5)
|
|
31
|
+
registerRunner(configValidationRunner); // Config/env validation (priority 8)
|
|
32
|
+
registerRunner(astGrepNapiRunner); // TS/JS structural analysis via NAPI (priority 15)
|
|
33
|
+
registerRunner(biomeRunner); // Biome formatting/linting (priority 10)
|
|
34
|
+
registerRunner(oxlintRunner); // Oxlint fast JS/TS linter (priority 12)
|
|
35
|
+
registerRunner(treeSitterRunner); // Tree-sitter structural analysis (priority 14)
|
|
36
|
+
registerRunner(ruffRunner); // Python linting (priority 10)
|
|
37
|
+
registerRunner(tsSlopRunner); // DISABLED - TypeScript slop via CLI (disabled, use NAPI)
|
|
38
|
+
registerRunner(pythonSlopRunner); // Python slop via CLI (priority 25)
|
|
39
|
+
registerRunner(typeSafetyRunner); // Type safety checks (priority 20)
|
|
40
|
+
registerRunner(shellcheckRunner); // Shell script linting (priority 20)
|
|
41
|
+
registerRunner(astGrepRunner); // Other languages via CLI (priority 30)
|
|
42
|
+
registerRunner(similarityRunner); // Semantic reuse detection (priority 35)
|
|
43
|
+
registerRunner(architectRunner); // Architectural rules (priority 40)
|
|
44
|
+
registerRunner(spellcheckRunner); // Spellcheck for markdown/docs (priority 30)
|
|
45
|
+
registerRunner(goVetRunner); // Go analysis (priority 50)
|
|
46
|
+
registerRunner(rustClippyRunner); // Rust analysis (priority 50)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Oxlint runner for dispatch system
|
|
3
|
+
*
|
|
4
|
+
* Fast Rust-based JavaScript/TypeScript linter from the Oxc project.
|
|
5
|
+
* Zero-config by default, compatible with ESLint rules.
|
|
6
|
+
*
|
|
7
|
+
* Why oxlint?
|
|
8
|
+
* - ~100x faster than ESLint (Rust-based)
|
|
9
|
+
* - Zero-config (works out of the box)
|
|
10
|
+
* - Growing rule set (eslint, typescript, react, unicorn, etc.)
|
|
11
|
+
* - JSON output for programmatic use
|
|
12
|
+
*
|
|
13
|
+
* Comparison:
|
|
14
|
+
* - vs Biome: Similar performance, different rule philosophy
|
|
15
|
+
* - vs ESLint: Much faster, fewer rules but catching up
|
|
16
|
+
*
|
|
17
|
+
* Install: npm install -D oxlint
|
|
18
|
+
* Or: cargo install oxlint
|
|
19
|
+
*
|
|
20
|
+
* Config: .oxlintrc.json (optional, zero-config works)
|
|
21
|
+
*/
|
|
22
|
+
import { safeSpawn } from "../../safe-spawn.js";
|
|
23
|
+
import { createAvailabilityChecker, createConfigFinder } from "./utils/runner-helpers.js";
|
|
24
|
+
const oxlint = createAvailabilityChecker("oxlint", ".exe");
|
|
25
|
+
const findOxlintConfig = createConfigFinder(".oxlintrc.json");
|
|
26
|
+
/**
|
|
27
|
+
* Parse oxlint JSON output
|
|
28
|
+
*
|
|
29
|
+
* Format: Array of diagnostic objects
|
|
30
|
+
* [{
|
|
31
|
+
* "ruleId": "no-unused-vars",
|
|
32
|
+
* "severity": 2,
|
|
33
|
+
* "message": "'foo' is assigned a value but never used.",
|
|
34
|
+
* "line": 10,
|
|
35
|
+
* "column": 7,
|
|
36
|
+
* "nodeType": "Identifier",
|
|
37
|
+
* "messageId": "unusedVar",
|
|
38
|
+
* "endLine": 10,
|
|
39
|
+
* "endColumn": 10,
|
|
40
|
+
* "fix": { "range": [95, 108], "text": "" }
|
|
41
|
+
* }]
|
|
42
|
+
*/
|
|
43
|
+
function parseOxlintOutput(raw, filePath) {
|
|
44
|
+
const diagnostics = [];
|
|
45
|
+
if (!raw.trim()) {
|
|
46
|
+
return diagnostics;
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const parsed = JSON.parse(raw);
|
|
50
|
+
if (!Array.isArray(parsed)) {
|
|
51
|
+
return diagnostics;
|
|
52
|
+
}
|
|
53
|
+
for (const item of parsed) {
|
|
54
|
+
if (!item.message || !item.line)
|
|
55
|
+
continue;
|
|
56
|
+
const severity = item.severity === 2 ? "error" : "warning";
|
|
57
|
+
diagnostics.push({
|
|
58
|
+
id: `oxlint-${item.line}-${item.ruleId || "unknown"}`,
|
|
59
|
+
message: item.message,
|
|
60
|
+
filePath,
|
|
61
|
+
line: item.line,
|
|
62
|
+
column: item.column || 1,
|
|
63
|
+
severity,
|
|
64
|
+
semantic: severity === "error" ? "blocking" : "warning",
|
|
65
|
+
tool: "oxlint",
|
|
66
|
+
rule: item.ruleId,
|
|
67
|
+
fixable: !!item.fix,
|
|
68
|
+
fixSuggestion: item.fix?.text,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// If JSON parsing fails, try line-based parsing for CLI output
|
|
74
|
+
const lines = raw.split("\n").filter((l) => l.trim());
|
|
75
|
+
for (const line of lines) {
|
|
76
|
+
// Try to match: file.ts:10:7: Error message [ruleId]
|
|
77
|
+
const match = line.match(/^(\d+):(\d+)\s+(.+?)\s*\[(\w+)\]$/);
|
|
78
|
+
if (match) {
|
|
79
|
+
diagnostics.push({
|
|
80
|
+
id: `oxlint-${match[1]}-${match[4]}`,
|
|
81
|
+
message: `${match[4]}: ${match[3]}`,
|
|
82
|
+
filePath,
|
|
83
|
+
line: parseInt(match[1], 10),
|
|
84
|
+
column: parseInt(match[2], 10),
|
|
85
|
+
severity: "warning",
|
|
86
|
+
semantic: "warning",
|
|
87
|
+
tool: "oxlint",
|
|
88
|
+
rule: match[4],
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return diagnostics;
|
|
94
|
+
}
|
|
95
|
+
const oxlintRunner = {
|
|
96
|
+
id: "oxlint",
|
|
97
|
+
appliesTo: ["jsts"],
|
|
98
|
+
priority: 12, // Between biome (10) and slop (25)
|
|
99
|
+
enabledByDefault: false, // Opt-in initially - let users choose between biome/oxlint
|
|
100
|
+
skipTestFiles: true, // Test files often use patterns that trigger false positives
|
|
101
|
+
async run(ctx) {
|
|
102
|
+
// Skip if oxlint is not installed
|
|
103
|
+
if (!oxlint.isAvailable(ctx.cwd || process.cwd())) {
|
|
104
|
+
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
105
|
+
}
|
|
106
|
+
// Check if user explicitly disabled oxlint (keep biome as primary)
|
|
107
|
+
if (ctx.pi.getFlag("no-oxlint")) {
|
|
108
|
+
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
109
|
+
}
|
|
110
|
+
// Build args
|
|
111
|
+
// --format json: JSON output
|
|
112
|
+
// --config: Only if config file exists (zero-config otherwise)
|
|
113
|
+
const args = ["--format", "json"];
|
|
114
|
+
// Check for config file
|
|
115
|
+
const configPath = findOxlintConfig(ctx.cwd);
|
|
116
|
+
if (configPath) {
|
|
117
|
+
args.push("--config", configPath);
|
|
118
|
+
}
|
|
119
|
+
// Add file path
|
|
120
|
+
args.push(ctx.filePath);
|
|
121
|
+
const result = safeSpawn(oxlint.getCommand(), args, {
|
|
122
|
+
timeout: 10000, // Fast - should complete quickly
|
|
123
|
+
});
|
|
124
|
+
// oxlint exits with code 1 if issues found, 0 if clean
|
|
125
|
+
if (result.status === 0 && !result.stdout?.trim()) {
|
|
126
|
+
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
127
|
+
}
|
|
128
|
+
// Parse diagnostics
|
|
129
|
+
const raw = result.stdout + result.stderr;
|
|
130
|
+
const diagnostics = parseOxlintOutput(raw, ctx.filePath);
|
|
131
|
+
if (diagnostics.length === 0) {
|
|
132
|
+
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
status: "failed",
|
|
136
|
+
diagnostics,
|
|
137
|
+
semantic: "warning",
|
|
138
|
+
};
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
export default oxlintRunner;
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for oxlint runner
|
|
3
|
+
*/
|
|
4
|
+
import * as fs from "node:fs";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
6
|
+
import * as path from "node:path";
|
|
7
|
+
import { describe, expect, it } from "vitest";
|
|
8
|
+
/**
|
|
9
|
+
* Delay helper for Windows file cleanup
|
|
10
|
+
* Windows may hold file handles briefly after process exit
|
|
11
|
+
*/
|
|
12
|
+
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
13
|
+
function createMockContext(filePath, overrides = {}) {
|
|
14
|
+
return {
|
|
15
|
+
filePath,
|
|
16
|
+
cwd: process.cwd(),
|
|
17
|
+
kind: "jsts",
|
|
18
|
+
autofix: false,
|
|
19
|
+
deltaMode: false,
|
|
20
|
+
baselines: { get: () => [], add: () => { }, save: () => { } },
|
|
21
|
+
pi: { getFlag: () => false, ...overrides.pi },
|
|
22
|
+
hasTool: async () => false,
|
|
23
|
+
log: () => { },
|
|
24
|
+
...overrides,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
describe("oxlint runner", () => {
|
|
28
|
+
const require = createRequire(import.meta.url);
|
|
29
|
+
it("should have correct runner definition", async () => {
|
|
30
|
+
const oxlintModule = await import("./oxlint.js");
|
|
31
|
+
const runner = oxlintModule.default;
|
|
32
|
+
expect(runner.id).toBe("oxlint");
|
|
33
|
+
expect(runner.appliesTo).toEqual(["jsts"]);
|
|
34
|
+
expect(runner.priority).toBe(12);
|
|
35
|
+
expect(runner.enabledByDefault).toBe(false); // Opt-in initially
|
|
36
|
+
expect(runner.skipTestFiles).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
it("should detect oxlint availability", () => {
|
|
39
|
+
const { spawnSync } = require("node:child_process");
|
|
40
|
+
const result = spawnSync("oxlint", ["--version"], {
|
|
41
|
+
encoding: "utf-8",
|
|
42
|
+
timeout: 10000,
|
|
43
|
+
shell: true,
|
|
44
|
+
});
|
|
45
|
+
expect(result.error || result.status !== 0 ? "not available" : "available").toBeTruthy(); // May or may not be installed
|
|
46
|
+
});
|
|
47
|
+
it("should detect common lint issues", async () => {
|
|
48
|
+
const tmpFile = path.join(process.env.TEMP || "/tmp", `oxlint_test_${Date.now()}.ts`);
|
|
49
|
+
fs.writeFileSync(tmpFile, `// Test file with issues
|
|
50
|
+
function test() {
|
|
51
|
+
// Double negation
|
|
52
|
+
const flag = !!value;
|
|
53
|
+
|
|
54
|
+
// Unused variable
|
|
55
|
+
const unused = 42;
|
|
56
|
+
|
|
57
|
+
// Console statement
|
|
58
|
+
console.log("test");
|
|
59
|
+
}
|
|
60
|
+
`);
|
|
61
|
+
try {
|
|
62
|
+
const oxlintModule = await import("./oxlint.js");
|
|
63
|
+
const runner = oxlintModule.default;
|
|
64
|
+
const result = await runner.run(createMockContext(tmpFile));
|
|
65
|
+
// If oxlint is installed, should detect issues
|
|
66
|
+
// If not installed, will be skipped
|
|
67
|
+
if (result.status !== "skipped") {
|
|
68
|
+
// Should detect at least some issues (console, unused vars, etc.)
|
|
69
|
+
expect(result.diagnostics.length).toBeGreaterThanOrEqual(1);
|
|
70
|
+
expect(result.diagnostics.some((d) => d.tool === "oxlint" &&
|
|
71
|
+
(d.message.includes("console") ||
|
|
72
|
+
d.message.includes("unused") ||
|
|
73
|
+
d.message.includes("!!")))).toBe(true);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
// Windows may hold file handles briefly - add small delay
|
|
78
|
+
await delay(100);
|
|
79
|
+
if (fs.existsSync(tmpFile)) {
|
|
80
|
+
fs.unlinkSync(tmpFile);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
it("should respect no-oxlint flag", async () => {
|
|
85
|
+
const tmpFile = path.join(process.env.TEMP || "/tmp", `oxlint_flag_${Date.now()}.ts`);
|
|
86
|
+
fs.writeFileSync(tmpFile, `function test() { console.log("test"); }`);
|
|
87
|
+
try {
|
|
88
|
+
const oxlintModule = await import("./oxlint.js");
|
|
89
|
+
const runner = oxlintModule.default;
|
|
90
|
+
// Create context with no-oxlint flag set to true
|
|
91
|
+
const ctxWithFlag = createMockContext(tmpFile, {
|
|
92
|
+
pi: { getFlag: (name) => name === "no-oxlint" },
|
|
93
|
+
});
|
|
94
|
+
const result = await runner.run(ctxWithFlag);
|
|
95
|
+
expect(result.status).toBe("skipped");
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
// Windows may hold file handles briefly - add small delay
|
|
99
|
+
await delay(100);
|
|
100
|
+
if (fs.existsSync(tmpFile)) {
|
|
101
|
+
fs.unlinkSync(tmpFile);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
it("should provide fix suggestions when available", async () => {
|
|
106
|
+
const tmpFile = path.join(process.env.TEMP || "/tmp", `oxlint_fix_${Date.now()}.ts`);
|
|
107
|
+
fs.writeFileSync(tmpFile, `// File with auto-fixable issues
|
|
108
|
+
const x = !!value;
|
|
109
|
+
`);
|
|
110
|
+
try {
|
|
111
|
+
const oxlintModule = await import("./oxlint.js");
|
|
112
|
+
const runner = oxlintModule.default;
|
|
113
|
+
const result = await runner.run(createMockContext(tmpFile));
|
|
114
|
+
if (result.status !== "skipped" && result.diagnostics.length > 0) {
|
|
115
|
+
// Some issues should be fixable
|
|
116
|
+
const fixableDiags = result.diagnostics.filter((d) => d.fixable);
|
|
117
|
+
// At least some diagnostics should have fixes
|
|
118
|
+
expect(fixableDiags.length).toBeGreaterThanOrEqual(0);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
finally {
|
|
122
|
+
// Windows may hold file handles briefly - add small delay
|
|
123
|
+
await delay(100);
|
|
124
|
+
if (fs.existsSync(tmpFile)) {
|
|
125
|
+
fs.unlinkSync(tmpFile);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
it("should pass clean TypeScript files", async () => {
|
|
130
|
+
const tmpFile = path.join(process.env.TEMP || "/tmp", `oxlint_ok_${Date.now()}.ts`);
|
|
131
|
+
fs.writeFileSync(tmpFile, `// Clean TypeScript file
|
|
132
|
+
function greet(name: string): string {
|
|
133
|
+
return \`Hello, \${name}!\`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const result = greet("world");
|
|
137
|
+
export { greet };
|
|
138
|
+
`);
|
|
139
|
+
try {
|
|
140
|
+
const oxlintModule = await import("./oxlint.js");
|
|
141
|
+
const runner = oxlintModule.default;
|
|
142
|
+
const result = await runner.run(createMockContext(tmpFile));
|
|
143
|
+
if (result.status !== "skipped") {
|
|
144
|
+
// Clean files should have no issues
|
|
145
|
+
expect(result.diagnostics.length).toBe(0);
|
|
146
|
+
expect(result.status).toBe("succeeded");
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
finally {
|
|
150
|
+
// Windows may hold file handles briefly - add small delay
|
|
151
|
+
await delay(100);
|
|
152
|
+
if (fs.existsSync(tmpFile)) {
|
|
153
|
+
fs.unlinkSync(tmpFile);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
it("should handle JSON output correctly", async () => {
|
|
158
|
+
const tmpFile = path.join(process.env.TEMP || "/tmp", `oxlint_json_${Date.now()}.ts`);
|
|
159
|
+
fs.writeFileSync(tmpFile, `const unused = 1;`);
|
|
160
|
+
try {
|
|
161
|
+
const oxlintModule = await import("./oxlint.js");
|
|
162
|
+
const runner = oxlintModule.default;
|
|
163
|
+
const result = await runner.run(createMockContext(tmpFile));
|
|
164
|
+
if (result.status !== "skipped") {
|
|
165
|
+
// All diagnostics should have required fields
|
|
166
|
+
for (const diag of result.diagnostics) {
|
|
167
|
+
expect(diag.id).toBeDefined();
|
|
168
|
+
expect(diag.message).toBeDefined();
|
|
169
|
+
expect(diag.tool).toBe("oxlint");
|
|
170
|
+
expect(diag.line).toBeGreaterThanOrEqual(1);
|
|
171
|
+
expect(diag.severity).toMatch(/^(error|warning|info)$/);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
finally {
|
|
176
|
+
// Windows may hold file handles briefly - add small delay
|
|
177
|
+
await delay(100);
|
|
178
|
+
if (fs.existsSync(tmpFile)) {
|
|
179
|
+
fs.unlinkSync(tmpFile);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
it("should skip when oxlint is not available", async () => {
|
|
184
|
+
const tmpFile = path.join(process.env.TEMP || "/tmp", `oxlint_skip_${Date.now()}.ts`);
|
|
185
|
+
fs.writeFileSync(tmpFile, `const x = 1;`);
|
|
186
|
+
try {
|
|
187
|
+
const oxlintModule = await import("./oxlint.js");
|
|
188
|
+
const runner = oxlintModule.default;
|
|
189
|
+
// Check if oxlint is available
|
|
190
|
+
const { spawnSync } = require("node:child_process");
|
|
191
|
+
const checkResult = spawnSync("oxlint", ["--version"], {
|
|
192
|
+
encoding: "utf-8",
|
|
193
|
+
timeout: 5000,
|
|
194
|
+
shell: true,
|
|
195
|
+
});
|
|
196
|
+
const isAvailable = !checkResult.error && checkResult.status === 0;
|
|
197
|
+
const result = await runner.run(createMockContext(tmpFile));
|
|
198
|
+
if (!isAvailable) {
|
|
199
|
+
expect(result.status).toBe("skipped");
|
|
200
|
+
expect(result.diagnostics).toHaveLength(0);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
finally {
|
|
204
|
+
// Windows may hold file handles briefly - add small delay
|
|
205
|
+
await delay(100);
|
|
206
|
+
if (fs.existsSync(tmpFile)) {
|
|
207
|
+
fs.unlinkSync(tmpFile);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
it("should handle parsing errors gracefully", async () => {
|
|
212
|
+
const tmpFile = path.join(process.env.TEMP || "/tmp", `oxlint_parse_${Date.now()}.ts`);
|
|
213
|
+
// Intentionally malformed file
|
|
214
|
+
fs.writeFileSync(tmpFile, `const x = `);
|
|
215
|
+
try {
|
|
216
|
+
const oxlintModule = await import("./oxlint.js");
|
|
217
|
+
const runner = oxlintModule.default;
|
|
218
|
+
const result = await runner.run(createMockContext(tmpFile));
|
|
219
|
+
// Should handle parse errors without crashing
|
|
220
|
+
expect(["succeeded", "failed", "skipped"]).toContain(result.status);
|
|
221
|
+
}
|
|
222
|
+
finally {
|
|
223
|
+
// Windows may hold file handles briefly - add small delay
|
|
224
|
+
await delay(100);
|
|
225
|
+
if (fs.existsSync(tmpFile)) {
|
|
226
|
+
fs.unlinkSync(tmpFile);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
});
|