@wrongstack/tools 0.310.1 → 0.313.1
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/dist/_shell-pick.d.ts +5 -10
- package/dist/audit.js +10 -4055
- package/dist/bash.js +9 -2332
- package/dist/batch-tool-use.js +2 -187
- package/dist/browser/index.js +25 -1339
- package/dist/builtin.js +69 -33985
- package/dist/chunk-2CTB3UK5.js +197 -0
- package/dist/chunk-2ME7ZWDD.js +1272 -0
- package/dist/chunk-2TFQDEPU.js +113 -0
- package/dist/chunk-2ZCJNKFE.js +315 -0
- package/dist/chunk-3PVYQFRQ.js +472 -0
- package/dist/chunk-3QMQBO5Z.js +89 -0
- package/dist/chunk-42AKKX7O.js +385 -0
- package/dist/chunk-42SKEETB.js +113 -0
- package/dist/chunk-4BHUSMNL.js +104 -0
- package/dist/chunk-4I4LWFOO.js +431 -0
- package/dist/chunk-553IQUMO.js +478 -0
- package/dist/chunk-55KF77OK.js +1944 -0
- package/dist/chunk-6HLZK37X.js +359 -0
- package/dist/chunk-6RNIFLG4.js +305 -0
- package/dist/chunk-A6BRWIXN.js +317 -0
- package/dist/chunk-AHHDWNXC.js +200 -0
- package/dist/chunk-B2CIOKWP.js +899 -0
- package/dist/chunk-BTSFTGIL.js +7 -0
- package/dist/chunk-D33S4RQG.js +222 -0
- package/dist/chunk-DIJKHSUO.js +134 -0
- package/dist/chunk-DPL47QGS.js +3515 -0
- package/dist/chunk-EMRGN4KM.js +170 -0
- package/dist/chunk-FGOABE4Z.js +955 -0
- package/dist/chunk-FW65TP4G.js +520 -0
- package/dist/chunk-GOIZNNOA.js +221 -0
- package/dist/chunk-H5MJUAA6.js +295 -0
- package/dist/chunk-H5OHH6F4.js +223 -0
- package/dist/chunk-HC5RM4WY.js +199 -0
- package/dist/chunk-HEQFMLZ7.js +190 -0
- package/dist/chunk-HFXSNKCV.js +196 -0
- package/dist/chunk-HXSBQ2SE.js +1723 -0
- package/dist/chunk-ILESNGNM.js +163 -0
- package/dist/chunk-INF5CGAO.js +137 -0
- package/dist/chunk-IWDFZ6XR.js +337 -0
- package/dist/chunk-IXMNTNW5.js +238 -0
- package/dist/chunk-J4SRJKBW.js +428 -0
- package/dist/chunk-J5SKD6LN.js +235 -0
- package/dist/chunk-JRJJX3L5.js +424 -0
- package/dist/chunk-KXNDHMUB.js +366 -0
- package/dist/chunk-LIJQMYYX.js +59 -0
- package/dist/chunk-MAN26PZ5.js +260 -0
- package/dist/chunk-MKRQMLZA.js +474 -0
- package/dist/chunk-NBDZMMG2.js +169 -0
- package/dist/chunk-NHA6BEIH.js +101 -0
- package/dist/chunk-OA6YJIWL.js +4412 -0
- package/dist/chunk-OZC255IC.js +2830 -0
- package/dist/chunk-PUR6WU2B.js +154 -0
- package/dist/chunk-Q5JPPCZC.js +12 -0
- package/dist/chunk-QBV725YG.js +128 -0
- package/dist/chunk-QHVW4AAM.js +892 -0
- package/dist/chunk-QNJ7AQ4B.js +1000 -0
- package/dist/chunk-RGISBZBD.js +231 -0
- package/dist/chunk-RJZQWEMS.js +84 -0
- package/dist/chunk-RP2ZA47V.js +15 -0
- package/dist/chunk-RXISBFR5.js +315 -0
- package/dist/chunk-S5CCLZL3.js +99 -0
- package/dist/chunk-TVTCSBJF.js +122 -0
- package/dist/chunk-U4D5S3VQ.js +21 -0
- package/dist/chunk-U4VAATKP.js +193 -0
- package/dist/chunk-UKU2ZX4C.js +203 -0
- package/dist/chunk-UNSKG6DC.js +159 -0
- package/dist/chunk-URFKEIHM.js +1091 -0
- package/dist/chunk-UTV7YAW7.js +178 -0
- package/dist/chunk-V43EQ6VR.js +68 -0
- package/dist/chunk-VB3MJGCV.js +610 -0
- package/dist/chunk-WHIIIREL.js +223 -0
- package/dist/chunk-XMIFYKUT.js +1371 -0
- package/dist/chunk-YF2RSV34.js +54 -0
- package/dist/chunk-Z6DAKQ3U.js +1 -0
- package/dist/chunk-ZIGAZFWE.js +522 -0
- package/dist/circuit-breaker.js +3 -191
- package/dist/codebase-index/index.js +84 -13688
- package/dist/codebase-index/parser-worker-script.js +8 -3995
- package/dist/codebase-index/project-server.js +60 -8548
- package/dist/codebase-index/worker.js +20 -8416
- package/dist/design.js +2 -299
- package/dist/diff.js +4 -256
- package/dist/document.js +4 -222
- package/dist/e2e.js +5 -476
- package/dist/edit.js +14 -10200
- package/dist/exec.js +16 -3131
- package/dist/fetch.js +8 -398
- package/dist/format.js +10 -3750
- package/dist/generic-parser-VUXDIAOZ.js +13 -0
- package/dist/git.js +4 -380
- package/dist/glob.js +6 -280
- package/dist/go-parser-6CA77WZ4.js +469 -0
- package/dist/grep.js +7 -604
- package/dist/index.js +318 -35423
- package/dist/install.js +10 -4091
- package/dist/json-parser-7YMDJSBJ.js +213 -0
- package/dist/json.js +4 -665
- package/dist/kanban.js +3 -2096
- package/dist/languages/index.js +23 -4664
- package/dist/legacy-bridge-7UKZT46G.js +18 -0
- package/dist/lint.js +10 -3706
- package/dist/logs.js +4 -287
- package/dist/memory.js +6 -215
- package/dist/mode.js +3 -99
- package/dist/outdated.js +4 -5170
- package/dist/pack.js +65 -33933
- package/dist/parser-dispatch-VPOFDO2U.js +14 -0
- package/dist/patch.js +13 -9935
- package/dist/plan.js +5 -3286
- package/dist/process-registry.js +8 -651
- package/dist/ps-slash.js +12 -1439
- package/dist/py-parser-GPM5VYRG.js +16 -0
- package/dist/read.js +13 -9816
- package/dist/replace.js +15 -10014
- package/dist/rs-parser-WVQ4KYCX.js +81 -0
- package/dist/scaffold.js +4 -253
- package/dist/search.js +5 -585
- package/dist/session-kanban.js +30 -972
- package/dist/skill.js +2 -215
- package/dist/task.js +5 -3410
- package/dist/test.js +10 -3773
- package/dist/todo.js +4 -2891
- package/dist/tool-help.js +3 -123
- package/dist/tool-search.js +3 -79
- package/dist/tool-tier.js +68 -34020
- package/dist/tool-use.js +2 -93
- package/dist/tree-sitter-parser-YCILHGZD.js +17 -0
- package/dist/tree.js +4 -288
- package/dist/ts-parser-YH4ZMWMH.js +232 -0
- package/dist/typecheck.js +10 -3753
- package/dist/win32.js +6 -60
- package/dist/write.js +14 -9882
- package/dist/yaml-parser-GFAOKV53.js +157 -0
- package/package.json +5 -5
|
@@ -0,0 +1,892 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolvePythonBinary
|
|
3
|
+
} from "./chunk-42AKKX7O.js";
|
|
4
|
+
import {
|
|
5
|
+
parseParserBatchOutput,
|
|
6
|
+
withSpawnGate
|
|
7
|
+
} from "./chunk-42SKEETB.js";
|
|
8
|
+
import {
|
|
9
|
+
resolveWin32Command
|
|
10
|
+
} from "./chunk-V43EQ6VR.js";
|
|
11
|
+
|
|
12
|
+
// src/codebase-index/import-extractor.ts
|
|
13
|
+
var IMPORT_MAX_FILE_CHARS = 512 * 1024;
|
|
14
|
+
var IMPORT_MAX_PER_FILE = 400;
|
|
15
|
+
var DOTTED_IMPORT = [
|
|
16
|
+
{ re: /^[ \t]*import\s+(?:static\s+)?([\w.]+(?:\.\*)?)\s*;?\s*$/gm }
|
|
17
|
+
];
|
|
18
|
+
var LANG_IMPORTS = {
|
|
19
|
+
// Go and Python have real AST extractors; these patterns are the fallback for
|
|
20
|
+
// machines with no Go toolchain or Python interpreter installed, where the
|
|
21
|
+
// parser degrades to regex symbols and would otherwise contribute no edges.
|
|
22
|
+
go: [
|
|
23
|
+
{ re: /^[ \t]*import\s+(?:[\w.]+\s+)?"([^"]+)"/gm },
|
|
24
|
+
// Grouped form: inside `import ( … )` each line is an optional alias plus a
|
|
25
|
+
// quoted path. A stray match elsewhere resolves to no file and is dropped.
|
|
26
|
+
{ re: /^[ \t]*(?:[A-Za-z_.]\w*\s+)?"([^"]+)"\s*$/gm }
|
|
27
|
+
],
|
|
28
|
+
py: [{ re: /^[ \t]*import\s+([\w.]+)/gm }, { re: /^[ \t]*from\s+([.\w]+)\s+import\b/gm }],
|
|
29
|
+
rs: [
|
|
30
|
+
// use a::b::C; | use a::b::{C, D}; → the path before any brace
|
|
31
|
+
{ re: /^[ \t]*(?:pub\s+)?use\s+([\w:]+?)(?:::\{|\s*;|\s+as\b)/gm },
|
|
32
|
+
// mod foo; (a declaration *and* a dependency on foo.rs / foo/mod.rs)
|
|
33
|
+
{ re: /^[ \t]*(?:pub\s+)?mod\s+(\w+)\s*;/gm }
|
|
34
|
+
],
|
|
35
|
+
java: DOTTED_IMPORT,
|
|
36
|
+
kotlin: DOTTED_IMPORT,
|
|
37
|
+
scala: [{ re: /^[ \t]*import\s+([\w.]+(?:\.[_*])?)\s*$/gm }],
|
|
38
|
+
csharp: [
|
|
39
|
+
// using Foo.Bar; | using static Foo.Bar; | using Alias = Foo.Bar;
|
|
40
|
+
{ re: /^[ \t]*global\s+using\s+(?:static\s+)?([\w.]+)\s*;/gm, name: "full" },
|
|
41
|
+
{ re: /^[ \t]*using\s+(?:static\s+)?(?:\w+\s*=\s*)?([\w.]+)\s*;/gm, name: "full" }
|
|
42
|
+
],
|
|
43
|
+
// Quoted includes only: <stdio.h> is a system header with no indexed file.
|
|
44
|
+
c: [{ re: /^[ \t]*#\s*include\s+"([^"]+)"/gm }],
|
|
45
|
+
cpp: [{ re: /^[ \t]*#\s*include\s+"([^"]+)"/gm }],
|
|
46
|
+
ruby: [{ re: /^[ \t]*(?:require|require_relative|load)\s*\(?\s*['"]([^'"]+)['"]/gm }],
|
|
47
|
+
php: [
|
|
48
|
+
// `use A\B\C` imports the class C, which is what the index has a symbol
|
|
49
|
+
// for — the namespace symbol only covers the `A\B` prefix.
|
|
50
|
+
{ re: /^[ \t]*use\s+(?:function\s+|const\s+)?([\w\\]+)/gm },
|
|
51
|
+
{ re: /^[ \t]*(?:require|require_once|include|include_once)\s*\(?\s*['"]([^'"]+)['"]/gm }
|
|
52
|
+
],
|
|
53
|
+
swift: [{ re: /^[ \t]*import\s+(?:struct\s+|class\s+|func\s+)?([\w.]+)\s*$/gm }],
|
|
54
|
+
dart: [{ re: /^[ \t]*(?:import|export|part)\s+['"]([^'"]+)['"]/gm }],
|
|
55
|
+
lua: [{ re: /\brequire\s*\(?\s*['"]([^'"]+)['"]/g }],
|
|
56
|
+
elixir: [{ re: /^[ \t]*(?:alias|import|require|use)\s+([A-Z][\w.]*)/gm, name: "full" }],
|
|
57
|
+
haskell: [{ re: /^[ \t]*import\s+(?:qualified\s+)?([\w.]+)/gm, name: "full" }],
|
|
58
|
+
zig: [{ re: /@import\s*\(\s*"([^"]+)"\s*\)/g }],
|
|
59
|
+
proto: [{ re: /^[ \t]*import\s+(?:public\s+|weak\s+)?"([^"]+)"\s*;/gm }],
|
|
60
|
+
// `@import "x"`, `@use "x"`, `@forward "x"` — Sass and plain CSS alike.
|
|
61
|
+
css: [{ re: /^[ \t]*@(?:import|use|forward)\s+(?:url\()?\s*['"]([^'"]+)['"]/gm }],
|
|
62
|
+
// A .vue/.svelte file's <script> block is JS; the same ESM syntax applies.
|
|
63
|
+
vue: [{ re: /^[ \t]*import\s[^'"]*from\s*['"]([^'"]+)['"]/gm }],
|
|
64
|
+
svelte: [{ re: /^[ \t]*import\s[^'"]*from\s*['"]([^'"]+)['"]/gm }],
|
|
65
|
+
html: [
|
|
66
|
+
{ re: /<script[^>]+src\s*=\s*['"]([^'"]+)['"]/g },
|
|
67
|
+
{ re: /<link[^>]+href\s*=\s*['"]([^'"]+)['"]/g }
|
|
68
|
+
],
|
|
69
|
+
shell: [{ re: /^[ \t]*(?:source|\.)\s+(\S+)/gm }],
|
|
70
|
+
r: [{ re: /\b(?:source|library|require)\s*\(\s*['"]?([\w./-]+)['"]?\s*\)/g }]
|
|
71
|
+
};
|
|
72
|
+
function lastSegment(specifier) {
|
|
73
|
+
const pathLike = /[/\\]|::/.test(specifier);
|
|
74
|
+
const segments = specifier.split(/[/\\]|::/).filter(Boolean);
|
|
75
|
+
let last = segments[segments.length - 1] ?? specifier;
|
|
76
|
+
if (last === "*" || last === "_") {
|
|
77
|
+
last = segments[segments.length - 2] ?? specifier;
|
|
78
|
+
}
|
|
79
|
+
if (pathLike) return last.replace(/\.[A-Za-z0-9]{1,8}$/, "") || last;
|
|
80
|
+
const dotted = last.split(".").filter((part) => part && part !== "*" && part !== "_");
|
|
81
|
+
return dotted[dotted.length - 1] ?? last;
|
|
82
|
+
}
|
|
83
|
+
function newlineOffsets(content) {
|
|
84
|
+
const offsets = [];
|
|
85
|
+
for (let i = 0; i < content.length; i++) {
|
|
86
|
+
if (content.charCodeAt(i) === 10) offsets.push(i);
|
|
87
|
+
}
|
|
88
|
+
return offsets;
|
|
89
|
+
}
|
|
90
|
+
function lineAt(offsets, index) {
|
|
91
|
+
let low = 0;
|
|
92
|
+
let high = offsets.length;
|
|
93
|
+
while (low < high) {
|
|
94
|
+
const mid = low + high >>> 1;
|
|
95
|
+
if ((offsets[mid] ?? 0) < index) low = mid + 1;
|
|
96
|
+
else high = mid;
|
|
97
|
+
}
|
|
98
|
+
return low + 1;
|
|
99
|
+
}
|
|
100
|
+
function hasImportPatterns(lang) {
|
|
101
|
+
return LANG_IMPORTS[lang] !== void 0;
|
|
102
|
+
}
|
|
103
|
+
function extractImports(opts) {
|
|
104
|
+
const patterns = LANG_IMPORTS[opts.lang];
|
|
105
|
+
if (!patterns || !opts.content) return [];
|
|
106
|
+
const limit = opts.maxImports ?? IMPORT_MAX_PER_FILE;
|
|
107
|
+
const content = opts.content.length > IMPORT_MAX_FILE_CHARS ? opts.content.slice(0, IMPORT_MAX_FILE_CHARS) : opts.content;
|
|
108
|
+
const refs = [];
|
|
109
|
+
const seen = /* @__PURE__ */ new Set();
|
|
110
|
+
const offsets = newlineOffsets(content);
|
|
111
|
+
for (const pattern of patterns) {
|
|
112
|
+
const re = new RegExp(pattern.re.source, pattern.re.flags);
|
|
113
|
+
for (const match of content.matchAll(re)) {
|
|
114
|
+
if (refs.length >= limit) return refs;
|
|
115
|
+
const specifier = match[1]?.trim();
|
|
116
|
+
if (!specifier) continue;
|
|
117
|
+
const module = specifier;
|
|
118
|
+
const toName = pattern.name === "full" ? module : lastSegment(module);
|
|
119
|
+
if (!toName) continue;
|
|
120
|
+
const key = `${module}\0${toName}`;
|
|
121
|
+
if (seen.has(key)) continue;
|
|
122
|
+
seen.add(key);
|
|
123
|
+
refs.push({
|
|
124
|
+
fromId: 0,
|
|
125
|
+
toName,
|
|
126
|
+
callType: "import",
|
|
127
|
+
line: lineAt(offsets, match.index ?? 0),
|
|
128
|
+
lang: opts.lang,
|
|
129
|
+
module
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return refs;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// src/codebase-index/parser-batch.ts
|
|
137
|
+
import { spawn } from "node:child_process";
|
|
138
|
+
import * as fsSync from "node:fs";
|
|
139
|
+
import * as fs from "node:fs/promises";
|
|
140
|
+
import * as os from "node:os";
|
|
141
|
+
import * as path from "node:path";
|
|
142
|
+
var MAX_BATCH_FILES = 100;
|
|
143
|
+
var MAX_BATCH_BYTES = 8 * 1024 * 1024;
|
|
144
|
+
function chunkBatchFiles(files) {
|
|
145
|
+
const chunks = [];
|
|
146
|
+
let current = [];
|
|
147
|
+
let bytes = 0;
|
|
148
|
+
for (const file of files) {
|
|
149
|
+
const size = Buffer.byteLength(file.content, "utf8");
|
|
150
|
+
if (current.length > 0 && (current.length >= MAX_BATCH_FILES || bytes + size > MAX_BATCH_BYTES)) {
|
|
151
|
+
chunks.push(current);
|
|
152
|
+
current = [];
|
|
153
|
+
bytes = 0;
|
|
154
|
+
}
|
|
155
|
+
current.push(file);
|
|
156
|
+
bytes += size;
|
|
157
|
+
}
|
|
158
|
+
if (current.length > 0) chunks.push(current);
|
|
159
|
+
return chunks;
|
|
160
|
+
}
|
|
161
|
+
function batchTimeoutMs(fileCount) {
|
|
162
|
+
return Math.min(12e4, 15e3 + fileCount * 1500);
|
|
163
|
+
}
|
|
164
|
+
var GO_BATCH_SCRIPT = `
|
|
165
|
+
package main
|
|
166
|
+
|
|
167
|
+
import (
|
|
168
|
+
"encoding/json"
|
|
169
|
+
"fmt"
|
|
170
|
+
"go/ast"
|
|
171
|
+
"go/parser"
|
|
172
|
+
"go/token"
|
|
173
|
+
"io"
|
|
174
|
+
"os"
|
|
175
|
+
"strconv"
|
|
176
|
+
"strings"
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
type Sym struct {
|
|
180
|
+
Name string \`json:"name"\`
|
|
181
|
+
Kind string \`json:"kind"\`
|
|
182
|
+
Line int \`json:"line"\`
|
|
183
|
+
Col int \`json:"col"\`
|
|
184
|
+
Signature string \`json:"signature"\`
|
|
185
|
+
Scope string \`json:"scope"\`
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
type Ref struct {
|
|
189
|
+
ToName string \`json:"toName"\`
|
|
190
|
+
CallType string \`json:"callType"\`
|
|
191
|
+
Line int \`json:"line"\`
|
|
192
|
+
Module string \`json:"module"\`
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
type FileResult struct {
|
|
196
|
+
File string \`json:"file"\`
|
|
197
|
+
Error string \`json:"error,omitempty"\`
|
|
198
|
+
Symbols []Sym \`json:"symbols"\`
|
|
199
|
+
Refs []Ref \`json:"refs"\`
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
type BatchResult struct {
|
|
203
|
+
Version int \`json:"version"\`
|
|
204
|
+
Results []FileResult \`json:"results"\`
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
type inputFile struct {
|
|
208
|
+
File string \`json:"file"\`
|
|
209
|
+
Content string \`json:"content"\`
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
func parseOne(name string, src []byte) FileResult {
|
|
213
|
+
res := FileResult{File: name, Symbols: []Sym{}, Refs: []Ref{}}
|
|
214
|
+
fset := token.NewFileSet()
|
|
215
|
+
node, err := parser.ParseFile(fset, "src.go", src, 0)
|
|
216
|
+
if err != nil {
|
|
217
|
+
res.Error = err.Error()
|
|
218
|
+
return res
|
|
219
|
+
}
|
|
220
|
+
pkgScope := node.Name.Name
|
|
221
|
+
for _, decl := range node.Decls {
|
|
222
|
+
switch d := decl.(type) {
|
|
223
|
+
case *ast.FuncDecl:
|
|
224
|
+
symName := d.Name.Name
|
|
225
|
+
kind := "function"
|
|
226
|
+
scope := pkgScope
|
|
227
|
+
if d.Recv != nil && len(d.Recv.List) > 0 {
|
|
228
|
+
scope = pkgScope + "." + recvTypeName(d.Recv.List[0].Type) + "." + symName
|
|
229
|
+
kind = "method"
|
|
230
|
+
} else {
|
|
231
|
+
scope = pkgScope + "." + symName
|
|
232
|
+
}
|
|
233
|
+
pos := fset.Position(d.Pos())
|
|
234
|
+
res.Symbols = append(res.Symbols, Sym{Name: symName, Kind: kind, Line: pos.Line, Col: pos.Column, Signature: formatFuncSig(d), Scope: scope})
|
|
235
|
+
case *ast.GenDecl:
|
|
236
|
+
for _, spec := range d.Specs {
|
|
237
|
+
switch s := spec.(type) {
|
|
238
|
+
case *ast.TypeSpec:
|
|
239
|
+
typeName := s.Name.Name
|
|
240
|
+
pos := fset.Position(s.Pos())
|
|
241
|
+
sig := "type " + typeName
|
|
242
|
+
if s.TypeParams != nil {
|
|
243
|
+
sig += formatTypeParams(s.TypeParams)
|
|
244
|
+
}
|
|
245
|
+
if st, ok := s.Type.(*ast.StructType); ok {
|
|
246
|
+
sig += " = struct { " + formatFields(st.Fields.List) + " }"
|
|
247
|
+
} else if it, ok := s.Type.(*ast.InterfaceType); ok {
|
|
248
|
+
sig += " = interface { " + formatMethods(it.Methods.List) + " }"
|
|
249
|
+
} else {
|
|
250
|
+
sig += " = " + formatType(s.Type)
|
|
251
|
+
}
|
|
252
|
+
res.Symbols = append(res.Symbols, Sym{Name: typeName, Kind: "type", Line: pos.Line, Col: pos.Column, Signature: sig, Scope: pkgScope})
|
|
253
|
+
case *ast.ValueSpec:
|
|
254
|
+
for _, n := range s.Names {
|
|
255
|
+
valueName := n.Name
|
|
256
|
+
pos := fset.Position(n.Pos())
|
|
257
|
+
kind := "var"
|
|
258
|
+
if d.Tok == token.CONST {
|
|
259
|
+
kind = "const"
|
|
260
|
+
}
|
|
261
|
+
sig := kind + " " + valueName
|
|
262
|
+
if s.Type != nil {
|
|
263
|
+
sig += " " + formatType(s.Type)
|
|
264
|
+
}
|
|
265
|
+
res.Symbols = append(res.Symbols, Sym{Name: valueName, Kind: kind, Line: pos.Line, Col: pos.Column, Signature: sig, Scope: pkgScope})
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
ast.Inspect(node, func(n ast.Node) bool {
|
|
272
|
+
switch expr := n.(type) {
|
|
273
|
+
case *ast.CallExpr:
|
|
274
|
+
line := fset.Position(expr.Pos()).Line
|
|
275
|
+
switch fun := expr.Fun.(type) {
|
|
276
|
+
case *ast.Ident:
|
|
277
|
+
res.Refs = append(res.Refs, Ref{ToName: fun.Name, CallType: "call", Line: line})
|
|
278
|
+
case *ast.SelectorExpr:
|
|
279
|
+
res.Refs = append(res.Refs, Ref{ToName: fun.Sel.Name, CallType: "call", Line: line})
|
|
280
|
+
}
|
|
281
|
+
case *ast.ImportSpec:
|
|
282
|
+
if expr.Path != nil {
|
|
283
|
+
if importPath, uerr := strconv.Unquote(expr.Path.Value); uerr == nil {
|
|
284
|
+
line := fset.Position(expr.Pos()).Line
|
|
285
|
+
name := importPath
|
|
286
|
+
if idx := strings.LastIndex(importPath, "/"); idx >= 0 {
|
|
287
|
+
name = importPath[idx+1:]
|
|
288
|
+
}
|
|
289
|
+
res.Refs = append(res.Refs, Ref{ToName: name, CallType: "import", Line: line, Module: importPath})
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return true
|
|
294
|
+
})
|
|
295
|
+
return res
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
func main() {
|
|
299
|
+
raw, err := io.ReadAll(os.Stdin)
|
|
300
|
+
if err != nil {
|
|
301
|
+
out, _ := json.Marshal(BatchResult{Version: 1, Results: []FileResult{}})
|
|
302
|
+
fmt.Print(string(out))
|
|
303
|
+
return
|
|
304
|
+
}
|
|
305
|
+
var inputs []inputFile
|
|
306
|
+
if err := json.Unmarshal(raw, &inputs); err != nil {
|
|
307
|
+
out, _ := json.Marshal(BatchResult{Version: 1, Results: []FileResult{}})
|
|
308
|
+
fmt.Print(string(out))
|
|
309
|
+
return
|
|
310
|
+
}
|
|
311
|
+
results := make([]FileResult, 0, len(inputs))
|
|
312
|
+
for _, in := range inputs {
|
|
313
|
+
results = append(results, parseOne(in.File, []byte(in.Content)))
|
|
314
|
+
}
|
|
315
|
+
data, err := json.Marshal(BatchResult{Version: 1, Results: results})
|
|
316
|
+
if err != nil {
|
|
317
|
+
fmt.Print("{\\"version\\":1,\\"results\\":[]}")
|
|
318
|
+
return
|
|
319
|
+
}
|
|
320
|
+
fmt.Print(string(data))
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
func recvTypeName(t ast.Expr) string {
|
|
324
|
+
switch v := t.(type) {
|
|
325
|
+
case *ast.Ident:
|
|
326
|
+
return v.Name
|
|
327
|
+
case *ast.StarExpr:
|
|
328
|
+
return recvTypeName(v.X)
|
|
329
|
+
default:
|
|
330
|
+
return "?"
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
func formatFuncSig(d *ast.FuncDecl) string {
|
|
335
|
+
scope := ""
|
|
336
|
+
if d.Recv != nil && len(d.Recv.List) > 0 {
|
|
337
|
+
scope = "(" + formatFieldList(d.Recv.List) + ") "
|
|
338
|
+
}
|
|
339
|
+
scope += formatFuncType(d.Type)
|
|
340
|
+
return "func " + scope
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
func formatFuncType(f *ast.FuncType) string {
|
|
344
|
+
params := formatFieldList(f.Params.List)
|
|
345
|
+
results := ""
|
|
346
|
+
if f.Results != nil {
|
|
347
|
+
results = " -> " + formatFieldList(f.Results.List)
|
|
348
|
+
}
|
|
349
|
+
return params + results
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
func formatFieldList(fields []*ast.Field) string {
|
|
353
|
+
if len(fields) == 0 {
|
|
354
|
+
return "()"
|
|
355
|
+
}
|
|
356
|
+
names := make([]string, 0, len(fields))
|
|
357
|
+
for _, f := range fields {
|
|
358
|
+
name := ""
|
|
359
|
+
if len(f.Names) > 0 {
|
|
360
|
+
name = f.Names[0].Name
|
|
361
|
+
}
|
|
362
|
+
t := formatType(f.Type)
|
|
363
|
+
if name != "" {
|
|
364
|
+
names = append(names, name+" "+t)
|
|
365
|
+
} else {
|
|
366
|
+
names = append(names, t)
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
return "(" + strings.Join(names, ", ") + ")"
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
func formatFields(fields []*ast.Field) string {
|
|
373
|
+
lines := make([]string, 0)
|
|
374
|
+
for _, f := range fields {
|
|
375
|
+
name := ""
|
|
376
|
+
if len(f.Names) > 0 {
|
|
377
|
+
name = f.Names[0].Name
|
|
378
|
+
}
|
|
379
|
+
t := formatType(f.Type)
|
|
380
|
+
if name != "" {
|
|
381
|
+
lines = append(lines, name+" "+t)
|
|
382
|
+
} else {
|
|
383
|
+
lines = append(lines, t)
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return strings.Join(lines, "; ")
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
func formatMethods(fields []*ast.Field) string {
|
|
390
|
+
return formatFields(fields)
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
func formatTypeParams(tp *ast.FieldList) string {
|
|
394
|
+
if tp == nil || len(tp.List) == 0 {
|
|
395
|
+
return ""
|
|
396
|
+
}
|
|
397
|
+
params := make([]string, len(tp.List))
|
|
398
|
+
for i, p := range tp.List {
|
|
399
|
+
if len(p.Names) > 0 {
|
|
400
|
+
params[i] = p.Names[0].Name
|
|
401
|
+
} else {
|
|
402
|
+
params[i] = "T"
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return "[" + strings.Join(params, ", ") + "]"
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
func formatType(t ast.Expr) string {
|
|
409
|
+
if t == nil {
|
|
410
|
+
return "?"
|
|
411
|
+
}
|
|
412
|
+
switch v := t.(type) {
|
|
413
|
+
case *ast.Ident:
|
|
414
|
+
return v.Name
|
|
415
|
+
case *ast.SelectorExpr:
|
|
416
|
+
return formatType(v.X) + "." + v.Sel.Name
|
|
417
|
+
case *ast.StarExpr:
|
|
418
|
+
return "*" + formatType(v.X)
|
|
419
|
+
case *ast.ArrayType:
|
|
420
|
+
if v.Len == nil {
|
|
421
|
+
return "[]" + formatType(v.Elt)
|
|
422
|
+
}
|
|
423
|
+
return "[...]" + formatType(v.Elt)
|
|
424
|
+
case *ast.MapType:
|
|
425
|
+
return "map[" + formatType(v.Key) + "]" + formatType(v.Value)
|
|
426
|
+
case *ast.InterfaceType:
|
|
427
|
+
return "interface{}"
|
|
428
|
+
case *ast.StructType:
|
|
429
|
+
return "struct{}"
|
|
430
|
+
case *ast.FuncType:
|
|
431
|
+
return formatFuncType(v)
|
|
432
|
+
case *ast.ChanType:
|
|
433
|
+
return "chan " + formatType(v.Value)
|
|
434
|
+
case *ast.BasicLit:
|
|
435
|
+
return v.Value
|
|
436
|
+
case *ast.IndexExpr:
|
|
437
|
+
return formatType(v.X) + "[" + formatType(v.Index) + "]"
|
|
438
|
+
case *ast.IndexListExpr:
|
|
439
|
+
args := make([]string, len(v.Indices))
|
|
440
|
+
for i, idx := range v.Indices {
|
|
441
|
+
args[i] = formatType(idx)
|
|
442
|
+
}
|
|
443
|
+
return formatType(v.X) + "[" + strings.Join(args, ", ") + "]"
|
|
444
|
+
default:
|
|
445
|
+
return "?"
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
`;
|
|
449
|
+
var PY_BATCH_SCRIPT = `import ast, json, sys
|
|
450
|
+
|
|
451
|
+
def get_name(node):
|
|
452
|
+
if isinstance(node, ast.Name):
|
|
453
|
+
return node.id
|
|
454
|
+
elif isinstance(node, ast.Attribute):
|
|
455
|
+
return get_name(node.value) + "." + node.attr
|
|
456
|
+
elif isinstance(node, ast.Subscript):
|
|
457
|
+
return get_name(node.value)
|
|
458
|
+
elif isinstance(node, ast.Call):
|
|
459
|
+
return get_name(node.func)
|
|
460
|
+
elif isinstance(node, ast.Constant):
|
|
461
|
+
return str(node.value)
|
|
462
|
+
return ""
|
|
463
|
+
|
|
464
|
+
def leaf_name(node):
|
|
465
|
+
if isinstance(node, ast.Attribute):
|
|
466
|
+
return node.attr
|
|
467
|
+
if isinstance(node, ast.Name):
|
|
468
|
+
return node.id
|
|
469
|
+
return get_name(node).split(".")[-1]
|
|
470
|
+
|
|
471
|
+
def is_private(name):
|
|
472
|
+
return name.startswith("__") and not name.endswith("__")
|
|
473
|
+
|
|
474
|
+
def parse_one(name, source, module_name):
|
|
475
|
+
result = {"file": name, "symbols": [], "refs": []}
|
|
476
|
+
try:
|
|
477
|
+
tree = ast.parse(source, filename=name)
|
|
478
|
+
except Exception as e:
|
|
479
|
+
result["error"] = str(e)
|
|
480
|
+
return result
|
|
481
|
+
syms = []
|
|
482
|
+
refs = []
|
|
483
|
+
scope_stack = [module_name]
|
|
484
|
+
|
|
485
|
+
def sym(d):
|
|
486
|
+
return {
|
|
487
|
+
"name": d["name"], "kind": d["kind"], "line": d["line"], "col": d["col"],
|
|
488
|
+
"signature": d["signature"], "scope": d["scope"],
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
class Visitor(ast.NodeVisitor):
|
|
492
|
+
def visit_ClassDef(self, node):
|
|
493
|
+
bases = [get_name(b) for b in node.bases]
|
|
494
|
+
sig = "class " + node.name
|
|
495
|
+
if bases:
|
|
496
|
+
sig += "(" + ", ".join(bases) + ")"
|
|
497
|
+
sig += ": ..."
|
|
498
|
+
syms.append(sym({
|
|
499
|
+
"name": node.name, "kind": "class", "line": node.lineno,
|
|
500
|
+
"col": node.col_offset, "signature": sig,
|
|
501
|
+
"scope": ".".join(scope_stack) + "." + node.name,
|
|
502
|
+
}))
|
|
503
|
+
scope_stack.append(node.name)
|
|
504
|
+
self.generic_visit(node)
|
|
505
|
+
scope_stack.pop()
|
|
506
|
+
|
|
507
|
+
def visit_FunctionDef(self, node):
|
|
508
|
+
args = ", ".join(a.arg for a in node.args.args)
|
|
509
|
+
returns = get_name(node.returns) if node.returns is not None else ""
|
|
510
|
+
is_async = isinstance(node, ast.AsyncFunctionDef)
|
|
511
|
+
kind = "function"
|
|
512
|
+
prefix = "def "
|
|
513
|
+
for dec in node.decorator_list:
|
|
514
|
+
d = get_name(dec)
|
|
515
|
+
if d.endswith(".staticmethod"):
|
|
516
|
+
kind = "staticmethod"
|
|
517
|
+
elif d.endswith(".classmethod"):
|
|
518
|
+
kind = "classmethod"
|
|
519
|
+
elif d == "property":
|
|
520
|
+
kind = "property"
|
|
521
|
+
if is_async:
|
|
522
|
+
kind = "async_" + kind
|
|
523
|
+
sig = f"{prefix}{node.name}({args})"
|
|
524
|
+
if returns:
|
|
525
|
+
sig += f" -> {returns}"
|
|
526
|
+
syms.append(sym({
|
|
527
|
+
"name": node.name, "kind": kind, "line": node.lineno,
|
|
528
|
+
"col": node.col_offset, "signature": sig,
|
|
529
|
+
"scope": ".".join(scope_stack) + "." + node.name,
|
|
530
|
+
}))
|
|
531
|
+
|
|
532
|
+
def visit_AsyncFunctionDef(self, node):
|
|
533
|
+
self.visit_FunctionDef(node)
|
|
534
|
+
|
|
535
|
+
def visit_Assign(self, node):
|
|
536
|
+
for target in node.targets:
|
|
537
|
+
if isinstance(target, ast.Name):
|
|
538
|
+
tname = target.id
|
|
539
|
+
if is_private(tname):
|
|
540
|
+
continue
|
|
541
|
+
kind = "const" if tname.isupper() else "var"
|
|
542
|
+
col = target.col_offset if hasattr(target, "col_offset") else 0
|
|
543
|
+
syms.append(sym({
|
|
544
|
+
"name": tname, "kind": kind, "line": node.lineno, "col": col,
|
|
545
|
+
"signature": f"{tname} = ...", "scope": ".".join(scope_stack),
|
|
546
|
+
}))
|
|
547
|
+
|
|
548
|
+
def visit_AnnAssign(self, node):
|
|
549
|
+
if isinstance(node.target, ast.Name):
|
|
550
|
+
tname = node.target.id
|
|
551
|
+
if is_private(tname):
|
|
552
|
+
return
|
|
553
|
+
kind = "const" if tname.isupper() else "var"
|
|
554
|
+
col = node.target.col_offset if hasattr(node.target, "col_offset") else 0
|
|
555
|
+
sig = f"{tname}: {get_name(node.annotation)}"
|
|
556
|
+
if node.value:
|
|
557
|
+
sig += " = ..."
|
|
558
|
+
syms.append(sym({
|
|
559
|
+
"name": tname, "kind": kind, "line": node.lineno, "col": col,
|
|
560
|
+
"signature": sig, "scope": ".".join(scope_stack),
|
|
561
|
+
}))
|
|
562
|
+
|
|
563
|
+
def visit_Import(self, node):
|
|
564
|
+
# Parity with the single-file parser: imports are symbols too.
|
|
565
|
+
for alias in node.names:
|
|
566
|
+
name = alias.asname or alias.name
|
|
567
|
+
syms.append(sym({
|
|
568
|
+
"name": name, "kind": "import", "line": node.lineno,
|
|
569
|
+
"col": node.col_offset, "signature": f"import {alias.name}",
|
|
570
|
+
"scope": ".".join(scope_stack),
|
|
571
|
+
}))
|
|
572
|
+
|
|
573
|
+
def visit_ImportFrom(self, node):
|
|
574
|
+
module = node.module or ""
|
|
575
|
+
for alias in node.names:
|
|
576
|
+
name = alias.asname or alias.name
|
|
577
|
+
syms.append(sym({
|
|
578
|
+
"name": name, "kind": "import", "line": node.lineno,
|
|
579
|
+
"col": node.col_offset, "signature": f"from {module} import {alias.name}",
|
|
580
|
+
"scope": ".".join(scope_stack),
|
|
581
|
+
}))
|
|
582
|
+
|
|
583
|
+
Visitor().visit(tree)
|
|
584
|
+
|
|
585
|
+
for node in ast.walk(tree):
|
|
586
|
+
if isinstance(node, ast.Call):
|
|
587
|
+
cname = leaf_name(node.func)
|
|
588
|
+
if cname:
|
|
589
|
+
refs.append({"toName": cname, "callType": "call", "line": node.lineno})
|
|
590
|
+
elif isinstance(node, ast.Import):
|
|
591
|
+
for alias in node.names:
|
|
592
|
+
refs.append({
|
|
593
|
+
"toName": alias.name.split(".")[-1], "callType": "import",
|
|
594
|
+
"line": node.lineno, "module": alias.name,
|
|
595
|
+
})
|
|
596
|
+
elif isinstance(node, ast.ImportFrom):
|
|
597
|
+
module = ("." * (node.level or 0)) + (node.module or "")
|
|
598
|
+
for alias in node.names:
|
|
599
|
+
refs.append({
|
|
600
|
+
"toName": alias.name, "callType": "import",
|
|
601
|
+
"line": node.lineno, "module": module,
|
|
602
|
+
})
|
|
603
|
+
elif isinstance(node, ast.ClassDef):
|
|
604
|
+
for base in node.bases:
|
|
605
|
+
bname = leaf_name(base)
|
|
606
|
+
if bname:
|
|
607
|
+
refs.append({"toName": bname, "callType": "inherit", "line": node.lineno})
|
|
608
|
+
|
|
609
|
+
result["symbols"] = syms
|
|
610
|
+
result["refs"] = refs
|
|
611
|
+
return result
|
|
612
|
+
|
|
613
|
+
def main():
|
|
614
|
+
try:
|
|
615
|
+
inputs = json.loads(sys.stdin.read())
|
|
616
|
+
except Exception:
|
|
617
|
+
print(json.dumps({"version": 1, "results": []}))
|
|
618
|
+
return
|
|
619
|
+
results = []
|
|
620
|
+
for entry in inputs:
|
|
621
|
+
name = entry.get("file", "")
|
|
622
|
+
module_name = name.rsplit("/", 1)[-1].rsplit("\\\\", 1)[-1][:-3]
|
|
623
|
+
results.append(parse_one(name, entry.get("content", ""), module_name))
|
|
624
|
+
print(json.dumps({"version": 1, "results": results}))
|
|
625
|
+
|
|
626
|
+
main()
|
|
627
|
+
`;
|
|
628
|
+
var _goBatchScriptPath = null;
|
|
629
|
+
var _pyBatchScriptPath = null;
|
|
630
|
+
async function ensureScriptPath(cached, prefix, fileName, script) {
|
|
631
|
+
if (cached) return { path: cached, wrote: false };
|
|
632
|
+
const dir = await fs.mkdtemp(path.join(os.tmpdir(), prefix));
|
|
633
|
+
const scriptPath = path.join(dir, fileName);
|
|
634
|
+
await fs.writeFile(scriptPath, script, { encoding: "utf8", flag: "wx" });
|
|
635
|
+
process.once("exit", () => {
|
|
636
|
+
try {
|
|
637
|
+
fsSync.rmSync(dir, { recursive: true, force: true });
|
|
638
|
+
} catch {
|
|
639
|
+
}
|
|
640
|
+
});
|
|
641
|
+
return { path: scriptPath, wrote: true };
|
|
642
|
+
}
|
|
643
|
+
function runToolchainChild(binary, args, stdinPayload, timeoutMs) {
|
|
644
|
+
return new Promise((resolve) => {
|
|
645
|
+
let settled = false;
|
|
646
|
+
let stdout = "";
|
|
647
|
+
let proc;
|
|
648
|
+
try {
|
|
649
|
+
proc = spawn(binary, args, { stdio: ["pipe", "pipe", "pipe"], windowsHide: true });
|
|
650
|
+
} catch {
|
|
651
|
+
resolve(null);
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
const finish = (value) => {
|
|
655
|
+
if (settled) return;
|
|
656
|
+
settled = true;
|
|
657
|
+
clearTimeout(timer);
|
|
658
|
+
resolve(value);
|
|
659
|
+
};
|
|
660
|
+
const timer = setTimeout(() => {
|
|
661
|
+
proc.kill("SIGKILL");
|
|
662
|
+
finish(null);
|
|
663
|
+
}, timeoutMs);
|
|
664
|
+
timer.unref?.();
|
|
665
|
+
proc.on("error", () => finish(null));
|
|
666
|
+
proc.stdout?.on("data", (chunk) => {
|
|
667
|
+
stdout += chunk.toString();
|
|
668
|
+
});
|
|
669
|
+
proc.stderr?.resume();
|
|
670
|
+
proc.stdin?.on("error", () => {
|
|
671
|
+
});
|
|
672
|
+
proc.stdin?.write(stdinPayload);
|
|
673
|
+
proc.stdin?.end();
|
|
674
|
+
proc.on("close", (code) => finish({ code, stdout }));
|
|
675
|
+
});
|
|
676
|
+
}
|
|
677
|
+
async function runGoBatch(files, goBinary) {
|
|
678
|
+
const out = /* @__PURE__ */ new Map();
|
|
679
|
+
if (files.length === 0) return out;
|
|
680
|
+
const { path: scriptPath } = await ensureScriptPath(
|
|
681
|
+
_goBatchScriptPath,
|
|
682
|
+
"ws-go-parse",
|
|
683
|
+
"batch.go",
|
|
684
|
+
GO_BATCH_SCRIPT
|
|
685
|
+
);
|
|
686
|
+
_goBatchScriptPath = scriptPath;
|
|
687
|
+
const payload = JSON.stringify(files.map((f) => ({ file: f.file, content: f.content })));
|
|
688
|
+
const result = await withSpawnGate(
|
|
689
|
+
() => runToolchainChild(
|
|
690
|
+
goBinary ?? resolveWin32Command("go"),
|
|
691
|
+
["run", scriptPath],
|
|
692
|
+
payload,
|
|
693
|
+
batchTimeoutMs(files.length)
|
|
694
|
+
)
|
|
695
|
+
);
|
|
696
|
+
if (result?.code !== 0 || !result.stdout.trim()) return out;
|
|
697
|
+
for (const entry of parseParserBatchOutput(result.stdout, "go")) {
|
|
698
|
+
if (entry.error !== void 0) continue;
|
|
699
|
+
out.set(entry.file, {
|
|
700
|
+
file: entry.file,
|
|
701
|
+
lang: "go",
|
|
702
|
+
symbols: entry.symbols.map((s) => ({
|
|
703
|
+
id: 0,
|
|
704
|
+
lang: "go",
|
|
705
|
+
kind: s.kind,
|
|
706
|
+
name: s.name,
|
|
707
|
+
file: entry.file,
|
|
708
|
+
line: s.line,
|
|
709
|
+
col: s.col,
|
|
710
|
+
signature: s.signature ?? "",
|
|
711
|
+
docComment: "",
|
|
712
|
+
scope: s.scope ?? "",
|
|
713
|
+
text: `${s.name} ${s.signature ?? ""}`.trim()
|
|
714
|
+
})),
|
|
715
|
+
refs: entry.refs,
|
|
716
|
+
mtimeMs: Date.now()
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
return out;
|
|
720
|
+
}
|
|
721
|
+
async function runPyBatch(files, pythonBinary) {
|
|
722
|
+
const out = /* @__PURE__ */ new Map();
|
|
723
|
+
if (files.length === 0) return out;
|
|
724
|
+
const { path: scriptPath } = await ensureScriptPath(
|
|
725
|
+
_pyBatchScriptPath,
|
|
726
|
+
"ws-py-parse",
|
|
727
|
+
"batch.py",
|
|
728
|
+
PY_BATCH_SCRIPT
|
|
729
|
+
);
|
|
730
|
+
_pyBatchScriptPath = scriptPath;
|
|
731
|
+
const payload = JSON.stringify(files.map((f) => ({ file: f.file, content: f.content })));
|
|
732
|
+
const result = await withSpawnGate(
|
|
733
|
+
() => runToolchainChild(pythonBinary, [scriptPath], payload, batchTimeoutMs(files.length))
|
|
734
|
+
);
|
|
735
|
+
if (result?.code !== 0 || !result.stdout.trim()) return out;
|
|
736
|
+
for (const entry of parseParserBatchOutput(result.stdout, "py")) {
|
|
737
|
+
if (entry.error !== void 0) continue;
|
|
738
|
+
out.set(entry.file, {
|
|
739
|
+
file: entry.file,
|
|
740
|
+
lang: "py",
|
|
741
|
+
symbols: entry.symbols.map((s) => ({
|
|
742
|
+
id: 0,
|
|
743
|
+
lang: "py",
|
|
744
|
+
kind: s.kind,
|
|
745
|
+
name: s.name,
|
|
746
|
+
file: entry.file,
|
|
747
|
+
line: s.line,
|
|
748
|
+
col: s.col,
|
|
749
|
+
signature: s.signature ?? "",
|
|
750
|
+
docComment: "",
|
|
751
|
+
scope: s.scope ?? "",
|
|
752
|
+
text: `${s.name} ${s.signature ?? ""}`.trim()
|
|
753
|
+
})),
|
|
754
|
+
refs: entry.refs,
|
|
755
|
+
mtimeMs: Date.now()
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
return out;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// src/codebase-index/parser-dispatch.ts
|
|
762
|
+
async function parseFileContent(file, content, lang) {
|
|
763
|
+
const parsed = await dispatch(file, content, lang);
|
|
764
|
+
return withRelations(parsed, content, lang);
|
|
765
|
+
}
|
|
766
|
+
async function parseFilesContent(files) {
|
|
767
|
+
if (files.length === 0) return [];
|
|
768
|
+
const slots = files.map(() => ({ result: null }));
|
|
769
|
+
const batchingEnabled = process.env["WRONGSTACK_TOOLCHAIN_BATCH"] !== "0";
|
|
770
|
+
if (batchingEnabled) {
|
|
771
|
+
const goFiles = [];
|
|
772
|
+
const pyFiles = [];
|
|
773
|
+
files.forEach((f, index) => {
|
|
774
|
+
if (f.lang === "go") goFiles.push({ ...f, index });
|
|
775
|
+
else if (f.lang === "py") pyFiles.push({ ...f, index });
|
|
776
|
+
});
|
|
777
|
+
if (goFiles.length > 0) {
|
|
778
|
+
await applyBatchResults(slots, goFiles, (chunks) => runGoBatch(chunks), "go");
|
|
779
|
+
}
|
|
780
|
+
if (pyFiles.length > 0) {
|
|
781
|
+
const pyBinary = await resolvePythonBinary();
|
|
782
|
+
if (pyBinary) {
|
|
783
|
+
await applyBatchResults(slots, pyFiles, (chunks) => runPyBatch(chunks, pyBinary), "py");
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
const jobs = [];
|
|
788
|
+
for (let i = 0; i < files.length; i++) {
|
|
789
|
+
if (slots[i].result !== null) continue;
|
|
790
|
+
const { file, content, lang } = files[i];
|
|
791
|
+
const slot = slots[i];
|
|
792
|
+
jobs.push(
|
|
793
|
+
(async () => {
|
|
794
|
+
try {
|
|
795
|
+
slot.result = await parseFileContent(file, content, lang);
|
|
796
|
+
} catch (err) {
|
|
797
|
+
slot.error = err instanceof Error ? err.message : String(err);
|
|
798
|
+
}
|
|
799
|
+
})()
|
|
800
|
+
);
|
|
801
|
+
}
|
|
802
|
+
await Promise.all(jobs);
|
|
803
|
+
return slots;
|
|
804
|
+
}
|
|
805
|
+
async function applyBatchResults(slots, batchFiles, runBatch, lang) {
|
|
806
|
+
for (const chunk of chunkBatchFiles(batchFiles)) {
|
|
807
|
+
let byFile = null;
|
|
808
|
+
try {
|
|
809
|
+
byFile = await runBatch(chunk);
|
|
810
|
+
} catch {
|
|
811
|
+
byFile = null;
|
|
812
|
+
}
|
|
813
|
+
if (!byFile) continue;
|
|
814
|
+
for (const item of chunk) {
|
|
815
|
+
const parsed = byFile.get(item.file);
|
|
816
|
+
if (!parsed) continue;
|
|
817
|
+
slots[item.index] = { result: withRelations(parsed, item.content, lang) };
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
async function dispatch(file, content, lang) {
|
|
822
|
+
switch (lang) {
|
|
823
|
+
case "ts":
|
|
824
|
+
case "tsx":
|
|
825
|
+
case "js":
|
|
826
|
+
case "jsx": {
|
|
827
|
+
const { parseSymbols } = await import("./ts-parser-YH4ZMWMH.js");
|
|
828
|
+
return parseSymbols({ file, content, lang });
|
|
829
|
+
}
|
|
830
|
+
case "go": {
|
|
831
|
+
const { parseSymbols } = await import("./go-parser-6CA77WZ4.js");
|
|
832
|
+
return parseSymbols({ file, content, lang: "go" });
|
|
833
|
+
}
|
|
834
|
+
case "py": {
|
|
835
|
+
const { parseSymbols } = await import("./py-parser-GPM5VYRG.js");
|
|
836
|
+
return parseSymbols({ file, content, lang: "py" });
|
|
837
|
+
}
|
|
838
|
+
case "rs": {
|
|
839
|
+
const { parseSymbols } = await import("./rs-parser-WVQ4KYCX.js");
|
|
840
|
+
return parseSymbols({ file, content, lang: "rs" });
|
|
841
|
+
}
|
|
842
|
+
case "json": {
|
|
843
|
+
const { parseSymbols } = await import("./json-parser-7YMDJSBJ.js");
|
|
844
|
+
return parseSymbols({ file, content, lang: "json" });
|
|
845
|
+
}
|
|
846
|
+
case "yaml": {
|
|
847
|
+
const { parseSymbols } = await import("./yaml-parser-GFAOKV53.js");
|
|
848
|
+
return parseSymbols({ file, content, lang: "yaml" });
|
|
849
|
+
}
|
|
850
|
+
// Phase 1: ten languages now route through the Tree-Sitter WASM
|
|
851
|
+
// universal parser (`tree-sitter-parser.ts`). The dispatch falls back to
|
|
852
|
+
// the regex extractor in `generic-parser.ts` whenever WASM loading fails
|
|
853
|
+
// or the parser returns zero symbols — preserving the indexable-file
|
|
854
|
+
// contract that "missing a parser must never mean skipping the file".
|
|
855
|
+
case "c":
|
|
856
|
+
case "cpp":
|
|
857
|
+
case "java":
|
|
858
|
+
case "csharp":
|
|
859
|
+
case "php":
|
|
860
|
+
case "ruby":
|
|
861
|
+
case "swift":
|
|
862
|
+
case "kotlin":
|
|
863
|
+
case "shell":
|
|
864
|
+
case "elixir": {
|
|
865
|
+
try {
|
|
866
|
+
const { parseSymbols: parseSymbols2 } = await import("./tree-sitter-parser-YCILHGZD.js");
|
|
867
|
+
const parsed = await parseSymbols2({ file, content, lang });
|
|
868
|
+
if (parsed.symbols.length > 0) return parsed;
|
|
869
|
+
} catch {
|
|
870
|
+
}
|
|
871
|
+
const { parseSymbols } = await import("./generic-parser-VUXDIAOZ.js");
|
|
872
|
+
return parseSymbols({ file, content, lang });
|
|
873
|
+
}
|
|
874
|
+
default: {
|
|
875
|
+
const { parseSymbols } = await import("./generic-parser-VUXDIAOZ.js");
|
|
876
|
+
return parseSymbols({ file, content, lang });
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
function withRelations(parsed, content, lang) {
|
|
881
|
+
let refs = parsed.refs ?? [];
|
|
882
|
+
if (refs.length === 0 && hasImportPatterns(lang)) {
|
|
883
|
+
refs = extractImports({ content, lang });
|
|
884
|
+
}
|
|
885
|
+
return { ...parsed, refs: refs.map((ref) => ref.lang ? ref : { ...ref, lang }) };
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
export {
|
|
889
|
+
parseFileContent,
|
|
890
|
+
parseFilesContent
|
|
891
|
+
};
|
|
892
|
+
//# sourceMappingURL=chunk-QHVW4AAM.js.map
|